@fleetbase/fleetops-engine 0.6.71 → 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 (378) hide show
  1. package/RELEASE.md +15 -18
  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/form/route.hbs +1 -1
  16. package/addon/components/order/form/route.js +13 -1
  17. package/addon/components/service-rate/details.hbs +1 -1
  18. package/addon/components/service-rate/form.hbs +1 -1
  19. package/addon/components/tracking-page/full-view.hbs +276 -0
  20. package/addon/components/tracking-page/full-view.js +474 -0
  21. package/addon/components/tracking-page/locale-selector.js +30 -0
  22. package/addon/components/tracking-page/map.hbs +44 -0
  23. package/addon/components/tracking-page/map.js +328 -0
  24. package/addon/components/tracking-page/order-list.hbs +35 -0
  25. package/addon/components/tracking-page/public-view.hbs +60 -0
  26. package/addon/components/tracking-page/settings-preview.hbs +21 -0
  27. package/addon/components/tracking-page/settings-preview.js +23 -0
  28. package/addon/components/tracking-page/verify-panel.hbs +109 -0
  29. package/addon/components/tracking-page.hbs +142 -0
  30. package/addon/components/tracking-page.js +564 -0
  31. package/addon/components/trailer/form.hbs +2 -2
  32. package/addon/components/vehicle/form.hbs +3 -3
  33. package/addon/components/warranty/form.hbs +2 -2
  34. package/addon/components/widget/live-fleet.js +54 -6
  35. package/addon/components/widget/proof-of-delivery.hbs +49 -0
  36. package/addon/components/widget/proof-of-delivery.js +62 -0
  37. package/addon/components/work-order/form.hbs +3 -3
  38. package/addon/controllers/operations/orders/index/details.js +19 -3
  39. package/addon/controllers/operations/scheduler/index.js +45 -14
  40. package/addon/controllers/settings/index.js +6 -0
  41. package/addon/controllers/settings/map.js +75 -0
  42. package/addon/controllers/settings/orchestrator.js +8 -6
  43. package/addon/controllers/settings/tracking-page.js +212 -0
  44. package/addon/extension.js +65 -1
  45. package/addon/helpers/parcel-box-image.js +16 -0
  46. package/addon/routes/operations/orders/index/new.js +5 -4
  47. package/addon/routes/operations/scheduler/index.js +1 -1
  48. package/addon/routes/settings/tracking-page.js +31 -0
  49. package/addon/routes.js +1 -0
  50. package/addon/services/location.js +69 -21
  51. package/addon/services/map-settings.js +28 -0
  52. package/addon/services/order-allocation.js +1 -1
  53. package/addon/styles/fleetops-engine.css +1391 -0
  54. package/addon/templates/settings/map.hbs +46 -0
  55. package/addon/templates/settings/tracking-page.hbs +318 -0
  56. package/addon/utils/identity-cell-resource.js +2 -56
  57. package/addon/utils/map-default-view.js +132 -0
  58. package/addon/utils/placeholder-images.js +4 -69
  59. package/addon/utils/resource-descriptors/assets.js +2 -57
  60. package/addon/utils/resource-descriptors/helpers.js +23 -122
  61. package/addon/utils/resource-descriptors/operations.js +2 -61
  62. package/addon/utils/resource-descriptors/people.js +3 -142
  63. package/addon/utils/resource-descriptors/shared.js +18 -0
  64. package/addon/utils/tracking-live-source.js +123 -0
  65. package/addon/utils/tracking-page-theme.js +123 -0
  66. package/app/components/admin/tracking-page-settings.js +1 -0
  67. package/app/components/tracking-page/full-view.js +1 -0
  68. package/app/components/tracking-page/locale-selector.js +1 -0
  69. package/app/components/tracking-page/map.js +1 -0
  70. package/app/components/tracking-page/order-list.js +1 -0
  71. package/app/components/tracking-page/public-view.js +1 -0
  72. package/app/components/tracking-page/settings-preview.js +1 -0
  73. package/app/components/tracking-page/verify-panel.js +1 -0
  74. package/app/components/tracking-page.js +1 -0
  75. package/app/components/widget/proof-of-delivery.js +1 -0
  76. package/app/controllers/settings/tracking-page.js +1 -0
  77. package/app/helpers/parcel-box-image.js +1 -0
  78. package/app/routes/settings/tracking-page.js +1 -0
  79. package/app/templates/settings/tracking-page.js +1 -0
  80. package/app/utils/map-default-view.js +1 -0
  81. package/app/utils/tracking-live-source.js +1 -0
  82. package/app/utils/tracking-page-theme.js +1 -0
  83. package/composer.json +2 -2
  84. package/extension.json +1 -1
  85. package/package.json +4 -4
  86. package/scripts/pest-bootstrap.php +4 -0
  87. package/server/config/fleetops.php +4 -0
  88. package/server/migrations/2026_10_08_000001_create_tracking_sessions_tables.php +51 -0
  89. package/server/migrations/2026_10_10_000001_add_trashed_index_to_device_events.php +40 -0
  90. package/server/migrations/2026_10_10_000002_add_trashed_index_to_positions.php +40 -0
  91. package/server/migrations/2026_10_12_000001_add_deleted_at_to_tracking_sessions_tables.php +32 -0
  92. package/server/resources/views/labels/default.php +2 -2
  93. package/server/resources/views/labels/entity-label.php +2 -2
  94. package/server/resources/views/labels/waypoint-label.php +2 -2
  95. package/server/src/Auth/Schemas/FleetOps.php +5 -0
  96. package/server/src/Console/Commands/ProcessOperationalAlerts.php +1 -0
  97. package/server/src/Console/Commands/PruneTelematicsData.php +101 -26
  98. package/server/src/Events/OrderChanged.php +257 -0
  99. package/server/src/Events/OrderDriverUnassigned.php +68 -0
  100. package/server/src/Exceptions/OrderEditLockedException.php +32 -0
  101. package/server/src/Expansions/CompanyExpansion.php +3 -2
  102. package/server/src/Expansions/UserExpansion.php +12 -10
  103. package/server/src/Http/Controllers/Api/v1/CustomerController.php +108 -18
  104. package/server/src/Http/Controllers/Api/v1/DriverController.php +95 -10
  105. package/server/src/Http/Controllers/Api/v1/EntityController.php +66 -0
  106. package/server/src/Http/Controllers/Api/v1/FleetController.php +10 -4
  107. package/server/src/Http/Controllers/Api/v1/OrderController.php +139 -36
  108. package/server/src/Http/Controllers/Api/v1/PayloadController.php +76 -8
  109. package/server/src/Http/Controllers/Api/v1/PlaceController.php +3 -3
  110. package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +6 -32
  111. package/server/src/Http/Controllers/Api/v1/VehicleController.php +5 -0
  112. package/server/src/Http/Controllers/Internal/v1/ContactController.php +3 -0
  113. package/server/src/Http/Controllers/Internal/v1/DriverController.php +10 -0
  114. package/server/src/Http/Controllers/Internal/v1/FleetController.php +16 -2
  115. package/server/src/Http/Controllers/Internal/v1/InspectionSubmissionController.php +13 -8
  116. package/server/src/Http/Controllers/Internal/v1/IssueController.php +2 -0
  117. package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +4 -2
  118. package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +93 -11
  119. package/server/src/Http/Controllers/Internal/v1/OrderController.php +84 -24
  120. package/server/src/Http/Controllers/Internal/v1/PositionController.php +22 -0
  121. package/server/src/Http/Controllers/Internal/v1/ProofController.php +55 -4
  122. package/server/src/Http/Controllers/Internal/v1/SettingController.php +303 -10
  123. package/server/src/Http/Controllers/Internal/v1/TrailerController.php +1 -0
  124. package/server/src/Http/Controllers/Internal/v1/VehicleController.php +1 -0
  125. package/server/src/Http/Controllers/Public/TrackingController.php +518 -0
  126. package/server/src/Http/Filter/ContactFilter.php +1 -1
  127. package/server/src/Http/Filter/InspectionFormFilter.php +23 -0
  128. package/server/src/Http/Filter/InspectionSubmissionFilter.php +23 -0
  129. package/server/src/Http/Filter/MaintenanceFilter.php +23 -0
  130. package/server/src/Http/Filter/OrderFilter.php +39 -4
  131. package/server/src/Http/Filter/ProofFilter.php +18 -0
  132. package/server/src/Http/Filter/RouteFilter.php +18 -0
  133. package/server/src/Http/Filter/TelematicFilter.php +23 -0
  134. package/server/src/Http/Filter/WarrantyFilter.php +23 -0
  135. package/server/src/Http/Requests/CancelOrderRequest.php +2 -1
  136. package/server/src/Http/Resources/v1/Concerns/ResolvesPublicRelationFields.php +14 -1
  137. package/server/src/Http/Resources/v1/Index/Customer.php +18 -0
  138. package/server/src/Http/Resources/v1/Index/Order.php +11 -2
  139. package/server/src/Http/Resources/v1/PublicOrderTracking.php +153 -0
  140. package/server/src/Http/Resources/v1/TrackingNumber.php +8 -34
  141. package/server/src/Http/Resources/v1/Zone.php +31 -23
  142. package/server/src/Jobs/FinalizeApiOrderCreation.php +3 -1
  143. package/server/src/Jobs/ProcessAllocationJob.php +16 -6
  144. package/server/src/Jobs/PublishTrackingUpdate.php +50 -0
  145. package/server/src/Listeners/HandleGeofenceEntered.php +31 -15
  146. package/server/src/Listeners/HandleOrderCanceled.php +9 -1
  147. package/server/src/Listeners/HandleUserRemovedFromCompany.php +2 -1
  148. package/server/src/Listeners/PublishTrackingUpdates.php +27 -0
  149. package/server/src/Mail/CustomerCredentialsMail.php +4 -2
  150. package/server/src/Models/AssetConnection.php +3 -0
  151. package/server/src/Models/Contact.php +3 -0
  152. package/server/src/Models/Device.php +28 -0
  153. package/server/src/Models/DeviceEvent.php +7 -0
  154. package/server/src/Models/Driver.php +20 -7
  155. package/server/src/Models/Entity.php +12 -4
  156. package/server/src/Models/Fleet.php +11 -32
  157. package/server/src/Models/FleetDriver.php +3 -0
  158. package/server/src/Models/FleetVehicle.php +3 -0
  159. package/server/src/Models/FuelReport.php +5 -13
  160. package/server/src/Models/Issue.php +4 -16
  161. package/server/src/Models/Order.php +200 -9
  162. package/server/src/Models/Payload.php +227 -35
  163. package/server/src/Models/Place.php +7 -1
  164. package/server/src/Models/ServiceArea.php +7 -0
  165. package/server/src/Models/ServiceRate.php +7 -17
  166. package/server/src/Models/TrackingNumber.php +101 -2
  167. package/server/src/Models/TrackingSession.php +33 -0
  168. package/server/src/Models/TrackingSessionGrant.php +22 -0
  169. package/server/src/Models/TrackingStatus.php +6 -0
  170. package/server/src/Models/Vehicle.php +21 -2
  171. package/server/src/Models/Vendor.php +7 -0
  172. package/server/src/Models/Waypoint.php +13 -4
  173. package/server/src/Notifications/OrderAssigned.php +2 -1
  174. package/server/src/Notifications/OrderCanceled.php +7 -1
  175. package/server/src/Notifications/OrderChanged.php +87 -0
  176. package/server/src/Notifications/OrderCompleted.php +2 -1
  177. package/server/src/Notifications/OrderDispatchFailed.php +2 -1
  178. package/server/src/Notifications/OrderDispatched.php +2 -1
  179. package/server/src/Notifications/OrderFailed.php +2 -1
  180. package/server/src/Notifications/OrderUnassigned.php +66 -0
  181. package/server/src/Notifications/WaypointCompleted.php +2 -1
  182. package/server/src/Observers/CompanyUserObserver.php +8 -7
  183. package/server/src/Observers/DriverObserver.php +6 -1
  184. package/server/src/Observers/OrderObserver.php +141 -1
  185. package/server/src/Observers/TrackingNumberObserver.php +18 -6
  186. package/server/src/Observers/UserObserver.php +2 -1
  187. package/server/src/Observers/VehicleObserver.php +8 -3
  188. package/server/src/Orchestration/Engines/RouteSequencingEngine.php +21 -3
  189. package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +38 -8
  190. package/server/src/Orchestration/OrchestrationEngineRegistry.php +61 -1
  191. package/server/src/Orchestration/Support/OrchestratorSettings.php +61 -0
  192. package/server/src/Orchestration/Support/RouteMetrics.php +165 -0
  193. package/server/src/Providers/EventServiceProvider.php +11 -0
  194. package/server/src/Providers/FleetOpsServiceProvider.php +13 -0
  195. package/server/src/Support/ApiCacheThrottle.php +76 -0
  196. package/server/src/Support/LiveOrderQuery.php +3 -1
  197. package/server/src/Support/OrderEdit.php +365 -0
  198. package/server/src/Support/OrderEditPolicy.php +292 -0
  199. package/server/src/Support/ProfileAccountManager.php +54 -1
  200. package/server/src/Support/ResolvesOrderServiceStops.php +5 -0
  201. package/server/src/Support/SocketChannels.php +346 -0
  202. package/server/src/Support/Telematics/TelematicService.php +7 -2
  203. package/server/src/Support/Telematics/Telemetry/Inbox.php +8 -1
  204. package/server/src/Support/TrackingChannel.php +55 -0
  205. package/server/src/Support/TrackingCode.php +242 -0
  206. package/server/src/Support/TrackingPage/TrackingAccess.php +356 -0
  207. package/server/src/Support/TrackingPage/TrackingPageConfig.php +264 -0
  208. package/server/src/Support/TrackingPage/TrackingRecipient.php +111 -0
  209. package/server/src/Support/TrackingPage/TrackingResolver.php +201 -0
  210. package/server/src/Support/TrackingPage/TrackingTarget.php +40 -0
  211. package/server/src/Support/TrackingPage/TrackingView.php +543 -0
  212. package/server/src/Support/TrackingPublisher.php +261 -0
  213. package/server/src/Support/TrackingScope.php +182 -0
  214. package/server/src/Support/TrackingUpdate.php +402 -0
  215. package/server/src/Support/Utils.php +15 -3
  216. package/server/src/Traits/HasTrackingNumber.php +2 -0
  217. package/server/src/routes.php +39 -7
  218. package/server/tests/ApiCustomerControllerContractsTest.php +54 -7
  219. package/server/tests/ApiDriverPasswordContractsTest.php +25 -21
  220. package/server/tests/ApiEntityControllerContractsTest.php +84 -0
  221. package/server/tests/ApiOrderControllerContractsTest.php +245 -0
  222. package/server/tests/ApiPayloadControllerContractsTest.php +121 -0
  223. package/server/tests/ApiPlaceControllerContractsTest.php +1 -1
  224. package/server/tests/ApiTrackingNumberControllerContractsTest.php +6 -9
  225. package/server/tests/CompactResourceSerializationTest.php +23 -59
  226. package/server/tests/ControllerFilterContractsTest.php +1 -1
  227. package/server/tests/CustomerContactIdentitySafetyTest.php +1 -1
  228. package/server/tests/EventContractsTest.php +26 -60
  229. package/server/tests/ExpansionContractsTest.php +15 -2
  230. package/server/tests/Feature/Http/Api/CustomerControllerHelperSeamsTest.php +29 -3
  231. package/server/tests/Feature/Http/Api/DriverControllerAuthFlowsTest.php +23 -0
  232. package/server/tests/Feature/Http/Api/OrderControllerNearbyFiltersTest.php +16 -16
  233. package/server/tests/Feature/Http/Api/OrderControllerQueryFiltersTest.php +41 -14
  234. package/server/tests/Feature/Http/Api/TrackingNumberControllerHelpersTest.php +57 -22
  235. package/server/tests/Feature/Http/Internal/DriverControllerCreateRecordTest.php +23 -9
  236. package/server/tests/Feature/Http/Internal/OrchestrationControllerContractsTest.php +171 -1
  237. package/server/tests/Feature/Http/Internal/OrderControllerContractsTest.php +110 -14
  238. package/server/tests/Feature/Http/Internal/OrderControllerHelpersTest.php +7 -5
  239. package/server/tests/Feature/Http/Internal/PositionControllerReplayChannelTest.php +135 -0
  240. package/server/tests/Feature/Http/Internal/ProofControllerContractsTest.php +3 -3
  241. package/server/tests/Feature/Http/Internal/ProofControllerRecentTest.php +170 -0
  242. package/server/tests/Feature/Http/Public/TrackingControllerTest.php +495 -0
  243. package/server/tests/IndexCustomerPhotoTest.php +151 -0
  244. package/server/tests/ModelAccessorContractsTest.php +4 -3
  245. package/server/tests/NotificationAndMailContractsTest.php +5 -8
  246. package/server/tests/ObserverContractsTest.php +72 -10
  247. package/server/tests/OrderActivityFlowRegressionTest.php +3 -2
  248. package/server/tests/OrderFilterExecutionTest.php +167 -2
  249. package/server/tests/ProcessAllocationJobContractsTest.php +20 -0
  250. package/server/tests/PublicOrderTrackingResourceTest.php +221 -0
  251. package/server/tests/QueueJobContractsTest.php +2 -1
  252. package/server/tests/RequestContractsTest.php +1 -1
  253. package/server/tests/RouteRegistrationExecutionTest.php +26 -0
  254. package/server/tests/RouteSequencingEngineTest.php +17 -0
  255. package/server/tests/SettingControllerContractsTest.php +110 -0
  256. package/server/tests/Support/TrackingPageDatabase.php +200 -0
  257. package/server/tests/TenantScopingTest.php +206 -0
  258. package/server/tests/TrackingPageSettingsTest.php +343 -0
  259. package/server/tests/Unit/Console/PruneTelematicsDataCommandTest.php +51 -0
  260. package/server/tests/Unit/Http/Filter/ContactFilterAddressTest.php +61 -0
  261. package/server/tests/Unit/Http/Resources/IndexOrderResourceTest.php +30 -0
  262. package/server/tests/Unit/Jobs/FinalizeApiOrderCreationDispatchGuardTest.php +266 -0
  263. package/server/tests/Unit/Listeners/HandleGeofenceEnteredTest.php +182 -22
  264. package/server/tests/Unit/Listeners/HandleUserRemovedFromCompanyTest.php +5 -0
  265. package/server/tests/Unit/Models/DriverAssignVehicleTest.php +81 -0
  266. package/server/tests/Unit/Models/FleetTest.php +4 -3
  267. package/server/tests/Unit/Models/OrderCancelReasonTest.php +143 -0
  268. package/server/tests/Unit/Models/OrderPayloadConfigAndDistanceTest.php +60 -0
  269. package/server/tests/Unit/Models/OrderPayloadRouteTest.php +4 -2
  270. package/server/tests/Unit/Models/PayloadTest.php +18 -4
  271. package/server/tests/Unit/Models/ServiceRatePersistenceAndServicabilityTest.php +2 -2
  272. package/server/tests/Unit/Models/TrackingNumberTest.php +67 -6
  273. package/server/tests/Unit/Models/VehicleTest.php +16 -2
  274. package/server/tests/Unit/Models/WaypointTest.php +4 -3
  275. package/server/tests/Unit/Notifications/OrderChangeNotificationsTest.php +59 -0
  276. package/server/tests/Unit/Notifications/TerminalOrderNotificationsTest.php +3 -3
  277. package/server/tests/Unit/Observers/DriverDeletionCleanupTest.php +158 -0
  278. package/server/tests/Unit/Observers/FleetOpsCompanyUserAndServiceAreaObserversTest.php +20 -0
  279. package/server/tests/Unit/Observers/ObserverListenerSeamsTest.php +3 -3
  280. package/server/tests/Unit/Observers/OrderAssignmentObserverTest.php +100 -0
  281. package/server/tests/Unit/Observers/OrderDeleteCascadeTest.php +213 -0
  282. package/server/tests/Unit/Observers/VehicleObserverDeleteTest.php +67 -0
  283. package/server/tests/Unit/Orchestration/EngineSelectionAndRouteMetricsTest.php +336 -0
  284. package/server/tests/Unit/Orchestration/Engines/VroomOrchestrationEngineLifecycleTest.php +8 -1
  285. package/server/tests/Unit/Support/ApiCacheDependenciesTest.php +347 -0
  286. package/server/tests/Unit/Support/OrderEditPolicyTest.php +156 -0
  287. package/server/tests/Unit/Support/OrderOperationsTest.php +514 -0
  288. package/server/tests/Unit/Support/OsrmProofAndIssueFilterTest.php +4 -3
  289. package/server/tests/Unit/Support/ProfileAccountManagerTest.php +141 -0
  290. package/server/tests/Unit/Support/QuerySeamsTest.php +5 -1
  291. package/server/tests/Unit/Support/SocketChannelsTest.php +396 -0
  292. package/server/tests/Unit/Support/TrackingChannelTest.php +232 -0
  293. package/server/tests/Unit/Support/TrackingCodeTest.php +186 -0
  294. package/server/tests/Unit/Support/TrackingPage/TrackingAccessTest.php +200 -0
  295. package/server/tests/Unit/Support/TrackingPage/TrackingRecipientTest.php +51 -0
  296. package/server/tests/Unit/Support/TrackingPage/TrackingResolverTest.php +181 -0
  297. package/server/tests/Unit/Support/TrackingPage/TrackingViewTest.php +479 -0
  298. package/server/tests/Unit/Support/TrackingPublisherTest.php +425 -0
  299. package/server/tests/Unit/Support/TrackingUpdateTest.php +363 -0
  300. package/server/tests/Unit/Support/UtilsAdditionalTest.php +9 -0
  301. package/server/tests/Unit/Support/UtilsGeoMatrixAndVendorTest.php +25 -0
  302. package/server/tests/VehicleResourceContractsTest.php +46 -0
  303. package/server/tests/VroomOrchestrationEngineTest.php +34 -1
  304. package/server/tests/ZoneGeofenceSettingsResourceTest.php +121 -0
  305. package/translations/ar-ae.yml +274 -0
  306. package/translations/bg-bg.yaml +274 -0
  307. package/translations/en-us.yaml +287 -0
  308. package/translations/es-pa.yaml +274 -0
  309. package/translations/fr-fr.yaml +274 -0
  310. package/translations/mn-mn.yaml +274 -0
  311. package/translations/pt-br.yaml +274 -0
  312. package/translations/ru-ru.yaml +276 -2
  313. package/translations/uk-ua.yaml +275 -1
  314. package/translations/vi-vn.yaml +274 -0
  315. package/addon/components/cell/contact-identity.hbs +0 -1
  316. package/addon/components/cell/customer-identity.hbs +0 -1
  317. package/addon/components/cell/driver-identity.hbs +0 -1
  318. package/addon/components/cell/fleet-identity.hbs +0 -1
  319. package/addon/components/cell/order-identity.hbs +0 -1
  320. package/addon/components/cell/place-identity.hbs +0 -1
  321. package/addon/components/cell/vehicle-identity.hbs +0 -1
  322. package/addon/components/cell/vendor-identity.hbs +0 -1
  323. package/addon/components/contact/pill.hbs +0 -24
  324. package/addon/components/contact/summary.hbs +0 -1
  325. package/addon/components/customer/pill.hbs +0 -24
  326. package/addon/components/customer/summary.hbs +0 -1
  327. package/addon/components/driver/pill.hbs +0 -24
  328. package/addon/components/driver/summary.hbs +0 -1
  329. package/addon/components/fleet/pill.hbs +0 -24
  330. package/addon/components/fleet/summary.hbs +0 -1
  331. package/addon/components/order/pill.hbs +0 -24
  332. package/addon/components/order/summary.hbs +0 -1
  333. package/addon/components/place/pill.hbs +0 -24
  334. package/addon/components/place/summary.hbs +0 -1
  335. package/addon/components/select-option/contact.hbs +0 -12
  336. package/addon/components/select-option/customer.hbs +0 -12
  337. package/addon/components/select-option/driver.hbs +0 -12
  338. package/addon/components/select-option/fleet.hbs +0 -12
  339. package/addon/components/select-option/order.hbs +0 -12
  340. package/addon/components/select-option/place.hbs +0 -12
  341. package/addon/components/select-option/vehicle.hbs +0 -12
  342. package/addon/components/select-option/vendor.hbs +0 -12
  343. package/addon/components/vehicle/pill.hbs +0 -24
  344. package/addon/components/vehicle/summary.hbs +0 -1
  345. package/addon/components/vendor/pill.hbs +0 -24
  346. package/addon/components/vendor/summary.hbs +0 -1
  347. package/app/components/cell/contact-identity.js +0 -1
  348. package/app/components/cell/customer-identity.js +0 -1
  349. package/app/components/cell/driver-identity.js +0 -1
  350. package/app/components/cell/fleet-identity.js +0 -1
  351. package/app/components/cell/order-identity.js +0 -1
  352. package/app/components/cell/place-identity.js +0 -1
  353. package/app/components/cell/vehicle-identity.js +0 -1
  354. package/app/components/cell/vendor-identity.js +0 -1
  355. package/app/components/contact/pill.js +0 -1
  356. package/app/components/contact/summary.js +0 -1
  357. package/app/components/customer/pill.js +0 -1
  358. package/app/components/customer/summary.js +0 -1
  359. package/app/components/driver/pill.js +0 -1
  360. package/app/components/driver/summary.js +0 -1
  361. package/app/components/fleet/pill.js +0 -1
  362. package/app/components/fleet/summary.js +0 -1
  363. package/app/components/order/pill.js +0 -1
  364. package/app/components/order/summary.js +0 -1
  365. package/app/components/place/pill.js +0 -1
  366. package/app/components/place/summary.js +0 -1
  367. package/app/components/select-option/contact.js +0 -1
  368. package/app/components/select-option/customer.js +0 -1
  369. package/app/components/select-option/driver.js +0 -1
  370. package/app/components/select-option/fleet.js +0 -1
  371. package/app/components/select-option/order.js +0 -1
  372. package/app/components/select-option/place.js +0 -1
  373. package/app/components/select-option/vehicle.js +0 -1
  374. package/app/components/select-option/vendor.js +0 -1
  375. package/app/components/vehicle/pill.js +0 -1
  376. package/app/components/vehicle/summary.js +0 -1
  377. package/app/components/vendor/pill.js +0 -1
  378. package/app/components/vendor/summary.js +0 -1
