@fleetbase/fleetops-engine 0.6.70 → 0.6.72

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 (510) hide show
  1. package/RELEASE.md +18 -47
  2. package/addon/components/admin/tracking-page-settings.hbs +56 -0
  3. package/addon/components/admin/tracking-page-settings.js +67 -0
  4. package/addon/components/device/form.hbs +2 -2
  5. package/addon/components/driver/details.hbs +1 -1
  6. package/addon/components/driver/form.hbs +1 -1
  7. package/addon/components/equipment/form.hbs +1 -1
  8. package/addon/components/layout/fleet-ops-sidebar.js +11 -3
  9. package/addon/components/maintenance/form.hbs +3 -3
  10. package/addon/components/map/google-live-map.js +2 -2
  11. package/addon/components/map/leaflet-live-map.js +45 -32
  12. package/addon/components/orchestrator/phase-builder.js +2 -1
  13. package/addon/components/orchestrator-workbench.hbs +7 -1
  14. package/addon/components/orchestrator-workbench.js +16 -2
  15. package/addon/components/order/details/activity.hbs +8 -6
  16. package/addon/components/order/details/activity.js +9 -0
  17. package/addon/components/order/details.hbs +29 -0
  18. package/addon/components/order/details.js +26 -0
  19. package/addon/components/order/form/details.hbs +30 -4
  20. package/addon/components/order/form/details.js +46 -0
  21. package/addon/components/order/form/route.hbs +5 -3
  22. package/addon/components/order/form/route.js +24 -1
  23. package/addon/components/order/form.hbs +12 -0
  24. package/addon/components/order/form.js +21 -1
  25. package/addon/components/order/kanban.js +72 -0
  26. package/addon/components/order-config-manager/activity-flow.js +45 -10
  27. package/addon/components/order-config-manager/lifecycle.hbs +250 -0
  28. package/addon/components/order-config-manager/lifecycle.js +358 -0
  29. package/addon/components/order-config-manager.js +5 -1
  30. package/addon/components/service-rate/details.hbs +1 -1
  31. package/addon/components/service-rate/form.hbs +1 -1
  32. package/addon/components/tracking-page/full-view.hbs +276 -0
  33. package/addon/components/tracking-page/full-view.js +474 -0
  34. package/addon/components/tracking-page/locale-selector.js +30 -0
  35. package/addon/components/tracking-page/map.hbs +44 -0
  36. package/addon/components/tracking-page/map.js +328 -0
  37. package/addon/components/tracking-page/order-list.hbs +35 -0
  38. package/addon/components/tracking-page/public-view.hbs +60 -0
  39. package/addon/components/tracking-page/settings-preview.hbs +21 -0
  40. package/addon/components/tracking-page/settings-preview.js +23 -0
  41. package/addon/components/tracking-page/verify-panel.hbs +109 -0
  42. package/addon/components/tracking-page.hbs +142 -0
  43. package/addon/components/tracking-page.js +564 -0
  44. package/addon/components/trailer/form.hbs +2 -2
  45. package/addon/components/vehicle/form.hbs +3 -3
  46. package/addon/components/warranty/form.hbs +2 -2
  47. package/addon/components/widget/live-fleet.js +54 -6
  48. package/addon/components/widget/proof-of-delivery.hbs +49 -0
  49. package/addon/components/widget/proof-of-delivery.js +62 -0
  50. package/addon/components/work-order/form.hbs +3 -3
  51. package/addon/controllers/analytics/reports/index.js +10 -1
  52. package/addon/controllers/connectivity/devices/index/details.js +1 -0
  53. package/addon/controllers/connectivity/devices/index.js +8 -2
  54. package/addon/controllers/connectivity/events/index.js +31 -1
  55. package/addon/controllers/connectivity/sensors/index/details.js +1 -1
  56. package/addon/controllers/connectivity/sensors/index.js +37 -1
  57. package/addon/controllers/maintenance/equipment/index/details.js +2 -2
  58. package/addon/controllers/maintenance/equipment/index.js +28 -9
  59. package/addon/controllers/maintenance/inspection-forms/index.js +32 -12
  60. package/addon/controllers/maintenance/inspection-submissions/index/details.js +2 -1
  61. package/addon/controllers/maintenance/inspection-submissions/index.js +49 -9
  62. package/addon/controllers/maintenance/maintenances/index/details.js +2 -0
  63. package/addon/controllers/maintenance/maintenances/index.js +20 -1
  64. package/addon/controllers/maintenance/parts/index/details.js +2 -2
  65. package/addon/controllers/maintenance/parts/index.js +28 -8
  66. package/addon/controllers/maintenance/schedules/index.js +33 -4
  67. package/addon/controllers/maintenance/work-orders/index/details.js +3 -3
  68. package/addon/controllers/maintenance/work-orders/index.js +39 -8
  69. package/addon/controllers/management/contacts/customers.js +13 -0
  70. package/addon/controllers/management/contacts/index.js +43 -1
  71. package/addon/controllers/management/drivers/index/details.js +1 -0
  72. package/addon/controllers/management/drivers/index.js +32 -2
  73. package/addon/controllers/management/fleets/index/details.js +1 -0
  74. package/addon/controllers/management/fleets/index.js +39 -1
  75. package/addon/controllers/management/fuel-reports/index.js +22 -2
  76. package/addon/controllers/management/fuel-transactions/index.js +43 -7
  77. package/addon/controllers/management/issues/index/details.js +1 -0
  78. package/addon/controllers/management/issues/index.js +22 -2
  79. package/addon/controllers/management/places/index.js +36 -1
  80. package/addon/controllers/management/trailers/index/details.js +1 -0
  81. package/addon/controllers/management/trailers/index.js +50 -2
  82. package/addon/controllers/management/vehicles/index/details.js +1 -0
  83. package/addon/controllers/management/vehicles/index.js +33 -2
  84. package/addon/controllers/management/vendors/index.js +26 -2
  85. package/addon/controllers/operations/orders/index/details.js +50 -7
  86. package/addon/controllers/operations/orders/index.js +59 -4
  87. package/addon/controllers/operations/scheduler/index.js +45 -14
  88. package/addon/controllers/operations/service-rates/index.js +15 -1
  89. package/addon/controllers/settings/index.js +6 -0
  90. package/addon/controllers/settings/map.js +75 -0
  91. package/addon/controllers/settings/orchestrator.js +8 -6
  92. package/addon/controllers/settings/tracking-page.js +212 -0
  93. package/addon/extension.js +97 -1
  94. package/addon/helpers/parcel-box-image.js +16 -0
  95. package/addon/routes/operations/orders/index/details.js +1 -0
  96. package/addon/routes/operations/orders/index/new.js +5 -4
  97. package/addon/routes/operations/scheduler/index.js +1 -1
  98. package/addon/routes/settings/tracking-page.js +31 -0
  99. package/addon/routes.js +1 -0
  100. package/addon/services/contact-actions.js +1 -0
  101. package/addon/services/customer-actions.js +2 -1
  102. package/addon/services/device-actions.js +1 -0
  103. package/addon/services/device-event-actions.js +1 -0
  104. package/addon/services/driver-actions.js +4 -13
  105. package/addon/services/equipment-actions.js +1 -0
  106. package/addon/services/fleet-actions.js +1 -0
  107. package/addon/services/fuel-report-actions.js +1 -0
  108. package/addon/services/inspection-form-actions.js +1 -0
  109. package/addon/services/inspection-submission-actions.js +1 -0
  110. package/addon/services/integrated-vendor-actions.js +1 -0
  111. package/addon/services/issue-actions.js +1 -0
  112. package/addon/services/location.js +69 -21
  113. package/addon/services/maintenance-actions.js +1 -0
  114. package/addon/services/maintenance-schedule-actions.js +2 -1
  115. package/addon/services/map-settings.js +28 -0
  116. package/addon/services/order-actions.js +7 -0
  117. package/addon/services/order-allocation.js +1 -1
  118. package/addon/services/order-presentation.js +129 -0
  119. package/addon/services/part-actions.js +1 -0
  120. package/addon/services/place-actions.js +1 -0
  121. package/addon/services/sensor-actions.js +1 -0
  122. package/addon/services/service-area-actions.js +1 -0
  123. package/addon/services/service-rate-actions.js +1 -0
  124. package/addon/services/telematic-actions.js +1 -0
  125. package/addon/services/trailer-actions.js +4 -14
  126. package/addon/services/vehicle-actions.js +4 -13
  127. package/addon/services/vendor-actions.js +1 -0
  128. package/addon/services/work-order-actions.js +1 -0
  129. package/addon/services/zone-actions.js +1 -0
  130. package/addon/styles/fleetops-engine.css +1391 -0
  131. package/addon/templates/analytics/reports/index/details.hbs +1 -0
  132. package/addon/templates/analytics/reports/index.hbs +1 -0
  133. package/addon/templates/connectivity/devices/index/details.hbs +1 -0
  134. package/addon/templates/connectivity/devices/index.hbs +1 -0
  135. package/addon/templates/connectivity/events/index.hbs +1 -0
  136. package/addon/templates/connectivity/sensors/index/details.hbs +1 -0
  137. package/addon/templates/connectivity/sensors/index.hbs +1 -0
  138. package/addon/templates/maintenance/equipment/index/details.hbs +1 -0
  139. package/addon/templates/maintenance/equipment/index.hbs +2 -0
  140. package/addon/templates/maintenance/inspection-forms/index/details.hbs +1 -0
  141. package/addon/templates/maintenance/inspection-forms/index.hbs +1 -0
  142. package/addon/templates/maintenance/inspection-submissions/index/details.hbs +1 -0
  143. package/addon/templates/maintenance/inspection-submissions/index.hbs +1 -0
  144. package/addon/templates/maintenance/maintenances/index/details.hbs +1 -0
  145. package/addon/templates/maintenance/maintenances/index.hbs +1 -0
  146. package/addon/templates/maintenance/parts/index/details.hbs +1 -0
  147. package/addon/templates/maintenance/parts/index.hbs +2 -0
  148. package/addon/templates/maintenance/schedules/index/details.hbs +1 -0
  149. package/addon/templates/maintenance/schedules/index.hbs +2 -0
  150. package/addon/templates/maintenance/work-orders/index/details.hbs +1 -0
  151. package/addon/templates/maintenance/work-orders/index.hbs +1 -0
  152. package/addon/templates/management/contacts/customers/details.hbs +1 -0
  153. package/addon/templates/management/contacts/customers.hbs +1 -0
  154. package/addon/templates/management/contacts/index/details.hbs +1 -0
  155. package/addon/templates/management/contacts/index.hbs +1 -0
  156. package/addon/templates/management/contacts.hbs +1 -0
  157. package/addon/templates/management/drivers/index/details.hbs +1 -0
  158. package/addon/templates/management/drivers/index.hbs +2 -0
  159. package/addon/templates/management/fleets/index/details.hbs +1 -0
  160. package/addon/templates/management/fleets/index.hbs +1 -0
  161. package/addon/templates/management/fuel-reports/index/details.hbs +1 -0
  162. package/addon/templates/management/fuel-reports/index.hbs +1 -0
  163. package/addon/templates/management/fuel-transactions/index.hbs +1 -0
  164. package/addon/templates/management/issues/index/details.hbs +1 -0
  165. package/addon/templates/management/issues/index.hbs +1 -0
  166. package/addon/templates/management/places/index/details.hbs +1 -0
  167. package/addon/templates/management/places/index.hbs +1 -0
  168. package/addon/templates/management/trailers/index/details.hbs +1 -0
  169. package/addon/templates/management/trailers/index.hbs +2 -0
  170. package/addon/templates/management/vehicles/index/details.hbs +1 -0
  171. package/addon/templates/management/vehicles/index.hbs +2 -0
  172. package/addon/templates/management/vendors/index/details.hbs +1 -0
  173. package/addon/templates/management/vendors/index.hbs +2 -0
  174. package/addon/templates/management/vendors/integrated.hbs +1 -0
  175. package/addon/templates/operations/orders/index/details.hbs +1 -0
  176. package/addon/templates/operations/orders/index.hbs +1 -0
  177. package/addon/templates/operations/service-rates/index/details.hbs +1 -0
  178. package/addon/templates/operations/service-rates/index.hbs +1 -0
  179. package/addon/templates/settings/map.hbs +46 -0
  180. package/addon/templates/settings/tracking-page.hbs +318 -0
  181. package/addon/utils/identity-cell-resource.js +2 -56
  182. package/addon/utils/map-default-view.js +132 -0
  183. package/addon/utils/normalize-order-config-flow.js +6 -1
  184. package/addon/utils/placeholder-images.js +4 -69
  185. package/addon/utils/resource-descriptors/assets.js +2 -57
  186. package/addon/utils/resource-descriptors/helpers.js +23 -122
  187. package/addon/utils/resource-descriptors/operations.js +2 -61
  188. package/addon/utils/resource-descriptors/people.js +3 -142
  189. package/addon/utils/resource-descriptors/shared.js +18 -0
  190. package/addon/utils/tracking-live-source.js +123 -0
  191. package/addon/utils/tracking-page-theme.js +123 -0
  192. package/app/components/admin/tracking-page-settings.js +1 -0
  193. package/app/components/tracking-page/full-view.js +1 -0
  194. package/app/components/tracking-page/locale-selector.js +1 -0
  195. package/app/components/tracking-page/map.js +1 -0
  196. package/app/components/tracking-page/order-list.js +1 -0
  197. package/app/components/tracking-page/public-view.js +1 -0
  198. package/app/components/tracking-page/settings-preview.js +1 -0
  199. package/app/components/tracking-page/verify-panel.js +1 -0
  200. package/app/components/tracking-page.js +1 -0
  201. package/app/components/widget/proof-of-delivery.js +1 -0
  202. package/app/controllers/settings/tracking-page.js +1 -0
  203. package/app/helpers/parcel-box-image.js +1 -0
  204. package/app/routes/settings/tracking-page.js +1 -0
  205. package/app/services/order-presentation.js +1 -0
  206. package/app/templates/settings/tracking-page.js +1 -0
  207. package/app/utils/map-default-view.js +1 -0
  208. package/app/utils/tracking-live-source.js +1 -0
  209. package/app/utils/tracking-page-theme.js +1 -0
  210. package/composer.json +2 -2
  211. package/extension.json +1 -1
  212. package/package.json +4 -4
  213. package/scripts/pest-bootstrap.php +4 -0
  214. package/server/config/fleetops.php +4 -0
  215. package/server/migrations/2026_10_08_000001_create_tracking_sessions_tables.php +51 -0
  216. package/server/migrations/2026_10_10_000001_add_trashed_index_to_device_events.php +40 -0
  217. package/server/migrations/2026_10_10_000002_add_trashed_index_to_positions.php +40 -0
  218. package/server/migrations/2026_10_12_000001_add_deleted_at_to_tracking_sessions_tables.php +32 -0
  219. package/server/resources/views/labels/default.php +2 -2
  220. package/server/resources/views/labels/entity-label.php +2 -2
  221. package/server/resources/views/labels/waypoint-label.php +2 -2
  222. package/server/src/Auth/Schemas/FleetOps.php +5 -0
  223. package/server/src/Console/Commands/ProcessOperationalAlerts.php +1 -0
  224. package/server/src/Console/Commands/PruneTelematicsData.php +101 -26
  225. package/server/src/Events/OrderChanged.php +257 -0
  226. package/server/src/Events/OrderDriverUnassigned.php +68 -0
  227. package/server/src/Exceptions/OrderEditLockedException.php +32 -0
  228. package/server/src/Expansions/CompanyExpansion.php +3 -2
  229. package/server/src/Expansions/UserExpansion.php +12 -10
  230. package/server/src/Http/Controllers/Api/v1/CustomerController.php +108 -18
  231. package/server/src/Http/Controllers/Api/v1/DriverController.php +95 -10
  232. package/server/src/Http/Controllers/Api/v1/EntityController.php +66 -0
  233. package/server/src/Http/Controllers/Api/v1/FleetController.php +10 -4
  234. package/server/src/Http/Controllers/Api/v1/OrderController.php +139 -36
  235. package/server/src/Http/Controllers/Api/v1/PayloadController.php +76 -8
  236. package/server/src/Http/Controllers/Api/v1/PlaceController.php +3 -3
  237. package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +6 -32
  238. package/server/src/Http/Controllers/Api/v1/VehicleController.php +5 -0
  239. package/server/src/Http/Controllers/Internal/v1/ContactController.php +3 -0
  240. package/server/src/Http/Controllers/Internal/v1/DriverController.php +10 -0
  241. package/server/src/Http/Controllers/Internal/v1/FleetController.php +16 -2
  242. package/server/src/Http/Controllers/Internal/v1/InspectionSubmissionController.php +13 -8
  243. package/server/src/Http/Controllers/Internal/v1/IssueController.php +2 -0
  244. package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +4 -2
  245. package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +93 -11
  246. package/server/src/Http/Controllers/Internal/v1/OrderController.php +118 -28
  247. package/server/src/Http/Controllers/Internal/v1/PositionController.php +22 -0
  248. package/server/src/Http/Controllers/Internal/v1/ProofController.php +55 -4
  249. package/server/src/Http/Controllers/Internal/v1/SettingController.php +303 -10
  250. package/server/src/Http/Controllers/Internal/v1/TrailerController.php +1 -0
  251. package/server/src/Http/Controllers/Internal/v1/VehicleController.php +1 -0
  252. package/server/src/Http/Controllers/Public/TrackingController.php +518 -0
  253. package/server/src/Http/Filter/ContactFilter.php +1 -1
  254. package/server/src/Http/Filter/InspectionFormFilter.php +23 -0
  255. package/server/src/Http/Filter/InspectionSubmissionFilter.php +23 -0
  256. package/server/src/Http/Filter/MaintenanceFilter.php +23 -0
  257. package/server/src/Http/Filter/OrderFilter.php +39 -4
  258. package/server/src/Http/Filter/ProofFilter.php +18 -0
  259. package/server/src/Http/Filter/RouteFilter.php +18 -0
  260. package/server/src/Http/Filter/TelematicFilter.php +23 -0
  261. package/server/src/Http/Filter/WarrantyFilter.php +23 -0
  262. package/server/src/Http/Requests/CancelOrderRequest.php +2 -1
  263. package/server/src/Http/Resources/v1/Concerns/ResolvesPublicRelationFields.php +14 -1
  264. package/server/src/Http/Resources/v1/Index/Customer.php +18 -0
  265. package/server/src/Http/Resources/v1/Index/Order.php +11 -2
  266. package/server/src/Http/Resources/v1/PublicOrderTracking.php +153 -0
  267. package/server/src/Http/Resources/v1/TrackingNumber.php +8 -34
  268. package/server/src/Http/Resources/v1/Zone.php +31 -23
  269. package/server/src/Jobs/FinalizeApiOrderCreation.php +3 -1
  270. package/server/src/Jobs/ProcessAllocationJob.php +16 -6
  271. package/server/src/Jobs/PublishTrackingUpdate.php +50 -0
  272. package/server/src/Listeners/HandleGeofenceEntered.php +31 -15
  273. package/server/src/Listeners/HandleOrderCanceled.php +9 -1
  274. package/server/src/Listeners/HandleUserRemovedFromCompany.php +2 -1
  275. package/server/src/Listeners/PublishTrackingUpdates.php +27 -0
  276. package/server/src/Mail/CustomerCredentialsMail.php +4 -2
  277. package/server/src/Models/AssetConnection.php +3 -0
  278. package/server/src/Models/Contact.php +3 -0
  279. package/server/src/Models/Device.php +28 -0
  280. package/server/src/Models/DeviceEvent.php +7 -0
  281. package/server/src/Models/Driver.php +20 -7
  282. package/server/src/Models/Entity.php +12 -4
  283. package/server/src/Models/Fleet.php +11 -32
  284. package/server/src/Models/FleetDriver.php +3 -0
  285. package/server/src/Models/FleetVehicle.php +3 -0
  286. package/server/src/Models/FuelReport.php +5 -13
  287. package/server/src/Models/Issue.php +4 -16
  288. package/server/src/Models/Order.php +234 -11
  289. package/server/src/Models/OrderConfig.php +129 -0
  290. package/server/src/Models/Payload.php +227 -35
  291. package/server/src/Models/Place.php +7 -1
  292. package/server/src/Models/ServiceArea.php +7 -0
  293. package/server/src/Models/ServiceRate.php +7 -17
  294. package/server/src/Models/TrackingNumber.php +109 -6
  295. package/server/src/Models/TrackingSession.php +33 -0
  296. package/server/src/Models/TrackingSessionGrant.php +22 -0
  297. package/server/src/Models/TrackingStatus.php +6 -0
  298. package/server/src/Models/Vehicle.php +21 -2
  299. package/server/src/Models/Vendor.php +7 -0
  300. package/server/src/Models/Waypoint.php +13 -4
  301. package/server/src/Notifications/OrderAssigned.php +2 -1
  302. package/server/src/Notifications/OrderCanceled.php +7 -1
  303. package/server/src/Notifications/OrderChanged.php +87 -0
  304. package/server/src/Notifications/OrderCompleted.php +2 -1
  305. package/server/src/Notifications/OrderDispatchFailed.php +2 -1
  306. package/server/src/Notifications/OrderDispatched.php +2 -1
  307. package/server/src/Notifications/OrderFailed.php +2 -1
  308. package/server/src/Notifications/OrderUnassigned.php +66 -0
  309. package/server/src/Notifications/WaypointCompleted.php +2 -1
  310. package/server/src/Observers/CompanyUserObserver.php +8 -7
  311. package/server/src/Observers/DriverObserver.php +6 -1
  312. package/server/src/Observers/OrderObserver.php +141 -1
  313. package/server/src/Observers/TrackingNumberObserver.php +18 -6
  314. package/server/src/Observers/UserObserver.php +2 -1
  315. package/server/src/Observers/VehicleObserver.php +8 -3
  316. package/server/src/Orchestration/Engines/RouteSequencingEngine.php +21 -3
  317. package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +38 -8
  318. package/server/src/Orchestration/OrchestrationEngineRegistry.php +61 -1
  319. package/server/src/Orchestration/Support/OrchestratorSettings.php +61 -0
  320. package/server/src/Orchestration/Support/RouteMetrics.php +165 -0
  321. package/server/src/Providers/EventServiceProvider.php +11 -0
  322. package/server/src/Providers/FleetOpsServiceProvider.php +13 -0
  323. package/server/src/Support/ApiCacheThrottle.php +76 -0
  324. package/server/src/Support/LiveOrderQuery.php +3 -1
  325. package/server/src/Support/OrderEdit.php +365 -0
  326. package/server/src/Support/OrderEditPolicy.php +292 -0
  327. package/server/src/Support/ProfileAccountManager.php +54 -1
  328. package/server/src/Support/ResolvesOrderServiceStops.php +5 -0
  329. package/server/src/Support/SocketChannels.php +346 -0
  330. package/server/src/Support/Telematics/TelematicService.php +7 -2
  331. package/server/src/Support/Telematics/Telemetry/Inbox.php +8 -1
  332. package/server/src/Support/TrackingChannel.php +55 -0
  333. package/server/src/Support/TrackingCode.php +242 -0
  334. package/server/src/Support/TrackingPage/TrackingAccess.php +356 -0
  335. package/server/src/Support/TrackingPage/TrackingPageConfig.php +264 -0
  336. package/server/src/Support/TrackingPage/TrackingRecipient.php +111 -0
  337. package/server/src/Support/TrackingPage/TrackingResolver.php +201 -0
  338. package/server/src/Support/TrackingPage/TrackingTarget.php +40 -0
  339. package/server/src/Support/TrackingPage/TrackingView.php +543 -0
  340. package/server/src/Support/TrackingPublisher.php +261 -0
  341. package/server/src/Support/TrackingScope.php +182 -0
  342. package/server/src/Support/TrackingUpdate.php +402 -0
  343. package/server/src/Support/Utils.php +15 -3
  344. package/server/src/Traits/HasTrackingNumber.php +2 -0
  345. package/server/src/routes.php +39 -7
  346. package/server/tests/ApiCustomerControllerContractsTest.php +54 -7
  347. package/server/tests/ApiDriverPasswordContractsTest.php +25 -21
  348. package/server/tests/ApiEntityControllerContractsTest.php +84 -0
  349. package/server/tests/ApiOrderControllerContractsTest.php +245 -0
  350. package/server/tests/ApiPayloadControllerContractsTest.php +121 -0
  351. package/server/tests/ApiPlaceControllerContractsTest.php +1 -1
  352. package/server/tests/ApiTrackingNumberControllerContractsTest.php +6 -9
  353. package/server/tests/CompactResourceSerializationTest.php +23 -59
  354. package/server/tests/ControllerFilterContractsTest.php +1 -1
  355. package/server/tests/CustomerContactIdentitySafetyTest.php +1 -1
  356. package/server/tests/EventContractsTest.php +26 -60
  357. package/server/tests/ExpansionContractsTest.php +15 -2
  358. package/server/tests/Feature/Http/Api/CustomerControllerHelperSeamsTest.php +29 -3
  359. package/server/tests/Feature/Http/Api/DriverControllerAuthFlowsTest.php +23 -0
  360. package/server/tests/Feature/Http/Api/OrderControllerNearbyFiltersTest.php +16 -16
  361. package/server/tests/Feature/Http/Api/OrderControllerQueryFiltersTest.php +41 -14
  362. package/server/tests/Feature/Http/Api/TrackingNumberControllerHelpersTest.php +57 -22
  363. package/server/tests/Feature/Http/Internal/DriverControllerCreateRecordTest.php +23 -9
  364. package/server/tests/Feature/Http/Internal/OrchestrationControllerContractsTest.php +171 -1
  365. package/server/tests/Feature/Http/Internal/OrderControllerActivityFlowsTest.php +72 -0
  366. package/server/tests/Feature/Http/Internal/OrderControllerContractsTest.php +110 -14
  367. package/server/tests/Feature/Http/Internal/OrderControllerCreateRecordTest.php +26 -0
  368. package/server/tests/Feature/Http/Internal/OrderControllerHelpersTest.php +7 -5
  369. package/server/tests/Feature/Http/Internal/PositionControllerReplayChannelTest.php +135 -0
  370. package/server/tests/Feature/Http/Internal/ProofControllerContractsTest.php +3 -3
  371. package/server/tests/Feature/Http/Internal/ProofControllerRecentTest.php +170 -0
  372. package/server/tests/Feature/Http/Public/TrackingControllerTest.php +495 -0
  373. package/server/tests/IndexCustomerPhotoTest.php +151 -0
  374. package/server/tests/ModelAccessorContractsTest.php +4 -3
  375. package/server/tests/NotificationAndMailContractsTest.php +5 -8
  376. package/server/tests/ObserverContractsTest.php +72 -10
  377. package/server/tests/OrderActivityFlowRegressionTest.php +3 -2
  378. package/server/tests/OrderConfigLifecycleTest.php +120 -0
  379. package/server/tests/OrderFilterExecutionTest.php +167 -2
  380. package/server/tests/ProcessAllocationJobContractsTest.php +20 -0
  381. package/server/tests/PublicOrderTrackingResourceTest.php +221 -0
  382. package/server/tests/QueueJobContractsTest.php +2 -1
  383. package/server/tests/RequestContractsTest.php +1 -1
  384. package/server/tests/RouteRegistrationExecutionTest.php +26 -0
  385. package/server/tests/RouteSequencingEngineTest.php +17 -0
  386. package/server/tests/SettingControllerContractsTest.php +110 -0
  387. package/server/tests/Support/TrackingPageDatabase.php +200 -0
  388. package/server/tests/TenantScopingTest.php +206 -0
  389. package/server/tests/TrackingPageSettingsTest.php +343 -0
  390. package/server/tests/Unit/Console/PruneTelematicsDataCommandTest.php +51 -0
  391. package/server/tests/Unit/Events/OrderDispatchFailedTest.php +2 -1
  392. package/server/tests/Unit/Http/Filter/ContactFilterAddressTest.php +61 -0
  393. package/server/tests/Unit/Http/Resources/IndexOrderResourceTest.php +30 -0
  394. package/server/tests/Unit/Jobs/FinalizeApiOrderCreationDispatchGuardTest.php +266 -0
  395. package/server/tests/Unit/Listeners/HandleGeofenceEnteredTest.php +182 -22
  396. package/server/tests/Unit/Listeners/HandleUserRemovedFromCompanyTest.php +5 -0
  397. package/server/tests/Unit/Models/DriverAssignVehicleTest.php +81 -0
  398. package/server/tests/Unit/Models/FleetTest.php +4 -3
  399. package/server/tests/Unit/Models/OrderCancelReasonTest.php +143 -0
  400. package/server/tests/Unit/Models/OrderPayloadConfigAndDistanceTest.php +60 -0
  401. package/server/tests/Unit/Models/OrderPayloadRouteTest.php +4 -2
  402. package/server/tests/Unit/Models/PayloadTest.php +18 -4
  403. package/server/tests/Unit/Models/ServiceRatePersistenceAndServicabilityTest.php +2 -2
  404. package/server/tests/Unit/Models/TrackingNumberTest.php +67 -6
  405. package/server/tests/Unit/Models/VehicleTest.php +16 -2
  406. package/server/tests/Unit/Models/WaypointTest.php +4 -3
  407. package/server/tests/Unit/Notifications/OrderChangeNotificationsTest.php +59 -0
  408. package/server/tests/Unit/Notifications/TerminalOrderNotificationsTest.php +3 -3
  409. package/server/tests/Unit/Observers/DriverDeletionCleanupTest.php +158 -0
  410. package/server/tests/Unit/Observers/FleetOpsCompanyUserAndServiceAreaObserversTest.php +20 -0
  411. package/server/tests/Unit/Observers/ObserverListenerSeamsTest.php +3 -3
  412. package/server/tests/Unit/Observers/OrderAssignmentObserverTest.php +100 -0
  413. package/server/tests/Unit/Observers/OrderDeleteCascadeTest.php +213 -0
  414. package/server/tests/Unit/Observers/VehicleObserverDeleteTest.php +67 -0
  415. package/server/tests/Unit/Orchestration/EngineSelectionAndRouteMetricsTest.php +336 -0
  416. package/server/tests/Unit/Orchestration/Engines/VroomOrchestrationEngineLifecycleTest.php +8 -1
  417. package/server/tests/Unit/Support/ApiCacheDependenciesTest.php +347 -0
  418. package/server/tests/Unit/Support/OrderEditPolicyTest.php +156 -0
  419. package/server/tests/Unit/Support/OrderOperationsTest.php +514 -0
  420. package/server/tests/Unit/Support/OsrmProofAndIssueFilterTest.php +4 -3
  421. package/server/tests/Unit/Support/ProfileAccountManagerTest.php +141 -0
  422. package/server/tests/Unit/Support/QuerySeamsTest.php +5 -1
  423. package/server/tests/Unit/Support/SocketChannelsTest.php +396 -0
  424. package/server/tests/Unit/Support/TrackingChannelTest.php +232 -0
  425. package/server/tests/Unit/Support/TrackingCodeTest.php +186 -0
  426. package/server/tests/Unit/Support/TrackingPage/TrackingAccessTest.php +200 -0
  427. package/server/tests/Unit/Support/TrackingPage/TrackingRecipientTest.php +51 -0
  428. package/server/tests/Unit/Support/TrackingPage/TrackingResolverTest.php +181 -0
  429. package/server/tests/Unit/Support/TrackingPage/TrackingViewTest.php +479 -0
  430. package/server/tests/Unit/Support/TrackingPublisherTest.php +425 -0
  431. package/server/tests/Unit/Support/TrackingUpdateTest.php +363 -0
  432. package/server/tests/Unit/Support/UtilsAdditionalTest.php +9 -0
  433. package/server/tests/Unit/Support/UtilsGeoMatrixAndVendorTest.php +25 -0
  434. package/server/tests/VehicleResourceContractsTest.php +46 -0
  435. package/server/tests/VroomOrchestrationEngineTest.php +34 -1
  436. package/server/tests/ZoneGeofenceSettingsResourceTest.php +121 -0
  437. package/translations/ar-ae.yml +274 -0
  438. package/translations/bg-bg.yaml +274 -0
  439. package/translations/en-us.yaml +347 -0
  440. package/translations/es-pa.yaml +274 -0
  441. package/translations/fr-fr.yaml +274 -0
  442. package/translations/mn-mn.yaml +274 -0
  443. package/translations/pt-br.yaml +274 -0
  444. package/translations/ru-ru.yaml +276 -2
  445. package/translations/uk-ua.yaml +275 -1
  446. package/translations/vi-vn.yaml +274 -0
  447. package/addon/components/cell/contact-identity.hbs +0 -1
  448. package/addon/components/cell/customer-identity.hbs +0 -1
  449. package/addon/components/cell/driver-identity.hbs +0 -1
  450. package/addon/components/cell/fleet-identity.hbs +0 -1
  451. package/addon/components/cell/order-identity.hbs +0 -1
  452. package/addon/components/cell/place-identity.hbs +0 -1
  453. package/addon/components/cell/vehicle-identity.hbs +0 -1
  454. package/addon/components/cell/vendor-identity.hbs +0 -1
  455. package/addon/components/contact/pill.hbs +0 -24
  456. package/addon/components/contact/summary.hbs +0 -1
  457. package/addon/components/customer/pill.hbs +0 -24
  458. package/addon/components/customer/summary.hbs +0 -1
  459. package/addon/components/driver/pill.hbs +0 -24
  460. package/addon/components/driver/summary.hbs +0 -1
  461. package/addon/components/fleet/pill.hbs +0 -24
  462. package/addon/components/fleet/summary.hbs +0 -1
  463. package/addon/components/order/pill.hbs +0 -24
  464. package/addon/components/order/summary.hbs +0 -1
  465. package/addon/components/place/pill.hbs +0 -24
  466. package/addon/components/place/summary.hbs +0 -1
  467. package/addon/components/select-option/contact.hbs +0 -12
  468. package/addon/components/select-option/customer.hbs +0 -12
  469. package/addon/components/select-option/driver.hbs +0 -12
  470. package/addon/components/select-option/fleet.hbs +0 -12
  471. package/addon/components/select-option/order.hbs +0 -12
  472. package/addon/components/select-option/place.hbs +0 -12
  473. package/addon/components/select-option/vehicle.hbs +0 -12
  474. package/addon/components/select-option/vendor.hbs +0 -12
  475. package/addon/components/vehicle/pill.hbs +0 -24
  476. package/addon/components/vehicle/summary.hbs +0 -1
  477. package/addon/components/vendor/pill.hbs +0 -24
  478. package/addon/components/vendor/summary.hbs +0 -1
  479. package/app/components/cell/contact-identity.js +0 -1
  480. package/app/components/cell/customer-identity.js +0 -1
  481. package/app/components/cell/driver-identity.js +0 -1
  482. package/app/components/cell/fleet-identity.js +0 -1
  483. package/app/components/cell/order-identity.js +0 -1
  484. package/app/components/cell/place-identity.js +0 -1
  485. package/app/components/cell/vehicle-identity.js +0 -1
  486. package/app/components/cell/vendor-identity.js +0 -1
  487. package/app/components/contact/pill.js +0 -1
  488. package/app/components/contact/summary.js +0 -1
  489. package/app/components/customer/pill.js +0 -1
  490. package/app/components/customer/summary.js +0 -1
  491. package/app/components/driver/pill.js +0 -1
  492. package/app/components/driver/summary.js +0 -1
  493. package/app/components/fleet/pill.js +0 -1
  494. package/app/components/fleet/summary.js +0 -1
  495. package/app/components/order/pill.js +0 -1
  496. package/app/components/order/summary.js +0 -1
  497. package/app/components/place/pill.js +0 -1
  498. package/app/components/place/summary.js +0 -1
  499. package/app/components/select-option/contact.js +0 -1
  500. package/app/components/select-option/customer.js +0 -1
  501. package/app/components/select-option/driver.js +0 -1
  502. package/app/components/select-option/fleet.js +0 -1
  503. package/app/components/select-option/order.js +0 -1
  504. package/app/components/select-option/place.js +0 -1
  505. package/app/components/select-option/vehicle.js +0 -1
  506. package/app/components/select-option/vendor.js +0 -1
  507. package/app/components/vehicle/pill.js +0 -1
  508. package/app/components/vehicle/summary.js +0 -1
  509. package/app/components/vendor/pill.js +0 -1
  510. package/app/components/vendor/summary.js +0 -1
