Resolve recommended-profile Critical and High findings, retain narrow analyzer exceptions, and update the edge-broker WebSocket dependency to a non-vulnerable release.
134 lines
6.0 KiB
PHP
134 lines
6.0 KiB
PHP
<?php
|
|
|
|
app_require('routes/InvoicingPeriodRoute.php');
|
|
|
|
use routes\InvoicingPeriodRoute;
|
|
|
|
it('requires superuser permission for invoicing period distribution all endpoint', function (): void {
|
|
$routeFile = app_path('routes/InvoicingPeriodRoute.php');
|
|
$content = file_get_contents($routeFile);
|
|
|
|
expect($content)->not->toBeFalse();
|
|
expect($content)->toMatch(
|
|
"/\\/superuser\\/invoicing\\/period\\/distribution\\/all'.*?\\\$this->requirePermission\\('superuser_invoicing_period'\\);/s"
|
|
);
|
|
});
|
|
|
|
it('uses shared date-range normalization across invoicing period endpoints', function (): void {
|
|
$routeFile = app_path('routes/InvoicingPeriodRoute.php');
|
|
$content = file_get_contents($routeFile);
|
|
|
|
expect($content)->not->toBeFalse();
|
|
expect(substr_count((string)$content, 'requireAndNormalizeDateRange()'))->toBeGreaterThanOrEqual(5);
|
|
});
|
|
|
|
it('keeps the main period response local-only for booked state and customer names', function (): void {
|
|
$routeFile = app_path('routes/InvoicingPeriodRoute.php');
|
|
$content = file_get_contents($routeFile);
|
|
|
|
expect($content)->not->toBeFalse();
|
|
$content = (string)$content;
|
|
|
|
expect($content)->not->toContain('isBooked(true)')
|
|
->and($content)->toContain('isTransactionBookedFromLocalState($transaction)')
|
|
->and($content)->toContain('SELECT booked_invoice_id FROM collected_order_invoices')
|
|
->and($content)->toContain('SELECT invoice_id FROM economic_module_orders')
|
|
->and($content)->toContain('getCustomerNames(array_keys($customer_numbers), false)')
|
|
->and($content)->toContain('getCustomerNames(array_map(\'intval\', $customer_numbers), false)');
|
|
});
|
|
|
|
it('streams the main period response instead of encoding the full payload at once', function (): void {
|
|
$routeFile = app_path('routes/InvoicingPeriodRoute.php');
|
|
$content = file_get_contents($routeFile);
|
|
|
|
expect($content)->not->toBeFalse();
|
|
$content = (string)$content;
|
|
|
|
expect($content)->toContain('private static function streamInvoicingPeriodResponse(array $period): void')
|
|
->and($content)->toContain("\$includeInvoicePeriodFlags = \$this->hasPermission('list_invoice_period_flags');")
|
|
->and($content)->toContain('$period = self::getInvoicingPeriod($dateFrom, $dateTo, $customerNumbers, $includeInvoicePeriodFlags);')
|
|
->and($content)->toContain('self::streamInvoicingPeriodResponse($period);')
|
|
->and($content)->not->toContain('$response->success([' . PHP_EOL . ' ...self::getInvoicingPeriod($dateFrom, $dateTo, $customerNumbers)')
|
|
->and($content)->toContain('echo self::jsonFragment($customer);');
|
|
});
|
|
|
|
it('only includes invoice period flags when the list permission is granted', function (): void {
|
|
$content = file_get_contents(app_path('routes/InvoicingPeriodRoute.php'));
|
|
|
|
expect($content)->not->toBeFalse();
|
|
$content = (string)$content;
|
|
|
|
expect($content)
|
|
->toContain("\$includeInvoicePeriodFlags = \$this->hasPermission('list_invoice_period_flags');")
|
|
->and($content)->toContain('bool $includeInvoicePeriodFlags = false')
|
|
->and($content)->toContain('if ($includeInvoicePeriodFlags) {')
|
|
->and($content)->toContain('applyFlagsToPeriodTypes(');
|
|
});
|
|
|
|
it('maps batched period transaction rows to the legacy transaction response shape', function (): void {
|
|
$reflection = new ReflectionClass(InvoicingPeriodRoute::class);
|
|
$method = $reflection->getMethod('constructTransactionObjectFromPeriodRow');
|
|
|
|
$transaction = $method->invokeArgs(null, [[
|
|
'id' => '42',
|
|
'created_at' => '2026-04-10 12:34:56',
|
|
'net_amount' => '123.50',
|
|
'booked' => '1',
|
|
'department_id' => '7',
|
|
'customer_id' => '27983',
|
|
'order_reference' => 'REF-42',
|
|
'order_po' => 'PO-42',
|
|
'order_notes' => 'Driver note',
|
|
'reg_1' => 'AB12345',
|
|
'reg_2' => 'CD67890',
|
|
'reg_3' => '',
|
|
'invoice_collection_id' => '314',
|
|
'include_in_invoice_effective' => '0',
|
|
]]);
|
|
|
|
expect($transaction)->toMatchArray([
|
|
'id' => 42,
|
|
'date' => '2026-04-10 12:34:56',
|
|
'amount' => 123.5,
|
|
'booked' => true,
|
|
'department_id' => 7,
|
|
'customer_number' => 27983,
|
|
'reference' => 'REF-42',
|
|
'po' => 'PO-42',
|
|
'notes' => 'Driver note',
|
|
'reg_1' => 'AB12345',
|
|
'reg_2' => 'CD67890',
|
|
'reg_3' => '',
|
|
'excluded' => true,
|
|
'invoice_collection_id' => 314,
|
|
'queue_status' => null,
|
|
'queue_job_id' => null,
|
|
]);
|
|
});
|
|
|
|
it('uses batched period transactions and keyed customer maps in the main period route', function (): void {
|
|
$content = file_get_contents(app_path('routes/InvoicingPeriodRoute.php'));
|
|
|
|
expect($content)->not->toBeFalse();
|
|
$content = (string)$content;
|
|
|
|
expect($content)->toContain('getPeriodTransactionsForCustomersInDateRange(')
|
|
->and($content)->toContain('private static function indexCustomersByNumber(array $customers): array')
|
|
->and($content)->toContain('$customers_by_number = self::indexCustomersByNumber($customersWithTransactions);')
|
|
->and($content)->toContain('invoicing_period_utils::filterPossibleDuplicates($ordersByRegistration, 86400)')
|
|
->and($content)->not->toContain('getOrdersWithPossibleDuplicates($dateFrom, $dateTo)');
|
|
});
|
|
|
|
it('falls back to configured e-conomic default department for missing customer default department in distributions', function (): void {
|
|
$content = file_get_contents(app_path('routes/InvoicingPeriodRoute.php'));
|
|
|
|
expect($content)->not->toBeFalse();
|
|
$content = (string)$content;
|
|
|
|
expect($content)
|
|
->toContain('private static function getEconomicFallbackDepartmentId(): int')
|
|
->and($content)->toContain('(new economic())->getDefaultDistributionDepartmentId()')
|
|
->and($content)->toContain(': self::getEconomicFallbackDepartmentId();')
|
|
->and($content)->toContain("\$department_totals[\$fallback_department_id] = (float)\$customer['meta']['fixed_pricing']['price'];");
|
|
});
|