Fix economic v2 invoice endpoint authorization scope
This commit is contained in:
@@ -13,6 +13,7 @@ use Exception;
|
||||
use objects\collected_order_invoices_o;
|
||||
use objects\customer_fixed_pricing_o;
|
||||
use objects\logs_o;
|
||||
use objects\orders_o;
|
||||
use objects\users_o;
|
||||
use traits\route_t;
|
||||
|
||||
@@ -1289,6 +1290,7 @@ class orderInvoicesRoute
|
||||
$warnings = [];
|
||||
$invoice = (new collected_order_invoices_o())->select($collected_invoice_id);
|
||||
$invoice->requireSelected();
|
||||
$this->requireCollectedInvoiceContextAccess($invoice);
|
||||
|
||||
$draft_id = null;
|
||||
$booked_id = null;
|
||||
@@ -1408,6 +1410,56 @@ class orderInvoicesRoute
|
||||
];
|
||||
}
|
||||
|
||||
private function requireCollectedInvoiceContextAccess(collected_order_invoices_o $invoice): void
|
||||
{
|
||||
global $response;
|
||||
|
||||
if ($this->hasPermission('superuser')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$invoice_customer_number = (int)$invoice->customer_number->value();
|
||||
if ($invoice_customer_number > 0 && $this->isOwnCustomerContext($invoice_customer_number)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->hasAccessToAllCollectedInvoiceDepartments((int)$invoice->id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$response->error('Permission denied for requested collected invoice.', 403);
|
||||
}
|
||||
|
||||
private function hasAccessToAllCollectedInvoiceDepartments(int $collected_invoice_id): bool
|
||||
{
|
||||
$orders = new orders_o();
|
||||
$order_departments = $orders->getFieldsWhere(
|
||||
[
|
||||
'invoice_collection_id' => $collected_invoice_id,
|
||||
'deleted_at' => null,
|
||||
],
|
||||
['department_id']
|
||||
);
|
||||
|
||||
$department_ids = array_values(array_unique(array_filter(array_map(static function (array $order): int {
|
||||
return (int)($order['department_id'] ?? 0);
|
||||
}, $order_departments), static function (int $department_id): bool {
|
||||
return $department_id > 0;
|
||||
})));
|
||||
|
||||
if (empty($department_ids)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($department_ids as $department_id) {
|
||||
if (!$this->hasDepartmentAccess((string)$department_id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function extractEconomicCustomerNumber(mixed $invoice_raw): ?int
|
||||
{
|
||||
if ($invoice_raw === null) {
|
||||
|
||||
@@ -66,3 +66,15 @@ it('keeps legacy compare endpoint path for backward compatibility', function ():
|
||||
expect($content)->toContain('/collected-invoices/economic/compare');
|
||||
expect($content)->toContain("requirePermission('compare_collected_invoice_economic')");
|
||||
});
|
||||
|
||||
it('enforces customer or department context before building v2 invoice details payload', function (): void {
|
||||
$routeFile = app_path('routes/orderInvoicesRoute.php');
|
||||
$content = file_get_contents($routeFile);
|
||||
|
||||
expect($content)->not->toBeFalse();
|
||||
expect($content)->toContain('private function requireCollectedInvoiceContextAccess');
|
||||
expect($content)->toContain('$this->requireCollectedInvoiceContextAccess($invoice);');
|
||||
expect($content)->toContain("$this->hasPermission('superuser')");
|
||||
expect($content)->toContain('$this->isOwnCustomerContext($invoice_customer_number)');
|
||||
expect($content)->toContain('$this->hasAccessToAllCollectedInvoiceDepartments((int)$invoice->id)');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user