@@ -13,7 +13,7 @@ export default class ManagementVendorsIndexController extends Controller {
13
13
  @service appCache;
14
14
 
15
15
  /** query params */
16
- @tracked queryParams = [
16
+ @tracked queryParams = this.vendorActions.queryParamsFor([
17
17
  'page',
18
18
  'limit',
19
19
  'sort',
@@ -30,7 +30,7 @@ export default class ManagementVendorsIndexController extends Controller {
30
30
  'country',
31
31
  'address',
32
32
  'website_url',
33
- ];
33
+ ]);
34
34
  @tracked page = 1;
35
35
  @tracked limit;
36
36
  @tracked sort = '-created_at';
@@ -55,16 +55,19 @@ export default class ManagementVendorsIndexController extends Controller {
55
55
  get actionButtons() {
56
56
  return [
57
57
  {
58
+ id: 'more',
58
59
  component: 'dropdown-button',
59
60
  icon: 'display',
60
61
  size: 'xs',
61
62
  items: [
62
63
  {
64
+ id: 'table-view',
63
65
  label: this.intl.t('common.table-view'),
64
66
  icon: 'table-list',
65
67
  onClick: () => this.setLayout('table'),
66
68
  },
67
69
  {
70
+ id: 'grid-view',
68
71
  label: this.intl.t('common.grid-view'),
69
72
  icon: 'grip',
70
73
  onClick: () => this.setLayout('grid'),
@@ -74,11 +77,13 @@ export default class ManagementVendorsIndexController extends Controller {
74
77
  helpText: this.intl.t('common.change-layout'),
75
78
  },
76
79
  {
80
+ id: 'refresh',
77
81
  icon: 'refresh',
78
82
  onClick: this.vendorActions.refresh,
79
83
  helpText: this.intl.t('common.refresh'),
80
84
  },
81
85
  {
86
+ id: 'create',
82
87
  text: this.intl.t('common.new'),
83
88
  type: 'primary',
84
89
  icon: 'plus',
@@ -86,6 +91,7 @@ export default class ManagementVendorsIndexController extends Controller {
86
91
  permission: 'fleet-ops create vendor',
87
92
  },
88
93
  {
94
+ id: 'import',
89
95
  text: this.intl.t('common.import'),
90
96
  type: 'magic',
91
97
  icon: 'upload',
@@ -93,6 +99,7 @@ export default class ManagementVendorsIndexController extends Controller {
93
99
  permission: 'fleet-ops import vendor',
94
100
  },
95
101
  {
102
+ id: 'export',
96
103
  text: this.intl.t('common.export'),
97
104
  icon: 'long-arrow-up',
98
105
  iconClass: 'rotate-icon-45',
@@ -109,6 +116,7 @@ export default class ManagementVendorsIndexController extends Controller {
109
116
 
110
117
  return [
111
118
  {
119
+ id: 'bulk-delete',
112
120
  label: this.intl.t('common.delete-selected-count', { count: selected.length }),
113
121
  class: 'text-red-500',
114
122
  fn: this.vendorActions.bulkDelete,
@@ -121,6 +129,7 @@ export default class ManagementVendorsIndexController extends Controller {
121
129
  get columns() {
122
130
  return [
123
131
  {
132
+ id: 'name',
124
133
  sticky: true,
125
134
  label: this.intl.t('column.name'),
126
135
  valuePath: 'name',
@@ -134,6 +143,7 @@ export default class ManagementVendorsIndexController extends Controller {
134
143
  filterComponent: 'filter/string',
135
144
  },
136
145
  {
146
+ id: 'public-id',
137
147
  label: this.intl.t('column.id'),
138
148
  valuePath: 'public_id',
139
149
  cellComponent: 'click-to-copy',
@@ -143,6 +153,7 @@ export default class ManagementVendorsIndexController extends Controller {
143
153
  filterComponent: 'filter/string',
144
154
  },
145
155
  {
156
+ id: 'internal-id',
146
157
  label: this.intl.t('column.internal-id'),
147
158
  valuePath: 'internal_id',
148
159
  cellComponent: 'click-to-copy',
@@ -152,6 +163,7 @@ export default class ManagementVendorsIndexController extends Controller {
152
163
  filterComponent: 'filter/string',
153
164
  },
154
165
  {
166
+ id: 'email',
155
167
  label: this.intl.t('column.email'),
156
168
  valuePath: 'email',
157
169
  cellComponent: 'click-to-copy',
@@ -162,6 +174,7 @@ export default class ManagementVendorsIndexController extends Controller {
162
174
  filterComponent: 'filter/string',
163
175
  },
164
176
  {
177
+ id: 'website-url',
165
178
  label: this.intl.t('column.website-url'),
166
179
  valuePath: 'website_url',
167
180
  cellComponent: 'click-to-copy',
@@ -172,6 +185,7 @@ export default class ManagementVendorsIndexController extends Controller {
172
185
  filterComponent: 'filter/string',
173
186
  },
174
187
  {
188
+ id: 'phone',
175
189
  label: this.intl.t('column.phone'),
176
190
  valuePath: 'phone',
177
191
  cellComponent: 'click-to-copy',
@@ -182,6 +196,7 @@ export default class ManagementVendorsIndexController extends Controller {
182
196
  filterComponent: 'filter/string',
183
197
  },
184
198
  {
199
+ id: 'address',
185
200
  label: this.intl.t('column.address'),
186
201
  valuePath: 'address',
187
202
  cellComponent: 'cell/place-identity',
@@ -194,6 +209,7 @@ export default class ManagementVendorsIndexController extends Controller {
194
209
  filterComponent: 'filter/string',
195
210
  },
196
211
  {
212
+ id: 'pretty-type',
197
213
  label: this.intl.t('column.type'),
198
214
  valuePath: 'prettyType',
199
215
  humanize: true,
@@ -204,6 +220,7 @@ export default class ManagementVendorsIndexController extends Controller {
204
220
  filterComponent: 'filter/string',
205
221
  },
206
222
  {
223
+ id: 'country',
207
224
  label: this.intl.t('column.country'),
208
225
  valuePath: 'country',
209
226
  cellComponent: 'table/cell/base',
@@ -216,6 +233,7 @@ export default class ManagementVendorsIndexController extends Controller {
216
233
  filterParam: 'country',
217
234
  },
218
235
  {
236
+ id: 'created-at',
219
237
  label: this.intl.t('column.created-at'),
220
238
  valuePath: 'createdAt',
221
239
  sortParam: 'created_at',
@@ -225,6 +243,7 @@ export default class ManagementVendorsIndexController extends Controller {
225
243
  filterComponent: 'filter/date',
226
244
  },
227
245
  {
246
+ id: 'updated-at',
228
247
  label: this.intl.t('column.updated-at'),
229
248
  valuePath: 'updatedAt',
230
249
  sortParam: 'updated_at',
@@ -235,6 +254,7 @@ export default class ManagementVendorsIndexController extends Controller {
235
254
  filterComponent: 'filter/date',
236
255
  },
237
256
  {
257
+ id: 'status',
238
258
  label: this.intl.t('column.status'),
239
259
  valuePath: 'status',
240
260
  cellComponent: 'table/cell/status',
@@ -247,6 +267,7 @@ export default class ManagementVendorsIndexController extends Controller {
247
267
  filterOptions: fleetOpsOptions('vendorStatuses'),
248
268
  },
249
269
  {
270
+ id: 'row-actions',
250
271
  label: '',
251
272
  cellComponent: 'table/cell/dropdown',
252
273
  ddButtonText: false,
@@ -259,11 +280,13 @@ export default class ManagementVendorsIndexController extends Controller {
259
280
  width: 60,
260
281
  actions: [
261
282
  {
283
+ id: 'view',
262
284
  label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.vendor') }),
263
285
  fn: this.vendorActions.transition.view,
264
286
  permission: 'fleet-ops view vendor',
265
287
  },
266
288
  {
289
+ id: 'edit',
267
290
  label: this.intl.t('common.edit-resource', { resource: this.intl.t('resource.vendor') }),
268
291
  fn: this.vendorActions.transition.edit,
269
292
  permission: 'fleet-ops update vendor',
@@ -272,6 +295,7 @@ export default class ManagementVendorsIndexController extends Controller {
272
295
  separator: true,
273
296
  },
274
297
  {
298
+ id: 'delete',
275
299
  label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.vendor') }),
276
300
  fn: this.vendorActions.delete,
277
301
  permission: 'fleet-ops delete vendor',
@@ -1,4 +1,5 @@
1
1
  import Controller, { inject as controller } from '@ember/controller';
2
+ import { getOwner } from '@ember/application';
2
3
  import { tracked } from '@glimmer/tracking';
3
4
  import { action } from '@ember/object';
4
5
  import { inject as service } from '@ember/service';
@@ -17,6 +18,7 @@ export default class OperationsOrdersIndexDetailsController extends Controller {
17
18
  @service hostRouter;
18
19
  @service universe;
19
20
  @service sidebar;
21
+ @service orderPresentation;
20
22
  @service abilities;
21
23
  @tracked routingControl;
22
24
  @tracked routingCompleted = false;
@@ -77,6 +79,9 @@ export default class OperationsOrdersIndexDetailsController extends Controller {
77
79
  return [
78
80
  {
79
81
  route: 'operations.orders.index.details.index',
82
+ // Pass the order explicitly: without it the link's href is generated from whatever
83
+ // transition is in flight, and leaving for a shallower route throws in the router.
84
+ model: this.model?.public_id,
80
85
  label: 'Overview',
81
86
  icon: 'folder-open',
82
87
  },
@@ -84,28 +89,46 @@ export default class OperationsOrdersIndexDetailsController extends Controller {
84
89
  ];
85
90
  }
86
91
 
92
+ /** True when the order reached a terminal activity (default or configured lifecycle). */
93
+ get isClosed() {
94
+ const status = this.model.status;
95
+ const lifecycle = this.model.order_config?.meta?.lifecycle;
96
+ if (!lifecycle) {
97
+ return status === 'canceled';
98
+ }
99
+
100
+ // Matches OrderConfig::getTerminalActivityCodes(): `terminal` plus the configured completed and canceled codes.
101
+ const terminal = [...(Array.isArray(lifecycle.terminal) ? lifecycle.terminal : []), lifecycle.completed, lifecycle.canceled].filter(Boolean);
102
+ return status === 'canceled' || terminal.includes(status);
103
+ }
104
+
87
105
  get actionButtons() {
106
+ const isHidden = (id) => this.orderPresentation.isHidden(this.model, 'actions', id);
107
+
88
108
  return [
89
109
  {
90
110
  items: [
91
111
  {
112
+ id: 'edit-order-details',
92
113
  text: 'Edit details',
93
114
  icon: 'pencil',
115
+ disabled: this.isClosed,
94
116
  permission: 'fleet-ops update order',
95
- disabled: this.model.status === 'canceled',
96
117
  fn: () => this.orderActions.editOrderDetails(this.model),
97
118
  },
98
119
  {
120
+ id: 'update-activity',
99
121
  text: 'Update activity',
100
122
  icon: 'signal',
123
+ disabled: this.isClosed,
101
124
  permission: 'fleet-ops update order',
102
- disabled: this.model.status === 'canceled',
103
125
  fn: () =>
104
126
  this.orderActions.updateActivity(this.model, {
105
127
  onFinish: this.handleActivityModalFinish,
106
128
  }),
107
129
  },
108
130
  {
131
+ id: this.model.has_driver_assigned ? 'unassign-driver' : 'assign-driver',
109
132
  text: this.model.has_driver_assigned ? 'Unassign driver' : 'Assign driver',
110
133
  icon: this.model.has_driver_assigned ? 'user-xmark' : 'edit',
111
134
  permission: 'fleet-ops assign-driver-for order',
@@ -113,6 +136,7 @@ export default class OperationsOrdersIndexDetailsController extends Controller {
113
136
  fn: () => (this.model.has_driver_assigned ? this.orderActions.unassignDriver(this.model) : this.orderActions.assignDriver(this.model)),
114
137
  },
115
138
  {
139
+ id: 'view-label',
116
140
  text: 'View order label',
117
141
  icon: 'file-invoice',
118
142
  permission: 'fleet-ops view order',
@@ -122,11 +146,13 @@ export default class OperationsOrdersIndexDetailsController extends Controller {
122
146
  separator: true,
123
147
  },
124
148
  {
149
+ id: 'listen-to-socket-channel',
125
150
  text: 'Listen to socket channel',
126
151
  icon: 'headphones',
127
152
  fn: () => this.hostRouter.transitionTo('console.developers.sockets.view', `order.${this.model.public_id}`),
128
153
  },
129
154
  {
155
+ id: 'view-metadata',
130
156
  text: 'View metadata',
131
157
  icon: 'table',
132
158
  fn: () => this.orderActions.viewMetadata(this.model),
@@ -135,14 +161,16 @@ export default class OperationsOrdersIndexDetailsController extends Controller {
135
161
  separator: true,
136
162
  },
137
163
  {
164
+ id: 'cancel',
138
165
  text: 'Cancel order',
139
166
  icon: 'ban',
140
167
  class: 'text-danger',
168
+ disabled: this.isClosed,
141
169
  permission: 'fleet-ops cancel order',
142
- disabled: this.model.status === 'canceled',
143
170
  fn: () => this.orderActions.cancel(this.model),
144
171
  },
145
172
  {
173
+ id: 'delete',
146
174
  text: 'Delete order',
147
175
  icon: 'trash',
148
176
  class: 'text-danger',
@@ -156,7 +184,10 @@ export default class OperationsOrdersIndexDetailsController extends Controller {
156
184
  },
157
185
  }),
158
186
  },
159
- ].filter(Boolean),
187
+ ]
188
+ .filter(Boolean)
189
+ .filter((item) => !item.id || !isHidden(item.id))
190
+ .filter((item, index, items) => !(item.separator && (index === 0 || items[index - 1]?.separator))),
160
191
  },
161
192
  ].map((actionButton) => ({ ...actionButton, items: this.permittedMenuItems(actionButton.items) }));
162
193
  }
@@ -192,10 +223,22 @@ export default class OperationsOrdersIndexDetailsController extends Controller {
192
223
  }
193
224
 
194
225
  @task *refresh() {
226
+ yield this.refreshDetails();
227
+ }
228
+
229
+ /**
230
+ * Reload only the order details route. A bare `hostRouter.refresh()` re-runs every route
231
+ * from the application down (console, the engine's application `beforeModel`, the orders
232
+ * list), so a socket event during navigation leaves a slow refresh in flight.
233
+ */
234
+ async refreshDetails() {
195
235
  try {
196
- yield this.hostRouter.refresh();
236
+ await getOwner(this).lookup('route:operations.orders.index.details').refresh();
197
237
  } catch (error) {
198
- return error;
238
+ // A refresh superseded by a newer transition is expected, not an error.
239
+ if (error?.name !== 'TransitionAborted') {
240
+ throw error;
241
+ }
199
242
  }
200
243
  }
201
244
 
@@ -219,7 +262,7 @@ export default class OperationsOrdersIndexDetailsController extends Controller {
219
262
  this.model,
220
263
  async (_msg, { reloadable }) => {
221
264
  if (reloadable) {
222
- await this.hostRouter.refresh();
265
+ await this.refreshDetails();
223
266
  }
224
267
  },
225
268
  { debounceMs: 250 }
@@ -7,6 +7,7 @@ import relationValue from '../../../utils/relation-value';
7
7
 
8
8
  export default class OperationsOrdersIndexController extends Controller {
9
9
  @service orderActions;
10
+ @service orderPresentation;
10
11
  @service driverActions;
11
12
  @service vehicleActions;
12
13
  @service store;
@@ -18,7 +19,7 @@ export default class OperationsOrdersIndexController extends Controller {
18
19
  @service intl;
19
20
 
20
21
  /** query params */
21
- @tracked queryParams = [
22
+ @tracked queryParams = this.orderActions.queryParamsFor([
22
23
  'page',
23
24
  'limit',
24
25
  'sort',
@@ -46,7 +47,7 @@ export default class OperationsOrdersIndexController extends Controller {
46
47
  'drawerOpen',
47
48
  'drawerTab',
48
49
  'orderPanelOpen',
49
- ];
50
+ ]);
50
51
  @tracked page = 1;
51
52
  @tracked limit;
52
53
  @tracked sort = '-created_at';
@@ -77,11 +78,13 @@ export default class OperationsOrdersIndexController extends Controller {
77
78
  get actionButtons() {
78
79
  return [
79
80
  {
81
+ id: 'refresh',
80
82
  icon: 'refresh',
81
83
  onClick: this.orderActions.refresh,
82
84
  helpText: this.intl.t('common.refresh'),
83
85
  },
84
86
  {
87
+ id: 'create',
85
88
  text: this.intl.t('common.new'),
86
89
  type: 'primary',
87
90
  icon: 'plus',
@@ -89,6 +92,7 @@ export default class OperationsOrdersIndexController extends Controller {
89
92
  permission: 'fleet-ops create order',
90
93
  },
91
94
  {
95
+ id: 'export',
92
96
  text: this.intl.t('common.export'),
93
97
  icon: 'long-arrow-up',
94
98
  iconClass: 'rotate-icon-45',
@@ -97,6 +101,7 @@ export default class OperationsOrdersIndexController extends Controller {
97
101
  permission: 'fleet-ops export order',
98
102
  },
99
103
  {
104
+ id: 'import-orders',
100
105
  text: this.intl.t('common.import'),
101
106
  icon: 'file-import',
102
107
  wrapperClass: 'hidden md:flex',
@@ -110,12 +115,14 @@ export default class OperationsOrdersIndexController extends Controller {
110
115
  get bulkActions() {
111
116
  return [
112
117
  {
118
+ id: 'bulk-cancel',
113
119
  label: this.intl.t('common.cancel-resource', { resource: this.intl.t('resource.orders') }),
114
120
  icon: 'ban',
115
121
  fn: this.orderActions.bulkCancel,
116
122
  permission: 'fleet-ops cancel order',
117
123
  },
118
124
  {
125
+ id: 'bulk-delete',
119
126
  label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.orders') }),
120
127
  icon: 'trash',
121
128
  class: 'text-red-500',
@@ -124,12 +131,14 @@ export default class OperationsOrdersIndexController extends Controller {
124
131
  },
125
132
  { separator: true },
126
133
  {
134
+ id: 'bulk-dispatch',
127
135
  label: this.intl.t('common.dispatch-orders'),
128
136
  icon: 'rocket',
129
137
  fn: this.orderActions.bulkDispatch,
130
138
  permission: 'fleet-ops dispatch order',
131
139
  },
132
140
  {
141
+ id: 'bulk-assign-driver',
133
142
  label: this.intl.t('common.assign-drivers'),
134
143
  icon: 'user-plus',
135
144
  fn: this.orderActions.bulkAssignDriver,
@@ -142,6 +151,7 @@ export default class OperationsOrdersIndexController extends Controller {
142
151
  get columns() {
143
152
  return [
144
153
  {
154
+ id: 'public-id',
145
155
  sticky: true,
146
156
  label: this.intl.t('column.id'),
147
157
  valuePath: 'public_id',
@@ -155,6 +165,7 @@ export default class OperationsOrdersIndexController extends Controller {
155
165
  filterComponent: 'filter/string',
156
166
  },
157
167
  {
168
+ id: 'payload-waypoints-length',
158
169
  label: this.intl.t('column.route-type'),
159
170
  valuePath: 'payload.waypoints.length',
160
171
  cellComponent: 'cell/order-route-type',
@@ -162,6 +173,7 @@ export default class OperationsOrdersIndexController extends Controller {
162
173
  resizable: true,
163
174
  },
164
175
  {
176
+ id: 'internal-id',
165
177
  label: this.intl.t('column.internal-id'),
166
178
  valuePath: 'internal_id',
167
179
  cellComponent: 'click-to-copy',
@@ -174,6 +186,7 @@ export default class OperationsOrdersIndexController extends Controller {
174
186
  filterComponentPlaceholder: this.intl.t('order.placeholders.filter-internal-id'),
175
187
  },
176
188
  {
189
+ id: 'payload-public-id',
177
190
  label: this.intl.t('column.payload'),
178
191
  valuePath: 'payload.public_id',
179
192
  cellComponent: 'cell/payload-identity',
@@ -186,6 +199,7 @@ export default class OperationsOrdersIndexController extends Controller {
186
199
  filterComponent: 'filter/string',
187
200
  },
188
201
  {
202
+ id: 'driver-assigned',
189
203
  label: this.intl.t('column.driver-assigned'),
190
204
  cellComponent: 'cell/driver-identity',
191
205
  valuePath: 'driver_assigned',
@@ -203,6 +217,7 @@ export default class OperationsOrdersIndexController extends Controller {
203
217
  model: 'driver',
204
218
  },
205
219
  {
220
+ id: 'pickup-name',
206
221
  label: this.intl.t('column.pickup'),
207
222
  valuePath: 'pickupName',
208
223
  cellComponent: 'cell/place-identity',
@@ -219,6 +234,7 @@ export default class OperationsOrdersIndexController extends Controller {
219
234
  model: 'place',
220
235
  },
221
236
  {
237
+ id: 'dropoff-name',
222
238
  label: this.intl.t('column.dropoff'),
223
239
  valuePath: 'dropoffName',
224
240
  cellComponent: 'cell/place-identity',
@@ -234,6 +250,7 @@ export default class OperationsOrdersIndexController extends Controller {
234
250
  model: 'place',
235
251
  },
236
252
  {
253
+ id: 'customer-name',
237
254
  label: this.intl.t('column.customer'),
238
255
  valuePath: 'customer.name',
239
256
  cellComponent: 'cell/customer-identity',
@@ -248,6 +265,7 @@ export default class OperationsOrdersIndexController extends Controller {
248
265
  model: 'customer',
249
266
  },
250
267
  {
268
+ id: 'vehicle-assigned-display-name',
251
269
  label: this.intl.t('column.vehicle-assigned'),
252
270
  cellComponent: 'cell/vehicle-identity',
253
271
  valuePath: 'vehicle_assigned.display_name',
@@ -271,6 +289,7 @@ export default class OperationsOrdersIndexController extends Controller {
271
289
  model: 'vehicle',
272
290
  },
273
291
  {
292
+ id: 'facilitator-name',
274
293
  label: this.intl.t('column.facilitator'),
275
294
  valuePath: 'facilitator.name',
276
295
  cellComponent: 'cell/facilitator-identity',
@@ -285,6 +304,7 @@ export default class OperationsOrdersIndexController extends Controller {
285
304
  model: 'vendor',
286
305
  },
287
306
  {
307
+ id: 'scheduled-at',
288
308
  label: this.intl.t('column.scheduled-at'),
289
309
  valuePath: 'scheduledAt',
290
310
  sortParam: 'scheduled_at',
@@ -295,6 +315,7 @@ export default class OperationsOrdersIndexController extends Controller {
295
315
  filterComponent: 'filter/date',
296
316
  },
297
317
  {
318
+ id: 'item-count',
298
319
  label: this.intl.t('column.items'),
299
320
  cellComponent: 'table/cell/base',
300
321
  valuePath: 'item_count',
@@ -302,6 +323,7 @@ export default class OperationsOrdersIndexController extends Controller {
302
323
  hidden: true,
303
324
  },
304
325
  {
326
+ id: 'transaction-amount',
305
327
  label: this.intl.t('column.transaction'),
306
328
  cellComponent: 'table/cell/currency',
307
329
  valuePath: 'transaction_amount',
@@ -310,6 +332,7 @@ export default class OperationsOrdersIndexController extends Controller {
310
332
  sortable: true,
311
333
  },
312
334
  {
335
+ id: 'tracking-number-tracking-number',
313
336
  label: this.intl.t('column.tracking'),
314
337
  valuePath: 'tracking_number.tracking_number',
315
338
  cellComponent: 'click-to-copy',
@@ -319,6 +342,7 @@ export default class OperationsOrdersIndexController extends Controller {
319
342
  filterComponent: 'filter/string',
320
343
  },
321
344
  {
345
+ id: 'type',
322
346
  label: this.intl.t('column.type'),
323
347
  valuePath: 'type',
324
348
  resizable: true,
@@ -330,6 +354,7 @@ export default class OperationsOrdersIndexController extends Controller {
330
354
  filterComponentPlaceholder: 'Filter by order config',
331
355
  },
332
356
  {
357
+ id: 'status',
333
358
  label: this.intl.t('column.status'),
334
359
  valuePath: 'status',
335
360
  cellComponent: 'table/cell/status',
@@ -340,6 +365,7 @@ export default class OperationsOrdersIndexController extends Controller {
340
365
  fetchUri: 'orders/statuses',
341
366
  },
342
367
  {
368
+ id: 'created-at',
343
369
  label: this.intl.t('column.created-at'),
344
370
  valuePath: 'createdAt',
345
371
  sortParam: 'created_at',
@@ -350,6 +376,7 @@ export default class OperationsOrdersIndexController extends Controller {
350
376
  filterComponent: 'filter/date',
351
377
  },
352
378
  {
379
+ id: 'updated-at',
353
380
  label: this.intl.t('column.updated-at'),
354
381
  valuePath: 'updatedAt',
355
382
  sortParam: 'updated_at',
@@ -361,6 +388,7 @@ export default class OperationsOrdersIndexController extends Controller {
361
388
  filterComponent: 'filter/date',
362
389
  },
363
390
  {
391
+ id: 'created-by-name',
364
392
  label: this.intl.t('column.created-by'),
365
393
  valuePath: 'created_by_name',
366
394
  cellComponent: 'table/cell/user-identity',
@@ -374,6 +402,7 @@ export default class OperationsOrdersIndexController extends Controller {
374
402
  model: 'user',
375
403
  },
376
404
  {
405
+ id: 'updated-by-name',
377
406
  label: this.intl.t('column.updated-by'),
378
407
  valuePath: 'updated_by_name',
379
408
  cellComponent: 'table/cell/user-identity',
@@ -397,6 +426,7 @@ export default class OperationsOrdersIndexController extends Controller {
397
426
  hidden: true,
398
427
  },
399
428
  {
429
+ id: 'row-actions',
400
430
  label: '',
401
431
  cellComponent: 'table/cell/dropdown',
402
432
  ddButtonText: false,
@@ -407,14 +437,16 @@ export default class OperationsOrdersIndexController extends Controller {
407
437
  wrapperClass: 'flex items-center justify-end mx-2',
408
438
  sticky: 'right',
409
439
  width: 60,
410
- actions: [
440
+ actions: this.withPresentationProfile([
411
441
  {
442
+ id: 'view',
412
443
  label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.order') }),
413
444
  icon: 'eye',
414
445
  fn: this.orderActions.transition.view,
415
446
  permission: 'fleet-ops view order',
416
447
  },
417
448
  {
449
+ id: 'dispatch',
418
450
  label: this.intl.t('common.dispatch-order'),
419
451
  icon: 'paper-plane',
420
452
  fn: this.orderActions.dispatch,
@@ -422,6 +454,7 @@ export default class OperationsOrdersIndexController extends Controller {
422
454
  isVisible: (order) => order.canBeDispatched,
423
455
  },
424
456
  {
457
+ id: 'assign-driver',
425
458
  label: this.intl.t('common.assign-driver'),
426
459
  icon: 'edit',
427
460
  fn: this.orderActions.assignDriver,
@@ -429,6 +462,7 @@ export default class OperationsOrdersIndexController extends Controller {
429
462
  isVisible: (order) => !order.has_driver_assigned,
430
463
  },
431
464
  {
465
+ id: 'unassign-driver',
432
466
  label: this.intl.t('common.unassign-driver'),
433
467
  icon: 'edit',
434
468
  fn: this.orderActions.unassignDriver,
@@ -436,6 +470,7 @@ export default class OperationsOrdersIndexController extends Controller {
436
470
  isVisible: (order) => order.has_driver_assigned,
437
471
  },
438
472
  {
473
+ id: 'cancel',
439
474
  label: this.intl.t('common.cancel-resource', { resource: this.intl.t('resource.order') }),
440
475
  icon: 'ban',
441
476
  fn: this.orderActions.cancel,
@@ -445,12 +480,13 @@ export default class OperationsOrdersIndexController extends Controller {
445
480
  separator: true,
446
481
  },
447
482
  {
483
+ id: 'delete',
448
484
  label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.order') }),
449
485
  icon: 'trash',
450
486
  fn: this.orderActions.delete,
451
487
  permission: 'fleet-ops delete order',
452
488
  },
453
- ],
489
+ ]),
454
490
  sortable: false,
455
491
  filterable: false,
456
492
  resizable: false,
@@ -459,6 +495,25 @@ export default class OperationsOrdersIndexController extends Controller {
459
495
  ];
460
496
  }
461
497
 
498
+ /**
499
+ * Hides the row actions an order's presentation profile lists in `hidden.actions`, by id,
500
+ * the same way the details panel does.
501
+ */
502
+ withPresentationProfile(actions) {
503
+ return actions.map((item) => {
504
+ if (!item.id) {
505
+ return item;
506
+ }
507
+
508
+ const isVisible = item.isVisible;
509
+ const builtInVisible = (order, ...rest) => (typeof isVisible === 'function' ? isVisible(order, ...rest) : isVisible !== false);
510
+ return {
511
+ ...item,
512
+ isVisible: (order, ...rest) => !this.orderPresentation.isHidden(order, 'actions', item.id) && builtInVisible(order, ...rest),
513
+ };
514
+ });
515
+ }
516
+
462
517
  constructor() {
463
518
  super(...arguments);
464
519
  this.orderSocketEvents.startCompany();