From 82a3684f053017e930d4bdf32209328aef91a386 Mon Sep 17 00:00:00 2001 From: Jeppe B <2jepp9350@gmail.com> Date: Mon, 10 Aug 2026 20:33:10 +0200 Subject: [PATCH] fix(api): order getOrdersWithRegistrationNumberInDateRange by id ASC (#362) ## Summary orders_o::getOrdersWithRegistrationNumberInDateRange() selects orders matching a registration number within a date range without an explicit ORDER BY clause. MySQL is free to return rows in any order. The endpoint at routes/orderInvoicesRoute.php then iterates the result and calls assignToInvoiceCollection() on each row, so the audit-log + invoice-collection numbering depend on the arbitrary backend row order. Add a stable `ORDER BY id ASC` to the SELECT and pin the contract with a new Pest unit test. ## Test plan - New Pest test `OrdersRegistrationDateRangeQueryTest` asserts the SELECT still carries `ORDER BY id ASC`. - Existing tests in the same file still pass unchanged (they don't assert on ordering). - Manual php -l on both modified files shows no syntax errors. ## Commits - bbd50239 fix(api): order getOrdersWithRegistrationNumberInDateRange by id ASC Co-authored-by: Worktree Fix Verifier --- services/nginx/app/objects/orders_o.php | 3 ++- .../OrdersRegistrationDateRangeQueryTest.php | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/services/nginx/app/objects/orders_o.php b/services/nginx/app/objects/orders_o.php index a039d3dd..ef54330d 100644 --- a/services/nginx/app/objects/orders_o.php +++ b/services/nginx/app/objects/orders_o.php @@ -2207,7 +2207,8 @@ class orders_o extends db $sql = "SELECT id FROM $this->table WHERE (UPPER(TRIM(reg_1)) = '$reg' OR UPPER(TRIM(reg_2)) = '$reg' OR UPPER(TRIM(reg_3)) = '$reg') AND created_at BETWEEN '$from_date' AND '$to_date' - AND deleted_at IS NULL"; + AND deleted_at IS NULL + ORDER BY id ASC"; $result = $db->query($sql); if ($result->num_rows === 0) { return []; // No orders found with the registration number in the date range diff --git a/services/nginx/app/tests/Unit/Orders/OrdersRegistrationDateRangeQueryTest.php b/services/nginx/app/tests/Unit/Orders/OrdersRegistrationDateRangeQueryTest.php index 3a2ff650..81a29236 100644 --- a/services/nginx/app/tests/Unit/Orders/OrdersRegistrationDateRangeQueryTest.php +++ b/services/nginx/app/tests/Unit/Orders/OrdersRegistrationDateRangeQueryTest.php @@ -126,3 +126,26 @@ it('returns early when registration number is blank', function (): void { } } }); + +it('orders registration-matched orders by id ASC so invoice-collection reassignment is deterministic', function (): void { + $dbStub = new OrdersRegistrationDateRangeDbStub(); + $hadDb = array_key_exists('db', $GLOBALS); + $previousDb = $hadDb ? $GLOBALS['db'] : null; + $GLOBALS['db'] = $dbStub; + + try { + (new orders_o())->getOrdersWithRegistrationNumberInDateRange( + 'EC21235', + '2025-03-01 00:00:00', + '2025-04-30 23:59:59' + ); + + expect($dbStub->lastQuery)->toContain('ORDER BY id ASC'); + } finally { + if ($hadDb) { + $GLOBALS['db'] = $previousDb; + } else { + unset($GLOBALS['db']); + } + } +});