@@ -8,8 +8,11 @@ use Fleetbase\FleetOps\Events\OrderCanceled;
8
8
  use Fleetbase\FleetOps\Events\OrderCompleted;
9
9
  use Fleetbase\FleetOps\Events\OrderDispatched;
10
10
  use Fleetbase\FleetOps\Events\OrderDriverAssigned;
11
+ use Fleetbase\FleetOps\Events\OrderDriverUnassigned;
11
12
  use Fleetbase\FleetOps\Flow\Activity;
13
+ use Fleetbase\FleetOps\Notifications\OrderUnassigned;
12
14
  use Fleetbase\FleetOps\Support\LabelPdf;
15
+ use Fleetbase\FleetOps\Support\OrderEditPolicy;
13
16
  use Fleetbase\FleetOps\Support\OrderTracker;
14
17
  use Fleetbase\FleetOps\Support\Utils;
15
18
  use Fleetbase\FleetOps\Traits\HasTrackingNumber;
@@ -35,6 +38,7 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
35
38
  use Illuminate\Database\Eloquent\Relations\Relation;
36
39
  use Illuminate\Support\Carbon;
37
40
  use Illuminate\Support\Collection;
41
+ use Illuminate\Support\Facades\Log;
38
42
  use Illuminate\Support\Str;
