@fleetbase/fleetops-engine 0.6.49 → 0.6.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/addon/components/customer/create-order-form.hbs +2 -2
- package/addon/components/customer/form.hbs +2 -2
- package/addon/components/customer/order-form.hbs +2 -2
- package/addon/components/customer/orders.hbs +2 -2
- package/addon/components/display-place.hbs +2 -2
- package/addon/components/map/google-live-map.js +6 -2
- package/addon/components/map/leaflet-live-map.hbs +48 -14
- package/addon/components/map/leaflet-live-map.js +184 -20
- package/addon/components/modals/order-change-destination.hbs +46 -0
- package/addon/components/modals/order-change-destination.js +106 -0
- package/addon/components/modals/stop-activity.hbs +28 -0
- package/addon/components/modals/stop-activity.js +52 -0
- package/addon/components/modals/update-order-activity.hbs +45 -3
- package/addon/components/modals/update-order-activity.js +143 -5
- package/addon/components/orchestrator/resource-panel.hbs +0 -10
- package/addon/components/orchestrator/resource-panel.js +2 -4
- package/addon/components/order/activity-list.hbs +2 -2
- package/addon/components/order/activity-timeline.hbs +31 -29
- package/addon/components/order/details/activity.hbs +3 -3
- package/addon/components/order/details/activity.js +11 -0
- package/addon/components/order/details/documents.js +2 -0
- package/addon/components/order/details/purchase-rate.hbs +2 -2
- package/addon/components/order/details/route.hbs +11 -3
- package/addon/components/order/details/route.js +91 -14
- package/addon/components/order/details/tracking.hbs +101 -72
- package/addon/components/order/details/tracking.js +149 -2
- package/addon/components/order/form/details.hbs +3 -3
- package/addon/components/order/form/documents.js +11 -4
- package/addon/components/order/form/route.hbs +108 -104
- package/addon/components/order/form/route.js +37 -1
- package/addon/components/order/form/service-rate.hbs +2 -2
- package/addon/components/order-config-manager/activity-flow.hbs +4 -1
- package/addon/components/order-config-manager/activity-flow.js +178 -12
- package/addon/components/place/address.js +1 -1
- package/addon/components/route-list.hbs +17 -17
- package/addon/components/route-list.js +42 -10
- package/addon/components/service-rate/details.hbs +41 -0
- package/addon/components/service-rate/form.hbs +118 -0
- package/addon/components/service-rate/form.js +55 -0
- package/addon/components/vehicle/form.js +1 -1
- package/addon/components/vehicle/pill.hbs +1 -1
- package/addon/controllers/management/vehicles/index/new.js +1 -1
- package/addon/controllers/operations/orders/index/details.js +4 -4
- package/addon/controllers/operations/orders/index.js +14 -0
- package/addon/helpers/place-address-html.js +2 -2
- package/addon/routes/operations/service-rates/index.js +1 -1
- package/addon/services/geofence.js +163 -19
- package/addon/services/leaflet-contextmenu-manager.js +27 -0
- package/addon/services/vehicle-actions.js +1 -1
- package/addon/styles/fleetops-engine.css +91 -1
- package/addon/utils/fleet-ops-options.js +2 -1
- package/addon/utils/normalize-order-config-flow.js +41 -0
- package/addon/utils/place-address-html.js +3 -2
- package/addon/utils/route-visualization.js +54 -7
- package/app/components/modals/order-change-destination.js +1 -0
- package/app/components/modals/stop-activity.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +3 -3
- package/server/migrations/2026_05_21_000001_add_geographic_rules_to_service_rate_fees_table.php +37 -0
- package/server/migrations/2026_05_25_000001_add_endpoint_tracking_refs_to_payloads_table.php +50 -0
- package/server/migrations/2026_05_27_000001_default_driver_vehicle_statuses_to_available.php +48 -0
- package/server/resources/views/labels/default.php +57 -49
- package/server/resources/views/labels/waypoint-label.php +27 -20
- package/server/seeders/Testing/ConnectivitySeeder.php +1 -0
- package/server/seeders/Testing/FleetSeeder.php +22 -22
- package/server/seeders/Testing/OrdersSeeder.php +6 -22
- package/server/seeders/Testing/VroomOrchestrationSeeder.php +21 -21
- package/server/src/Console/Commands/AuditCustomerUserConflicts.php +75 -0
- package/server/src/Exceptions/CustomerUserConflictException.php +13 -0
- package/server/src/Http/Controllers/Api/v1/ContactController.php +17 -2
- package/server/src/Http/Controllers/Api/v1/CustomerController.php +876 -0
- package/server/src/Http/Controllers/Api/v1/DriverController.php +1 -1
- package/server/src/Http/Controllers/Api/v1/OrderConfigController.php +54 -0
- package/server/src/Http/Controllers/Api/v1/OrderController.php +98 -70
- package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +2 -2
- package/server/src/Http/Controllers/Api/v1/VehicleController.php +20 -3
- package/server/src/Http/Controllers/Internal/v1/ContactController.php +19 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +101 -66
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +429 -26
- package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +1 -1
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +2 -2
- package/server/src/Http/Controllers/Internal/v1/VehicleController.php +54 -1
- package/server/src/Http/Middleware/AuthenticateCustomerToken.php +34 -0
- package/server/src/Http/Requests/CreateCustomerOrderRequest.php +63 -0
- package/server/src/Http/Requests/CreateCustomerRequest.php +48 -0
- package/server/src/Http/Requests/CreateDriverRequest.php +1 -1
- package/server/src/Http/Requests/CreateVehicleRequest.php +25 -1
- package/server/src/Http/Requests/Internal/CreateDriverRequest.php +1 -1
- package/server/src/Http/Requests/VerifyCreateCustomerRequest.php +29 -0
- package/server/src/Http/Resources/Internal/v1/OrderConfig.php +41 -0
- package/server/src/Http/Resources/v1/Customer.php +79 -0
- package/server/src/Http/Resources/v1/OrderConfig.php +74 -0
- package/server/src/Http/Resources/v1/Payload.php +23 -20
- package/server/src/Http/Resources/v1/ServiceArea.php +33 -19
- package/server/src/Http/Resources/v1/ServiceRateFee.php +7 -0
- package/server/src/Listeners/HandleOrderDispatched.php +2 -2
- package/server/src/Models/Contact.php +92 -15
- package/server/src/Models/Customer.php +64 -0
- package/server/src/Models/Driver.php +12 -3
- package/server/src/Models/Entity.php +2 -2
- package/server/src/Models/Order.php +29 -4
- package/server/src/Models/Payload.php +17 -1
- package/server/src/Models/ServiceRate.php +273 -1
- package/server/src/Models/ServiceRateFee.php +39 -9
- package/server/src/Models/TrackingNumber.php +8 -2
- package/server/src/Models/Vehicle.php +18 -2
- package/server/src/Models/Waypoint.php +2 -2
- package/server/src/Notifications/LateDeparture.php +2 -2
- package/server/src/Notifications/ProlongedStoppage.php +2 -2
- package/server/src/Notifications/RouteDeviation.php +2 -2
- package/server/src/Observers/ContactObserver.php +2 -0
- package/server/src/Observers/ServiceRateObserver.php +6 -6
- package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +1 -1
- package/server/src/Providers/FleetOpsServiceProvider.php +1 -0
- package/server/src/Support/Analytics/AbstractAnalytics.php +6 -6
- package/server/src/Support/Analytics/FuelEfficiency.php +2 -2
- package/server/src/Support/Analytics/OrdersByStatus.php +1 -1
- package/server/src/Support/Analytics/RevenueTrend.php +0 -1
- package/server/src/Support/Analytics/TopDrivers.php +1 -1
- package/server/src/Support/CustomerAuth.php +98 -0
- package/server/src/Support/LabelPdf.php +52 -0
- package/server/src/Support/Metrics/AbstractMetric.php +4 -4
- package/server/src/Support/ResolvesOrderServiceStops.php +512 -0
- package/server/src/Tracking/TrackingContextBuilder.php +41 -38
- package/server/src/Tracking/TrackingIntelligenceService.php +109 -9
- package/server/src/Tracking/TrackingStop.php +13 -11
- package/server/src/routes.php +43 -9
- package/server/tests/CapacityAllocationEngineTest.php +10 -10
- package/server/tests/CustomerContactIdentitySafetyTest.php +54 -0
- package/server/tests/CustomerEndpointTest.php +199 -0
- package/server/tests/DriverVehicleStatusDefaultTest.php +39 -0
- package/server/tests/LabelPdfRenderingTest.php +23 -0
- package/server/tests/LiveControllerViewportTest.php +60 -0
- package/server/tests/MetricsRegistryTest.php +4 -8
- package/server/tests/OrchestrationPayloadBuilderTest.php +2 -2
- package/server/tests/OrderConfigEndpointTest.php +86 -0
- package/server/tests/OrderFileAttachmentTest.php +20 -0
- package/server/tests/ServiceAreaZoneApiShapeTest.php +34 -0
- package/server/tests/VehicleDriverAssignmentTest.php +18 -0
- package/translations/en-us.yaml +1 -0
- package/server/migrations/2026_05_13_000001_repair_customer_contact_user_types.php +0 -86
|
@@ -257,7 +257,7 @@ class VroomOrchestrationSeeder extends Seeder
|
|
|
257
257
|
'model' => $vehicle['model'],
|
|
258
258
|
'year' => '2024',
|
|
259
259
|
'type' => 'van',
|
|
260
|
-
'status' => '
|
|
260
|
+
'status' => 'available',
|
|
261
261
|
'online' => true,
|
|
262
262
|
'location' => isset($vehicle['lat'], $vehicle['lng']) ? new Point($vehicle['lat'], $vehicle['lng']) : null,
|
|
263
263
|
'skills' => $vehicle['skills'] ?? [],
|
|
@@ -287,22 +287,22 @@ class VroomOrchestrationSeeder extends Seeder
|
|
|
287
287
|
$orders = [
|
|
288
288
|
'endpoint_only' => [
|
|
289
289
|
'payload_seed_id' => 'endpoint_only',
|
|
290
|
-
'name'
|
|
291
|
-
'pickup'
|
|
292
|
-
'dropoff'
|
|
293
|
-
'waypoints'
|
|
294
|
-
'entities'
|
|
290
|
+
'name' => 'VROOM Test Order - Pickup Dropoff',
|
|
291
|
+
'pickup' => $places['depot'],
|
|
292
|
+
'dropoff' => $places['orchard'],
|
|
293
|
+
'waypoints' => [],
|
|
294
|
+
'entities' => [
|
|
295
295
|
['name' => 'Small carton', 'type' => 'parcel', 'weight' => 12, 'weight_unit' => 'kg', 'length' => 60, 'width' => 40, 'height' => 35, 'dimensions_unit' => 'cm'],
|
|
296
296
|
['name' => 'Fragile tote', 'type' => 'parcel', 'weight' => 8, 'weight_unit' => 'kg', 'length' => 50, 'width' => 35, 'height' => 30, 'dimensions_unit' => 'cm'],
|
|
297
297
|
],
|
|
298
298
|
],
|
|
299
299
|
'waypoint_only' => [
|
|
300
300
|
'payload_seed_id' => 'waypoint_only',
|
|
301
|
-
'name'
|
|
302
|
-
'pickup'
|
|
303
|
-
'dropoff'
|
|
304
|
-
'waypoints'
|
|
305
|
-
'entities'
|
|
301
|
+
'name' => 'VROOM Test Order - Waypoints Only',
|
|
302
|
+
'pickup' => null,
|
|
303
|
+
'dropoff' => null,
|
|
304
|
+
'waypoints' => [$places['rochor'], $places['novena'], $places['serangoon']],
|
|
305
|
+
'entities' => [
|
|
306
306
|
['name' => 'Multi-stop parcel 1', 'type' => 'parcel', 'weight' => 25, 'weight_unit' => 'kg', 'length' => 80, 'width' => 50, 'height' => 40, 'dimensions_unit' => 'cm'],
|
|
307
307
|
['name' => 'Multi-stop parcel 2', 'type' => 'parcel', 'weight' => 18, 'weight_unit' => 'kg', 'length' => 70, 'width' => 45, 'height' => 35, 'dimensions_unit' => 'cm'],
|
|
308
308
|
['name' => 'Multi-stop parcel 3', 'type' => 'parcel', 'weight' => 15, 'weight_unit' => 'kg', 'length' => 65, 'width' => 40, 'height' => 35, 'dimensions_unit' => 'cm'],
|
|
@@ -310,22 +310,22 @@ class VroomOrchestrationSeeder extends Seeder
|
|
|
310
310
|
],
|
|
311
311
|
'mixed' => [
|
|
312
312
|
'payload_seed_id' => 'mixed',
|
|
313
|
-
'name'
|
|
314
|
-
'pickup'
|
|
315
|
-
'dropoff'
|
|
316
|
-
'waypoints'
|
|
317
|
-
'entities'
|
|
313
|
+
'name' => 'VROOM Test Order - Mixed Stops',
|
|
314
|
+
'pickup' => $places['depot'],
|
|
315
|
+
'dropoff' => $places['changi'],
|
|
316
|
+
'waypoints' => [$places['paya_lebar'], $places['tampines']],
|
|
317
|
+
'entities' => [
|
|
318
318
|
['name' => 'Heavy equipment crate', 'type' => 'freight', 'weight' => 180, 'weight_unit' => 'kg', 'length' => 120, 'width' => 80, 'height' => 90, 'dimensions_unit' => 'cm'],
|
|
319
319
|
['name' => 'Accessory box', 'type' => 'parcel', 'weight' => 22, 'weight_unit' => 'kg', 'length' => 75, 'width' => 55, 'height' => 45, 'dimensions_unit' => 'cm'],
|
|
320
320
|
],
|
|
321
321
|
],
|
|
322
322
|
'single_waypoint' => [
|
|
323
323
|
'payload_seed_id' => 'single_waypoint',
|
|
324
|
-
'name'
|
|
325
|
-
'pickup'
|
|
326
|
-
'dropoff'
|
|
327
|
-
'waypoints'
|
|
328
|
-
'entities'
|
|
324
|
+
'name' => 'VROOM Test Order - Single Waypoint',
|
|
325
|
+
'pickup' => null,
|
|
326
|
+
'dropoff' => null,
|
|
327
|
+
'waypoints' => [$places['woodlands']],
|
|
328
|
+
'entities' => [
|
|
329
329
|
['name' => 'Oversized sample case', 'type' => 'parcel', 'weight' => 60, 'weight_unit' => 'kg', 'length' => 100, 'width' => 60, 'height' => 60, 'dimensions_unit' => 'cm'],
|
|
330
330
|
],
|
|
331
331
|
],
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Console\Commands;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\FleetOps\Models\Contact;
|
|
6
|
+
use Illuminate\Console\Command;
|
|
7
|
+
|
|
8
|
+
class AuditCustomerUserConflicts extends Command
|
|
9
|
+
{
|
|
10
|
+
protected $signature = 'fleetops:audit-customer-user-conflicts {--company= : Limit audit to a company UUID} {--json : Output JSON instead of a table}';
|
|
11
|
+
|
|
12
|
+
protected $description = 'Reports customer contacts linked to users that may have been incorrectly promoted from staff/admin accounts.';
|
|
13
|
+
|
|
14
|
+
public function handle(): int
|
|
15
|
+
{
|
|
16
|
+
$query = Contact::where('type', 'customer')->whereNotNull('user_uuid')->with(['anyUser.companyUsers.roles', 'company']);
|
|
17
|
+
|
|
18
|
+
if ($company = $this->option('company')) {
|
|
19
|
+
$query->where('company_uuid', $company);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
$rows = $query->get()->map(function (Contact $contact) {
|
|
23
|
+
$user = $contact->anyUser;
|
|
24
|
+
$companyUser = $user?->companyUsers?->firstWhere('company_uuid', $contact->company_uuid);
|
|
25
|
+
$roles = $companyUser?->roles?->pluck('name')->filter()->values()->all() ?? [];
|
|
26
|
+
$unexpected = array_values(array_filter($roles, fn ($role) => $role !== 'Fleet-Ops Customer'));
|
|
27
|
+
$reasons = [];
|
|
28
|
+
|
|
29
|
+
if (!$user) {
|
|
30
|
+
$reasons[] = 'missing linked user';
|
|
31
|
+
} elseif ($user->type !== 'customer') {
|
|
32
|
+
$reasons[] = 'linked user type is ' . $user->type;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!empty($unexpected)) {
|
|
36
|
+
$reasons[] = 'linked user has non-customer roles: ' . implode(', ', $unexpected);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (empty($reasons)) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return [
|
|
44
|
+
'contact_id' => $contact->public_id,
|
|
45
|
+
'contact_uuid' => $contact->uuid,
|
|
46
|
+
'contact_name' => $contact->name,
|
|
47
|
+
'contact_email' => $contact->email,
|
|
48
|
+
'user_uuid' => $user?->uuid,
|
|
49
|
+
'user_email' => $user?->email,
|
|
50
|
+
'user_type' => $user?->type,
|
|
51
|
+
'roles' => implode(', ', $roles),
|
|
52
|
+
'company_uuid' => $contact->company_uuid,
|
|
53
|
+
'company_name' => $contact->company?->name,
|
|
54
|
+
'updated_at' => optional($contact->updated_at)->toDateTimeString(),
|
|
55
|
+
'reason' => implode('; ', $reasons),
|
|
56
|
+
];
|
|
57
|
+
})->filter()->values();
|
|
58
|
+
|
|
59
|
+
if ($this->option('json')) {
|
|
60
|
+
$this->line($rows->toJson(JSON_PRETTY_PRINT));
|
|
61
|
+
|
|
62
|
+
return self::SUCCESS;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if ($rows->isEmpty()) {
|
|
66
|
+
$this->info('No suspicious customer user conflicts found.');
|
|
67
|
+
|
|
68
|
+
return self::SUCCESS;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
$this->table(array_keys($rows->first()), $rows->all());
|
|
72
|
+
|
|
73
|
+
return self::SUCCESS;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Exceptions;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Models\User;
|
|
6
|
+
|
|
7
|
+
class CustomerUserConflictException extends UserAlreadyExistsException
|
|
8
|
+
{
|
|
9
|
+
public function __construct(string $message = '', ?User $user = null, int $code = 0, ?\Throwable $previous = null)
|
|
10
|
+
{
|
|
11
|
+
parent::__construct($message, $user, $code, $previous);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -39,6 +39,10 @@ class ContactController extends Controller
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
try {
|
|
42
|
+
$contactCandidate = new Contact($input);
|
|
43
|
+
$contactCandidate->company_uuid = session('company');
|
|
44
|
+
$contactCandidate->assertCustomerIdentityIsAvailable();
|
|
45
|
+
|
|
42
46
|
// create the contact
|
|
43
47
|
$contact = Contact::updateOrCreate(
|
|
44
48
|
[
|
|
@@ -106,8 +110,19 @@ class ContactController extends Controller
|
|
|
106
110
|
}
|
|
107
111
|
}
|
|
108
112
|
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
try {
|
|
114
|
+
// update the contact
|
|
115
|
+
$contactCandidate = $contact->replicate();
|
|
116
|
+
$contactCandidate->forceFill($contact->getAttributes());
|
|
117
|
+
$contactCandidate->exists = $contact->exists;
|
|
118
|
+
$contactCandidate->forceFill($input);
|
|
119
|
+
$contactCandidate->assertCustomerIdentityIsAvailable();
|
|
120
|
+
|
|
121
|
+
$contact->update($input);
|
|
122
|
+
} catch (\Exception $e) {
|
|
123
|
+
return response()->apiError($e->getMessage());
|
|
124
|
+
}
|
|
125
|
+
|
|
111
126
|
$contact->flushAttributesCache();
|
|
112
127
|
|
|
113
128
|
// response the contact resource
|