@fleetbase/fleetops-engine 0.6.47 → 0.6.49

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.
Files changed (223) hide show
  1. package/addon/components/admin/routing-settings.hbs +71 -0
  2. package/addon/components/admin/routing-settings.js +124 -0
  3. package/addon/components/customer/orders.js +1 -1
  4. package/addon/components/display-place.hbs +1 -1
  5. package/addon/components/driver/details.hbs +5 -1
  6. package/addon/components/driver/form.hbs +11 -1
  7. package/addon/components/fleet-listing-panel.hbs +2 -2
  8. package/addon/components/fleet-listing-panel.js +10 -0
  9. package/addon/components/map/google-live-map.js +12 -73
  10. package/addon/components/map/leaflet-live-map.hbs +149 -33
  11. package/addon/components/map/order-list-overlay/order.hbs +18 -3
  12. package/addon/components/map/toolbar.hbs +2 -2
  13. package/addon/components/map/toolbar.js +10 -2
  14. package/addon/components/orchestrator/phase-builder.hbs +49 -5
  15. package/addon/components/orchestrator/phase-builder.js +34 -1
  16. package/addon/components/orchestrator/resource-panel.hbs +19 -1
  17. package/addon/components/orchestrator/resource-panel.js +4 -0
  18. package/addon/components/orchestrator-workbench.js +4 -1
  19. package/addon/components/order/details/purchase-rate.hbs +19 -22
  20. package/addon/components/order/details/route.hbs +26 -1
  21. package/addon/components/order/details/route.js +50 -0
  22. package/addon/components/order/details/tracking.hbs +171 -27
  23. package/addon/components/order/details/tracking.js +457 -0
  24. package/addon/components/order/form.hbs +2 -2
  25. package/addon/components/order/kanban-card.hbs +18 -3
  26. package/addon/components/order-list-overlay/order.hbs +18 -3
  27. package/addon/components/order-progress-card.hbs +21 -6
  28. package/addon/components/order-tracking-lookup.hbs +7 -7
  29. package/addon/components/order-tracking-lookup.js +1 -1
  30. package/addon/components/route-list.hbs +78 -8
  31. package/addon/components/route-list.js +48 -6
  32. package/addon/components/tracking-stop-progress.hbs +45 -0
  33. package/addon/components/tracking-stop-progress.js +79 -0
  34. package/addon/components/widget/fleet-ops-key-metrics.hbs +19 -17
  35. package/addon/components/widget/fleet-ops-key-metrics.js +26 -0
  36. package/addon/components/widget/fuel-efficiency.hbs +26 -0
  37. package/addon/components/widget/fuel-efficiency.js +43 -0
  38. package/addon/components/widget/geofence-violations.hbs +44 -0
  39. package/addon/components/widget/geofence-violations.js +55 -0
  40. package/addon/components/widget/issues-insights.hbs +43 -0
  41. package/addon/components/widget/issues-insights.js +62 -0
  42. package/addon/components/widget/kpi-active-orders.hbs +10 -0
  43. package/addon/components/widget/kpi-active-orders.js +5 -0
  44. package/addon/components/widget/kpi-aov.hbs +10 -0
  45. package/addon/components/widget/kpi-aov.js +5 -0
  46. package/addon/components/widget/kpi-distance.hbs +10 -0
  47. package/addon/components/widget/kpi-distance.js +5 -0
  48. package/addon/components/widget/kpi-drivers-online.hbs +10 -0
  49. package/addon/components/widget/kpi-drivers-online.js +5 -0
  50. package/addon/components/widget/kpi-earnings.hbs +10 -0
  51. package/addon/components/widget/kpi-earnings.js +5 -0
  52. package/addon/components/widget/kpi-open-issues.hbs +11 -0
  53. package/addon/components/widget/kpi-open-issues.js +5 -0
  54. package/addon/components/widget/kpi-tile.hbs +59 -0
  55. package/addon/components/widget/kpi-tile.js +168 -0
  56. package/addon/components/widget/live-fleet.hbs +122 -0
  57. package/addon/components/widget/live-fleet.js +365 -0
  58. package/addon/components/widget/maintenance-overview.hbs +45 -0
  59. package/addon/components/widget/maintenance-overview.js +40 -0
  60. package/addon/components/widget/on-time-delivery.hbs +27 -0
  61. package/addon/components/widget/on-time-delivery.js +73 -0
  62. package/addon/components/widget/operations-pulse.hbs +51 -0
  63. package/addon/components/widget/operations-pulse.js +173 -0
  64. package/addon/components/widget/orders-by-status.hbs +26 -0
  65. package/addon/components/widget/orders-by-status.js +54 -0
  66. package/addon/components/widget/revenue-trend.hbs +34 -0
  67. package/addon/components/widget/revenue-trend.js +67 -0
  68. package/addon/components/widget/top-drivers.hbs +44 -0
  69. package/addon/components/widget/top-drivers.js +54 -0
  70. package/addon/controllers/settings/routing.js +124 -1
  71. package/addon/extension.js +172 -3
  72. package/addon/helpers/format-duration.js +38 -0
  73. package/addon/routes/application.js +6 -0
  74. package/addon/services/map-adapter/google.js +13 -2
  75. package/addon/services/order-list-overlay.js +2 -2
  76. package/addon/styles/fleetops-engine.css +806 -46
  77. package/addon/templates/maintenance/equipment/index.hbs +1 -1
  78. package/addon/templates/maintenance/parts/index.hbs +1 -1
  79. package/addon/templates/maintenance/schedules/index.hbs +1 -1
  80. package/addon/templates/management/vehicles/index.hbs +1 -1
  81. package/addon/templates/settings/avatars.hbs +1 -1
  82. package/addon/templates/settings/custom-fields.hbs +1 -1
  83. package/addon/templates/settings/map.hbs +1 -1
  84. package/addon/templates/settings/navigator-app.hbs +1 -1
  85. package/addon/templates/settings/notifications.hbs +1 -1
  86. package/addon/templates/settings/orchestrator.hbs +1 -1
  87. package/addon/templates/settings/payments/index.hbs +1 -1
  88. package/addon/templates/settings/payments/onboard.hbs +1 -1
  89. package/addon/templates/settings/routing.hbs +82 -4
  90. package/addon/templates/settings/scheduling.hbs +1 -1
  91. package/addon/utils/live-map-card-content.js +171 -0
  92. package/app/components/tracking-stop-progress.js +1 -0
  93. package/app/components/widget/fuel-efficiency.js +1 -0
  94. package/app/components/widget/geofence-violations.js +1 -0
  95. package/app/components/widget/issues-insights.js +1 -0
  96. package/app/components/widget/kpi-active-orders.js +1 -0
  97. package/app/components/widget/kpi-aov.js +1 -0
  98. package/app/components/widget/kpi-distance.js +1 -0
  99. package/app/components/widget/kpi-drivers-online.js +1 -0
  100. package/app/components/widget/kpi-earnings.js +1 -0
  101. package/app/components/widget/kpi-open-issues.js +1 -0
  102. package/app/components/widget/kpi-tile.js +1 -0
  103. package/app/components/widget/live-fleet.js +1 -0
  104. package/app/components/widget/maintenance-overview.js +1 -0
  105. package/app/components/widget/on-time-delivery.js +1 -0
  106. package/app/components/widget/operations-pulse.js +1 -0
  107. package/app/components/widget/orders-by-status.js +1 -0
  108. package/app/components/widget/revenue-trend.js +1 -0
  109. package/app/components/widget/top-drivers.js +1 -0
  110. package/app/helpers/format-duration.js +1 -0
  111. package/app/utils/live-map-card-content.js +1 -0
  112. package/composer.json +1 -1
  113. package/extension.json +1 -1
  114. package/package.json +3 -3
  115. package/pnpm-workspace.yaml +1 -0
  116. package/server/config/fleetops.php +32 -11
  117. package/server/config/telematics.php +111 -1
  118. package/server/migrations/2026_05_13_000001_repair_customer_contact_user_types.php +86 -0
  119. package/server/migrations/2026_05_18_000001_add_license_expiry_to_drivers_table.php +25 -0
  120. package/server/seeders/Testing/Concerns/SeedsTestingData.php +183 -0
  121. package/server/seeders/Testing/ConnectivitySeeder.php +212 -0
  122. package/server/seeders/Testing/FleetSeeder.php +341 -0
  123. package/server/seeders/Testing/MaintenanceSeeder.php +238 -0
  124. package/server/seeders/Testing/NetworkSeeder.php +250 -0
  125. package/server/seeders/Testing/OrdersSeeder.php +214 -0
  126. package/server/seeders/Testing/TestingSeeder.php +40 -0
  127. package/server/seeders/Testing/VroomOrchestrationSeeder.php +409 -0
  128. package/server/src/Console/Commands/ProcessOperationalAlerts.php +279 -0
  129. package/server/src/Http/Controllers/Api/v1/OrchestrationController.php +64 -0
  130. package/server/src/Http/Controllers/Api/v1/OrderController.php +26 -26
  131. package/server/src/Http/Controllers/Api/v1/PayloadController.php +10 -10
  132. package/server/src/Http/Controllers/Api/v1/ServiceQuoteController.php +1 -1
  133. package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +119 -0
  134. package/server/src/Http/Controllers/Internal/v1/ContactController.php +41 -0
  135. package/server/src/Http/Controllers/Internal/v1/LiveController.php +6 -42
  136. package/server/src/Http/Controllers/Internal/v1/MetricsController.php +82 -3
  137. package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +1 -1
  138. package/server/src/Http/Controllers/Internal/v1/OrderController.php +52 -21
  139. package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +1 -1
  140. package/server/src/Http/Controllers/Internal/v1/SettingController.php +164 -12
  141. package/server/src/Http/Resources/v1/Driver.php +2 -0
  142. package/server/src/Http/Resources/v1/Fleet.php +4 -0
  143. package/server/src/Http/Resources/v1/Index/Driver.php +48 -0
  144. package/server/src/Http/Resources/v1/Index/Payload.php +2 -2
  145. package/server/src/Http/Resources/v1/Index/Vehicle.php +74 -1
  146. package/server/src/Models/Contact.php +122 -13
  147. package/server/src/Models/Driver.php +2 -0
  148. package/server/src/Models/Order.php +1 -1
  149. package/server/src/Models/OrderConfig.php +14 -11
  150. package/server/src/Models/Payload.php +8 -8
  151. package/server/src/Models/Place.php +0 -3
  152. package/server/src/Models/ServiceRate.php +1 -1
  153. package/server/src/Notifications/LateDeparture.php +48 -0
  154. package/server/src/Notifications/ProlongedStoppage.php +48 -0
  155. package/server/src/Notifications/RouteDeviation.php +48 -0
  156. package/server/src/Observers/ContactObserver.php +8 -0
  157. package/server/src/Orchestration/Engines/CapacityAllocationEngine.php +220 -0
  158. package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +357 -38
  159. package/server/src/Orchestration/Support/OrchestrationPayloadBuilder.php +259 -51
  160. package/server/src/Providers/FleetOpsServiceProvider.php +32 -0
  161. package/server/src/Providers/NotificationServiceProvider.php +3 -0
  162. package/server/src/Support/Analytics/AbstractAnalytics.php +77 -0
  163. package/server/src/Support/Analytics/FuelEfficiency.php +83 -0
  164. package/server/src/Support/Analytics/GeofenceViolations.php +63 -0
  165. package/server/src/Support/Analytics/IssuesInsights.php +67 -0
  166. package/server/src/Support/Analytics/LiveFleet.php +127 -0
  167. package/server/src/Support/Analytics/MaintenanceOverview.php +70 -0
  168. package/server/src/Support/Analytics/OnTimeDelivery.php +75 -0
  169. package/server/src/Support/Analytics/OperationsPulse.php +86 -0
  170. package/server/src/Support/Analytics/OrdersByStatus.php +64 -0
  171. package/server/src/Support/Analytics/RevenueTrend.php +79 -0
  172. package/server/src/Support/Analytics/TopDrivers.php +92 -0
  173. package/server/src/Support/LiveOrderQuery.php +75 -0
  174. package/server/src/Support/Metrics/AbstractMetric.php +170 -0
  175. package/server/src/Support/Metrics/ActiveLiveOrdersMetric.php +28 -0
  176. package/server/src/Support/Metrics/AvgOrderValueMetric.php +53 -0
  177. package/server/src/Support/Metrics/DriversOnlineMetric.php +30 -0
  178. package/server/src/Support/Metrics/EarningsMetric.php +30 -0
  179. package/server/src/Support/Metrics/FuelCostsMetric.php +30 -0
  180. package/server/src/Support/Metrics/MoneyMetric.php +30 -0
  181. package/server/src/Support/Metrics/OpenIssuesMetric.php +35 -0
  182. package/server/src/Support/Metrics/OrdersCanceledMetric.php +35 -0
  183. package/server/src/Support/Metrics/OrdersCompletedMetric.php +35 -0
  184. package/server/src/Support/Metrics/OrdersInProgressMetric.php +51 -0
  185. package/server/src/Support/Metrics/OrdersScheduledMetric.php +37 -0
  186. package/server/src/Support/Metrics/Registry.php +46 -0
  187. package/server/src/Support/Metrics/ResolvedIssuesMetric.php +35 -0
  188. package/server/src/Support/Metrics/TotalCustomersMetric.php +29 -0
  189. package/server/src/Support/Metrics/TotalDistanceTraveledMetric.php +35 -0
  190. package/server/src/Support/Metrics/TotalDriversMetric.php +28 -0
  191. package/server/src/Support/Metrics/TotalTimeTraveledMetric.php +35 -0
  192. package/server/src/Support/Metrics.php +46 -234
  193. package/server/src/Support/OSRM.php +11 -6
  194. package/server/src/Support/OrderTracker.php +7 -582
  195. package/server/src/Support/Telematics/Providers/AfaqyProvider.php +290 -0
  196. package/server/src/Support/Telematics/Providers/SafeeProvider.php +333 -0
  197. package/server/src/Support/Utils.php +1 -1
  198. package/server/src/Tracking/Contracts/TrackingProviderInterface.php +19 -0
  199. package/server/src/Tracking/Providers/CalculatedTrackingProvider.php +65 -0
  200. package/server/src/Tracking/Providers/GoogleRoutesTrackingProvider.php +118 -0
  201. package/server/src/Tracking/Providers/OsrmTrackingProvider.php +71 -0
  202. package/server/src/Tracking/README.md +25 -0
  203. package/server/src/Tracking/Support/FakeTrackingProvider.php +42 -0
  204. package/server/src/Tracking/TrackingContext.php +63 -0
  205. package/server/src/Tracking/TrackingContextBuilder.php +204 -0
  206. package/server/src/Tracking/TrackingIntelligenceService.php +180 -0
  207. package/server/src/Tracking/TrackingOptions.php +49 -0
  208. package/server/src/Tracking/TrackingProviderCapabilities.php +30 -0
  209. package/server/src/Tracking/TrackingProviderManager.php +89 -0
  210. package/server/src/Tracking/TrackingProviderRegistry.php +35 -0
  211. package/server/src/Tracking/TrackingProviderResult.php +20 -0
  212. package/server/src/Tracking/TrackingStop.php +59 -0
  213. package/server/src/routes.php +27 -0
  214. package/server/tests/AnalyticsRoutesTest.php +41 -0
  215. package/server/tests/CapacityAllocationEngineTest.php +108 -0
  216. package/server/tests/LiveOrderQueryTest.php +34 -0
  217. package/server/tests/MetricsRegistryTest.php +88 -0
  218. package/server/tests/OrchestrationPayloadBuilderTest.php +132 -0
  219. package/server/tests/OrchestratorConsumableApiTest.php +74 -0
  220. package/server/tests/PingDriverEndpointTest.php +19 -0
  221. package/server/tests/TrackingIntelligenceTest.php +176 -0
  222. package/server/tests/VroomOrchestrationEngineTest.php +250 -0
  223. package/translations/en-us.yaml +41 -0