39
43
  use Spatie\Activitylog\LogOptions;
40
44
  use Spatie\Activitylog\Traits\LogsActivity;
@@ -196,6 +200,38 @@ class Order extends Model
196
200
  */
197
201
  protected $with = [];
198
202
 
203
+ /**
204
+ * Relation paths and tables the cached order lists embed, so a write to any
205
+ * of them invalidates those lists (fleetbase/core-api#301).
206
+ *
207
+ * They mirror OrderFilter::queryForInternal()'s eager loads and whereHas
208
+ * membership, the payload relation's own `with`, Payload's `$with` and the
209
+ * public query's loads. customer and facilitator are morphTo relations, so
210
+ * their tables (contacts, vendors, integrated_vendors) are named instead;
211
+ * a vendor loads its place, which payload.pickup already covers. files
212
+ * (customer photo, vendor logo) is left out: every upload writes it, and a
213
+ * new photo is set by writing the contact's or vendor's own row.
214
+ *
215
+ * @var string[]
216
+ */
217
+ protected $apiCacheDependencies = [
218
+ 'payload',
219
+ 'payload.pickup',
220
+ 'payload.dropoff',
221
+ 'payload.return',
222
+ 'payload.entities',
223
+ 'payload.waypoints',
224
+ 'payload.firstWaypointMarker.place',
225
+ 'payload.lastWaypointMarker.place',
226
+ 'trackingNumber',
227
+ 'trackingStatuses',
228
+ 'driverAssigned',
229
+ 'vehicleAssigned',
230
+ 'contacts',
231
+ 'vendors',
232
+ 'integrated_vendors',
233
+ ];
234
+
199
235
  /**
200
236
  * The attributes that should be cast to native types.
201
237
  *
@@ -244,6 +280,16 @@ class Order extends Model
244
280
  '_key',
245
281
  ];
246
282
 
283
+ /**
284
+ * Set for one save: the driver assignment being saved sends no assignment notification.
285
+ */
286
+ public bool $silentDriverAssignment = false;
287
+
288
+ /**
289
+ * Set for one save: the driver taken off the order is not sent an unassigned push (they declined it themselves).
290
+ */
291
+ public bool $quietDriverUnassignment = false;
292
+
247
293
  /**
248
294
  * Enforce a morph map.
249
295
  */
