Add unit tests for InvoicingPeriodDraftOverlay and reference suggestion logic, including fake DB integration and aggregation methods

- Implemented `InvoicingPeriodDraftOverlayTest` with coverage for blocking and permitting invoicing actions based on draft states, transactions, and metadata.
- Created `ReferenceSuggestionsApiTest` to validate ranked and filtered suggestions across bookings, orders, and vehicles with varied match relevance, context, and frequency.
- Added `order_reference_suggestions_service` class, including query methods, normalization utilities, and aggregation logic for reference suggestions.
- Enhanced query handling in `InvoicingPeriodDraftOverlayFakeDb` to validate SQL constraints and column cache resets in overlapping invoicing contexts.
This commit is contained in:
Jeppe Bundgaard
2026-05-11 18:18:08 +02:00
parent bea7e5697b
commit 6d4066be1c
26 changed files with 2563 additions and 43 deletions
+47
View File
@@ -7,6 +7,7 @@ use classes\attachment_store;
use classes\attachments;
use classes\authentication;
use classes\economic;
use classes\order_reference_suggestions_service;
use classes\orders_input_normalizer;
use classes\response;
use classes\stripe;
@@ -28,6 +29,52 @@ class ordersRoute
public function run(): void
{
$this->get('/orders/reference-suggestions', function () {
global $response;
$auth = new authentication();
$user = $auth->get_user();
if ($user === false) {
(new logs_o())->add('orders', 'global', 1, 0, 'LIST_ORDER_REFERENCE_SUGGESTIONS', 'No user found, or invalid session');
$response->error('Invalid session', 400);
}
$this->requirePermission('list_orders');
self::requireParameters(['department_id']);
$departmentId = (int)self::getParameter('department_id');
self::requireParameterIntPositive($departmentId, 'department_id');
self::requireDepartmentAccess((string)$departmentId);
$search = trim((string)(self::getParameter('search') ?? ''));
if (strlen($search) > 255) {
$response->error('Parameter search must be at most 255 characters long', 400);
}
foreach (['reg_1', 'reg_2', 'reg_3'] as $plateParameter) {
$plateValue = (string)(self::getParameter($plateParameter) ?? '');
if (strlen($plateValue) > 32) {
$response->error('Parameter ' . $plateParameter . ' must be at most 32 characters long', 400);
}
}
$suggestions = (new order_reference_suggestions_service())->suggest([
'search' => $search,
'department_id' => $departmentId,
'customer_id' => self::getParameter('customer_id') ?? null,
'reg_1' => self::getParameter('reg_1') ?? '',
'reg_2' => self::getParameter('reg_2') ?? '',
'reg_3' => self::getParameter('reg_3') ?? '',
'limit' => self::getParameter('limit') ?? null,
]);
(new logs_o())->add('orders', (string)$departmentId, 1, (int)$user->id, 'LIST_ORDER_REFERENCE_SUGGESTIONS', 'Successfully listed POS reference suggestions');
$response->success($suggestions);
},
[
'list_orders' => 'List POS order reference suggestions',
'department_access_:id' => 'Access to the department used for reference suggestions',
]
);
$this->get('/orders', function () {
// Require the user to be logged in
global $response;