@fleetbase/fleetops-engine 0.6.58 → 0.6.59

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 (685) hide show
  1. package/README.md +3 -0
  2. package/addon/components/customer/form.hbs +0 -49
  3. package/addon/components/entity/card.hbs +1 -0
  4. package/addon/components/modals/order-label.hbs +1 -1
  5. package/addon/components/place/form.hbs +1 -1
  6. package/addon/services/entity-actions.js +32 -0
  7. package/addon/styles/fleetops-engine.css +0 -1
  8. package/composer.json +8 -3
  9. package/extension.json +1 -1
  10. package/index.js +7 -1
  11. package/package.json +2 -1
  12. package/scripts/coverage-file-runner.php +240 -0
  13. package/scripts/coverage-runner.php +2 -1
  14. package/scripts/coverage-summary.php +41 -2
  15. package/scripts/pest-bootstrap.php +237 -3
  16. package/scripts/pest-file-runner.php +13 -1
  17. package/scripts/pest-runner.php +57 -2
  18. package/server/resources/views/labels/entity-label.php +4 -4
  19. package/server/src/Casts/MultiPolygon.php +8 -3
  20. package/server/src/Casts/OrderConfigEntities.php +10 -3
  21. package/server/src/Casts/Point.php +10 -6
  22. package/server/src/Casts/Polygon.php +5 -2
  23. package/server/src/Console/Commands/AssignCustomerRoles.php +28 -6
  24. package/server/src/Console/Commands/AssignDriverRoles.php +36 -6
  25. package/server/src/Console/Commands/AuditCustomerUserConflicts.php +6 -1
  26. package/server/src/Console/Commands/DispatchAdhocOrders.php +12 -2
  27. package/server/src/Console/Commands/FixCustomerCompanies.php +46 -11
  28. package/server/src/Console/Commands/FixDriverCompanies.php +18 -3
  29. package/server/src/Console/Commands/FixLegacyOrderConfigs.php +31 -6
  30. package/server/src/Console/Commands/ProcessMaintenanceTriggers.php +94 -42
  31. package/server/src/Console/Commands/PurgeUnpurchasedServiceQuotes.php +42 -12
  32. package/server/src/Console/Commands/ReplayVehicleLocations.php +120 -55
  33. package/server/src/Console/Commands/SendDriverNotification.php +25 -4
  34. package/server/src/Console/Commands/SendMaintenanceReminders.php +43 -23
  35. package/server/src/Console/Commands/SimulateOrderRouteNavigation.php +36 -6
  36. package/server/src/Console/Commands/TrackOrderDistanceAndTime.php +6 -1
  37. package/server/src/Events/DriverLocationChanged.php +1 -1
  38. package/server/src/Events/DriverSimulatedLocationChanged.php +1 -1
  39. package/server/src/Events/EntityActivityChanged.php +1 -1
  40. package/server/src/Events/EntityCompleted.php +1 -1
  41. package/server/src/Events/EntityDriverAssigned.php +1 -1
  42. package/server/src/Events/FuelProviderTransactionImported.php +1 -1
  43. package/server/src/Events/FuelProviderTransactionMatched.php +1 -1
  44. package/server/src/Events/FuelProviderTransactionUnmatched.php +1 -1
  45. package/server/src/Events/FuelReportCreatedFromProvider.php +1 -1
  46. package/server/src/Events/GeofenceDwelled.php +1 -1
  47. package/server/src/Events/GeofenceEntered.php +1 -1
  48. package/server/src/Events/GeofenceExited.php +1 -1
  49. package/server/src/Events/VehicleLocationChanged.php +1 -1
  50. package/server/src/Events/WaypointActivityChanged.php +1 -1
  51. package/server/src/Events/WaypointCompleted.php +1 -1
  52. package/server/src/Exceptions/IntegratedVendorException.php +2 -2
  53. package/server/src/Exceptions/TelematicRateLimitExceededException.php +1 -1
  54. package/server/src/Http/Controllers/Api/v1/ContactController.php +89 -22
  55. package/server/src/Http/Controllers/Api/v1/CustomerController.php +296 -97
  56. package/server/src/Http/Controllers/Api/v1/DeviceController.php +48 -14
  57. package/server/src/Http/Controllers/Api/v1/DriverController.php +168 -63
  58. package/server/src/Http/Controllers/Api/v1/EntityController.php +112 -66
  59. package/server/src/Http/Controllers/Api/v1/EquipmentController.php +40 -10
  60. package/server/src/Http/Controllers/Api/v1/FleetController.php +54 -14
  61. package/server/src/Http/Controllers/Api/v1/FuelReportController.php +54 -14
  62. package/server/src/Http/Controllers/Api/v1/FuelTransactionController.php +36 -11
  63. package/server/src/Http/Controllers/Api/v1/GeofenceController.php +39 -21
  64. package/server/src/Http/Controllers/Api/v1/IssueController.php +54 -14
  65. package/server/src/Http/Controllers/Api/v1/LabelController.php +61 -22
  66. package/server/src/Http/Controllers/Api/v1/NavigatorController.php +21 -5
  67. package/server/src/Http/Controllers/Api/v1/OrderConfigController.php +35 -5
  68. package/server/src/Http/Controllers/Api/v1/OrderController.php +388 -203
  69. package/server/src/Http/Controllers/Api/v1/PartController.php +40 -10
  70. package/server/src/Http/Controllers/Api/v1/PayloadController.php +90 -30
  71. package/server/src/Http/Controllers/Api/v1/PlaceController.php +188 -91
  72. package/server/src/Http/Controllers/Api/v1/PurchaseRateController.php +100 -36
  73. package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +96 -26
  74. package/server/src/Http/Controllers/Api/v1/ServiceQuoteController.php +169 -81
  75. package/server/src/Http/Controllers/Api/v1/ServiceRateController.php +104 -75
  76. package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +83 -14
  77. package/server/src/Http/Controllers/Api/v1/TrackingStatusController.php +66 -16
  78. package/server/src/Http/Controllers/Api/v1/VehicleController.php +121 -67
  79. package/server/src/Http/Controllers/Api/v1/VendorController.php +54 -14
  80. package/server/src/Http/Controllers/Api/v1/WorkOrderController.php +47 -12
  81. package/server/src/Http/Controllers/Api/v1/ZoneController.php +84 -24
  82. package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +15 -5
  83. package/server/src/Http/Controllers/Internal/v1/ContactController.php +113 -28
  84. package/server/src/Http/Controllers/Internal/v1/CustomerController.php +36 -11
  85. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +9 -4
  86. package/server/src/Http/Controllers/Internal/v1/DriverController.php +167 -69
  87. package/server/src/Http/Controllers/Internal/v1/EquipmentController.php +18 -3
  88. package/server/src/Http/Controllers/Internal/v1/FleetController.php +137 -60
  89. package/server/src/Http/Controllers/Internal/v1/FleetOpsLookupController.php +24 -9
  90. package/server/src/Http/Controllers/Internal/v1/FuelReportController.php +18 -3
  91. package/server/src/Http/Controllers/Internal/v1/GeocoderController.php +26 -8
  92. package/server/src/Http/Controllers/Internal/v1/GettingStartedController.php +12 -2
  93. package/server/src/Http/Controllers/Internal/v1/IntegratedVendorController.php +27 -6
  94. package/server/src/Http/Controllers/Internal/v1/IssueController.php +82 -29
  95. package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +34 -26
  96. package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +141 -97
  97. package/server/src/Http/Controllers/Internal/v1/ManifestController.php +28 -8
  98. package/server/src/Http/Controllers/Internal/v1/MetricsController.php +21 -12
  99. package/server/src/Http/Controllers/Internal/v1/MorphController.php +90 -18
  100. package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +88 -35
  101. package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +149 -39
  102. package/server/src/Http/Controllers/Internal/v1/OrderConfigController.php +54 -18
  103. package/server/src/Http/Controllers/Internal/v1/OrderController.php +298 -86
  104. package/server/src/Http/Controllers/Internal/v1/PartController.php +18 -3
  105. package/server/src/Http/Controllers/Internal/v1/PaymentController.php +46 -14
  106. package/server/src/Http/Controllers/Internal/v1/PlaceController.php +31 -5
  107. package/server/src/Http/Controllers/Internal/v1/ProofController.php +88 -48
  108. package/server/src/Http/Controllers/Internal/v1/SearchController.php +1 -1
  109. package/server/src/Http/Controllers/Internal/v1/SensorController.php +6 -1
  110. package/server/src/Http/Controllers/Internal/v1/ServiceAreaController.php +6 -1
  111. package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +255 -105
  112. package/server/src/Http/Controllers/Internal/v1/SettingController.php +88 -35
  113. package/server/src/Http/Controllers/Internal/v1/TelematicController.php +1 -4
  114. package/server/src/Http/Controllers/Internal/v1/Traits/DriverSchedulingTrait.php +42 -14
  115. package/server/src/Http/Controllers/Internal/v1/VendorController.php +103 -33
  116. package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +42 -12
  117. package/server/src/Http/Filter/DriverFilter.php +2 -2
  118. package/server/src/Http/Filter/OrderFilter.php +1 -1
  119. package/server/src/Http/Filter/VehicleFilter.php +21 -7
  120. package/server/src/Http/Middleware/AuthenticateCustomerToken.php +12 -2
  121. package/server/src/Http/Requests/BulkDispatchRequest.php +3 -9
  122. package/server/src/Http/Requests/CancelOrderRequest.php +2 -6
  123. package/server/src/Http/Requests/CreateContactRequest.php +2 -6
  124. package/server/src/Http/Requests/CreateDeviceRequest.php +2 -2
  125. package/server/src/Http/Requests/CreateDriverRequest.php +3 -9
  126. package/server/src/Http/Requests/CreateEntityRequest.php +2 -6
  127. package/server/src/Http/Requests/CreateEquipmentRequest.php +2 -2
  128. package/server/src/Http/Requests/CreateFleetRequest.php +2 -6
  129. package/server/src/Http/Requests/CreateFuelReportRequest.php +2 -6
  130. package/server/src/Http/Requests/CreateFuelTransactionRequest.php +2 -2
  131. package/server/src/Http/Requests/CreateIssueRequest.php +2 -6
  132. package/server/src/Http/Requests/CreateOrderRequest.php +7 -8
  133. package/server/src/Http/Requests/CreatePartRequest.php +2 -2
  134. package/server/src/Http/Requests/CreatePayloadRequest.php +7 -9
  135. package/server/src/Http/Requests/CreatePlaceRequest.php +2 -6
  136. package/server/src/Http/Requests/CreatePurchaseRateRequest.php +2 -6
  137. package/server/src/Http/Requests/CreateSensorRequest.php +2 -2
  138. package/server/src/Http/Requests/CreateServiceAreaRequest.php +2 -6
  139. package/server/src/Http/Requests/CreateServiceQuoteRequest.php +2 -6
  140. package/server/src/Http/Requests/CreateServiceRateRequest.php +2 -6
  141. package/server/src/Http/Requests/CreateTrackingNumberRequest.php +2 -6
  142. package/server/src/Http/Requests/CreateTrackingStatusRequest.php +2 -6
  143. package/server/src/Http/Requests/CreateVehicleRequest.php +2 -6
  144. package/server/src/Http/Requests/CreateVendorRequest.php +2 -6
  145. package/server/src/Http/Requests/CreateWorkOrderRequest.php +2 -2
  146. package/server/src/Http/Requests/CreateZoneRequest.php +2 -6
  147. package/server/src/Http/Requests/DecodeTrackingNumberQR.php +2 -6
  148. package/server/src/Http/Requests/DriverSimulationRequest.php +2 -6
  149. package/server/src/Http/Requests/Internal/AssignOrderRequest.php +3 -7
  150. package/server/src/Http/Requests/Internal/CreateDriverRequest.php +4 -12
  151. package/server/src/Http/Requests/Internal/CreateOrderConfigRequest.php +2 -6
  152. package/server/src/Http/Requests/Internal/CreateOrderRequest.php +7 -8
  153. package/server/src/Http/Requests/Internal/FleetActionRequest.php +18 -12
  154. package/server/src/Http/Requests/Internal/UpdateDriverRequest.php +6 -3
  155. package/server/src/Http/Requests/QueryServiceQuotesRequest.php +2 -6
  156. package/server/src/Http/Requests/ScheduleOrderRequest.php +2 -6
  157. package/server/src/Http/Requests/UpdateIssueRequest.php +1 -3
  158. package/server/src/Http/Resources/v1/Customer.php +2 -2
  159. package/server/src/Http/Resources/v1/Maintenance.php +3 -4
  160. package/server/src/Http/Resources/v1/MaintenanceSchedule.php +3 -4
  161. package/server/src/Http/Resources/v1/Order.php +3 -7
  162. package/server/src/Http/Resources/v1/PurchaseRate.php +4 -6
  163. package/server/src/Http/Resources/v1/TrackingStatus.php +4 -6
  164. package/server/src/Http/Resources/v1/WorkOrder.php +3 -4
  165. package/server/src/Imports/ContactImport.php +10 -1
  166. package/server/src/Imports/DriverImport.php +10 -1
  167. package/server/src/Imports/EquipmentImport.php +6 -1
  168. package/server/src/Imports/FleetImport.php +10 -1
  169. package/server/src/Imports/FuelReportImport.php +10 -1
  170. package/server/src/Imports/IssueImport.php +10 -1
  171. package/server/src/Imports/MaintenanceImport.php +6 -1
  172. package/server/src/Imports/MaintenanceScheduleImport.php +6 -1
  173. package/server/src/Imports/PartImport.php +6 -1
  174. package/server/src/Imports/PlaceImport.php +10 -1
  175. package/server/src/Imports/VehicleImport.php +10 -1
  176. package/server/src/Imports/VendorImport.php +10 -1
  177. package/server/src/Imports/WorkOrderImport.php +6 -1
  178. package/server/src/Integrations/Lalamove/Lalamove.php +3 -7
  179. package/server/src/Integrations/Lalamove/LalamoveServiceType.php +5 -8
  180. package/server/src/Jobs/CheckGeofenceDwell.php +41 -16
  181. package/server/src/Jobs/FinalizeApiOrderCreation.php +17 -2
  182. package/server/src/Jobs/FinalizeInternalOrderCreation.php +11 -1
  183. package/server/src/Jobs/NotifyBulkAssignedDriver.php +29 -16
  184. package/server/src/Jobs/ProcessAllocationJob.php +59 -25
  185. package/server/src/Jobs/ReplayPositions.php +17 -10
  186. package/server/src/Jobs/SendPositionReplay.php +18 -7
  187. package/server/src/Jobs/SimulateDrivingRoute.php +14 -3
  188. package/server/src/Jobs/SyncFuelProviderTransactionsJob.php +12 -2
  189. package/server/src/Listeners/HandleDeliveryCompletion.php +11 -1
  190. package/server/src/Listeners/HandleGeofenceDwelled.php +6 -1
  191. package/server/src/Listeners/HandleGeofenceEntered.php +4 -2
  192. package/server/src/Listeners/HandleGeofenceExited.php +6 -1
  193. package/server/src/Listeners/HandleOrderCanceled.php +18 -3
  194. package/server/src/Listeners/HandleOrderDispatchFailed.php +12 -2
  195. package/server/src/Listeners/HandleOrderDispatched.php +61 -26
  196. package/server/src/Listeners/HandleOrderDriverAssigned.php +12 -2
  197. package/server/src/Listeners/HandleUserRemovedFromCompany.php +19 -6
  198. package/server/src/Listeners/NotifyDriverOnShiftChange.php +24 -4
  199. package/server/src/Listeners/NotifyOrderEvent.php +11 -6
  200. package/server/src/Models/Contact.php +6 -7
  201. package/server/src/Models/Device.php +26 -3
  202. package/server/src/Models/Driver.php +0 -6
  203. package/server/src/Models/Entity.php +4 -4
  204. package/server/src/Models/Equipment.php +1 -1
  205. package/server/src/Models/FuelReport.php +5 -1
  206. package/server/src/Models/IntegratedVendor.php +2 -2
  207. package/server/src/Models/Issue.php +5 -1
  208. package/server/src/Models/MaintenanceSchedule.php +25 -10
  209. package/server/src/Models/Order.php +18 -15
  210. package/server/src/Models/OrderConfig.php +1 -1
  211. package/server/src/Models/Payload.php +9 -16
  212. package/server/src/Models/Place.php +20 -13
  213. package/server/src/Models/ServiceArea.php +3 -6
  214. package/server/src/Models/ServiceQuote.php +5 -0
  215. package/server/src/Models/ServiceRate.php +13 -6
  216. package/server/src/Models/Telematic.php +2 -2
  217. package/server/src/Models/TrackingNumber.php +55 -10
  218. package/server/src/Models/TrackingStatus.php +24 -4
  219. package/server/src/Models/Waypoint.php +44 -10
  220. package/server/src/Models/Zone.php +3 -6
  221. package/server/src/Notifications/DriverArrivedAtGeofence.php +1 -1
  222. package/server/src/Notifications/OrderDispatched.php +3 -9
  223. package/server/src/Notifications/OrderPing.php +3 -9
  224. package/server/src/Observers/CategoryObserver.php +6 -1
  225. package/server/src/Observers/CompanyObserver.php +5 -0
  226. package/server/src/Observers/CompanyUserObserver.php +12 -2
  227. package/server/src/Observers/DriverObserver.php +19 -4
  228. package/server/src/Observers/FleetObserver.php +6 -1
  229. package/server/src/Observers/PurchaseRateObserver.php +66 -11
  230. package/server/src/Observers/ServiceAreaObserver.php +12 -2
  231. package/server/src/Observers/ServiceRateObserver.php +21 -6
  232. package/server/src/Observers/TrackingNumberObserver.php +19 -4
  233. package/server/src/Observers/UserObserver.php +6 -1
  234. package/server/src/Observers/VehicleObserver.php +27 -7
  235. package/server/src/Observers/WorkOrderObserver.php +27 -7
  236. package/server/src/Orchestration/Engines/DriverAssignmentEngine.php +8 -3
  237. package/server/src/Orchestration/Support/OrchestrationPayloadBuilder.php +2 -2
  238. package/server/src/Providers/FleetOpsServiceProvider.php +12 -0
  239. package/server/src/Providers/NotificationServiceProvider.php +6 -0
  240. package/server/src/Support/Ai/Capabilities/AssetStatusCapability.php +36 -26
  241. package/server/src/Support/Ai/Capabilities/CreateOrderPreviewCapability.php +18 -5
  242. package/server/src/Support/Ai/Capabilities/OrderInsightsCapability.php +6 -1
  243. package/server/src/Support/Ai/Capabilities/SearchResourcesCapability.php +26 -6
  244. package/server/src/Support/Analytics/FuelEfficiency.php +9 -3
  245. package/server/src/Support/Analytics/FuelProviderSummary.php +14 -5
  246. package/server/src/Support/Analytics/GeofenceViolations.php +40 -20
  247. package/server/src/Support/Analytics/IssuesInsights.php +38 -18
  248. package/server/src/Support/Analytics/MaintenanceOverview.php +51 -21
  249. package/server/src/Support/Analytics/OnTimeDelivery.php +3 -2
  250. package/server/src/Support/Analytics/OperationsPulse.php +59 -35
  251. package/server/src/Support/Analytics/OrdersByStatus.php +12 -7
  252. package/server/src/Support/Analytics/RevenueTrend.php +16 -6
  253. package/server/src/Support/Analytics/TopDrivers.php +3 -2
  254. package/server/src/Support/FleetOps.php +109 -104
  255. package/server/src/Support/Geocoding.php +52 -14
  256. package/server/src/Support/GeofenceIntersectionService.php +47 -27
  257. package/server/src/Support/LiveOrderQuery.php +6 -1
  258. package/server/src/Support/Metrics/ActiveRevenueQuery.php +3 -2
  259. package/server/src/Support/Metrics/FuelCostsMetric.php +6 -1
  260. package/server/src/Support/ResolvesOrderServiceStops.php +10 -0
  261. package/server/src/Support/Telematics/Providers/GeotabProvider.php +9 -4
  262. package/server/src/Support/Utils.php +122 -16
  263. package/server/src/Tracking/Providers/GoogleRoutesTrackingProvider.php +6 -1
  264. package/server/src/Tracking/Providers/OsrmTrackingProvider.php +11 -6
  265. package/server/src/Tracking/TrackingProviderManager.php +2 -3
  266. package/server/src/Tracking/TrackingProviderRegistry.php +8 -4
  267. package/server/src/Traits/PayloadAccessors.php +6 -1
  268. package/server/src/routes.php +23 -16
  269. package/server/tests/AiOperationalQueryCapabilityTest.php +457 -1
  270. package/server/tests/AiPreviewCapabilityContractsTest.php +180 -0
  271. package/server/tests/AnalyticsRoutesTest.php +380 -1
  272. package/server/tests/AnalyticsWidgetContractsTest.php +740 -0
  273. package/server/tests/ApiContactControllerContractsTest.php +284 -0
  274. package/server/tests/ApiCustomerControllerContractsTest.php +962 -0
  275. package/server/tests/ApiDriverControllerContractsTest.php +571 -0
  276. package/server/tests/ApiEntityControllerContractsTest.php +329 -0
  277. package/server/tests/ApiEquipmentControllerContractsTest.php +239 -0
  278. package/server/tests/ApiFleetControllerContractsTest.php +176 -0
  279. package/server/tests/ApiFuelReportControllerContractsTest.php +217 -0
  280. package/server/tests/ApiIssueControllerContractsTest.php +217 -0
  281. package/server/tests/ApiOrderControllerContractsTest.php +1030 -0
  282. package/server/tests/ApiPartControllerContractsTest.php +251 -0
  283. package/server/tests/ApiPayloadControllerContractsTest.php +314 -0
  284. package/server/tests/ApiPlaceControllerContractsTest.php +541 -0
  285. package/server/tests/ApiPurchaseRateControllerContractsTest.php +283 -0
  286. package/server/tests/ApiServiceAreaZoneControllerContractsTest.php +442 -0
  287. package/server/tests/ApiServiceQuoteControllerContractsTest.php +322 -0
  288. package/server/tests/ApiTrackingNumberControllerContractsTest.php +225 -0
  289. package/server/tests/ApiTrackingStatusControllerContractsTest.php +254 -0
  290. package/server/tests/ApiVehicleControllerContractsTest.php +368 -0
  291. package/server/tests/ApiVendorControllerContractsTest.php +199 -0
  292. package/server/tests/AssetAndPlaceSearchContractsTest.php +220 -0
  293. package/server/tests/BackendSmallModelContractsTest.php +354 -0
  294. package/server/tests/CapacityAllocationEngineTest.php +56 -0
  295. package/server/tests/CommandContractsTest.php +2695 -0
  296. package/server/tests/CompactResourceSerializationTest.php +2745 -0
  297. package/server/tests/ControllerFilterContractsTest.php +1273 -0
  298. package/server/tests/ControllerHelperContractsTest.php +1740 -0
  299. package/server/tests/ControllerSerializationContractsTest.php +141 -0
  300. package/server/tests/CoverageSummaryScriptTest.php +93 -0
  301. package/server/tests/CustomerContactIdentitySafetyTest.php +1 -6
  302. package/server/tests/CustomerEndpointTest.php +165 -1
  303. package/server/tests/DriverFilterExecutionTest.php +263 -0
  304. package/server/tests/DriverGeofenceProcessingTest.php +153 -0
  305. package/server/tests/DriverResourceSerializationTest.php +245 -0
  306. package/server/tests/DriverSchedulingTraitContractsTest.php +259 -0
  307. package/server/tests/EventContractsTest.php +1259 -0
  308. package/server/tests/ExceptionContractsTest.php +81 -0
  309. package/server/tests/ExpansionContractsTest.php +242 -0
  310. package/server/tests/ExportCoverageTest.php +116 -0
  311. package/server/tests/Feature/Http/Api/ContactControllerPhotoAndDeleteTest.php +199 -0
  312. package/server/tests/Feature/Http/Api/CustomerControllerHelperSeamsTest.php +831 -0
  313. package/server/tests/Feature/Http/Api/DeviceControllerContractsTest.php +347 -0
  314. package/server/tests/Feature/Http/Api/DeviceControllerCrudTest.php +176 -0
  315. package/server/tests/Feature/Http/Api/DriverControllerAuthFlowsTest.php +451 -0
  316. package/server/tests/Feature/Http/Api/DriverControllerHelpersTest.php +240 -0
  317. package/server/tests/Feature/Http/Api/DriverControllerLookupTest.php +186 -0
  318. package/server/tests/Feature/Http/Api/DriverControllerOrganizationsTest.php +112 -0
  319. package/server/tests/Feature/Http/Api/DriverControllerSessionHelpersTest.php +207 -0
  320. package/server/tests/Feature/Http/Api/DriverControllerSwitchOrgAndGeofenceTest.php +329 -0
  321. package/server/tests/Feature/Http/Api/DriverControllerTrackTest.php +383 -0
  322. package/server/tests/Feature/Http/Api/EntityControllerHelpersTest.php +150 -0
  323. package/server/tests/Feature/Http/Api/FuelTransactionControllerContractsTest.php +352 -0
  324. package/server/tests/Feature/Http/Api/GeofenceControllerContractsTest.php +364 -0
  325. package/server/tests/Feature/Http/Api/LabelControllerSubjectsTest.php +148 -0
  326. package/server/tests/Feature/Http/Api/OrderConfigControllerTest.php +112 -0
  327. package/server/tests/Feature/Http/Api/OrderControllerCreateTest.php +279 -0
  328. package/server/tests/Feature/Http/Api/OrderControllerIntegratedVendorTest.php +295 -0
  329. package/server/tests/Feature/Http/Api/OrderControllerLifecycleActionsTest.php +279 -0
  330. package/server/tests/Feature/Http/Api/OrderControllerLookupHelpersTest.php +207 -0
  331. package/server/tests/Feature/Http/Api/OrderControllerNearbyFiltersTest.php +282 -0
  332. package/server/tests/Feature/Http/Api/OrderControllerPersistenceHelpersTest.php +216 -0
  333. package/server/tests/Feature/Http/Api/OrderControllerQueryFiltersTest.php +184 -0
  334. package/server/tests/Feature/Http/Api/OrderControllerStartActivityTest.php +663 -0
  335. package/server/tests/Feature/Http/Api/PayloadControllerHelpersTest.php +134 -0
  336. package/server/tests/Feature/Http/Api/PlaceAndServiceQuoteSeamsTest.php +479 -0
  337. package/server/tests/Feature/Http/Api/PurchaseRateControllerHelpersTest.php +176 -0
  338. package/server/tests/Feature/Http/Api/PurchaseRateControllerOrderCreationTest.php +268 -0
  339. package/server/tests/Feature/Http/Api/SensorControllerCrudTest.php +239 -0
  340. package/server/tests/Feature/Http/Api/ServiceAreaControllerBorderAndSeamsTest.php +187 -0
  341. package/server/tests/Feature/Http/Api/ServiceQuoteControllerQueryTest.php +405 -0
  342. package/server/tests/Feature/Http/Api/ServiceQuoteControllerVendorBridgeTest.php +212 -0
  343. package/server/tests/Feature/Http/Api/ServiceRateControllerContractsTest.php +263 -0
  344. package/server/tests/Feature/Http/Api/SmallApiControllerHelpersTest.php +272 -0
  345. package/server/tests/Feature/Http/Api/TrackingNumberControllerHelpersTest.php +154 -0
  346. package/server/tests/Feature/Http/Api/TrackingStatusControllerHelpersTest.php +165 -0
  347. package/server/tests/Feature/Http/Api/VehicleControllerTrackingTest.php +483 -0
  348. package/server/tests/Feature/Http/Api/WorkOrderControllerContractsTest.php +326 -0
  349. package/server/tests/Feature/Http/Api/WorkOrderControllerHelpersTest.php +130 -0
  350. package/server/tests/Feature/Http/Api/ZoneControllerBordersAndSeamsTest.php +294 -0
  351. package/server/tests/Feature/Http/FleetOpsRouteRegistrationTest.php +189 -0
  352. package/server/tests/Feature/Http/Internal/AnalyticsControllerSeamsTest.php +53 -0
  353. package/server/tests/Feature/Http/Internal/ContactControllerContractsTest.php +240 -0
  354. package/server/tests/Feature/Http/Internal/ContactControllerCustomerGuardsTest.php +128 -0
  355. package/server/tests/Feature/Http/Internal/ContactControllerEndpointsTest.php +294 -0
  356. package/server/tests/Feature/Http/Internal/CustomerControllerCredentialsTest.php +196 -0
  357. package/server/tests/Feature/Http/Internal/DeviceControllerContractsTest.php +370 -0
  358. package/server/tests/Feature/Http/Internal/DeviceControllerExportAndFiltersTest.php +151 -0
  359. package/server/tests/Feature/Http/Internal/DriverControllerContractsTest.php +1109 -0
  360. package/server/tests/Feature/Http/Internal/DriverControllerCreateRecordTest.php +233 -0
  361. package/server/tests/Feature/Http/Internal/DriverControllerExistingUserAdoptionTest.php +710 -0
  362. package/server/tests/Feature/Http/Internal/DriverControllerHelpersTest.php +218 -0
  363. package/server/tests/Feature/Http/Internal/FleetAssignmentsAndTriggersTest.php +198 -0
  364. package/server/tests/Feature/Http/Internal/FleetOpsLookupControllerDbTest.php +90 -0
  365. package/server/tests/Feature/Http/Internal/HubControllerTest.php +206 -0
  366. package/server/tests/Feature/Http/Internal/IssueControllerContractsTest.php +404 -0
  367. package/server/tests/Feature/Http/Internal/IssueControllerExportImportTest.php +118 -0
  368. package/server/tests/Feature/Http/Internal/LiveControllerEndpointsTest.php +246 -0
  369. package/server/tests/Feature/Http/Internal/LiveControllerTest.php +778 -0
  370. package/server/tests/Feature/Http/Internal/MaintenanceScheduleControllerContractsTest.php +263 -0
  371. package/server/tests/Feature/Http/Internal/MaintenanceScheduleControllerSurfacesTest.php +214 -0
  372. package/server/tests/Feature/Http/Internal/MetricsControllerContractsTest.php +249 -0
  373. package/server/tests/Feature/Http/Internal/MetricsControllerHelpersTest.php +66 -0
  374. package/server/tests/Feature/Http/Internal/MorphControllerHelpersTest.php +125 -0
  375. package/server/tests/Feature/Http/Internal/NavigatorControllerHelpersTest.php +201 -0
  376. package/server/tests/Feature/Http/Internal/OrchestrationControllerContractsTest.php +928 -0
  377. package/server/tests/Feature/Http/Internal/OrchestrationControllerHelpersTest.php +214 -0
  378. package/server/tests/Feature/Http/Internal/OrchestrationControllerImportOrdersTest.php +340 -0
  379. package/server/tests/Feature/Http/Internal/OrderConfigControllerContractsTest.php +314 -0
  380. package/server/tests/Feature/Http/Internal/OrderControllerActivityFlowsTest.php +663 -0
  381. package/server/tests/Feature/Http/Internal/OrderControllerCapturePhotoTest.php +507 -0
  382. package/server/tests/Feature/Http/Internal/OrderControllerContractsTest.php +1742 -0
  383. package/server/tests/Feature/Http/Internal/OrderControllerCreateRecordTest.php +488 -0
  384. package/server/tests/Feature/Http/Internal/OrderControllerHelperSeamsTest.php +298 -0
  385. package/server/tests/Feature/Http/Internal/OrderControllerHelpersTest.php +267 -0
  386. package/server/tests/Feature/Http/Internal/OrderControllerImportFromFilesTest.php +179 -0
  387. package/server/tests/Feature/Http/Internal/OrderControllerUpstreamNotFoundTest.php +80 -0
  388. package/server/tests/Feature/Http/Internal/PaymentControllerPaymentsTest.php +154 -0
  389. package/server/tests/Feature/Http/Internal/PlaceControllerTest.php +252 -0
  390. package/server/tests/Feature/Http/Internal/PositionControllerReplayMetricsTest.php +163 -0
  391. package/server/tests/Feature/Http/Internal/ProofControllerContractsTest.php +219 -0
  392. package/server/tests/Feature/Http/Internal/SearchControllerEndpointTest.php +151 -0
  393. package/server/tests/Feature/Http/Internal/ServiceQuoteControllerHelpersTest.php +208 -0
  394. package/server/tests/Feature/Http/Internal/ServiceQuoteControllerQueryRecordTest.php +217 -0
  395. package/server/tests/Feature/Http/Internal/ServiceQuoteControllerVendorBridgeTest.php +239 -0
  396. package/server/tests/Feature/Http/Internal/ServiceQuotePreliminaryQueryTest.php +271 -0
  397. package/server/tests/Feature/Http/Internal/SettingControllerHelpersTest.php +133 -0
  398. package/server/tests/Feature/Http/Internal/SmallInternalControllersTest.php +180 -0
  399. package/server/tests/Feature/Http/Internal/TelematicControllerEndpointsTest.php +417 -0
  400. package/server/tests/Feature/Http/Internal/VehicleControllerEndpointsTest.php +361 -0
  401. package/server/tests/Feature/Http/Internal/VendorControllerEndpointsTest.php +203 -0
  402. package/server/tests/Feature/Http/Internal/WorkOrderAndConfigSurfacesTest.php +289 -0
  403. package/server/tests/Feature/Http/Internal/WorkOrderControllerContractsTest.php +199 -0
  404. package/server/tests/Feature/Http/TelematicWebhookIngestTest.php +343 -0
  405. package/server/tests/Feature/Http/Telematics/TelematicWebhookControllerProcessingTest.php +254 -0
  406. package/server/tests/FleetOpsSupportContractsTest.php +187 -0
  407. package/server/tests/FlespiProviderContractsTest.php +244 -0
  408. package/server/tests/FlowResourceTest.php +295 -0
  409. package/server/tests/FuelProviderConnectionControllerContractsTest.php +303 -0
  410. package/server/tests/FuelProviderImplementationTest.php +753 -0
  411. package/server/tests/FuelProviderResourceContractsTest.php +171 -0
  412. package/server/tests/FuelProviderTransactionControllerContractsTest.php +181 -0
  413. package/server/tests/GeofenceIntersectionServiceContractsTest.php +164 -0
  414. package/server/tests/HOSConstraintContractsTest.php +128 -0
  415. package/server/tests/HubAndGettingStartedContractsTest.php +158 -0
  416. package/server/tests/ImportContractsTest.php +191 -0
  417. package/server/tests/InternalCustomerControllerContractsTest.php +238 -0
  418. package/server/tests/InternalFleetControllerContractsTest.php +389 -0
  419. package/server/tests/InternalImportExportControllerContractsTest.php +289 -0
  420. package/server/tests/InternalMetricsControllerContractsTest.php +69 -0
  421. package/server/tests/InternalPlaceWorkOrderControllerContractsTest.php +207 -0
  422. package/server/tests/InternalServiceQuoteCheckoutControllerContractsTest.php +470 -0
  423. package/server/tests/InternalVendorControllerContractsTest.php +331 -0
  424. package/server/tests/InventoryTelemetryModelContractsTest.php +516 -0
  425. package/server/tests/IssueTimelineContractsTest.php +191 -0
  426. package/server/tests/LabelPdfRenderingTest.php +57 -0
  427. package/server/tests/LalamoveIntegrationContractsTest.php +167 -0
  428. package/server/tests/LiveOrderQueryTest.php +145 -18
  429. package/server/tests/LookupAndGeocoderControllerContractsTest.php +357 -0
  430. package/server/tests/MaintainableTraitContractsTest.php +245 -0
  431. package/server/tests/MaintenanceScheduleControllerContractsTest.php +101 -0
  432. package/server/tests/MaintenanceWarrantyContractsTest.php +237 -0
  433. package/server/tests/ManifestControllerContractsTest.php +310 -0
  434. package/server/tests/MetricsRegistryTest.php +596 -10
  435. package/server/tests/MiddlewareContractsTest.php +150 -0
  436. package/server/tests/ModelAccessorContractsTest.php +3201 -0
  437. package/server/tests/MorphControllerContractsTest.php +410 -0
  438. package/server/tests/NavigatorControllerContractsTest.php +206 -0
  439. package/server/tests/NotificationAndMailContractsTest.php +677 -0
  440. package/server/tests/ObserverContractsTest.php +1414 -0
  441. package/server/tests/OperationalAlgorithmContractsTest.php +852 -0
  442. package/server/tests/OperationsMonitorEndpointTest.php +2 -1
  443. package/server/tests/OrchestrationPayloadBuilderTest.php +87 -0
  444. package/server/tests/OrderActivityFlowRegressionTest.php +354 -7
  445. package/server/tests/OrderDispatchListenerContractsTest.php +577 -0
  446. package/server/tests/OrderFilterExecutionTest.php +244 -0
  447. package/server/tests/OrderQueuedClosureRegressionTest.php +2 -1
  448. package/server/tests/PaymentControllerContractsTest.php +199 -0
  449. package/server/tests/PointResolutionTest.php +54 -0
  450. package/server/tests/ProcessAllocationJobContractsTest.php +224 -0
  451. package/server/tests/ProofAndSensorControllerContractsTest.php +44 -0
  452. package/server/tests/ProviderContractsTest.php +409 -0
  453. package/server/tests/PublicApiControllerInputContractsTest.php +294 -0
  454. package/server/tests/QueueJobContractsTest.php +764 -0
  455. package/server/tests/ReportSchemaContractsTest.php +271 -0
  456. package/server/tests/RequestContractsTest.php +966 -0
  457. package/server/tests/RouteRegistrationExecutionTest.php +178 -0
  458. package/server/tests/RouteSequencingEngineTest.php +179 -0
  459. package/server/tests/RulesAndCastsTest.php +246 -0
  460. package/server/tests/SamsaraProviderContractsTest.php +272 -0
  461. package/server/tests/SearchControllerContractsTest.php +311 -0
  462. package/server/tests/ServiceRateRouteValidationTest.php +76 -0
  463. package/server/tests/SettingControllerContractsTest.php +410 -0
  464. package/server/tests/SmallControllerContractsTest.php +456 -0
  465. package/server/tests/SupportAnalyticsCustomerAuthContractsTest.php +221 -0
  466. package/server/tests/SupportJobAndAiCoverageTest.php +812 -0
  467. package/server/tests/SupportServiceContractsTest.php +287 -0
  468. package/server/tests/SupportValueObjectsTest.php +155 -0
  469. package/server/tests/TelematicControllerContractsTest.php +185 -0
  470. package/server/tests/TelematicProviderRegistryTest.php +167 -0
  471. package/server/tests/TelematicServiceHelperContractsTest.php +315 -0
  472. package/server/tests/TelematicWebhookControllerContractsTest.php +253 -0
  473. package/server/tests/TelematicsHardeningTest.php +642 -86
  474. package/server/tests/TrackingIntelligenceTest.php +644 -1
  475. package/server/tests/TrackingNumberTraitContractsTest.php +106 -0
  476. package/server/tests/Unit/Casts/SpatialCastBranchesTest.php +75 -0
  477. package/server/tests/Unit/Console/AssignCustomerRolesCommandTest.php +102 -0
  478. package/server/tests/Unit/Console/AssignDriverRolesCommandTest.php +113 -0
  479. package/server/tests/Unit/Console/Commands/FixLegacyOrderConfigsHelpersTest.php +108 -0
  480. package/server/tests/Unit/Console/Commands/ProcessOperationalAlertsCommandTest.php +265 -0
  481. package/server/tests/Unit/Console/Commands/ReplayVehicleLocationsCommandTest.php +320 -0
  482. package/server/tests/Unit/Console/Commands/SimulateGeofenceEventsCommandTest.php +207 -0
  483. package/server/tests/Unit/Console/FixCommandsAndMaintenanceControllerTest.php +256 -0
  484. package/server/tests/Unit/Console/FleetOpsCommandsTest.php +198 -0
  485. package/server/tests/Unit/Console/ReplayVehicleLocationsCommandTest.php +252 -0
  486. package/server/tests/Unit/Console/SendMaintenanceRemindersTest.php +212 -0
  487. package/server/tests/Unit/Console/SimulateGeofenceEventsCommandTest.php +232 -0
  488. package/server/tests/Unit/Console/SyncTelematicsCommandTest.php +136 -0
  489. package/server/tests/Unit/Constraints/HOSConstraintTest.php +158 -0
  490. package/server/tests/Unit/Events/EventModelRecordTest.php +93 -0
  491. package/server/tests/Unit/Events/OrderDispatchFailedTest.php +34 -0
  492. package/server/tests/Unit/Exports/ExportCollectionsTest.php +142 -0
  493. package/server/tests/Unit/Exports/OperationalExportMappingTest.php +651 -0
  494. package/server/tests/Unit/Exports/VehicleExportTest.php +284 -0
  495. package/server/tests/Unit/Flow/EventFiringTest.php +95 -0
  496. package/server/tests/Unit/Http/Api/QueryWithRequestSeamsTest.php +198 -0
  497. package/server/tests/Unit/Http/Api/SensorInputTest.php +95 -0
  498. package/server/tests/Unit/Http/Filter/DeviceFilterTest.php +199 -0
  499. package/server/tests/Unit/Http/Filter/EmptyValueGuardsTest.php +66 -0
  500. package/server/tests/Unit/Http/Filter/FilterDateRangesTest.php +72 -0
  501. package/server/tests/Unit/Http/Filter/FuelProviderTransactionFilterTest.php +172 -0
  502. package/server/tests/Unit/Http/Filter/InternalRelationUuidLookupTest.php +135 -0
  503. package/server/tests/Unit/Http/Filter/IssueFilterTest.php +129 -0
  504. package/server/tests/Unit/Http/Filter/PartFilterTest.php +173 -0
  505. package/server/tests/Unit/Http/Internal/ControllerDelegationSeamsTest.php +136 -0
  506. package/server/tests/Unit/Http/Internal/ControllerExcelSeamsTest.php +89 -0
  507. package/server/tests/Unit/Http/Middleware/SetupDriverSessionTest.php +32 -0
  508. package/server/tests/Unit/Http/Requests/CreateFuelReportRequestTest.php +47 -0
  509. package/server/tests/Unit/Http/Requests/FleetActionRequestTest.php +80 -0
  510. package/server/tests/Unit/Http/Requests/RequestAuthorizationTest.php +50 -0
  511. package/server/tests/Unit/Http/Resources/CustomerResourceTest.php +108 -0
  512. package/server/tests/Unit/Http/Resources/EntityCustomerTypeTest.php +35 -0
  513. package/server/tests/Unit/Http/Resources/FleetResourceTest.php +102 -0
  514. package/server/tests/Unit/Http/Resources/IndexOrderResourceTest.php +210 -0
  515. package/server/tests/Unit/Http/Resources/IndexVehicleResourceTest.php +194 -0
  516. package/server/tests/Unit/Http/Resources/MaintenanceResourcesTest.php +182 -0
  517. package/server/tests/Unit/Http/Resources/OrderAndDriverResourceTest.php +121 -0
  518. package/server/tests/Unit/Http/Resources/OrderConfigResourceTest.php +47 -0
  519. package/server/tests/Unit/Http/Resources/PayloadResourceTest.php +111 -0
  520. package/server/tests/Unit/Http/Resources/RelationResourceFallbacksTest.php +32 -0
  521. package/server/tests/Unit/Http/Resources/ResourceRelationResolutionTest.php +55 -0
  522. package/server/tests/Unit/Http/Resources/TrackingNumberResourceTest.php +174 -0
  523. package/server/tests/Unit/Http/Resources/WaypointResourceTest.php +295 -0
  524. package/server/tests/Unit/Http/Resources/WorkOrderResourceTest.php +164 -0
  525. package/server/tests/Unit/Imports/ImportDelegationTest.php +151 -0
  526. package/server/tests/Unit/Integrations/Lalamove/LalamoveDeliveryStopTest.php +79 -0
  527. package/server/tests/Unit/Integrations/Lalamove/LalamoveLifecycleTest.php +211 -0
  528. package/server/tests/Unit/Integrations/Lalamove/LalamoveQuoteAndServiceOrderTest.php +381 -0
  529. package/server/tests/Unit/Integrations/Lalamove/LalamoveServiceTypeTest.php +51 -0
  530. package/server/tests/Unit/Integrations/LalamoveQuotationTest.php +194 -0
  531. package/server/tests/Unit/Integrations/LalamoveResponseHandlingTest.php +58 -0
  532. package/server/tests/Unit/Jobs/GeofenceDwellAndBulkNotifyTest.php +183 -0
  533. package/server/tests/Unit/Jobs/ReplayPositionsTest.php +57 -0
  534. package/server/tests/Unit/Jobs/SimulateWaypointReachedTest.php +92 -0
  535. package/server/tests/Unit/Listeners/HandleGeofenceEnteredTest.php +256 -0
  536. package/server/tests/Unit/Listeners/HandleOrderDispatchFailedListenerTest.php +101 -0
  537. package/server/tests/Unit/Listeners/HandleOrderDispatchedConcreteTest.php +203 -0
  538. package/server/tests/Unit/Listeners/HandleOrderDispatchedHelpersTest.php +186 -0
  539. package/server/tests/Unit/Listeners/HandleUserRemovedFromCompanyTest.php +65 -0
  540. package/server/tests/Unit/Listeners/ListenerDelegationSeamsTest.php +83 -0
  541. package/server/tests/Unit/Models/AssetTest.php +469 -0
  542. package/server/tests/Unit/Models/ContactCustomerUserTest.php +370 -0
  543. package/server/tests/Unit/Models/ContactTest.php +577 -0
  544. package/server/tests/Unit/Models/DeviceEventTest.php +481 -0
  545. package/server/tests/Unit/Models/DeviceLastPositionDefaultTest.php +128 -0
  546. package/server/tests/Unit/Models/DriverModelHelpersTest.php +268 -0
  547. package/server/tests/Unit/Models/DriverTest.php +401 -0
  548. package/server/tests/Unit/Models/EntityTest.php +171 -0
  549. package/server/tests/Unit/Models/EquipmentTest.php +434 -0
  550. package/server/tests/Unit/Models/FleetTest.php +153 -0
  551. package/server/tests/Unit/Models/FuelProviderTransactionTest.php +82 -0
  552. package/server/tests/Unit/Models/FuelReportImportAndLabelsTest.php +193 -0
  553. package/server/tests/Unit/Models/ImportRowFallbackSeamsTest.php +100 -0
  554. package/server/tests/Unit/Models/IntegratedVendorLifecycleTest.php +203 -0
  555. package/server/tests/Unit/Models/IntegratedVendorTest.php +135 -0
  556. package/server/tests/Unit/Models/IssueTest.php +160 -0
  557. package/server/tests/Unit/Models/MaintenanceScheduleTest.php +319 -0
  558. package/server/tests/Unit/Models/MaintenanceTest.php +277 -0
  559. package/server/tests/Unit/Models/MaintenanceWorkOrderImportTest.php +161 -0
  560. package/server/tests/Unit/Models/ManifestStopTest.php +121 -0
  561. package/server/tests/Unit/Models/ManifestTest.php +163 -0
  562. package/server/tests/Unit/Models/ModelLookupFallbackSeamsTest.php +149 -0
  563. package/server/tests/Unit/Models/OrderConfigTest.php +341 -0
  564. package/server/tests/Unit/Models/OrderDynamicContractsTest.php +190 -0
  565. package/server/tests/Unit/Models/OrderPayloadConfigAndDistanceTest.php +426 -0
  566. package/server/tests/Unit/Models/OrderPayloadRouteTest.php +227 -0
  567. package/server/tests/Unit/Models/OrderPurchaseAndDriversTest.php +188 -0
  568. package/server/tests/Unit/Models/OrderTest.php +917 -0
  569. package/server/tests/Unit/Models/PartTest.php +399 -0
  570. package/server/tests/Unit/Models/PayloadTest.php +710 -0
  571. package/server/tests/Unit/Models/PayloadWaypointsAndEntitiesTest.php +317 -0
  572. package/server/tests/Unit/Models/PlaceCreationAndImportTest.php +384 -0
  573. package/server/tests/Unit/Models/PlaceGeocodingResultsTest.php +253 -0
  574. package/server/tests/Unit/Models/PlaceSharedAndGeocodingTest.php +271 -0
  575. package/server/tests/Unit/Models/PlaceTest.php +589 -0
  576. package/server/tests/Unit/Models/PositionTest.php +49 -0
  577. package/server/tests/Unit/Models/RouteTest.php +55 -0
  578. package/server/tests/Unit/Models/SensorReadingsTest.php +168 -0
  579. package/server/tests/Unit/Models/SensorTest.php +284 -0
  580. package/server/tests/Unit/Models/ServiceAreaGeometryTest.php +129 -0
  581. package/server/tests/Unit/Models/ServiceAreaTest.php +125 -0
  582. package/server/tests/Unit/Models/ServiceQuoteTest.php +617 -0
  583. package/server/tests/Unit/Models/ServiceRateFeeTest.php +73 -0
  584. package/server/tests/Unit/Models/ServiceRatePersistenceAndServicabilityTest.php +428 -0
  585. package/server/tests/Unit/Models/ServiceRateTest.php +533 -0
  586. package/server/tests/Unit/Models/SmallModelSurfacesTest.php +294 -0
  587. package/server/tests/Unit/Models/TrackingNumberTest.php +199 -0
  588. package/server/tests/Unit/Models/TrackingStatusTest.php +131 -0
  589. package/server/tests/Unit/Models/VehicleDeviceTest.php +115 -0
  590. package/server/tests/Unit/Models/VehiclePositionsAndImportTest.php +220 -0
  591. package/server/tests/Unit/Models/VehicleTest.php +266 -0
  592. package/server/tests/Unit/Models/VendorRelationsAndImportTest.php +107 -0
  593. package/server/tests/Unit/Models/WarrantyTest.php +187 -0
  594. package/server/tests/Unit/Models/WaypointTest.php +366 -0
  595. package/server/tests/Unit/Models/WorkOrderTest.php +272 -0
  596. package/server/tests/Unit/Models/ZoneTest.php +83 -0
  597. package/server/tests/Unit/Notifications/MonitoringNotificationsTest.php +136 -0
  598. package/server/tests/Unit/Notifications/OrderAssignedChannelsTest.php +53 -0
  599. package/server/tests/Unit/Notifications/OrderDispatchedChannelsTest.php +81 -0
  600. package/server/tests/Unit/Notifications/OrderFailedChannelsTest.php +73 -0
  601. package/server/tests/Unit/Notifications/OrderPingChannelsTest.php +69 -0
  602. package/server/tests/Unit/Notifications/TerminalOrderNotificationsTest.php +185 -0
  603. package/server/tests/Unit/Observers/FleetOpsCompanyUserAndServiceAreaObserversTest.php +133 -0
  604. package/server/tests/Unit/Observers/ObserverHelperExecutionTest.php +135 -0
  605. package/server/tests/Unit/Observers/ObserverListenerSeamsTest.php +267 -0
  606. package/server/tests/Unit/Observers/PurchaseRateObserverAndOrderJobsTest.php +169 -0
  607. package/server/tests/Unit/Orchestration/Engines/DriverAssignmentEngineTest.php +393 -0
  608. package/server/tests/Unit/Orchestration/Engines/VroomOrchestrationEngineLifecycleTest.php +397 -0
  609. package/server/tests/Unit/Orchestration/OrchestrationEngineRegistryTest.php +45 -0
  610. package/server/tests/Unit/Orchestration/VroomEngineTransportAndSettingsTest.php +253 -0
  611. package/server/tests/Unit/Providers/FleetOpsAiRegistrationTest.php +59 -0
  612. package/server/tests/Unit/Rules/ResolvableVehicleTest.php +85 -0
  613. package/server/tests/Unit/Support/Ai/AssetStatusCapabilityQueriesTest.php +120 -0
  614. package/server/tests/Unit/Support/Ai/Capabilities/CreateOrderPreviewCapabilityTest.php +385 -0
  615. package/server/tests/Unit/Support/Ai/Capabilities/OrderInsightsCapabilityTest.php +226 -0
  616. package/server/tests/Unit/Support/Ai/Capabilities/SearchResourcesCapabilityTest.php +237 -0
  617. package/server/tests/Unit/Support/AiCapabilityPermissionsTest.php +124 -0
  618. package/server/tests/Unit/Support/AlgoEdgeBranchesTest.php +24 -0
  619. package/server/tests/Unit/Support/Analytics/GeofenceViolationsTest.php +109 -0
  620. package/server/tests/Unit/Support/Analytics/LiveFleetTest.php +205 -0
  621. package/server/tests/Unit/Support/Analytics/MaintenanceOverviewTest.php +236 -0
  622. package/server/tests/Unit/Support/Analytics/OnTimeDeliveryAndTopDriversTest.php +250 -0
  623. package/server/tests/Unit/Support/CreateOrderPreviewDraftingTest.php +235 -0
  624. package/server/tests/Unit/Support/CustomerAuthTest.php +132 -0
  625. package/server/tests/Unit/Support/FuelEfficiencyAndCanceledHandlersTest.php +164 -0
  626. package/server/tests/Unit/Support/FuelProviderRegistryResolutionTest.php +51 -0
  627. package/server/tests/Unit/Support/FuelProviderServiceMatchingTest.php +280 -0
  628. package/server/tests/Unit/Support/GeocodingInjectedClientTest.php +268 -0
  629. package/server/tests/Unit/Support/GeocodingLocateTest.php +32 -0
  630. package/server/tests/Unit/Support/GeofenceIntersectionServiceTest.php +188 -0
  631. package/server/tests/Unit/Support/GettingStartedTest.php +164 -0
  632. package/server/tests/Unit/Support/GuardReturnSeamsTest.php +172 -0
  633. package/server/tests/Unit/Support/IntegratedVendorsResolverTest.php +250 -0
  634. package/server/tests/Unit/Support/IssuesInsightsAndAllocationJobTest.php +156 -0
  635. package/server/tests/Unit/Support/MagicAccessorSeamsTest.php +54 -0
  636. package/server/tests/Unit/Support/MaintainableAndOperationalAlertsTest.php +215 -0
  637. package/server/tests/Unit/Support/Metrics/AvgOrderValueMetricTest.php +308 -0
  638. package/server/tests/Unit/Support/Metrics/CountMetricsTest.php +280 -0
  639. package/server/tests/Unit/Support/Metrics/FuelCostsMetricTest.php +102 -0
  640. package/server/tests/Unit/Support/Metrics/MetricQuerySeamsTest.php +129 -0
  641. package/server/tests/Unit/Support/Metrics/OrdersScheduledMetricTest.php +146 -0
  642. package/server/tests/Unit/Support/MoreQuerySeamsTest.php +410 -0
  643. package/server/tests/Unit/Support/OperationalQueryDistributionTest.php +152 -0
  644. package/server/tests/Unit/Support/OperationsPulseTest.php +130 -0
  645. package/server/tests/Unit/Support/OptimizeOrderRouteCapabilityTest.php +147 -0
  646. package/server/tests/Unit/Support/OrchestrationPayloadBuilderTest.php +135 -0
  647. package/server/tests/Unit/Support/OrchestrationRouteAndVehicleTasksTest.php +254 -0
  648. package/server/tests/Unit/Support/OsrmProofAndIssueFilterTest.php +247 -0
  649. package/server/tests/Unit/Support/PetroAppFuelProviderTest.php +165 -0
  650. package/server/tests/Unit/Support/PlaceSearchRankingTest.php +191 -0
  651. package/server/tests/Unit/Support/QuerySeamsTest.php +309 -0
  652. package/server/tests/Unit/Support/ResolvesOrderServiceStopsDbTest.php +303 -0
  653. package/server/tests/Unit/Support/ResolvesOrderServiceStopsTest.php +382 -0
  654. package/server/tests/Unit/Support/SkipAndFallbackGuardsTest.php +70 -0
  655. package/server/tests/Unit/Support/TelematicCredentialResolutionTest.php +31 -0
  656. package/server/tests/Unit/Support/TelematicServiceTest.php +256 -0
  657. package/server/tests/Unit/Support/Telematics/Providers/AbstractProviderTest.php +154 -0
  658. package/server/tests/Unit/Support/Telematics/Providers/AfaqyProviderTest.php +191 -0
  659. package/server/tests/Unit/Support/Telematics/Providers/AfaqyProviderTransportTest.php +138 -0
  660. package/server/tests/Unit/Support/Telematics/Providers/GeotabProviderTest.php +329 -0
  661. package/server/tests/Unit/Support/Telematics/Providers/ProviderTransportSeamsTest.php +133 -0
  662. package/server/tests/Unit/Support/Telematics/Providers/SafeeProviderTest.php +487 -0
  663. package/server/tests/Unit/Support/Telematics/TelematicProviderRegistryTest.php +39 -0
  664. package/server/tests/Unit/Support/Telematics/TelematicServiceLifecycleTest.php +711 -0
  665. package/server/tests/Unit/Support/Telematics/TelematicServiceTelemetryTest.php +364 -0
  666. package/server/tests/Unit/Support/UtilsAdditionalTest.php +256 -0
  667. package/server/tests/Unit/Support/UtilsGeoMatrixAndVendorTest.php +382 -0
  668. package/server/tests/Unit/Tracking/TrackingContextTest.php +114 -0
  669. package/server/tests/Unit/Tracking/TrackingIntelligenceAndContextTest.php +477 -0
  670. package/server/tests/Unit/Tracking/TrackingProviderManagerFallbacksTest.php +208 -0
  671. package/server/tests/Unit/Traits/HasTrackingNumberTest.php +303 -0
  672. package/server/tests/Unit/Traits/PayloadAccessorsTest.php +150 -0
  673. package/server/tests/UtilsContractsTest.php +244 -0
  674. package/server/tests/VehicleControllerHelperContractsTest.php +488 -0
  675. package/server/tests/VehicleDataParsingTest.php +45 -0
  676. package/server/tests/VehicleResourceContractsTest.php +313 -0
  677. package/translations/bg-bg.yaml +2 -0
  678. package/translations/en-us.yaml +2 -0
  679. package/translations/es-pa.yaml +2 -0
  680. package/translations/fr-fr.yaml +2 -0
  681. package/translations/mn-mn.yaml +2 -0
  682. package/translations/pt-br.yaml +2 -0
  683. package/translations/ru-ru.yaml +2 -0
  684. package/server/tests/DeviceFilterTest.php +0 -44
  685. package/server/tests/LiveControllerViewportTest.php +0 -52
