Refactor orderBookingRoute to integrate subuser-specific permission checks

- Add dynamic authentication and subuser permission handling using `subusers_permission_node_key`.
- Refactor route-level permission logic for creating, viewing, editing, and deleting bookings to respect subuser context.
- Ensure proper error handling for unauthorized access and enforce departmental scope for admin-level actions.
This commit is contained in:
Jeppe Bundgaard
2026-02-12 15:37:03 +01:00
parent 497ef1496b
commit cd894b4e3b
@@ -36,6 +36,46 @@ class orderBookingRoute
$po = self::getTargetPo(); // String | Null $po = self::getTargetPo(); // String | Null
$pickup = self::getTargetPickup(); // Bool | Null $pickup = self::getTargetPickup(); // Bool | Null
$items = self::getTargetItems(); // Array of order_items_o objects $items = self::getTargetItems(); // Array of order_items_o objects
/**
* Authentication & Permissions
*/
$auth = new authentication();
$user = $auth->get_user(); // Classic user (may be false if a subuser token is used)
$permission_own = self::definePermission('add_own_bookings', subusers_permission_node_key::BOOKINGS_ADD); // Subuser-aware: can add for own customer only
$permission_other = self::definePermission('add_bookings'); // Admin/department scope: can add for any customer within permitted departments
$has_permission_own = self::hasPermission($permission_own);
$has_permission_other = self::hasPermission($permission_other);
$has_permission = false; // Updated below
// Own booking creation (either classic user for own customer or subuser with proper node on target customer)
if ($has_permission_own) {
$targetCustomer = (int)$customer_number->customer_number->value();
$subuser = $auth->get_subuser();
if ($subuser !== false) {
// For subusers ensure provided customer_number matches X-Customer-Number target context
$sub_target = $auth->get_subuser_customer_number_target();
if ((int)$sub_target !== $targetCustomer) {
$response->error('You do not have permission to create bookings for this customer.', 403);
}
$has_permission = true; // Node permission already validated via hasPermission above
} else {
// Classic user: ensure creating for own customer only in the "own" permission path
if ($user !== false && (int)$user->customer_number->value() === $targetCustomer) {
$has_permission = true;
}
}
}
// Department/admin booking creation for other customers
if (!$has_permission && $has_permission_other) {
// Must be within permitted department
self::requireDepartmentAccess((int)$department->id);
$has_permission = true;
}
if (!$has_permission) {
$response->error('You do not have permission to create this order booking.', 403);
}
/** /**
* Input data * Input data
*/ */
@@ -60,7 +100,8 @@ class orderBookingRoute
$response->success($order_bookings_o->asArray()); $response->success($order_bookings_o->asArray());
}, },
[ [
// No Permissions required. 'add_own_bookings' => 'Permission to create own order bookings. Subusers require node: BOOKINGS_ADD and X-Customer-Number header.',
'add_bookings' => 'Permission to create department order bookings.'
] ]
); );
@@ -74,7 +115,8 @@ class orderBookingRoute
/** /**
* Authentication * Authentication
*/ */
$user = (new authentication())->get_user(); $auth = new authentication();
$user = $auth->get_user();
/** /**
* Permissions * Permissions
*/ */
@@ -84,8 +126,20 @@ class orderBookingRoute
$has_permission_other = self::hasPermission($permission_other); $has_permission_other = self::hasPermission($permission_other);
$has_permission = false; // Updated below $has_permission = false; // Updated below
// Check if the user has permission to view their own bookings // Check if the user has permission to view their own bookings
if ($has_permission_own && (!$object || (int)$object->customer_number->value() === (int)$user->customer_number->value())) { if ($has_permission_own) {
$has_permission = true; if (!$object) {
$has_permission = true;
} else {
$subuser = $auth->get_subuser();
if ($subuser !== false) {
$sub_target = $auth->get_subuser_customer_number_target();
if ((int)$object->customer_number->value() === (int)$sub_target) {
$has_permission = true;
}
} elseif ($user !== false && (int)$object->customer_number->value() === (int)$user->customer_number->value()) {
$has_permission = true;
}
}
} }
// Check if the user has permission to view other users' bookings // Check if the user has permission to view other users' bookings
if (!$has_permission && $has_permission_other) { if (!$has_permission && $has_permission_other) {
@@ -145,7 +199,8 @@ class orderBookingRoute
/** /**
* Authentication * Authentication
*/ */
$user = (new authentication())->get_user(); $auth = new authentication();
$user = $auth->get_user();
/** /**
* Permissions * Permissions
*/ */
@@ -158,13 +213,23 @@ class orderBookingRoute
$has_permission_other = self::hasPermission($permission_other); $has_permission_other = self::hasPermission($permission_other);
$has_permission = false; // Updated below $has_permission = false; // Updated below
// Check if the user has permission to edit their own bookings // Check if the user has permission to edit their own bookings
if ($has_permission_own && (int)$object->customer_number->value() === (int)$user->customer_number->value()) { if ($has_permission_own) {
$isOwn = false;
$subuser = $auth->get_subuser();
if ($subuser !== false) {
$sub_target = $auth->get_subuser_customer_number_target();
$isOwn = ((int)$object->customer_number->value() === (int)$sub_target);
} elseif ($user !== false) {
$isOwn = ((int)$object->customer_number->value() === (int)$user->customer_number->value());
}
if ($isOwn) {
// Check if the booking has a transaction associated with it // Check if the booking has a transaction associated with it
// If this is the case, prevent user from editing the booking // If this is the case, prevent user from editing the booking
if (!$has_permission_other && $object->hasTransaction()) { if (!$has_permission_other && $object->hasTransaction()) {
$response->error('You cannot edit this order booking because it has a transaction associated with it.', 403); $response->error('You cannot edit this order booking because it has a transaction associated with it.', 403);
} }
$has_permission = true; $has_permission = true;
}
} }
// Check if the user has permission to edit other users' bookings // Check if the user has permission to edit other users' bookings
if (!$has_permission && $has_permission_other) { if (!$has_permission && $has_permission_other) {
@@ -217,7 +282,8 @@ class orderBookingRoute
/** /**
* Authentication * Authentication
*/ */
$user = (new authentication())->get_user(); $auth = new authentication();
$user = $auth->get_user();
/** /**
* Permissions * Permissions
*/ */
@@ -230,8 +296,16 @@ class orderBookingRoute
$has_permission_other = self::hasPermission($permission_other); $has_permission_other = self::hasPermission($permission_other);
$has_permission = false; // Updated below $has_permission = false; // Updated below
// Check if the user has permission to delete their own bookings // Check if the user has permission to delete their own bookings
if ($has_permission_own && (int)$object->customer_number->value() === (int)$user->customer_number->value()) { if ($has_permission_own) {
$has_permission = true; $subuser = $auth->get_subuser();
if ($subuser !== false) {
$sub_target = $auth->get_subuser_customer_number_target();
if ((int)$object->customer_number->value() === (int)$sub_target) {
$has_permission = true;
}
} elseif ($user !== false && (int)$object->customer_number->value() === (int)$user->customer_number->value()) {
$has_permission = true;
}
} }
// Check if the user has permission to delete other users' bookings // Check if the user has permission to delete other users' bookings
if (!$has_permission && $has_permission_other) { if (!$has_permission && $has_permission_other) {