@@ -263,6 +309,31 @@ class Order extends Model
263
309
  );
264
310
  }
265
311
 
312
+ /**
313
+ * Bulk removal deletes the matched orders one at a time instead of with a single
314
+ * query, so the "deleted" event fires for each and OrderObserver cascades the soft
315
+ * delete to the order's payload, entities and tracking data. Matching, the tenant
316
+ * constraint (GHSA-3wj9-hh56-7fw7) and the returned count follow core-api's version.
317
+ */
318
+ public function bulkRemove($ids = [])
319
+ {
320
+ $orders = static::where(function ($query) use ($ids) {
321
+ $query->whereIn($this->getQualifiedKeyName(), $ids)->orWhereIn($this->getQualifiedPublicId(), $ids);
322
+ });
323
+
324
+ // Tenant constraint: never delete another company's orders.
325
+ $companyUuid = session('company');
326
+ if ($companyUuid) {
327
+ $orders->where($this->qualifyColumn('company_uuid'), $companyUuid);
328
+ }
329
+
330
+ $orders = $orders->get();
331
+ $orders->each->delete();
332
+ $this->invalidateApiCacheOnChange();
333
+
334
+ return $orders->count();
335
+ }
336
+
266
337
  /**
267
338
  * Get the activity log options for the model.
268
339
  */