@@ -24,17 +24,17 @@ class ZoneController extends Controller
24
24
  public function create(CreateZoneRequest $request)
25
25
  {
26
26
  // get request input
27
- $input = $request->only(['name', 'border', 'status', 'description', 'color', 'stroke_color', 'trigger_on_entry', 'trigger_on_exit', 'dwell_threshold_minutes', 'speed_limit_kmh']);
27
+ $input = $this->zoneInputFromRequest($request);
28
28
 
29
29
  // get radius for creating zone border - default to 500 meters
30
- $radius = $request->input('radius', 500);
30
+ $radius = $this->radiusFromRequest($request);
31
31
 
32
32
  // make sure company is set
33
33
  $input['company_uuid'] = session('company');
34
34
 
35
35
  // service area assignment
36
36
  if ($request->has('service_area')) {
37
- $input['service_area_uuid'] = Utils::getUuid('service_areas', [
37
+ $input['service_area_uuid'] = $this->serviceAreaUuid($request->input('service_area'), [
38
38
  'public_id' => $request->input('service_area'),
39
39
  'company_uuid' => session('company'),
40
40
  ]);
@@ -48,17 +48,17 @@ class ZoneController extends Controller
48
48
  $point = new Point($latitude, $longitude);
49
49
 
50
50
  if ($point instanceof Point) {
51
- $input['border'] = Zone::createPolygonFromPoint($point, $radius);
51
+ $input['border'] = $this->createBorderFromPoint($point, $radius);
52
52
  }
53
53
  }
54
54
 
55
55
  // if a location is provided
56
56
  if ($request->has('location')) {
57
57
  $location = $request->input('location');
58
- $point = Utils::getPointFromMixed($location);
58
+ $point = $this->pointFromLocation($location);
59
59
 
60
60
  if ($point instanceof Point) {
61
- $input['border'] = Zone::createPolygonFromPoint($point, $radius);
61
+ $input['border'] = $this->createBorderFromPoint($point, $radius);
62
62
  }
63
63
  }
64
64
 
@@ -68,11 +68,11 @@ class ZoneController extends Controller
68
68
  */
69
69
 
70
70
  // create the zone
71
- $zone = Zone::create($input);
71
+ $zone = $this->createZone($input);
72
72
  $zone->refresh();
73
73
 
74
74
  // response the zone resource
75
- return new ZoneResource($zone);
75
+ return $this->zoneResource($zone);
76
76
  }
77
77
 
78
78
  /**
@@ -87,9 +87,9 @@ class ZoneController extends Controller
87
87
  {
88
88
  // find for the zone
89
89
  try {
90
- $zone = Zone::findRecordOrFail($id);
90
+ $zone = $this->findZoneRecord($id);
91
91
  } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $exception) {
92
- return response()->json(
92
+ return $this->jsonResponse(
93
93
  [
94
94
  'error' => 'Zone resource not found.',
95
95
  ],
@@ -98,14 +98,14 @@ class ZoneController extends Controller
98
98
  }
99
99
 
100
100
  // get request input
101
- $input = $request->only(['name', 'border', 'status', 'description', 'color', 'stroke_color', 'trigger_on_entry', 'trigger_on_exit', 'dwell_threshold_minutes', 'speed_limit_kmh']);
101
+ $input = $this->zoneInputFromRequest($request);
102
102
 
103
103
  // get radius for creating zone border - default to 500 meters
104
- $radius = $request->input('radius', 500);
104
+ $radius = $this->radiusFromRequest($request);
105
105
 
106
106
  // service area assignment
107
107
  if ($request->has('service_area')) {
108
- $input['service_area_uuid'] = Utils::getUuid('service_areas', [
108
+ $input['service_area_uuid'] = $this->serviceAreaUuid($request->input('service_area'), [
109
109
  'public_id' => $request->input('service_area'),
110
110
  'company_uuid' => session('company'),
111
111
  ]);
@@ -119,17 +119,17 @@ class ZoneController extends Controller
119
119
  $point = new Point($latitude, $longitude);
120
120
 
121
121
  if ($point instanceof Point) {
122
- $input['border'] = Zone::createPolygonFromPoint($point, $radius);
122
+ $input['border'] = $this->createBorderFromPoint($point, $radius);
123
123
  }
124
124
  }
125
125
 
126
126
  // if a location is provided
127
127
  if ($request->has('location')) {
128
128
  $location = $request->input('location');
129
- $point = Utils::getPointFromMixed($location);
129
+ $point = $this->pointFromLocation($location);
130
130
 
131
131
  if ($point instanceof Point) {
132
- $input['border'] = Zone::createPolygonFromPoint($point, $radius);
132
+ $input['border'] = $this->createBorderFromPoint($point, $radius);
133
133
  }
134
134
  }
135
135
 
@@ -138,7 +138,7 @@ class ZoneController extends Controller
138
138
  $zone->refresh();
139
139
 
140
140
  // response the zone resource
141
- return new ZoneResource($zone);
141
+ return $this->zoneResource($zone);
142
142
  }
143
143
 
144
144
  /**
@@ -148,9 +148,9 @@ class ZoneController extends Controller
148
148
  */
149
149
  public function query(Request $request)
150
150
  {
151
- $results = Zone::queryWithRequest($request);
151
+ $results = $this->queryZones($request);
152
152
 
153
- return ZoneResource::collection($results);
153
+ return $this->zoneResourceCollection($results);
154
154
  }
155
155
 
156
156
  /**
@@ -162,9 +162,9 @@ class ZoneController extends Controller
162
162
  {
163
163
  // find for the zone
164
164
  try {
165
- $zone = Zone::findRecordOrFail($id);
165
+ $zone = $this->findZoneRecord($id);
166
166
  } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $exception) {
167
- return response()->json(
167
+ return $this->jsonResponse(
168
168
  [
169
169
  'error' => 'Zone resource not found.',
170
170
  ],
@@ -173,7 +173,7 @@ class ZoneController extends Controller
173
173
  }
174
174
 
175
175
  // response the zone resource
176
- return new ZoneResource($zone);
176
+ return $this->zoneResource($zone);
177
177
  }
178
178
 
179
179
  /**
@@ -185,9 +185,9 @@ class ZoneController extends Controller
185
185
  {
186
186
  // find for the driver
187
187
  try {
188
- $zone = Zone::findRecordOrFail($id);
188
+ $zone = $this->findZoneRecord($id);
189
189
  } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $exception) {
190
- return response()->json(
190
+ return $this->jsonResponse(
191
191
  [
192
192
  'error' => 'Zone resource not found.',
193
193
  ],
@@ -199,6 +199,66 @@ class ZoneController extends Controller
199
199
  $zone->delete();
200
200
 
201
201
  // response the zone resource
202
+ return $this->deletedZoneResource($zone);
203
+ }
204
+
205
+ protected function zoneInputFromRequest(Request $request): array
206
+ {
207
+ return $request->only(['name', 'border', 'status', 'description', 'color', 'stroke_color', 'trigger_on_entry', 'trigger_on_exit', 'dwell_threshold_minutes', 'speed_limit_kmh']);
208
+ }
209
+
210
+ protected function radiusFromRequest(Request $request): int
211
+ {
212
+ return (int) $request->input('radius', 500);
213
+ }
214
+
215
+ protected function serviceAreaUuid(string $publicId, array $where): ?string
216
+ {
217
+ return Utils::getUuid('service_areas', $where);
218
+ }
219
+
220
+ protected function createBorderFromPoint(Point $point, int $radius)
221
+ {
222
+ return Zone::createPolygonFromPoint($point, $radius);
223
+ }
224
+
225
+ protected function pointFromLocation(mixed $location)
226
+ {
227
+ return Utils::getPointFromMixed($location);
228
+ }
229
+
230
+ protected function createZone(array $input): Zone
231
+ {
232
+ return Zone::create($input);
233
+ }
234
+
235
+ protected function findZoneRecord(string $id): Zone
236
+ {
237
+ return Zone::findRecordOrFail($id);
238
+ }
239
+
240
+ protected function queryZones(Request $request)
241
+ {
242
+ return Zone::queryWithRequest($request);
243
+ }
244
+
245
+ protected function zoneResource(Zone $zone)
246
+ {
247
+ return new ZoneResource($zone);
248
+ }
249
+
250
+ protected function zoneResourceCollection($results)
251
+ {
252
+ return ZoneResource::collection($results);
253
+ }
254
+
255
+ protected function deletedZoneResource(Zone $zone)
256
+ {
202
257
  return new DeletedResource($zone);
203
258
  }
259
+
260
+ protected function jsonResponse(array $payload, int $status)
261
+ {
262
+ return response()->json($payload, $status);
263
+ }
204
264
  }
@@ -35,7 +35,7 @@ class AnalyticsController extends Controller
35
35
 
36
36
  public function revenueTrend(Request $request)
37
37
  {
38
- return $this->run($request, RevenueTrend::class, function (RevenueTrend $a) use ($request) {
38
+ return $this->run($request, RevenueTrend::class, function ($a) use ($request) {
39
39
  $a->groupBy($request->string('group_by', 'day')->toString());
40
40
  });
41
41
  }
@@ -47,14 +47,14 @@ class AnalyticsController extends Controller
47
47
 
48
48
  public function onTimeDelivery(Request $request)
49
49
  {
50
- return $this->run($request, OnTimeDelivery::class, function (OnTimeDelivery $a) use ($request) {
50
+ return $this->run($request, OnTimeDelivery::class, function ($a) use ($request) {
51
51
  $a->slaMinutes((int) $request->input('sla_minutes', 30));
52
52
  });
53
53
  }
54
54
 
55
55
  public function topDrivers(Request $request)
56
56
  {
57
- return $this->run($request, TopDrivers::class, function (TopDrivers $a) use ($request) {
57
+ return $this->run($request, TopDrivers::class, function ($a) use ($request) {
58
58
  $a->limit((int) $request->input('limit', 10));
59
59
  $a->sortBy($request->string('sort_by', 'orders_completed')->toString());
60
60
  });
@@ -106,7 +106,7 @@ class AnalyticsController extends Controller
106
106
 
107
107
  try {
108
108
  /** @var AbstractAnalytics $analytics */
109
- $analytics = $class::forCompany($request->user()->company)->between($start, $end);
109
+ $analytics = $this->analyticsForCompany($class, $request->user()->company)->between($start, $end);
110
110
 
111
111
  if ($configure !== null) {
112
112
  $configure($analytics);
@@ -114,7 +114,9 @@ class AnalyticsController extends Controller
114
114
 
115
115
  return response()->json($analytics->get());
116
116
  } catch (\Throwable $e) {
117
- report($e);
117
+ if (function_exists('report')) {
118
+ report($e);
119
+ }
118
120
 
119
121
  return response()->json([
120
122
  'error' => $e->getMessage(),
@@ -122,4 +124,12 @@ class AnalyticsController extends Controller
122
124
  ], 500);
123
125
  }
124
126
  }
127
+
128
+ /**
129
+ * @param class-string<AbstractAnalytics> $class
130
+ */
131
+ protected function analyticsForCompany(string $class, $company): AbstractAnalytics
132
+ {
133
+ return $class::forCompany($company);
134
+ }
125
135
  }