@@ -0,0 +1,250 @@
1
+ <?php
2
+
3
+ use Fleetbase\FleetOps\Orchestration\Engines\VroomOrchestrationEngine;
4
+
5
+ test('vroom maps multi stop route tasks to shipments', function () {
6
+ $engine = new VroomOrchestrationEngine();
7
+ $method = new ReflectionMethod($engine, 'mapTaskToShipment');
8
+ $reverse = [];
9
+
10
+ $method->setAccessible(true);
11
+
12
+ $shipment = $method->invokeArgs($engine, [[
13
+ 'id' => 'order_gkATxX2U3P',
14
+ 'stops' => [
15
+ ['role' => 'pickup', 'location' => [103.85, 1.28]],
16
+ ['role' => 'waypoint', 'location' => [103.87, 1.30]],
17
+ ['role' => 'dropoff', 'location' => [103.90, 1.31]],
18
+ ],
19
+ 'service' => 300,
20
+ 'amount' => [1, 0, 0, 1],
21
+ 'description' => 'order_gkATxX2U3P',
22
+ ], &$reverse]);
23
+
24
+ expect($shipment)->toHaveKeys(['pickup', 'delivery', 'amount']);
25
+ expect($shipment)->not->toHaveKey('location');
26
+ expect($shipment['pickup']['location'])->toBe([103.85, 1.28]);
27
+ expect($shipment['delivery']['location'])->toBe([103.90, 1.31]);
28
+ expect($shipment['delivery']['service'])->toBe(300);
29
+ expect(array_values($reverse))->toBe(['order_gkATxX2U3P', 'order_gkATxX2U3P']);
30
+ });
31
+
32
+ test('vroom maps single stop route tasks to jobs without pickup coordinates', function () {
33
+ $engine = new VroomOrchestrationEngine();
34
+ $method = new ReflectionMethod($engine, 'mapTaskToVroomJob');
35
+ $reverse = [];
36
+
37
+ $method->setAccessible(true);
38
+
39
+ $job = $method->invokeArgs($engine, [[
40
+ 'id' => 'order_waypointOnly',
41
+ 'stops' => [
42
+ ['role' => 'waypoint', 'location' => [103.86, 1.29]],
43
+ ],
44
+ 'service' => 300,
45
+ 'amount' => [1, 0, 0, 1],
46
+ 'description' => 'order_waypointOnly',
47
+ ], &$reverse]);
48
+
49
+ expect($job)->toMatchArray([
50
+ 'location' => [103.86, 1.29],
51
+ 'description' => 'order_waypointOnly',
52
+ 'service' => 300,
53
+ 'amount' => [1, 0, 0, 1],
54
+ ]);
55
+ expect($job)->not->toHaveKey('pickup');
56
+ expect(array_values($reverse))->toBe(['order_waypointOnly']);
57
+ });
58
+
59
+ test('vroom dedupes unassigned pickup and delivery task ids to one order id', function () {
60
+ $engine = new VroomOrchestrationEngine();
61
+ $method = new ReflectionMethod($engine, 'mapVroomResponse');
62
+
63
+ $method->setAccessible(true);
64
+
65
+ $result = $method->invoke($engine, [
66
+ 'routes' => [],
67
+ 'unassigned' => [
68
+ ['id' => 1001],
69
+ ['id' => 1002],
70
+ ],
71
+ 'summary' => ['routes' => 0],
72
+ ], [
73
+ 1001 => 'order_gkATxX2U3P',
74
+ 1002 => 'order_gkATxX2U3P',
75
+ ]);
76
+
77
+ expect($result['unassigned'])->toBe(['order_gkATxX2U3P']);
78
+ });
79
+
80
+ test('vroom maps shipment delivery steps back to fleetops assignments', function () {
81
+ $engine = new VroomOrchestrationEngine();
82
+ $method = new ReflectionMethod($engine, 'mapVroomResponse');
83
+
84
+ $method->setAccessible(true);
85
+
86
+ $result = $method->invoke($engine, [
87
+ 'routes' => [
88
+ [
89
+ 'description' => json_encode(['vehicle_id' => 'vehicle_w747Bat', 'driver_id' => null]),
90
+ 'steps' => [
91
+ ['type' => 'start'],
92
+ ['type' => 'pickup', 'id' => 1001],
93
+ ['type' => 'delivery', 'id' => 1002, 'arrival' => 1778918400, 'duration' => 900, 'distance' => 4200],
94
+ ['type' => 'end'],
95
+ ],
96
+ ],
97
+ ],
98
+ 'unassigned' => [],
99
+ 'summary' => ['routes' => 1],
100
+ ], [
101
+ 1001 => 'order_gkATxX2U3P',
102
+ 1002 => 'order_gkATxX2U3P',
103
+ ]);
104
+
105
+ expect($result['assignments'])->toHaveCount(1);
106
+ expect($result['assignments'][0])->toMatchArray([
107
+ 'order_id' => 'order_gkATxX2U3P',
108
+ 'vehicle_id' => 'vehicle_w747Bat',
109
+ 'driver_id' => null,
110
+ 'sequence' => 1,
111
+ 'arrival' => 1778918400,
112
+ 'duration' => 900,
113
+ 'distance' => 4200,
114
+ ]);
115
+ expect($result['summary'])->toBe(['routes' => 1]);
116
+ });
117
+
118
+ test('vroom capacity-only payload uses matrix indexes instead of coordinates', function () {
119
+ $engine = new VroomOrchestrationEngine();
120
+ $method = new ReflectionMethod($engine, 'buildCapacityOnlyPayload');
121
+ $reverse = [];
122
+
123
+ $method->setAccessible(true);
124
+
125
+ $payload = $method->invokeArgs($engine, [[
126
+ [
127
+ 'id' => 'order_capacity',
128
+ 'description' => 'order_capacity',
129
+ 'amount' => [100, 250, 1, 2],
130
+ 'skills' => [123],
131
+ ],
132
+ ], [
133
+ [
134
+ 'id' => 'vehicle_capacity',
135
+ 'driver_id' => null,
136
+ 'capacity' => [500, 1000, 4, 20],
137
+ 'skills' => [123],
138
+ 'max_tasks' => 3,
139
+ ],
140
+ ], [], &$reverse]);
141
+
142
+ expect($payload['vehicles'][0])->toMatchArray([
143
+ 'profile' => 'capacity_only',
144
+ 'start_index' => 0,
145
+ 'capacity' => [500, 1000, 4, 20],
146
+ 'skills' => [123],
147
+ 'max_tasks' => 3,
148
+ ]);
149
+ expect($payload['vehicles'][0])->not->toHaveKey('start');
150
+ expect($payload['jobs'][0])->toMatchArray([
151
+ 'location_index' => 1,
152
+ 'delivery' => [100, 250, 1, 2],
153
+ 'skills' => [123],
154
+ ]);
155
+ expect($payload['jobs'][0])->not->toHaveKey('location');
156
+ expect($payload['jobs'][0])->not->toHaveKey('pickup');
157
+ expect($payload['matrices']['capacity_only']['durations'])->toHaveCount(2);
158
+ expect(array_values($reverse))->toBe(['order_capacity']);
159
+ });
160
+
161
+ test('vroom capacity-only payload minimizes vehicles by default', function () {
162
+ $engine = new VroomOrchestrationEngine();
163
+ $method = new ReflectionMethod($engine, 'buildCapacityOnlyPayload');
164
+ $reverse = [];
165
+
166
+ $method->setAccessible(true);
167
+
168
+ $payload = $method->invokeArgs($engine, [[
169
+ ['id' => 'order_a', 'description' => 'order_a', 'amount' => [100, 250, 1, 2]],
170
+ ['id' => 'order_b', 'description' => 'order_b', 'amount' => [80, 100, 0, 1]],
171
+ ], [
172
+ ['id' => 'vehicle_large', 'driver_id' => null, 'capacity' => [500, 1000, 4, 20]],
173
+ ['id' => 'vehicle_spare', 'driver_id' => null, 'capacity' => [500, 1000, 4, 20]],
174
+ ], [], &$reverse]);
175
+
176
+ expect($payload['vehicles'][0]['costs'])->toBe(['fixed' => 100000]);
177
+ expect($payload['vehicles'][1]['costs'])->toBe(['fixed' => 100000]);
178
+ expect($payload['jobs'])->toHaveCount(2);
179
+ expect($payload['jobs'][0]['delivery'])->toBe([100, 250, 1, 2]);
180
+ expect($payload['jobs'][1]['delivery'])->toBe([80, 100, 0, 1]);
181
+ });
182
+
183
+ test('vroom capacity-only payload accepts custom minimize vehicles fixed cost', function () {
184
+ $engine = new VroomOrchestrationEngine();
185
+ $method = new ReflectionMethod($engine, 'buildCapacityOnlyPayload');
186
+ $reverse = [];
187
+
188
+ $method->setAccessible(true);
189
+
190
+ $payload = $method->invokeArgs($engine, [[
191
+ ['id' => 'order_a', 'description' => 'order_a', 'amount' => [100, 250, 1, 2]],
192
+ ], [
193
+ ['id' => 'vehicle_large', 'driver_id' => null, 'capacity' => [500, 1000, 4, 20]],
194
+ ], [
195
+ 'vehicle_packing' => 'minimize_vehicles',
196
+ 'vehicle_fixed_cost' => 50000,
197
+ ], &$reverse]);
198
+
199
+ expect($payload['vehicles'][0]['costs'])->toBe(['fixed' => 50000]);
200
+ });
201
+
202
+ test('vroom capacity-only payload can disable vehicle packing bias', function (string $packing) {
203
+ $engine = new VroomOrchestrationEngine();
204
+ $method = new ReflectionMethod($engine, 'buildCapacityOnlyPayload');
205
+ $reverse = [];
206
+
207
+ $method->setAccessible(true);
208
+
209
+ $payload = $method->invokeArgs($engine, [[
210
+ ['id' => 'order_a', 'description' => 'order_a', 'amount' => [100, 250, 1, 2]],
211
+ ], [
212
+ ['id' => 'vehicle_large', 'driver_id' => null, 'capacity' => [500, 1000, 4, 20]],
213
+ ], [
214
+ 'vehicle_packing' => $packing,
215
+ ], &$reverse]);
216
+
217
+ expect($payload['vehicles'][0])->not->toHaveKey('costs');
218
+ })->with(['balanced', 'none']);
219
+
220
+ test('vroom capacity-only response can assign multiple orders to one large vehicle', function () {
221
+ $engine = new VroomOrchestrationEngine();
222
+ $method = new ReflectionMethod($engine, 'mapVroomResponse');
223
+
224
+ $method->setAccessible(true);
225
+
226
+ $result = $method->invoke($engine, [
227
+ 'routes' => [
228
+ [
229
+ 'description' => json_encode(['vehicle_id' => 'vehicle_large', 'driver_id' => null]),
230
+ 'steps' => [
231
+ ['type' => 'start'],
232
+ ['type' => 'job', 'id' => 1001],
233
+ ['type' => 'job', 'id' => 1002],
234
+ ['type' => 'job', 'id' => 1003],
235
+ ['type' => 'end'],
236
+ ],
237
+ ],
238
+ ],
239
+ 'unassigned' => [],
240
+ 'summary' => ['routes' => 1],
241
+ ], [
242
+ 1001 => 'order_a',
243
+ 1002 => 'order_b',
244
+ 1003 => 'order_c',
245
+ ]);
246
+
247
+ expect($result['assignments'])->toHaveCount(3);
248
+ expect(collect($result['assignments'])->pluck('vehicle_id')->unique()->values()->all())->toBe(['vehicle_large']);
249
+ expect(collect($result['assignments'])->pluck('order_id')->all())->toBe(['order_a', 'order_b', 'order_c']);
250
+ });
@@ -435,6 +435,7 @@ driver:
435
435
  vendor: Vendor