@@ -1034,6 +1105,7 @@ class Order extends Model
1034
1105
  $route->save();
1035
1106
 
1036
1107
  $this->updateQuietly(['route_uuid' => $route->uuid]);
1108
+ $this->invalidateApiCache();
1037
1109
 
1038
1110
  return $this;
1039
1111
  }
@@ -1169,6 +1241,7 @@ class Order extends Model
1169
1241
  ]);
1170
1242
 
1171
1243
  if ($attached) {
1244
+ $this->invalidateApiCache();
1172
1245
  $this->setRelation('purchaseRate', $purchaseRate);
1173
1246
 
1174
1247
  if ($purchaseRate->transaction_uuid) {
@@ -1231,6 +1304,7 @@ class Order extends Model
1231
1304
  ]);
1232
1305
 
1233
1306
  $this->updateQuietly(['transaction_uuid' => $transaction->uuid]);
1307
+ $this->invalidateApiCache();
1234
1308
  } catch (\Throwable $e) {
1235
1309
  }
1236
1310
 
@@ -1270,6 +1344,7 @@ class Order extends Model
1270
1344
  if ($save) {
1271
1345
  $this->saveQuietly();
1272
1346
  $this->flushAttributesCache();
1347
+ $this->invalidateApiCache();
1273
1348
  }