@@ -79,7 +79,7 @@ class ContactController extends FleetOpsController
79
79
  */
80
80
  public function getAsFacilitator($id)
81
81
  {
82
- $contact = Contact::where('uuid', $id)->withTrashes()->first();
82
+ $contact = $this->contactByUuidWithTrashed($id);
83
83
 
84
84
  if (!$contact) {
85
85
  return response()->error('Facilitator not found.');
@@ -97,7 +97,7 @@ class ContactController extends FleetOpsController
97
97
  */
98
98
  public function getAsCustomer($id)
99
99
  {
100
- $contact = Contact::where('uuid', $id)->first();
100
+ $contact = $this->contactByUuid($id);
101
101
 
102
102
  if (!$contact) {
103
103
  return response()->error('Customer not found.');
@@ -110,15 +110,11 @@ class ContactController extends FleetOpsController
110
110
 
111
111
  public function convertToVendor(Request $request, string $id)
112
112
  {
113
- $contact = Contact::where('company_uuid', session('company'))
114
- ->where(function ($query) use ($id) {
115
- $query->where('uuid', $id)->orWhere('public_id', $id)->orWhere('id', $id);
116
- })
117
- ->firstOrFail();
113
+ $contact = $this->contactForVendorConversion($id);
118
114
 
119
- $vendor = DB::transaction(function () use ($contact, $request) {
115
+ $vendor = $this->runContactConversionTransaction(function () use ($contact, $request) {
120
116
  $originalType = $contact->type;
121
- $vendor = Vendor::create([
117
+ $vendor = $this->createVendorFromContact([
122
118
  'company_uuid' => $contact->company_uuid,
123
119
  'place_uuid' => $contact->place_uuid,
124
120
  'name' => $request->input('name', $contact->name),
@@ -134,7 +130,7 @@ class ContactController extends FleetOpsController
134
130
  ],
135
131
  ]);
136
132
 
137
- VendorPersonnel::updateOrCreate(
133
+ $this->updateOrCreateVendorPersonnel(
138
134
  ['vendor_uuid' => $vendor->uuid, 'contact_uuid' => $contact->uuid],
139
135
  ['role' => 'admin', 'status' => 'active', 'invited_by_uuid' => session('user')]
140
136
  );
@@ -155,7 +151,7 @@ class ContactController extends FleetOpsController
155
151
  });
156
152
 
157
153
  return response()->json([
158
- 'vendor' => (new VendorResource($vendor->load('personnels')))->resolve(),
154
+ 'vendor' => $this->vendorResourcePayload($vendor),
159
155
  ]);
160
156
  }
161
157
 
@@ -197,21 +193,57 @@ class ContactController extends FleetOpsController
197
193
  return response()->json(['status' => 'ok', 'message' => 'Import completed', 'imported' => $importedCount]);
198
194
  }
199
195
 
200
- private function migrateContactCustomerContextToVendor(Contact $contact, Vendor $vendor): void
196
+ protected function contactByUuidWithTrashed(string $id): ?Contact
197
+ {
198
+ return Contact::where('uuid', $id)->withTrashed()->first();
199
+ }
200
+
201
+ protected function contactByUuid(string $id): ?Contact
202
+ {
203
+ return Contact::where('uuid', $id)->first();
204
+ }
205
+
206
+ protected function contactForVendorConversion(string $id): Contact
207
+ {
208
+ return Contact::where('company_uuid', session('company'))
209
+ ->where(function ($query) use ($id) {
210
+ $query->where('uuid', $id)->orWhere('public_id', $id)->orWhere('id', $id);
211
+ })
212
+ ->firstOrFail();
213
+ }
214
+
215
+ protected function runContactConversionTransaction(callable $callback): mixed
216
+ {
217
+ return DB::transaction($callback);
218
+ }
219
+
220
+ protected function createVendorFromContact(array $attributes): Vendor
221
+ {
222
+ return Vendor::create($attributes);
223
+ }
224
+
225
+ protected function updateOrCreateVendorPersonnel(array $where, array $attributes): VendorPersonnel
226
+ {
227
+ return VendorPersonnel::updateOrCreate($where, $attributes);
228
+ }
229
+
230
+ protected function vendorResourcePayload(Vendor $vendor): array
231
+ {
232
+ return (new VendorResource($vendor->load('personnels')))->resolve();
233
+ }
234
+
235
+ protected function migrateContactCustomerContextToVendor(Contact $contact, Vendor $vendor): void
201
236
  {
202
237
  $contactType = Utils::getMutationType($contact);
203
238
  $vendorType = Utils::getMutationType($vendor);
204
239
  $filter = ['customer_uuid' => $contact->uuid, 'customer_type' => $contactType];
205
240
  $replacement = ['customer_uuid' => $vendor->uuid, 'customer_type' => $vendorType];
206
241
 
207
- Order::where($filter)->update($replacement);
208
- PurchaseRate::where($filter)->update($replacement);
209
- Entity::where($filter)->update($replacement);
242
+ $this->bulkUpdateCustomerContext(Order::class, $filter, $replacement);
243
+ $this->bulkUpdateCustomerContext(PurchaseRate::class, $filter, $replacement);
244
+ $this->bulkUpdateCustomerContext(Entity::class, $filter, $replacement);
210
245
 
211
- Issue::where('company_uuid', $contact->company_uuid)
212
- ->where('meta->customer_portal->customer_uuid', $contact->uuid)
213
- ->where('meta->customer_portal->customer_type', 'contact')
214
- ->get()
246
+ $this->customerPortalIssuesForContact($contact)
215
247
  ->each(function (Issue $issue) use ($vendor) {
216
248
  $meta = (array) $issue->meta;
217
249
  data_set($meta, 'customer_portal.customer_uuid', $vendor->uuid);
@@ -220,6 +252,19 @@ class ContactController extends FleetOpsController
220
252
  });
221
253
  }
222
254
 
255
+ protected function bulkUpdateCustomerContext(string $modelClass, array $filter, array $replacement): void
256
+ {
257
+ $modelClass::where($filter)->update($replacement);
258
+ }
259
+
260
+ protected function customerPortalIssuesForContact(Contact $contact)
261
+ {
262
+ return Issue::where('company_uuid', $contact->company_uuid)
263
+ ->where('meta->customer_portal->customer_uuid', $contact->uuid)
264
+ ->where('meta->customer_portal->customer_type', 'contact')
265
+ ->get();
266
+ }
267
+
223
268
  private function resolveUserInput(Request $request, array &$input): void
224
269
  {
225
270
  $user = data_get($input, 'user_uuid') ?? data_get($input, 'user') ?? $request->input('contact.user_uuid') ?? $request->input('contact.user');
@@ -232,11 +277,16 @@ class ContactController extends FleetOpsController
232
277
  return;
233
278
  }
234
279
 
235
- $input['user_uuid'] = User::where('uuid', $user)->orWhere('public_id', $user)->value('uuid') ?? $user;
280
+ $input['user_uuid'] = $this->resolveUserUuid($user);
236
281
  unset($input['user']);
237
282
  }
238
283
 
239
- private function assertCustomerPortalCanSendWelcomeEmail(array $input): void
284
+ protected function resolveUserUuid(string $user): string
285
+ {
286
+ return User::where('uuid', $user)->orWhere('public_id', $user)->value('uuid') ?? $user;
287
+ }
288
+
289
+ protected function assertCustomerPortalCanSendWelcomeEmail(array $input): void
240
290
  {
241
291
  $type = data_get($input, 'type', 'contact');
242
292
  if ($type !== 'customer' || !data_get($input, 'meta.customer_portal.send_welcome_email')) {
@@ -248,7 +298,7 @@ class ContactController extends FleetOpsController
248
298
  }
249
299
  }
250
300
 
251
- private function sendCustomerPortalWelcomeEmail(Contact $contact): void
301
+ protected function sendCustomerPortalWelcomeEmail(Contact $contact): void
252
302
  {
253
303
  if (!data_get($contact->meta, 'customer_portal.send_welcome_email')) {
254
304
  return;
@@ -258,29 +308,64 @@ class ContactController extends FleetOpsController
258
308
  throw new \Exception('Customer portal must be installed before sending a customer welcome email.');
259
309
  }
260
310
 
261
- $user = $contact->getUser() ?? Contact::createUserFromContact($contact, false, true);
311
+ $user = $this->contactUser($contact) ?? $this->createCustomerUserFromContact($contact);
262
312
  if (!$user) {
263
313
  throw new \Exception('Unable to create customer portal login.');
264
314
  }
265
315
 
266
- $password = Str::random(16);
316
+ $password = $this->customerPortalPassword();
267
317
  $user->changePassword($password);
268
318
 
269
319
  if ($user->status !== 'active') {
270
320
  $user->activate();
271
321
  }
272
322
 
273
- Mail::to($user)->send(new CustomerCredentialsMail($password, $contact));
323
+ $this->sendCustomerCredentialsMail($user, $password, $contact);
274
324
 
275
325
  $meta = (array) $contact->meta;
276
326
  data_forget($meta, 'customer_portal.send_welcome_email');
277
- $contact->forceFill(['meta' => $meta])->saveQuietly();
327
+ $this->saveContactMetaQuietly($contact, $meta);
278
328
  $contact->setAttribute('meta', $meta);
279
329
  }
280
330
 
281
- private function isCustomerPortalInstalled(): bool
331
+ protected function contactUser(Contact $contact): ?User
332
+ {
333
+ return $contact->getUser();
334
+ }
335
+
336
+ protected function createCustomerUserFromContact(Contact $contact): ?User
337
+ {
338
+ return Contact::createUserFromContact($contact, false, true);
339
+ }
340
+
341
+ protected function customerPortalPassword(): string
342
+ {
343
+ return Str::random(16);
344
+ }
345
+
346
+ protected function sendCustomerCredentialsMail(User $user, string $password, Contact $contact): void
347
+ {
348
+ Mail::to($user)->send(new CustomerCredentialsMail($password, $contact));
349
+ }
350
+
351
+ protected function saveContactMetaQuietly(Contact $contact, array $meta): void
352
+ {
353
+ $contact->forceFill(['meta' => $meta])->saveQuietly();
354
+ }
355
+
356
+ protected function isCustomerPortalInstalled(): bool
357
+ {
358
+ return $this->containsCustomerPortalExtension($this->installedFleetbaseExtensions());
359
+ }
360
+
361
+ protected function installedFleetbaseExtensions(): array
362
+ {
363
+ return Utils::getInstalledFleetbaseExtensions();
364
+ }
365
+
366
+ protected function containsCustomerPortalExtension(array $packages): bool
282
367
  {
283
- return collect(Utils::getInstalledFleetbaseExtensions())
368
+ return collect($packages)
284
369
  ->contains(fn ($package) => data_get($package, 'name') === 'fleetbase/customer-portal-api');
285
370
  }
286
371
 
@@ -26,7 +26,7 @@ class CustomerController extends Controller
26
26
  }
27
27
 
28
28
  return response()->json([
29
- 'customer' => $this->customerPayload($customer->fresh()),
29
+ 'customer' => $this->customerPayload($this->freshCustomer($customer)),
30
30
  ]);
31
31
  }
32
32
 
@@ -39,19 +39,19 @@ class CustomerController extends Controller
39
39
  return response()->error('Unable to send customer portal credentials.');
40
40
  }
41
41
 
42
- $password = Str::random(16);
42
+ $password = $this->randomPassword();
43
43
  $user->changePassword($password);
44
- Mail::to($user)->send(new CustomerCredentialsMail($password, $customer));
44
+ $this->sendCustomerCredentials($user, $password, $customer);
45
45
 
46
46
  return response()->json([
47
- 'customer' => $this->customerPayload($customer->fresh()),
47
+ 'customer' => $this->customerPayload($this->freshCustomer($customer)),
48
48
  ]);
49
49
  }
50
50
 
51
51
  public function deactivatePortalLogin(Request $request)
52
52
  {
53
53
  $customer = $this->resolveCustomer($request);
54
- $user = $customer->user_uuid ? User::where('uuid', $customer->user_uuid)->first() : null;
54
+ $user = $customer->user_uuid ? $this->findUser($customer->user_uuid) : null;
55
55
 
56
56
  if (!$user) {
57
57
  return response()->error('Customer portal login not found.');
@@ -60,14 +60,14 @@ class CustomerController extends Controller
60
60
  $user->deactivate();
61
61
 
62
62
  return response()->json([
63
- 'customer' => $this->customerPayload($customer->fresh()),
63
+ 'customer' => $this->customerPayload($this->freshCustomer($customer)),
64
64
  ]);
65
65
  }
66
66
 
67
67
  public function reactivatePortalLogin(Request $request)
68
68
  {
69
69
  $customer = $this->resolveCustomer($request);
70
- $user = $customer->user_uuid ? User::where('uuid', $customer->user_uuid)->first() : null;
70
+ $user = $customer->user_uuid ? $this->findUser($customer->user_uuid) : null;
71
71
 
72
72
  if (!$user) {
73
73
  return response()->error('Customer portal login not found.');
@@ -76,7 +76,7 @@ class CustomerController extends Controller
76
76
  $user->activate();
77
77
 
78
78
  return response()->json([
79
- 'customer' => $this->customerPayload($customer->fresh()),
79
+ 'customer' => $this->customerPayload($this->freshCustomer($customer)),
80
80
  ]);
81
81
  }
82
82
 
@@ -154,12 +154,12 @@ class CustomerController extends Controller
154
154
 
155
155
  // Send credentials to customer if opted
156
156
  if ($sendCredentials) {
157
- Mail::to($user)->send(new CustomerCredentialsMail($password, $customer));
157
+ $this->sendCustomerCredentials($user, $password, $customer);
158
158
  }
159
159
 
160
160
  return response()->json([
161
161
  'status' => 'ok',
162
- 'customer' => $this->customerPayload($customer->fresh()),
162
+ 'customer' => $this->customerPayload($this->freshCustomer($customer)),
163
163
  ]);
164
164
  }
165
165
 
@@ -180,7 +180,32 @@ class CustomerController extends Controller
180
180
 
181
181
  protected function resolveCustomerUser(Contact $customer): ?User
182
182
  {
183
- return $customer->user_uuid ? User::where('uuid', $customer->user_uuid)->first() : Contact::createUserFromContact($customer, false, true);
183
+ return $customer->user_uuid ? $this->findUser($customer->user_uuid) : $this->createUserFromCustomer($customer);
184
+ }
185
+
186
+ protected function findUser(string $uuid): ?User
187
+ {
188
+ return User::where('uuid', $uuid)->first();
189
+ }
190
+
191
+ protected function createUserFromCustomer(Contact $customer): ?User
192
+ {
193
+ return Contact::createUserFromContact($customer, false, true);
194
+ }
195
+
196
+ protected function randomPassword(): string
197
+ {
198
+ return Str::random(16);
199
+ }
200
+
201
+ protected function sendCustomerCredentials(User $user, string $password, Contact $customer): void
202
+ {
203
+ Mail::to($user)->send(new CustomerCredentialsMail($password, $customer));
204
+ }
205
+
206
+ protected function freshCustomer(Contact $customer): Contact
207
+ {
208
+ return $customer->fresh();
184
209
  }
185
210
 
186
211
  protected function customerPayload(Contact $customer): array
@@ -211,13 +211,18 @@ class DeviceController extends FleetOpsController
211
211
  {
212
212
  $query->where(function ($vehicleQuery) use ($vehicle) {
213
213
  $vehicleQuery->where('attachable_uuid', $vehicle)
214
- ->orWhereIn('attachable_uuid', Vehicle::query()
215
- ->where('company_uuid', session('company'))
216
- ->where('public_id', $vehicle)
217
- ->pluck('uuid'));
214
+ ->orWhereIn('attachable_uuid', static::vehicleUuidsForPublicId($vehicle));
218
215
  });
219
216
  }
220
217
 
218
+ protected static function vehicleUuidsForPublicId(string $vehicle)
219
+ {
220
+ return Vehicle::query()
221
+ ->where('company_uuid', session('company'))
222
+ ->where('public_id', $vehicle)
223
+ ->pluck('uuid');
224
+ }
225
+
221
226
  protected function logDeviceAttachmentLookupFailure(string $action, string $missingResource, string $deviceId, ?string $vehicleId): void
222
227
  {
223
228
  Log::warning('Device attachment lookup failed', [