Add economic V2 modules for history backfill, comparison, and distribution services.

This commit is contained in:
Jeppe Bundgaard
2026-03-12 17:57:27 +01:00
parent 72454ff328
commit 4ef20a1c90
25 changed files with 5328 additions and 23 deletions
+125 -2
View File
@@ -3,6 +3,7 @@
namespace routes;
use classes\authentication;
use classes\economic_v2_versioning_service;
use customers\economic_customer_mo;
use objects\bookings_o;
use objects\customer_vehicles_o;
@@ -180,6 +181,28 @@ class vehiclesRoute
$subscription ? 1 : 0,
$reference
);
try {
(new economic_v2_versioning_service())->recordVehicleSubscriptionVersion(
[
'vehicle_id' => (int)$vehicle->id,
'customer_number' => (int)$targetCustomer,
'reg' => (string)$reg,
'vehicle_type' => (int)$type,
'wash_subscription' => (bool)$subscription,
],
date('Y-m-d H:i:s'),
'live.vehicle.route',
1.0,
false,
[
'route' => '/vehicles',
'method' => 'POST',
'actor_user_id' => (int)($user->id ?? 0),
]
);
} catch (\Throwable $e) {
(new logs_o())->add('vehicles', 'global', 0, (int)($user->id ?? 0), 'ADD_VEHICLE_VERSIONING_FAILED', $e->getMessage());
}
(new logs_o())->add('vehicles', 'global', 1, (int)($user->id ?? 0), 'ADD_VEHICLE', 'Successfully added vehicle');
$response->success($vehicle->asArray());
@@ -204,6 +227,14 @@ class vehiclesRoute
(new logs_o())->add('vehicles', 'global', 1, (int)($user->id ?? 0), 'EDIT_VEHICLE', 'Vehicle not found');
$response->error('Vehicle not found', 404);
}
$before_state = [
'vehicle_id' => (int)$vehicle->id,
'customer_number' => (int)$vehicle->customer_id->value(),
'reg' => (string)$vehicle->reg->value(),
'vehicle_type' => (int)$vehicle->type->value(),
'wash_subscription' => (bool)$vehicle->wash_subscription->value(),
];
// Enforce access (own vs broader)
self::allowOwnOrDepartmentAccess(
$permission_own,
@@ -213,6 +244,22 @@ class vehiclesRoute
null,
'You are not allowed to edit vehicles from other users'
);
if (self::isParametersSet(['customer_id'])) {
$new_customer_number = (int)self::getParameter('customer_id');
self::requireType($new_customer_number, self::type_int());
self::requireMinValue($new_customer_number, 1);
self::requireMaxValue($new_customer_number, 9999999999);
// Require access for the destination customer context as well.
self::allowOwnOrDepartmentAccess(
$permission_own,
$permission_other,
$new_customer_number,
null,
null,
'You are not allowed to move vehicles to this customer'
);
$vehicle->customer_id->set($new_customer_number);
}
// Check all the fields, and if they are set, validate and set them
if (self::isParametersSet(['type'])) {
$type = (int)self::getParameter('type');
@@ -225,7 +272,6 @@ class vehiclesRoute
$vehicle->type->set(0);
// Turn off the subscription
$vehicle->wash_subscription->set(0);
return;
} else {
$products_o = new products_o();
$products_o->select((int)$type);
@@ -280,6 +326,61 @@ class vehiclesRoute
}
}
$vehicle->objectChanged();
$after_state = [
'vehicle_id' => (int)$vehicle->id,
'customer_number' => (int)$vehicle->customer_id->value(),
'reg' => (string)$vehicle->reg->value(),
'vehicle_type' => (int)$vehicle->type->value(),
'wash_subscription' => (bool)$vehicle->wash_subscription->value(),
];
$version_relevant_change = (
(int)$before_state['customer_number'] !== (int)$after_state['customer_number'] ||
(string)$before_state['reg'] !== (string)$after_state['reg'] ||
(int)$before_state['vehicle_type'] !== (int)$after_state['vehicle_type'] ||
(bool)$before_state['wash_subscription'] !== (bool)$after_state['wash_subscription']
);
if ($version_relevant_change) {
try {
$versioning = new economic_v2_versioning_service();
$effective_at = date('Y-m-d H:i:s');
$identity_changed = (
(int)$before_state['customer_number'] !== (int)$after_state['customer_number'] ||
(string)$before_state['reg'] !== (string)$after_state['reg']
);
if ($identity_changed) {
$versioning->closeActiveVehicleSubscriptionVersion(
(int)$before_state['customer_number'],
(string)$before_state['reg'],
$effective_at,
'live.vehicle.route',
1.0,
false,
[
'route' => '/vehicles',
'method' => 'PUT',
'actor_user_id' => (int)($user->id ?? 0),
'reason' => 'identity_change',
]
);
}
$versioning->recordVehicleSubscriptionVersion(
$after_state,
$effective_at,
'live.vehicle.route',
1.0,
false,
[
'route' => '/vehicles',
'method' => 'PUT',
'actor_user_id' => (int)($user->id ?? 0),
]
);
} catch (\Throwable $e) {
(new logs_o())->add('vehicles', 'global', 0, (int)($user->id ?? 0), 'EDIT_VEHICLE_VERSIONING_FAILED', $e->getMessage());
}
}
// Return the vehicle
$response->success($vehicle->asArray());
},
@@ -303,6 +404,11 @@ class vehiclesRoute
(new logs_o())->add('vehicles', 'global', 1, (int)($user->id ?? 0), 'DELETE_VEHICLE', 'Vehicle not found');
$response->error('Vehicle not found', 404);
}
$before_state = [
'customer_number' => (int)$vehicle->customer_id->value(),
'reg' => (string)$vehicle->reg->value(),
];
// Enforce access (own vs broader)
self::allowOwnOrDepartmentAccess(
$permission_own,
@@ -314,6 +420,23 @@ class vehiclesRoute
);
// Delete the vehicle
$vehicle->delete();
try {
(new economic_v2_versioning_service())->closeActiveVehicleSubscriptionVersion(
(int)$before_state['customer_number'],
(string)$before_state['reg'],
date('Y-m-d H:i:s'),
'live.vehicle.route',
1.0,
false,
[
'route' => '/vehicles',
'method' => 'DELETE',
'actor_user_id' => (int)($user->id ?? 0),
]
);
} catch (\Throwable $e) {
(new logs_o())->add('vehicles', 'global', 0, (int)($user->id ?? 0), 'DELETE_VEHICLE_VERSIONING_FAILED', $e->getMessage());
}
$response->success([
'success' => true,
'message' => 'Vehicle deleted successfully'
@@ -927,4 +1050,4 @@ class vehiclesRoute
$response->error('Notes are too long, they must be less than 250 characters', 400);
}
}
}
}