1274
1349
 
1275
1350
  dispatch(fn () => event(new OrderDispatched($this)))->afterCommit();
@@ -1308,6 +1383,29 @@ class Order extends Model
1308
1383
  return $this;
1309
1384
  }
1310
1385
 
1386
+ /**
1387
+ * Determine whether the order is still waiting to be dispatched.
1388
+ *
1389
+ * A deferred dispatch, such as the queued finalize job for orders created with
1390
+ * `dispatch: true`, can run after the order was already dispatched or started
1391
+ * through another path. Dispatching it then would move the status back to
1392
+ * "dispatched", so only an order that still sits at its initial status with no
1393
+ * dispatch or start recorded qualifies.
1394
+ */
1395
+ public function isAwaitingDispatch(): bool
1396
+ {
1397
+ if ($this->dispatched || $this->dispatched_at || $this->started || $this->started_at) {
1398
+ return false;
1399
+ }
1400
+
1401
+ $status = $this->status ?? 'created';
1402
+ if ($status !== 'created' && $status !== $this->config()?->getInitialStatusCode()) {
1403
+ return false;
1404
+ }
1405
+
1406
+ return !$this->hasDispatchedStatus();
1407
+ }
1408
+
1311
1409
  /**
1312
1410
  * Dispatches the order only if it hasn't been dispatched yet.
1313
1411
  * A check is performed before dispatching the order.
@@ -1345,11 +1443,33 @@ class Order extends Model
1345
1443
  * @return mixed the result of the OrderCanceled event
1346
1444
  */