436
436
  select-vendor: Select Vendor
437
437
  driver-license: Drivers License
438
+ license-expiry: License Expiry
438
439
  no-vehicle-assigned: No Vehicle Assigned
439
440
  actions:
440
441
  assign-order: Assign Order to Driver
@@ -1653,6 +1654,39 @@ modals:
1653
1654
  description-zone: Description of Zone
1654
1655
 
1655
1656
  widget:
1657
+ refresh: Refresh
1658
+ kpi-earnings:
1659
+ title: Earnings
1660
+ kpi-distance:
1661
+ title: Distance Travelled
1662
+ kpi-aov:
1663
+ title: Avg Order Value
1664
+ kpi-active-orders:
1665
+ title: Active Orders
1666
+ kpi-drivers-online:
1667
+ title: Drivers Online
1668
+ kpi-open-issues:
1669
+ title: Open Issues
1670
+ operations-pulse:
1671
+ title: Operations Pulse
1672
+ revenue-trend:
1673
+ title: Revenue Trend
1674
+ orders-by-status:
1675
+ title: Order Volume by Status
1676
+ on-time-delivery:
1677
+ title: On-Time Delivery
1678
+ top-drivers:
1679
+ title: Top Drivers
1680
+ fuel-efficiency:
1681
+ title: Fuel Cost & Efficiency
1682
+ issues-insights:
1683
+ title: Issues Insights
1684
+ maintenance-overview:
1685
+ title: Maintenance Overview
1686
+ geofence-violations:
1687
+ title: Geofence Violations
1688
+ live-fleet:
1689
+ title: Live Fleet Map
1656
1690
  fleet-ops-quickstart:
1657
1691
  message: Let's see what you can do to jumpstart operations...
1658
1692
  start-task: Start Task
@@ -1989,6 +2023,12 @@ orchestrator:
1989
2023
  mode-allocate: Allocate Orders
1990
2024
  mode-optimize: Optimize Routes
1991
2025
  engine: Engine
2026
+ allocation-strategy: Allocation Strategy
2027
+ allocation-strategy-route-aware: Route + Capacity
2028
+ allocation-strategy-capacity-only: Capacity Only
2029
+ vehicle-packing: Vehicle Packing
2030
+ vehicle-packing-minimize-vehicles: Minimize Vehicles
2031
+ vehicle-packing-balanced: Balanced
1992
2032
  respect-skills: Respect Skills
1993
2033
  respect-capacity: Respect Capacity
1994
2034
  return-to-depot: Return to Depot
@@ -2029,6 +2069,7 @@ orchestrator:
2029
2069
  no-search-results: No results match your search.
2030
2070
  search-drivers: Search drivers...
2031
2071
  search-vehicles: Search vehicles...
2072
+ no-position: No position
2032
2073
  filter-online: Online
2033
2074
  filter-offline: Offline
2034
2075
  filter-on-shift: On Job