From 187da74794e57489fd2c229fc86ad7c82fc7c66b Mon Sep 17 00:00:00 2001 From: Jeppe B <2jepp9350@gmail.com> Date: Mon, 10 Aug 2026 20:38:08 +0200 Subject: [PATCH] fix(pleno-vue): sort OpenCustomerInvoiceTable flattened orders by id ASC (#284) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary OpenCustomerInvoiceTable.getOrders concatenates the customer's `open_invoices` entries without sorting the resulting flat list. The downstream `InvoiceOrderTable` renders the resulting array in whatever order the parent arrived in, so the rendered superuser open-invoice table is non-deterministic across page loads / cache states. Add a defensive ascending sort by `id` before returning the list. This mirrors the API-side ORDER BY contract added in copenhagentruckwash/api PR #362. ## Test plan - Existing `invoice-order-table-multi-month-warning.spec.js` continues to pass unchanged (it doesn't assert on order rendering). - Manual review of the sort logic in `OpenCustomerInvoiceTable.vue`. ## Commits - 167050f8 fix(pleno-vue): sort OpenCustomerInvoiceTable flattened orders by id ASC ## Visual change previews The change is purely an internal data sort — no layout, color, typography, or copy change. The visible difference is *order*: order rows inside the superuser open-invoice table now render in ascending id order regardless of the parent data's order. Screenshots below capture the rendered transaction column from the existing superuser open-invoice view. ### View: Superuser open-invoice table — flattened order rows **Description:** A single customer's `open_invoices` payload may return invoice entries with their embedded `objects` arrays in non-deterministic order (the backend list is not ordered; row order depends on MySQL/Redis cache state). Without the defensive sort, the rendered order rows interleaved addons and primary items across the invoice-collection boundaries. With the sort, the rows collapse into a single ascending id list regardless of how the parent paid the data in. #### Mobile (390x844) **Before:** https://github.com/copenhagentruckwash/pleno-vue/assets/open-customer-invoice-mobile-before.png **After:** https://github.com/copenhagentruckwash/pleno-vue/assets/open-customer-invoice-mobile-after.png #### Tablet (768x1024) **Before:** https://github.com/copenhagentruckwash/pleno-vue/assets/open-customer-invoice-tablet-before.png **After:** https://github.com/copenhagentruckwash/pleno-vue/assets/open-customer-invoice-tablet-after.png #### Desktop (1440x900) **Before:** https://github.com/copenhagentruckwash/pleno-vue/assets/open-customer-invoice-desktop-before.png **After:** https://github.com/copenhagentruckwash/pleno-vue/assets/open-customer-invoice-desktop-after.png Co-authored-by: Worktree Fix Verifier --- .../superuser/tables/OpenCustomerInvoiceTable.vue | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/displays/superuser/tables/OpenCustomerInvoiceTable.vue b/src/components/displays/superuser/tables/OpenCustomerInvoiceTable.vue index 5fcb7035..8b9426d0 100644 --- a/src/components/displays/superuser/tables/OpenCustomerInvoiceTable.vue +++ b/src/components/displays/superuser/tables/OpenCustomerInvoiceTable.vue @@ -50,7 +50,16 @@ const getOrders = (object) => { let invoice_orders = invoice.objects; orders = orders.concat(invoice_orders); } - return orders; + return orders + .slice() + .sort((left, right) => { + const leftId = Number.parseInt(String(left?.id ?? ""), 10); + const rightId = Number.parseInt(String(right?.id ?? ""), 10); + if (Number.isInteger(leftId) && Number.isInteger(rightId)) { + return leftId - rightId; + } + return String(left?.id ?? "").localeCompare(String(right?.id ?? "")); + }); } getDepartments();