1347
1445
  public function cancel()
1446
+ {
1447
+ return $this->cancelWithReason(null);
1448
+ }
1449
+
1450
+ /**
1451
+ * Cancels the order, recording why.
1452
+ *
1453
+ * The reason becomes the details of the canceled tracking status and is carried on
1454
+ * the OrderCanceled event's activity, which the canceled notifications read.
1455
+ *
1456
+ * @return mixed the result of the OrderCanceled event
1457
+ */
1458
+ public function cancelWithReason(?string $reason = null)
1348
1459
  {
1349
1460
  // The canceled activity comes from the order config, which may define its own code.
1350
1461
  $this->loadMissing('orderConfig');
1351
1462
  $orderConfig = $this->orderConfig ?? $this->config();
1352
1463
  $canceledActivity = $orderConfig->getCanceledActivity();
1464
+
1465
+ // A reason given for the cancellation becomes the canceled status details, which
1466
+ // the canceled notifications read. The config's activity itself is left untouched.
1467
+ $reason = is_string($reason) ? trim($reason) : null;
1468
+ $reasonActivity = null;
1469
+ if ($reason !== null && $reason !== '' && $canceledActivity instanceof Activity) {
1470
+ $canceledActivity = $reasonActivity = (clone $canceledActivity)->set('details', $reason);
1471
+ }
1472
+
1353
1473
  $this->status = $canceledActivity->code ?? 'canceled';
1354
1474
  $this->updateActivity($canceledActivity);
1355
1475
 
@@ -1361,7 +1481,13 @@ class Order extends Model
1361
1481
  }
1362
1482
  }
1363
1483
 
1364
- return dispatch(fn () => event(new OrderCanceled($this)))->afterCommit();
1484
+ // The event carries the activity when a reason was given, so the canceled
1485
+ // notifications (which read the activity details) include it.
1486
+ return dispatch(function () use ($reasonActivity) {
1487
+ $event = new OrderCanceled($this);
1488
+ $event->activity = $reasonActivity;
1489
+ event($event);
1490
+ })->afterCommit();
1365
1491
  }
1366
1492
 
1367
1493
  /**
@@ -1377,6 +1503,52 @@ class Order extends Model
1377
1503
  }
1378
1504
  }
1379
1505
 
1506
+ /**
1507
+ * Tell a driver the order was taken off them: broadcasts `order.driver_unassigned`
1508
+ * on their channels and pushes `{ type: "order_unassigned", id }` to their devices.
1509
+ * The order is cleared as the driver's current job.
1510
+ *
1511
+ * @param Driver|string|null $driver the driver (or driver uuid) removed from the order
1512
+ */
1513
+ public function notifyDriverUnassigned($driver): bool
1514
+ {
1515
+ if (is_string($driver)) {
1516
+ $driver = Driver::where('uuid', $driver)->withoutGlobalScopes()->first();
1517
+ }
1518
+
1519
+ if (!$driver instanceof Driver) {
1520
+ return false;
1521
+ }
1522
+
1523
+ if ($driver->current_job_uuid && $driver->current_job_uuid === $this->uuid) {
1524
+ $driver->forceFill(['current_job_uuid' => null])->saveQuietly();
1525
+ }
1526
+
1527
+ try {
1528
+ event(new OrderDriverUnassigned($this, $driver));
1529
+ } catch (\Throwable $exception) {
1530
+ Log::warning('Unable to broadcast order.driver_unassigned', ['order' => $this->public_id, 'error' => $exception->getMessage()]);
1531
+ }
1532
+
1533
+ if (!$this->quietDriverUnassignment) {
1534
+ try {
1535
+ $driver->notify(new OrderUnassigned($this));
1536
+ } catch (\Throwable $exception) {
1537
+ Log::warning('Unable to notify driver of unassignment', ['order' => $this->public_id, 'error' => $exception->getMessage()]);
1538
+ }
1539
+ }
1540
+
1541
+ return true;
1542
+ }
1543
+
1544
+ /**
1545
+ * The edit policy for the order at its current status.
1546
+ */
1547
+ public function editPolicy(): OrderEditPolicy
1548
+ {
1549
+ return OrderEditPolicy::for($this);
1550
+ }
1551
+
1380
1552
  /**
1381
1553
  * Updates the activity of the order.
1382
1554
  * Updates the order status and inserts a new activity based on the provided activity details.
@@ -1634,7 +1806,7 @@ class Order extends Model
1634
1806
  return $this;
1635
1807
  }
1636
1808
 
1637
- return $this->assignDriver($driver);
1809
+ return $this->assignDriver($driver, $silent);
1638
1810
  }
1639
1811
 
1640
1812
  throw new \Exception('Invalid driver provided for assignment!');
@@ -1647,12 +1819,16 @@ class Order extends Model
1647
1819
  $this->setRelation('driverAssigned', $driver);
1648
1820
  }
1649
1821
 
1650
- if (!$silent) {
1651
- $this->notifyDriverAssigned();
1822
+ // The order observer sends OrderDriverAssigned once the assignment is saved
1823
+ // (and tells a replaced driver they were unassigned), so it is not fired here
1824
+ // as well. A silent assignment is flagged for that one save.
1825
+ $this->silentDriverAssignment = (bool) $silent;
1826
+ try {
1827
+ $this->save();
1828
+ } finally {
1829
+ $this->silentDriverAssignment = false;
1652
1830
  }
1653
1831
 
1654
- $this->save();
1655
-
1656
1832
  return $this;
1657
1833
  }
1658
1834
 
@@ -1672,7 +1848,10 @@ class Order extends Model
1672
1848
  $driverAssigned = Driver::where('uuid', $this->driver_assigned_uuid)->first();
1673
1849
  }
1674
1850
 
1675
- if ($driverAssigned instanceof Driver) {
1851
+ // A driver that has never reported a position still carries the
1852
+ // POINT(0 0) placeholder it was created with. Measuring from there
1853
+ // puts the origin at null island, so fall back to the pickup.
1854
+ if ($driverAssigned instanceof Driver && static::isKnownPosition($driverAssigned->location)) {
1676
1855
  return $driverAssigned->location;
1677
1856
  }
1678
1857
  }
@@ -1703,6 +1882,16 @@ class Order extends Model
1703
1882
  return $destination ? $destination->location : null;
1704
1883
  }
1705
1884
 
1885
+ /**
1886
+ * Determines whether a position is a real, resolved location rather than
1887
+ * missing or the POINT(0 0) placeholder stored for drivers that have not
1888
+ * reported a position yet and for places that failed to geocode.
1889
+ */
1890
+ public static function isKnownPosition($position): bool
1891
+ {
1892
+ return $position instanceof Point && ($position->getLat() != 0.0 || $position->getLng() != 0.0);
1893
+ }
1894
+
1706
1895
  /**
1707
1896
  * Sets the preliminary distance and time for the order.
1708
1897
  * Uses a utility method to calculate the distance and time between the current origin and destination positions.
@@ -1714,13 +1903,14 @@ class Order extends Model
1714
1903
  $origin = $this->getCurrentOriginPosition();
1715
1904
  $destination = $this->getDestinationPosition();
1716
1905
 
1717
- if ($origin === null || $destination === null) {
1906
+ if (!static::isKnownPosition($origin) || !static::isKnownPosition($destination)) {
1718
1907
  return $this;
1719
1908
  }
1720
1909
 
1721
1910
  $matrix = Utils::getPreliminaryDistanceMatrix($origin, $destination);
1722
1911
 
1723
1912
  $this->updateQuietly(['distance' => $matrix->distance, 'time' => $matrix->time]);
1913
+ $this->invalidateApiCache();
1724
1914
 
1725
1915
  return $this;
1726
1916
  }
@@ -1736,7 +1926,7 @@ class Order extends Model
1736
1926
  $origin = $this->getCurrentOriginPosition();
1737
1927
  $destination = $this->getDestinationPosition();
1738
1928
 
1739
- if (!$origin || !$destination) {
1929
+ if (!static::isKnownPosition($origin) || !static::isKnownPosition($destination)) {
1740
1930
  return $this;
1741
1931
  }
1742
1932
 
@@ -1758,6 +1948,7 @@ class Order extends Model
1758
1948
  'distance' => $matrix->distance,
1759
1949
  'time' => $matrix->time,
1760
1950
  ]);
1951
+ $this->invalidateApiCache();
1761
1952
  }
1762
1953
 
1763
1954
  return $this;