@fleetbase/fleetops-engine 0.6.57 → 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 (693) 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 +15 -3
  9. package/extension.json +1 -1
  10. package/index.js +7 -1
  11. package/package.json +3 -2
  12. package/phpunit.xml.dist +4 -4
  13. package/pnpm-workspace.yaml +2 -1
  14. package/scripts/coverage-file-runner.php +240 -0
  15. package/scripts/coverage-runner.php +52 -0
  16. package/scripts/coverage-summary.php +149 -0
  17. package/scripts/pest-bootstrap.php +411 -0
  18. package/scripts/pest-file-runner.php +94 -0
  19. package/scripts/pest-runner.php +119 -0
  20. package/server/resources/views/labels/entity-label.php +4 -4
  21. package/server/src/Casts/MultiPolygon.php +8 -3
  22. package/server/src/Casts/OrderConfigEntities.php +10 -3
  23. package/server/src/Casts/Point.php +10 -6
  24. package/server/src/Casts/Polygon.php +5 -2
  25. package/server/src/Console/Commands/AssignCustomerRoles.php +28 -6
  26. package/server/src/Console/Commands/AssignDriverRoles.php +36 -6
  27. package/server/src/Console/Commands/AuditCustomerUserConflicts.php +6 -1
  28. package/server/src/Console/Commands/DispatchAdhocOrders.php +12 -2
  29. package/server/src/Console/Commands/FixCustomerCompanies.php +46 -11
  30. package/server/src/Console/Commands/FixDriverCompanies.php +18 -3
  31. package/server/src/Console/Commands/FixLegacyOrderConfigs.php +31 -6
  32. package/server/src/Console/Commands/ProcessMaintenanceTriggers.php +94 -42
  33. package/server/src/Console/Commands/PurgeUnpurchasedServiceQuotes.php +42 -12
  34. package/server/src/Console/Commands/ReplayVehicleLocations.php +120 -55
  35. package/server/src/Console/Commands/SendDriverNotification.php +25 -4
  36. package/server/src/Console/Commands/SendMaintenanceReminders.php +43 -23
  37. package/server/src/Console/Commands/SimulateOrderRouteNavigation.php +36 -6
  38. package/server/src/Console/Commands/TrackOrderDistanceAndTime.php +6 -1
  39. package/server/src/Events/DriverLocationChanged.php +1 -1
  40. package/server/src/Events/DriverSimulatedLocationChanged.php +1 -1
  41. package/server/src/Events/EntityActivityChanged.php +1 -1
  42. package/server/src/Events/EntityCompleted.php +1 -1
  43. package/server/src/Events/EntityDriverAssigned.php +1 -1
  44. package/server/src/Events/FuelProviderTransactionImported.php +1 -1
  45. package/server/src/Events/FuelProviderTransactionMatched.php +1 -1
  46. package/server/src/Events/FuelProviderTransactionUnmatched.php +1 -1
  47. package/server/src/Events/FuelReportCreatedFromProvider.php +1 -1
  48. package/server/src/Events/GeofenceDwelled.php +1 -1
  49. package/server/src/Events/GeofenceEntered.php +1 -1
  50. package/server/src/Events/GeofenceExited.php +1 -1
  51. package/server/src/Events/VehicleLocationChanged.php +1 -1
  52. package/server/src/Events/WaypointActivityChanged.php +1 -1
  53. package/server/src/Events/WaypointCompleted.php +1 -1
  54. package/server/src/Exceptions/IntegratedVendorException.php +2 -2
  55. package/server/src/Exceptions/TelematicRateLimitExceededException.php +1 -1
  56. package/server/src/Http/Controllers/Api/v1/ContactController.php +89 -22
  57. package/server/src/Http/Controllers/Api/v1/CustomerController.php +296 -97
  58. package/server/src/Http/Controllers/Api/v1/DeviceController.php +48 -14
  59. package/server/src/Http/Controllers/Api/v1/DriverController.php +168 -63
  60. package/server/src/Http/Controllers/Api/v1/EntityController.php +112 -66
  61. package/server/src/Http/Controllers/Api/v1/EquipmentController.php +40 -10
  62. package/server/src/Http/Controllers/Api/v1/FleetController.php +54 -14
  63. package/server/src/Http/Controllers/Api/v1/FuelReportController.php +54 -14
  64. package/server/src/Http/Controllers/Api/v1/FuelTransactionController.php +36 -11
  65. package/server/src/Http/Controllers/Api/v1/GeofenceController.php +39 -21
  66. package/server/src/Http/Controllers/Api/v1/IssueController.php +54 -14
  67. package/server/src/Http/Controllers/Api/v1/LabelController.php +61 -22
  68. package/server/src/Http/Controllers/Api/v1/NavigatorController.php +21 -5
  69. package/server/src/Http/Controllers/Api/v1/OrderConfigController.php +35 -5
  70. package/server/src/Http/Controllers/Api/v1/OrderController.php +388 -203
  71. package/server/src/Http/Controllers/Api/v1/PartController.php +40 -10
  72. package/server/src/Http/Controllers/Api/v1/PayloadController.php +90 -30
  73. package/server/src/Http/Controllers/Api/v1/PlaceController.php +188 -91
  74. package/server/src/Http/Controllers/Api/v1/PurchaseRateController.php +100 -36
  75. package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +96 -26
  76. package/server/src/Http/Controllers/Api/v1/ServiceQuoteController.php +169 -81
  77. package/server/src/Http/Controllers/Api/v1/ServiceRateController.php +104 -75
  78. package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +83 -14
  79. package/server/src/Http/Controllers/Api/v1/TrackingStatusController.php +66 -16
  80. package/server/src/Http/Controllers/Api/v1/VehicleController.php +121 -67
  81. package/server/src/Http/Controllers/Api/v1/VendorController.php +54 -14
  82. package/server/src/Http/Controllers/Api/v1/WorkOrderController.php +47 -12
  83. package/server/src/Http/Controllers/Api/v1/ZoneController.php +84 -24
  84. package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +15 -5
  85. package/server/src/Http/Controllers/Internal/v1/ContactController.php +113 -28
  86. package/server/src/Http/Controllers/Internal/v1/CustomerController.php +36 -11
  87. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +9 -4
  88. package/server/src/Http/Controllers/Internal/v1/DriverController.php +167 -69
  89. package/server/src/Http/Controllers/Internal/v1/EquipmentController.php +18 -3
  90. package/server/src/Http/Controllers/Internal/v1/FleetController.php +137 -60
  91. package/server/src/Http/Controllers/Internal/v1/FleetOpsLookupController.php +24 -9
  92. package/server/src/Http/Controllers/Internal/v1/FuelReportController.php +18 -3
  93. package/server/src/Http/Controllers/Internal/v1/GeocoderController.php +26 -8
  94. package/server/src/Http/Controllers/Internal/v1/GettingStartedController.php +12 -2
  95. package/server/src/Http/Controllers/Internal/v1/IntegratedVendorController.php +27 -6
  96. package/server/src/Http/Controllers/Internal/v1/IssueController.php +82 -29
  97. package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +34 -26
  98. package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +141 -97
  99. package/server/src/Http/Controllers/Internal/v1/ManifestController.php +28 -8
  100. package/server/src/Http/Controllers/Internal/v1/MetricsController.php +21 -12
  101. package/server/src/Http/Controllers/Internal/v1/MorphController.php +90 -18
  102. package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +88 -35
  103. package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +149 -39
  104. package/server/src/Http/Controllers/Internal/v1/OrderConfigController.php +54 -18
  105. package/server/src/Http/Controllers/Internal/v1/OrderController.php +298 -86
  106. package/server/src/Http/Controllers/Internal/v1/PartController.php +18 -3
  107. package/server/src/Http/Controllers/Internal/v1/PaymentController.php +46 -14
  108. package/server/src/Http/Controllers/Internal/v1/PlaceController.php +31 -5
  109. package/server/src/Http/Controllers/Internal/v1/ProofController.php +88 -48
  110. package/server/src/Http/Controllers/Internal/v1/SearchController.php +1 -1
  111. package/server/src/Http/Controllers/Internal/v1/SensorController.php +6 -1
  112. package/server/src/Http/Controllers/Internal/v1/ServiceAreaController.php +6 -1
  113. package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +255 -105
  114. package/server/src/Http/Controllers/Internal/v1/SettingController.php +88 -35
  115. package/server/src/Http/Controllers/Internal/v1/TelematicController.php +1 -4
  116. package/server/src/Http/Controllers/Internal/v1/Traits/DriverSchedulingTrait.php +42 -14
  117. package/server/src/Http/Controllers/Internal/v1/VendorController.php +103 -33
  118. package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +42 -12
  119. package/server/src/Http/Filter/DriverFilter.php +2 -2
  120. package/server/src/Http/Filter/OrderFilter.php +1 -1
  121. package/server/src/Http/Filter/VehicleFilter.php +21 -7
  122. package/server/src/Http/Middleware/AuthenticateCustomerToken.php +12 -2
  123. package/server/src/Http/Requests/BulkDispatchRequest.php +3 -9
  124. package/server/src/Http/Requests/CancelOrderRequest.php +2 -6
  125. package/server/src/Http/Requests/CreateContactRequest.php +2 -6
  126. package/server/src/Http/Requests/CreateDeviceRequest.php +2 -2
  127. package/server/src/Http/Requests/CreateDriverRequest.php +3 -9
  128. package/server/src/Http/Requests/CreateEntityRequest.php +2 -6
  129. package/server/src/Http/Requests/CreateEquipmentRequest.php +2 -2
  130. package/server/src/Http/Requests/CreateFleetRequest.php +2 -6
  131. package/server/src/Http/Requests/CreateFuelReportRequest.php +2 -6
  132. package/server/src/Http/Requests/CreateFuelTransactionRequest.php +2 -2
  133. package/server/src/Http/Requests/CreateIssueRequest.php +2 -6
  134. package/server/src/Http/Requests/CreateOrderRequest.php +7 -8
  135. package/server/src/Http/Requests/CreatePartRequest.php +2 -2
  136. package/server/src/Http/Requests/CreatePayloadRequest.php +7 -9
  137. package/server/src/Http/Requests/CreatePlaceRequest.php +2 -6
  138. package/server/src/Http/Requests/CreatePurchaseRateRequest.php +2 -6
  139. package/server/src/Http/Requests/CreateSensorRequest.php +2 -2
  140. package/server/src/Http/Requests/CreateServiceAreaRequest.php +2 -6
  141. package/server/src/Http/Requests/CreateServiceQuoteRequest.php +2 -6
  142. package/server/src/Http/Requests/CreateServiceRateRequest.php +2 -6
  143. package/server/src/Http/Requests/CreateTrackingNumberRequest.php +2 -6
  144. package/server/src/Http/Requests/CreateTrackingStatusRequest.php +2 -6
  145. package/server/src/Http/Requests/CreateVehicleRequest.php +2 -6
  146. package/server/src/Http/Requests/CreateVendorRequest.php +2 -6
  147. package/server/src/Http/Requests/CreateWorkOrderRequest.php +2 -2
  148. package/server/src/Http/Requests/CreateZoneRequest.php +2 -6
  149. package/server/src/Http/Requests/DecodeTrackingNumberQR.php +2 -6
  150. package/server/src/Http/Requests/DriverSimulationRequest.php +2 -6
  151. package/server/src/Http/Requests/Internal/AssignOrderRequest.php +3 -7
  152. package/server/src/Http/Requests/Internal/CreateDriverRequest.php +4 -12
  153. package/server/src/Http/Requests/Internal/CreateOrderConfigRequest.php +2 -6
  154. package/server/src/Http/Requests/Internal/CreateOrderRequest.php +7 -8
  155. package/server/src/Http/Requests/Internal/FleetActionRequest.php +18 -12
  156. package/server/src/Http/Requests/Internal/UpdateDriverRequest.php +6 -3
  157. package/server/src/Http/Requests/QueryServiceQuotesRequest.php +2 -6
  158. package/server/src/Http/Requests/ScheduleOrderRequest.php +2 -6
  159. package/server/src/Http/Requests/UpdateIssueRequest.php +1 -3
  160. package/server/src/Http/Resources/v1/Customer.php +2 -2
  161. package/server/src/Http/Resources/v1/Maintenance.php +3 -4
  162. package/server/src/Http/Resources/v1/MaintenanceSchedule.php +3 -4
  163. package/server/src/Http/Resources/v1/Order.php +3 -7
  164. package/server/src/Http/Resources/v1/PurchaseRate.php +4 -6
  165. package/server/src/Http/Resources/v1/TrackingStatus.php +4 -6
  166. package/server/src/Http/Resources/v1/WorkOrder.php +3 -4
  167. package/server/src/Imports/ContactImport.php +10 -1
  168. package/server/src/Imports/DriverImport.php +10 -1
  169. package/server/src/Imports/EquipmentImport.php +6 -1
  170. package/server/src/Imports/FleetImport.php +10 -1
  171. package/server/src/Imports/FuelReportImport.php +10 -1
  172. package/server/src/Imports/IssueImport.php +10 -1
  173. package/server/src/Imports/MaintenanceImport.php +6 -1
  174. package/server/src/Imports/MaintenanceScheduleImport.php +6 -1
  175. package/server/src/Imports/PartImport.php +6 -1
  176. package/server/src/Imports/PlaceImport.php +10 -1
  177. package/server/src/Imports/VehicleImport.php +10 -1
  178. package/server/src/Imports/VendorImport.php +10 -1
  179. package/server/src/Imports/WorkOrderImport.php +6 -1
  180. package/server/src/Integrations/Lalamove/Lalamove.php +3 -7
  181. package/server/src/Integrations/Lalamove/LalamoveServiceType.php +5 -8
  182. package/server/src/Jobs/CheckGeofenceDwell.php +41 -16
  183. package/server/src/Jobs/FinalizeApiOrderCreation.php +17 -2
  184. package/server/src/Jobs/FinalizeInternalOrderCreation.php +11 -1
  185. package/server/src/Jobs/NotifyBulkAssignedDriver.php +29 -16
  186. package/server/src/Jobs/ProcessAllocationJob.php +59 -25
  187. package/server/src/Jobs/ReplayPositions.php +17 -10
  188. package/server/src/Jobs/SendPositionReplay.php +18 -7
  189. package/server/src/Jobs/SimulateDrivingRoute.php +14 -3
  190. package/server/src/Jobs/SyncFuelProviderTransactionsJob.php +12 -2
  191. package/server/src/Listeners/HandleDeliveryCompletion.php +11 -1
  192. package/server/src/Listeners/HandleGeofenceDwelled.php +6 -1
  193. package/server/src/Listeners/HandleGeofenceEntered.php +4 -2
  194. package/server/src/Listeners/HandleGeofenceExited.php +6 -1
  195. package/server/src/Listeners/HandleOrderCanceled.php +18 -3
  196. package/server/src/Listeners/HandleOrderDispatchFailed.php +12 -2
  197. package/server/src/Listeners/HandleOrderDispatched.php +61 -26
  198. package/server/src/Listeners/HandleOrderDriverAssigned.php +12 -2
  199. package/server/src/Listeners/HandleUserRemovedFromCompany.php +19 -6
  200. package/server/src/Listeners/NotifyDriverOnShiftChange.php +24 -4
  201. package/server/src/Listeners/NotifyOrderEvent.php +11 -6
  202. package/server/src/Models/Contact.php +6 -7
  203. package/server/src/Models/Device.php +26 -3
  204. package/server/src/Models/Driver.php +0 -6
  205. package/server/src/Models/Entity.php +4 -4
  206. package/server/src/Models/Equipment.php +1 -1
  207. package/server/src/Models/FuelReport.php +5 -1
  208. package/server/src/Models/IntegratedVendor.php +2 -2
  209. package/server/src/Models/Issue.php +5 -1
  210. package/server/src/Models/MaintenanceSchedule.php +25 -10
  211. package/server/src/Models/Order.php +18 -15
  212. package/server/src/Models/OrderConfig.php +1 -1
  213. package/server/src/Models/Payload.php +9 -16
  214. package/server/src/Models/Place.php +20 -13
  215. package/server/src/Models/ServiceArea.php +3 -6
  216. package/server/src/Models/ServiceQuote.php +5 -0
  217. package/server/src/Models/ServiceRate.php +13 -6
  218. package/server/src/Models/Telematic.php +2 -2
  219. package/server/src/Models/TrackingNumber.php +55 -10
  220. package/server/src/Models/TrackingStatus.php +24 -4
  221. package/server/src/Models/Waypoint.php +44 -10
  222. package/server/src/Models/Zone.php +3 -6
  223. package/server/src/Notifications/DriverArrivedAtGeofence.php +1 -1
  224. package/server/src/Notifications/OrderDispatched.php +3 -9
  225. package/server/src/Notifications/OrderPing.php +3 -9
  226. package/server/src/Observers/CategoryObserver.php +6 -1
  227. package/server/src/Observers/CompanyObserver.php +5 -0
  228. package/server/src/Observers/CompanyUserObserver.php +12 -2
  229. package/server/src/Observers/DriverObserver.php +19 -4
  230. package/server/src/Observers/FleetObserver.php +6 -1
  231. package/server/src/Observers/PurchaseRateObserver.php +66 -11
  232. package/server/src/Observers/ServiceAreaObserver.php +12 -2
  233. package/server/src/Observers/ServiceRateObserver.php +21 -6
  234. package/server/src/Observers/TrackingNumberObserver.php +19 -4
  235. package/server/src/Observers/UserObserver.php +6 -1
  236. package/server/src/Observers/VehicleObserver.php +27 -7
  237. package/server/src/Observers/WorkOrderObserver.php +27 -7
  238. package/server/src/Orchestration/Engines/DriverAssignmentEngine.php +8 -3
  239. package/server/src/Orchestration/Support/OrchestrationPayloadBuilder.php +5 -3
  240. package/server/src/Providers/FleetOpsServiceProvider.php +12 -0
  241. package/server/src/Providers/NotificationServiceProvider.php +6 -0
  242. package/server/src/Support/Ai/Capabilities/AssetStatusCapability.php +36 -26
  243. package/server/src/Support/Ai/Capabilities/CreateOrderPreviewCapability.php +18 -5
  244. package/server/src/Support/Ai/Capabilities/OrderInsightsCapability.php +6 -1
  245. package/server/src/Support/Ai/Capabilities/SearchResourcesCapability.php +26 -6
  246. package/server/src/Support/Analytics/FuelEfficiency.php +9 -3
  247. package/server/src/Support/Analytics/FuelProviderSummary.php +14 -5
  248. package/server/src/Support/Analytics/GeofenceViolations.php +40 -20
  249. package/server/src/Support/Analytics/IssuesInsights.php +38 -18
  250. package/server/src/Support/Analytics/MaintenanceOverview.php +51 -21
  251. package/server/src/Support/Analytics/OnTimeDelivery.php +3 -2
  252. package/server/src/Support/Analytics/OperationsPulse.php +59 -35
  253. package/server/src/Support/Analytics/OrdersByStatus.php +12 -7
  254. package/server/src/Support/Analytics/RevenueTrend.php +16 -6
  255. package/server/src/Support/Analytics/TopDrivers.php +3 -2
  256. package/server/src/Support/FleetOps.php +109 -104
  257. package/server/src/Support/Geocoding.php +52 -14
  258. package/server/src/Support/GeofenceIntersectionService.php +47 -27
  259. package/server/src/Support/LiveOrderQuery.php +6 -1
  260. package/server/src/Support/Metrics/ActiveRevenueQuery.php +3 -2
  261. package/server/src/Support/Metrics/FuelCostsMetric.php +6 -1
  262. package/server/src/Support/ResolvesOrderServiceStops.php +10 -0
  263. package/server/src/Support/Telematics/Providers/GeotabProvider.php +9 -4
  264. package/server/src/Support/Utils.php +122 -16
  265. package/server/src/Tracking/Providers/GoogleRoutesTrackingProvider.php +6 -1
  266. package/server/src/Tracking/Providers/OsrmTrackingProvider.php +11 -6
  267. package/server/src/Tracking/TrackingOptions.php +6 -1
  268. package/server/src/Tracking/TrackingProviderManager.php +2 -3
  269. package/server/src/Tracking/TrackingProviderRegistry.php +8 -4
  270. package/server/src/Traits/PayloadAccessors.php +6 -1
  271. package/server/src/routes.php +23 -27
  272. package/server/tests/AiOperationalQueryCapabilityTest.php +457 -1
  273. package/server/tests/AiPreviewCapabilityContractsTest.php +180 -0
  274. package/server/tests/AnalyticsRoutesTest.php +384 -3
  275. package/server/tests/AnalyticsWidgetContractsTest.php +740 -0
  276. package/server/tests/ApiContactControllerContractsTest.php +284 -0
  277. package/server/tests/ApiCustomerControllerContractsTest.php +962 -0
  278. package/server/tests/ApiDriverControllerContractsTest.php +571 -0
  279. package/server/tests/ApiEntityControllerContractsTest.php +329 -0
  280. package/server/tests/ApiEquipmentControllerContractsTest.php +239 -0
  281. package/server/tests/ApiFleetControllerContractsTest.php +176 -0
  282. package/server/tests/ApiFuelReportControllerContractsTest.php +217 -0
  283. package/server/tests/ApiIssueControllerContractsTest.php +217 -0
  284. package/server/tests/ApiOrderControllerContractsTest.php +1030 -0
  285. package/server/tests/ApiPartControllerContractsTest.php +251 -0
  286. package/server/tests/ApiPayloadControllerContractsTest.php +314 -0
  287. package/server/tests/ApiPlaceControllerContractsTest.php +541 -0
  288. package/server/tests/ApiPurchaseRateControllerContractsTest.php +283 -0
  289. package/server/tests/ApiServiceAreaZoneControllerContractsTest.php +442 -0
  290. package/server/tests/ApiServiceQuoteControllerContractsTest.php +322 -0
  291. package/server/tests/ApiTrackingNumberControllerContractsTest.php +225 -0
  292. package/server/tests/ApiTrackingStatusControllerContractsTest.php +254 -0
  293. package/server/tests/ApiVehicleControllerContractsTest.php +368 -0
  294. package/server/tests/ApiVendorControllerContractsTest.php +199 -0
  295. package/server/tests/AssetAndPlaceSearchContractsTest.php +220 -0
  296. package/server/tests/BackendSmallModelContractsTest.php +354 -0
  297. package/server/tests/CapacityAllocationEngineTest.php +56 -0
  298. package/server/tests/CommandContractsTest.php +2695 -0
  299. package/server/tests/CompactResourceSerializationTest.php +2745 -0
  300. package/server/tests/ControllerFilterContractsTest.php +1273 -0
  301. package/server/tests/ControllerHelperContractsTest.php +1740 -0
  302. package/server/tests/ControllerSerializationContractsTest.php +141 -0
  303. package/server/tests/CoverageSummaryScriptTest.php +93 -0
  304. package/server/tests/CustomerContactIdentitySafetyTest.php +1 -6
  305. package/server/tests/CustomerEndpointTest.php +166 -1
  306. package/server/tests/DriverFilterExecutionTest.php +263 -0
  307. package/server/tests/DriverGeofenceProcessingTest.php +153 -0
  308. package/server/tests/DriverResourceSerializationTest.php +245 -0
  309. package/server/tests/DriverSchedulingTraitContractsTest.php +259 -0
  310. package/server/tests/EventContractsTest.php +1259 -0
  311. package/server/tests/ExceptionContractsTest.php +81 -0
  312. package/server/tests/ExpansionContractsTest.php +242 -0
  313. package/server/tests/ExportCoverageTest.php +116 -0
  314. package/server/tests/Feature/Http/Api/ContactControllerPhotoAndDeleteTest.php +199 -0
  315. package/server/tests/Feature/Http/Api/CustomerControllerHelperSeamsTest.php +831 -0
  316. package/server/tests/Feature/Http/Api/DeviceControllerContractsTest.php +347 -0
  317. package/server/tests/Feature/Http/Api/DeviceControllerCrudTest.php +176 -0
  318. package/server/tests/Feature/Http/Api/DriverControllerAuthFlowsTest.php +451 -0
  319. package/server/tests/Feature/Http/Api/DriverControllerHelpersTest.php +240 -0
  320. package/server/tests/Feature/Http/Api/DriverControllerLookupTest.php +186 -0
  321. package/server/tests/Feature/Http/Api/DriverControllerOrganizationsTest.php +112 -0
  322. package/server/tests/Feature/Http/Api/DriverControllerSessionHelpersTest.php +207 -0
  323. package/server/tests/Feature/Http/Api/DriverControllerSwitchOrgAndGeofenceTest.php +329 -0
  324. package/server/tests/Feature/Http/Api/DriverControllerTrackTest.php +383 -0
  325. package/server/tests/Feature/Http/Api/EntityControllerHelpersTest.php +150 -0
  326. package/server/tests/Feature/Http/Api/FuelTransactionControllerContractsTest.php +352 -0
  327. package/server/tests/Feature/Http/Api/GeofenceControllerContractsTest.php +364 -0
  328. package/server/tests/Feature/Http/Api/LabelControllerSubjectsTest.php +148 -0
  329. package/server/tests/Feature/Http/Api/OrderConfigControllerTest.php +112 -0
  330. package/server/tests/Feature/Http/Api/OrderControllerCreateTest.php +279 -0
  331. package/server/tests/Feature/Http/Api/OrderControllerIntegratedVendorTest.php +295 -0
  332. package/server/tests/Feature/Http/Api/OrderControllerLifecycleActionsTest.php +279 -0
  333. package/server/tests/Feature/Http/Api/OrderControllerLookupHelpersTest.php +207 -0
  334. package/server/tests/Feature/Http/Api/OrderControllerNearbyFiltersTest.php +282 -0
  335. package/server/tests/Feature/Http/Api/OrderControllerPersistenceHelpersTest.php +216 -0
  336. package/server/tests/Feature/Http/Api/OrderControllerQueryFiltersTest.php +184 -0
  337. package/server/tests/Feature/Http/Api/OrderControllerStartActivityTest.php +663 -0
  338. package/server/tests/Feature/Http/Api/PayloadControllerHelpersTest.php +134 -0
  339. package/server/tests/Feature/Http/Api/PlaceAndServiceQuoteSeamsTest.php +479 -0
  340. package/server/tests/Feature/Http/Api/PurchaseRateControllerHelpersTest.php +176 -0
  341. package/server/tests/Feature/Http/Api/PurchaseRateControllerOrderCreationTest.php +268 -0
  342. package/server/tests/Feature/Http/Api/SensorControllerCrudTest.php +239 -0
  343. package/server/tests/Feature/Http/Api/ServiceAreaControllerBorderAndSeamsTest.php +187 -0
  344. package/server/tests/Feature/Http/Api/ServiceQuoteControllerQueryTest.php +405 -0
  345. package/server/tests/Feature/Http/Api/ServiceQuoteControllerVendorBridgeTest.php +212 -0
  346. package/server/tests/Feature/Http/Api/ServiceRateControllerContractsTest.php +263 -0
  347. package/server/tests/Feature/Http/Api/SmallApiControllerHelpersTest.php +272 -0
  348. package/server/tests/Feature/Http/Api/TrackingNumberControllerHelpersTest.php +154 -0
  349. package/server/tests/Feature/Http/Api/TrackingStatusControllerHelpersTest.php +165 -0
  350. package/server/tests/Feature/Http/Api/VehicleControllerTrackingTest.php +483 -0
  351. package/server/tests/Feature/Http/Api/WorkOrderControllerContractsTest.php +326 -0
  352. package/server/tests/Feature/Http/Api/WorkOrderControllerHelpersTest.php +130 -0
  353. package/server/tests/Feature/Http/Api/ZoneControllerBordersAndSeamsTest.php +294 -0
  354. package/server/tests/Feature/Http/FleetOpsRouteRegistrationTest.php +189 -0
  355. package/server/tests/Feature/Http/Internal/AnalyticsControllerSeamsTest.php +53 -0
  356. package/server/tests/Feature/Http/Internal/ContactControllerContractsTest.php +240 -0
  357. package/server/tests/Feature/Http/Internal/ContactControllerCustomerGuardsTest.php +128 -0
  358. package/server/tests/Feature/Http/Internal/ContactControllerEndpointsTest.php +294 -0
  359. package/server/tests/Feature/Http/Internal/CustomerControllerCredentialsTest.php +196 -0
  360. package/server/tests/Feature/Http/Internal/DeviceControllerContractsTest.php +370 -0
  361. package/server/tests/Feature/Http/Internal/DeviceControllerExportAndFiltersTest.php +151 -0
  362. package/server/tests/Feature/Http/Internal/DriverControllerContractsTest.php +1109 -0
  363. package/server/tests/Feature/Http/Internal/DriverControllerCreateRecordTest.php +233 -0
  364. package/server/tests/Feature/Http/Internal/DriverControllerExistingUserAdoptionTest.php +710 -0
  365. package/server/tests/Feature/Http/Internal/DriverControllerHelpersTest.php +218 -0
  366. package/server/tests/Feature/Http/Internal/FleetAssignmentsAndTriggersTest.php +198 -0
  367. package/server/tests/Feature/Http/Internal/FleetOpsLookupControllerDbTest.php +90 -0
  368. package/server/tests/Feature/Http/Internal/HubControllerTest.php +206 -0
  369. package/server/tests/Feature/Http/Internal/IssueControllerContractsTest.php +404 -0
  370. package/server/tests/Feature/Http/Internal/IssueControllerExportImportTest.php +118 -0
  371. package/server/tests/Feature/Http/Internal/LiveControllerEndpointsTest.php +246 -0
  372. package/server/tests/Feature/Http/Internal/LiveControllerTest.php +778 -0
  373. package/server/tests/Feature/Http/Internal/MaintenanceScheduleControllerContractsTest.php +263 -0
  374. package/server/tests/Feature/Http/Internal/MaintenanceScheduleControllerSurfacesTest.php +214 -0
  375. package/server/tests/Feature/Http/Internal/MetricsControllerContractsTest.php +249 -0
  376. package/server/tests/Feature/Http/Internal/MetricsControllerHelpersTest.php +66 -0
  377. package/server/tests/Feature/Http/Internal/MorphControllerHelpersTest.php +125 -0
  378. package/server/tests/Feature/Http/Internal/NavigatorControllerHelpersTest.php +201 -0
  379. package/server/tests/Feature/Http/Internal/OrchestrationControllerContractsTest.php +928 -0
  380. package/server/tests/Feature/Http/Internal/OrchestrationControllerHelpersTest.php +214 -0
  381. package/server/tests/Feature/Http/Internal/OrchestrationControllerImportOrdersTest.php +340 -0
  382. package/server/tests/Feature/Http/Internal/OrderConfigControllerContractsTest.php +314 -0
  383. package/server/tests/Feature/Http/Internal/OrderControllerActivityFlowsTest.php +663 -0
  384. package/server/tests/Feature/Http/Internal/OrderControllerCapturePhotoTest.php +507 -0
  385. package/server/tests/Feature/Http/Internal/OrderControllerContractsTest.php +1742 -0
  386. package/server/tests/Feature/Http/Internal/OrderControllerCreateRecordTest.php +488 -0
  387. package/server/tests/Feature/Http/Internal/OrderControllerHelperSeamsTest.php +298 -0
  388. package/server/tests/Feature/Http/Internal/OrderControllerHelpersTest.php +267 -0
  389. package/server/tests/Feature/Http/Internal/OrderControllerImportFromFilesTest.php +179 -0
  390. package/server/tests/Feature/Http/Internal/OrderControllerUpstreamNotFoundTest.php +80 -0
  391. package/server/tests/Feature/Http/Internal/PaymentControllerPaymentsTest.php +154 -0
  392. package/server/tests/Feature/Http/Internal/PlaceControllerTest.php +252 -0
  393. package/server/tests/Feature/Http/Internal/PositionControllerReplayMetricsTest.php +163 -0
  394. package/server/tests/Feature/Http/Internal/ProofControllerContractsTest.php +219 -0
  395. package/server/tests/Feature/Http/Internal/SearchControllerEndpointTest.php +151 -0
  396. package/server/tests/Feature/Http/Internal/ServiceQuoteControllerHelpersTest.php +208 -0
  397. package/server/tests/Feature/Http/Internal/ServiceQuoteControllerQueryRecordTest.php +217 -0
  398. package/server/tests/Feature/Http/Internal/ServiceQuoteControllerVendorBridgeTest.php +239 -0
  399. package/server/tests/Feature/Http/Internal/ServiceQuotePreliminaryQueryTest.php +271 -0
  400. package/server/tests/Feature/Http/Internal/SettingControllerHelpersTest.php +133 -0
  401. package/server/tests/Feature/Http/Internal/SmallInternalControllersTest.php +180 -0
  402. package/server/tests/Feature/Http/Internal/TelematicControllerEndpointsTest.php +417 -0
  403. package/server/tests/Feature/Http/Internal/VehicleControllerEndpointsTest.php +361 -0
  404. package/server/tests/Feature/Http/Internal/VendorControllerEndpointsTest.php +203 -0
  405. package/server/tests/Feature/Http/Internal/WorkOrderAndConfigSurfacesTest.php +289 -0
  406. package/server/tests/Feature/Http/Internal/WorkOrderControllerContractsTest.php +199 -0
  407. package/server/tests/Feature/Http/TelematicWebhookIngestTest.php +343 -0
  408. package/server/tests/Feature/Http/Telematics/TelematicWebhookControllerProcessingTest.php +254 -0
  409. package/server/tests/FleetOpsSupportContractsTest.php +187 -0
  410. package/server/tests/FlespiProviderContractsTest.php +244 -0
  411. package/server/tests/FlowResourceTest.php +295 -0
  412. package/server/tests/FuelProviderConnectionControllerContractsTest.php +303 -0
  413. package/server/tests/FuelProviderImplementationTest.php +753 -0
  414. package/server/tests/FuelProviderRegistryTest.php +7 -9
  415. package/server/tests/FuelProviderResourceContractsTest.php +171 -0
  416. package/server/tests/FuelProviderTransactionControllerContractsTest.php +181 -0
  417. package/server/tests/GeofenceIntersectionServiceContractsTest.php +164 -0
  418. package/server/tests/HOSConstraintContractsTest.php +128 -0
  419. package/server/tests/HubAndGettingStartedContractsTest.php +158 -0
  420. package/server/tests/ImportContractsTest.php +191 -0
  421. package/server/tests/InternalCustomerControllerContractsTest.php +238 -0
  422. package/server/tests/InternalFleetControllerContractsTest.php +389 -0
  423. package/server/tests/InternalImportExportControllerContractsTest.php +289 -0
  424. package/server/tests/InternalMetricsControllerContractsTest.php +69 -0
  425. package/server/tests/InternalPlaceWorkOrderControllerContractsTest.php +207 -0
  426. package/server/tests/InternalServiceQuoteCheckoutControllerContractsTest.php +470 -0
  427. package/server/tests/InternalVendorControllerContractsTest.php +331 -0
  428. package/server/tests/InventoryTelemetryModelContractsTest.php +516 -0
  429. package/server/tests/IssueTimelineContractsTest.php +191 -0
  430. package/server/tests/LabelPdfRenderingTest.php +57 -0
  431. package/server/tests/LalamoveIntegrationContractsTest.php +167 -0
  432. package/server/tests/LiveOrderQueryTest.php +140 -19
  433. package/server/tests/LookupAndGeocoderControllerContractsTest.php +357 -0
  434. package/server/tests/MaintainableTraitContractsTest.php +245 -0
  435. package/server/tests/MaintenanceScheduleControllerContractsTest.php +101 -0
  436. package/server/tests/MaintenanceWarrantyContractsTest.php +237 -0
  437. package/server/tests/ManifestControllerContractsTest.php +310 -0
  438. package/server/tests/MetricsRegistryTest.php +596 -10
  439. package/server/tests/MiddlewareContractsTest.php +150 -0
  440. package/server/tests/ModelAccessorContractsTest.php +3201 -0
  441. package/server/tests/MorphControllerContractsTest.php +410 -0
  442. package/server/tests/NavigatorControllerContractsTest.php +206 -0
  443. package/server/tests/NotificationAndMailContractsTest.php +677 -0
  444. package/server/tests/ObserverContractsTest.php +1414 -0
  445. package/server/tests/OperationalAlgorithmContractsTest.php +852 -0
  446. package/server/tests/OperationsMonitorEndpointTest.php +2 -1
  447. package/server/tests/OrchestrationPayloadBuilderTest.php +87 -0
  448. package/server/tests/OrderActivityFlowRegressionTest.php +354 -7
  449. package/server/tests/OrderDispatchListenerContractsTest.php +577 -0
  450. package/server/tests/OrderFilterExecutionTest.php +244 -0
  451. package/server/tests/OrderQueuedClosureRegressionTest.php +2 -1
  452. package/server/tests/PaymentControllerContractsTest.php +199 -0
  453. package/server/tests/PointResolutionTest.php +54 -0
  454. package/server/tests/ProcessAllocationJobContractsTest.php +224 -0
  455. package/server/tests/ProofAndSensorControllerContractsTest.php +44 -0
  456. package/server/tests/ProviderContractsTest.php +409 -0
  457. package/server/tests/PublicApiControllerInputContractsTest.php +294 -0
  458. package/server/tests/QueueJobContractsTest.php +764 -0
  459. package/server/tests/ReportSchemaContractsTest.php +271 -0
  460. package/server/tests/RequestContractsTest.php +966 -0
  461. package/server/tests/RouteRegistrationExecutionTest.php +178 -0
  462. package/server/tests/RouteSequencingEngineTest.php +179 -0
  463. package/server/tests/RulesAndCastsTest.php +246 -0
  464. package/server/tests/SamsaraProviderContractsTest.php +272 -0
  465. package/server/tests/SearchControllerContractsTest.php +311 -0
  466. package/server/tests/ServiceAreaZoneApiShapeTest.php +8 -9
  467. package/server/tests/ServiceRateAlgorithmWeightVariablesTest.php +1 -1
  468. package/server/tests/ServiceRateRouteValidationTest.php +76 -0
  469. package/server/tests/SettingControllerContractsTest.php +410 -0
  470. package/server/tests/SmallControllerContractsTest.php +456 -0
  471. package/server/tests/SupportAnalyticsCustomerAuthContractsTest.php +221 -0
  472. package/server/tests/SupportJobAndAiCoverageTest.php +812 -0
  473. package/server/tests/SupportServiceContractsTest.php +287 -0
  474. package/server/tests/SupportValueObjectsTest.php +155 -0
  475. package/server/tests/TelematicControllerContractsTest.php +185 -0
  476. package/server/tests/TelematicProviderRegistryTest.php +167 -0
  477. package/server/tests/TelematicServiceHelperContractsTest.php +315 -0
  478. package/server/tests/TelematicWebhookControllerContractsTest.php +253 -0
  479. package/server/tests/TelematicsHardeningTest.php +666 -105
  480. package/server/tests/TrackingIntelligenceTest.php +709 -26
  481. package/server/tests/TrackingNumberTraitContractsTest.php +106 -0
  482. package/server/tests/Unit/Casts/SpatialCastBranchesTest.php +75 -0
  483. package/server/tests/Unit/Console/AssignCustomerRolesCommandTest.php +102 -0
  484. package/server/tests/Unit/Console/AssignDriverRolesCommandTest.php +113 -0
  485. package/server/tests/Unit/Console/Commands/FixLegacyOrderConfigsHelpersTest.php +108 -0
  486. package/server/tests/Unit/Console/Commands/ProcessOperationalAlertsCommandTest.php +265 -0
  487. package/server/tests/Unit/Console/Commands/ReplayVehicleLocationsCommandTest.php +320 -0
  488. package/server/tests/Unit/Console/Commands/SimulateGeofenceEventsCommandTest.php +207 -0
  489. package/server/tests/Unit/Console/FixCommandsAndMaintenanceControllerTest.php +256 -0
  490. package/server/tests/Unit/Console/FleetOpsCommandsTest.php +198 -0
  491. package/server/tests/Unit/Console/ReplayVehicleLocationsCommandTest.php +252 -0
  492. package/server/tests/Unit/Console/SendMaintenanceRemindersTest.php +212 -0
  493. package/server/tests/Unit/Console/SimulateGeofenceEventsCommandTest.php +232 -0
  494. package/server/tests/Unit/Console/SyncTelematicsCommandTest.php +136 -0
  495. package/server/tests/Unit/Constraints/HOSConstraintTest.php +158 -0
  496. package/server/tests/Unit/Events/EventModelRecordTest.php +93 -0
  497. package/server/tests/Unit/Events/OrderDispatchFailedTest.php +34 -0
  498. package/server/tests/Unit/Exports/ExportCollectionsTest.php +142 -0
  499. package/server/tests/Unit/Exports/OperationalExportMappingTest.php +651 -0
  500. package/server/tests/Unit/Exports/VehicleExportTest.php +284 -0
  501. package/server/tests/Unit/Flow/EventFiringTest.php +95 -0
  502. package/server/tests/Unit/Http/Api/QueryWithRequestSeamsTest.php +198 -0
  503. package/server/tests/Unit/Http/Api/SensorInputTest.php +95 -0
  504. package/server/tests/Unit/Http/Filter/DeviceFilterTest.php +199 -0
  505. package/server/tests/Unit/Http/Filter/EmptyValueGuardsTest.php +66 -0
  506. package/server/tests/Unit/Http/Filter/FilterDateRangesTest.php +72 -0
  507. package/server/tests/Unit/Http/Filter/FuelProviderTransactionFilterTest.php +172 -0
  508. package/server/tests/Unit/Http/Filter/InternalRelationUuidLookupTest.php +135 -0
  509. package/server/tests/Unit/Http/Filter/IssueFilterTest.php +129 -0
  510. package/server/tests/Unit/Http/Filter/PartFilterTest.php +173 -0
  511. package/server/tests/Unit/Http/Internal/ControllerDelegationSeamsTest.php +136 -0
  512. package/server/tests/Unit/Http/Internal/ControllerExcelSeamsTest.php +89 -0
  513. package/server/tests/Unit/Http/Middleware/SetupDriverSessionTest.php +32 -0
  514. package/server/tests/Unit/Http/Requests/CreateFuelReportRequestTest.php +47 -0
  515. package/server/tests/Unit/Http/Requests/FleetActionRequestTest.php +80 -0
  516. package/server/tests/Unit/Http/Requests/RequestAuthorizationTest.php +50 -0
  517. package/server/tests/Unit/Http/Resources/CustomerResourceTest.php +108 -0
  518. package/server/tests/Unit/Http/Resources/EntityCustomerTypeTest.php +35 -0
  519. package/server/tests/Unit/Http/Resources/FleetResourceTest.php +102 -0
  520. package/server/tests/Unit/Http/Resources/IndexOrderResourceTest.php +210 -0
  521. package/server/tests/Unit/Http/Resources/IndexVehicleResourceTest.php +194 -0
  522. package/server/tests/Unit/Http/Resources/MaintenanceResourcesTest.php +182 -0
  523. package/server/tests/Unit/Http/Resources/OrderAndDriverResourceTest.php +121 -0
  524. package/server/tests/Unit/Http/Resources/OrderConfigResourceTest.php +47 -0
  525. package/server/tests/Unit/Http/Resources/PayloadResourceTest.php +111 -0
  526. package/server/tests/Unit/Http/Resources/RelationResourceFallbacksTest.php +32 -0
  527. package/server/tests/Unit/Http/Resources/ResourceRelationResolutionTest.php +55 -0
  528. package/server/tests/Unit/Http/Resources/TrackingNumberResourceTest.php +174 -0
  529. package/server/tests/Unit/Http/Resources/WaypointResourceTest.php +295 -0
  530. package/server/tests/Unit/Http/Resources/WorkOrderResourceTest.php +164 -0
  531. package/server/tests/Unit/Imports/ImportDelegationTest.php +151 -0
  532. package/server/tests/Unit/Integrations/Lalamove/LalamoveDeliveryStopTest.php +79 -0
  533. package/server/tests/Unit/Integrations/Lalamove/LalamoveLifecycleTest.php +211 -0
  534. package/server/tests/Unit/Integrations/Lalamove/LalamoveQuoteAndServiceOrderTest.php +381 -0
  535. package/server/tests/Unit/Integrations/Lalamove/LalamoveServiceTypeTest.php +51 -0
  536. package/server/tests/Unit/Integrations/LalamoveQuotationTest.php +194 -0
  537. package/server/tests/Unit/Integrations/LalamoveResponseHandlingTest.php +58 -0
  538. package/server/tests/Unit/Jobs/GeofenceDwellAndBulkNotifyTest.php +183 -0
  539. package/server/tests/Unit/Jobs/ReplayPositionsTest.php +57 -0
  540. package/server/tests/Unit/Jobs/SimulateWaypointReachedTest.php +92 -0
  541. package/server/tests/Unit/Listeners/HandleGeofenceEnteredTest.php +256 -0
  542. package/server/tests/Unit/Listeners/HandleOrderDispatchFailedListenerTest.php +101 -0
  543. package/server/tests/Unit/Listeners/HandleOrderDispatchedConcreteTest.php +203 -0
  544. package/server/tests/Unit/Listeners/HandleOrderDispatchedHelpersTest.php +186 -0
  545. package/server/tests/Unit/Listeners/HandleUserRemovedFromCompanyTest.php +65 -0
  546. package/server/tests/Unit/Listeners/ListenerDelegationSeamsTest.php +83 -0
  547. package/server/tests/Unit/Models/AssetTest.php +469 -0
  548. package/server/tests/Unit/Models/ContactCustomerUserTest.php +370 -0
  549. package/server/tests/Unit/Models/ContactTest.php +577 -0
  550. package/server/tests/Unit/Models/DeviceEventTest.php +481 -0
  551. package/server/tests/Unit/Models/DeviceLastPositionDefaultTest.php +128 -0
  552. package/server/tests/Unit/Models/DriverModelHelpersTest.php +268 -0
  553. package/server/tests/Unit/Models/DriverTest.php +401 -0
  554. package/server/tests/Unit/Models/EntityTest.php +171 -0
  555. package/server/tests/Unit/Models/EquipmentTest.php +434 -0
  556. package/server/tests/Unit/Models/FleetTest.php +153 -0
  557. package/server/tests/Unit/Models/FuelProviderTransactionTest.php +82 -0
  558. package/server/tests/Unit/Models/FuelReportImportAndLabelsTest.php +193 -0
  559. package/server/tests/Unit/Models/ImportRowFallbackSeamsTest.php +100 -0
  560. package/server/tests/Unit/Models/IntegratedVendorLifecycleTest.php +203 -0
  561. package/server/tests/Unit/Models/IntegratedVendorTest.php +135 -0
  562. package/server/tests/Unit/Models/IssueTest.php +160 -0
  563. package/server/tests/Unit/Models/MaintenanceScheduleTest.php +319 -0
  564. package/server/tests/Unit/Models/MaintenanceTest.php +277 -0
  565. package/server/tests/Unit/Models/MaintenanceWorkOrderImportTest.php +161 -0
  566. package/server/tests/Unit/Models/ManifestStopTest.php +121 -0
  567. package/server/tests/Unit/Models/ManifestTest.php +163 -0
  568. package/server/tests/Unit/Models/ModelLookupFallbackSeamsTest.php +149 -0
  569. package/server/tests/Unit/Models/OrderConfigTest.php +341 -0
  570. package/server/tests/Unit/Models/OrderDynamicContractsTest.php +190 -0
  571. package/server/tests/Unit/Models/OrderPayloadConfigAndDistanceTest.php +426 -0
  572. package/server/tests/Unit/Models/OrderPayloadRouteTest.php +227 -0
  573. package/server/tests/Unit/Models/OrderPurchaseAndDriversTest.php +188 -0
  574. package/server/tests/Unit/Models/OrderTest.php +917 -0
  575. package/server/tests/Unit/Models/PartTest.php +399 -0
  576. package/server/tests/Unit/Models/PayloadTest.php +710 -0
  577. package/server/tests/Unit/Models/PayloadWaypointsAndEntitiesTest.php +317 -0
  578. package/server/tests/Unit/Models/PlaceCreationAndImportTest.php +384 -0
  579. package/server/tests/Unit/Models/PlaceGeocodingResultsTest.php +253 -0
  580. package/server/tests/Unit/Models/PlaceSharedAndGeocodingTest.php +271 -0
  581. package/server/tests/Unit/Models/PlaceTest.php +589 -0
  582. package/server/tests/Unit/Models/PositionTest.php +49 -0
  583. package/server/tests/Unit/Models/RouteTest.php +55 -0
  584. package/server/tests/Unit/Models/SensorReadingsTest.php +168 -0
  585. package/server/tests/Unit/Models/SensorTest.php +284 -0
  586. package/server/tests/Unit/Models/ServiceAreaGeometryTest.php +129 -0
  587. package/server/tests/Unit/Models/ServiceAreaTest.php +125 -0
  588. package/server/tests/Unit/Models/ServiceQuoteTest.php +617 -0
  589. package/server/tests/Unit/Models/ServiceRateFeeTest.php +73 -0
  590. package/server/tests/Unit/Models/ServiceRatePersistenceAndServicabilityTest.php +428 -0
  591. package/server/tests/Unit/Models/ServiceRateTest.php +533 -0
  592. package/server/tests/Unit/Models/SmallModelSurfacesTest.php +294 -0
  593. package/server/tests/Unit/Models/TrackingNumberTest.php +199 -0
  594. package/server/tests/Unit/Models/TrackingStatusTest.php +131 -0
  595. package/server/tests/Unit/Models/VehicleDeviceTest.php +115 -0
  596. package/server/tests/Unit/Models/VehiclePositionsAndImportTest.php +220 -0
  597. package/server/tests/Unit/Models/VehicleTest.php +266 -0
  598. package/server/tests/Unit/Models/VendorRelationsAndImportTest.php +107 -0
  599. package/server/tests/Unit/Models/WarrantyTest.php +187 -0
  600. package/server/tests/Unit/Models/WaypointTest.php +366 -0
  601. package/server/tests/Unit/Models/WorkOrderTest.php +272 -0
  602. package/server/tests/Unit/Models/ZoneTest.php +83 -0
  603. package/server/tests/Unit/Notifications/MonitoringNotificationsTest.php +136 -0
  604. package/server/tests/Unit/Notifications/OrderAssignedChannelsTest.php +53 -0
  605. package/server/tests/Unit/Notifications/OrderDispatchedChannelsTest.php +81 -0
  606. package/server/tests/Unit/Notifications/OrderFailedChannelsTest.php +73 -0
  607. package/server/tests/Unit/Notifications/OrderPingChannelsTest.php +69 -0
  608. package/server/tests/Unit/Notifications/TerminalOrderNotificationsTest.php +185 -0
  609. package/server/tests/Unit/Observers/FleetOpsCompanyUserAndServiceAreaObserversTest.php +133 -0
  610. package/server/tests/Unit/Observers/ObserverHelperExecutionTest.php +135 -0
  611. package/server/tests/Unit/Observers/ObserverListenerSeamsTest.php +267 -0
  612. package/server/tests/Unit/Observers/PurchaseRateObserverAndOrderJobsTest.php +169 -0
  613. package/server/tests/Unit/Orchestration/Engines/DriverAssignmentEngineTest.php +393 -0
  614. package/server/tests/Unit/Orchestration/Engines/VroomOrchestrationEngineLifecycleTest.php +397 -0
  615. package/server/tests/Unit/Orchestration/OrchestrationEngineRegistryTest.php +45 -0
  616. package/server/tests/Unit/Orchestration/VroomEngineTransportAndSettingsTest.php +253 -0
  617. package/server/tests/Unit/Providers/FleetOpsAiRegistrationTest.php +59 -0
  618. package/server/tests/Unit/Rules/ResolvableVehicleTest.php +85 -0
  619. package/server/tests/Unit/Support/Ai/AssetStatusCapabilityQueriesTest.php +120 -0
  620. package/server/tests/Unit/Support/Ai/Capabilities/CreateOrderPreviewCapabilityTest.php +385 -0
  621. package/server/tests/Unit/Support/Ai/Capabilities/OrderInsightsCapabilityTest.php +226 -0
  622. package/server/tests/Unit/Support/Ai/Capabilities/SearchResourcesCapabilityTest.php +237 -0
  623. package/server/tests/Unit/Support/AiCapabilityPermissionsTest.php +124 -0
  624. package/server/tests/Unit/Support/AlgoEdgeBranchesTest.php +24 -0
  625. package/server/tests/Unit/Support/Analytics/GeofenceViolationsTest.php +109 -0
  626. package/server/tests/Unit/Support/Analytics/LiveFleetTest.php +205 -0
  627. package/server/tests/Unit/Support/Analytics/MaintenanceOverviewTest.php +236 -0
  628. package/server/tests/Unit/Support/Analytics/OnTimeDeliveryAndTopDriversTest.php +250 -0
  629. package/server/tests/Unit/Support/CreateOrderPreviewDraftingTest.php +235 -0
  630. package/server/tests/Unit/Support/CustomerAuthTest.php +132 -0
  631. package/server/tests/Unit/Support/FuelEfficiencyAndCanceledHandlersTest.php +164 -0
  632. package/server/tests/Unit/Support/FuelProviderRegistryResolutionTest.php +51 -0
  633. package/server/tests/Unit/Support/FuelProviderServiceMatchingTest.php +280 -0
  634. package/server/tests/Unit/Support/GeocodingInjectedClientTest.php +268 -0
  635. package/server/tests/Unit/Support/GeocodingLocateTest.php +32 -0
  636. package/server/tests/Unit/Support/GeofenceIntersectionServiceTest.php +188 -0
  637. package/server/tests/Unit/Support/GettingStartedTest.php +164 -0
  638. package/server/tests/Unit/Support/GuardReturnSeamsTest.php +172 -0
  639. package/server/tests/Unit/Support/IntegratedVendorsResolverTest.php +250 -0
  640. package/server/tests/Unit/Support/IssuesInsightsAndAllocationJobTest.php +156 -0
  641. package/server/tests/Unit/Support/MagicAccessorSeamsTest.php +54 -0
  642. package/server/tests/Unit/Support/MaintainableAndOperationalAlertsTest.php +215 -0
  643. package/server/tests/Unit/Support/Metrics/AvgOrderValueMetricTest.php +308 -0
  644. package/server/tests/Unit/Support/Metrics/CountMetricsTest.php +280 -0
  645. package/server/tests/Unit/Support/Metrics/FuelCostsMetricTest.php +102 -0
  646. package/server/tests/Unit/Support/Metrics/MetricQuerySeamsTest.php +129 -0
  647. package/server/tests/Unit/Support/Metrics/OrdersScheduledMetricTest.php +146 -0
  648. package/server/tests/Unit/Support/MoreQuerySeamsTest.php +410 -0
  649. package/server/tests/Unit/Support/OperationalQueryDistributionTest.php +152 -0
  650. package/server/tests/Unit/Support/OperationsPulseTest.php +130 -0
  651. package/server/tests/Unit/Support/OptimizeOrderRouteCapabilityTest.php +147 -0
  652. package/server/tests/Unit/Support/OrchestrationPayloadBuilderTest.php +135 -0
  653. package/server/tests/Unit/Support/OrchestrationRouteAndVehicleTasksTest.php +254 -0
  654. package/server/tests/Unit/Support/OsrmProofAndIssueFilterTest.php +247 -0
  655. package/server/tests/Unit/Support/PetroAppFuelProviderTest.php +165 -0
  656. package/server/tests/Unit/Support/PlaceSearchRankingTest.php +191 -0
  657. package/server/tests/Unit/Support/QuerySeamsTest.php +309 -0
  658. package/server/tests/Unit/Support/ResolvesOrderServiceStopsDbTest.php +303 -0
  659. package/server/tests/Unit/Support/ResolvesOrderServiceStopsTest.php +382 -0
  660. package/server/tests/Unit/Support/SkipAndFallbackGuardsTest.php +70 -0
  661. package/server/tests/Unit/Support/TelematicCredentialResolutionTest.php +31 -0
  662. package/server/tests/Unit/Support/TelematicServiceTest.php +256 -0
  663. package/server/tests/Unit/Support/Telematics/Providers/AbstractProviderTest.php +154 -0
  664. package/server/tests/Unit/Support/Telematics/Providers/AfaqyProviderTest.php +191 -0
  665. package/server/tests/Unit/Support/Telematics/Providers/AfaqyProviderTransportTest.php +138 -0
  666. package/server/tests/Unit/Support/Telematics/Providers/GeotabProviderTest.php +329 -0
  667. package/server/tests/Unit/Support/Telematics/Providers/ProviderTransportSeamsTest.php +133 -0
  668. package/server/tests/Unit/Support/Telematics/Providers/SafeeProviderTest.php +487 -0
  669. package/server/tests/Unit/Support/Telematics/TelematicProviderRegistryTest.php +39 -0
  670. package/server/tests/Unit/Support/Telematics/TelematicServiceLifecycleTest.php +711 -0
  671. package/server/tests/Unit/Support/Telematics/TelematicServiceTelemetryTest.php +364 -0
  672. package/server/tests/Unit/Support/UtilsAdditionalTest.php +256 -0
  673. package/server/tests/Unit/Support/UtilsGeoMatrixAndVendorTest.php +382 -0
  674. package/server/tests/Unit/Tracking/TrackingContextTest.php +114 -0
  675. package/server/tests/Unit/Tracking/TrackingIntelligenceAndContextTest.php +477 -0
  676. package/server/tests/Unit/Tracking/TrackingProviderManagerFallbacksTest.php +208 -0
  677. package/server/tests/Unit/Traits/HasTrackingNumberTest.php +303 -0
  678. package/server/tests/Unit/Traits/PayloadAccessorsTest.php +150 -0
  679. package/server/tests/UtilsContractsTest.php +244 -0
  680. package/server/tests/VehicleControllerHelperContractsTest.php +488 -0
  681. package/server/tests/VehicleDataParsingTest.php +45 -0
  682. package/server/tests/VehicleDriverAssignmentTest.php +8 -9
  683. package/server/tests/VehicleResourceContractsTest.php +313 -0
  684. package/translations/bg-bg.yaml +2 -0
  685. package/translations/en-us.yaml +2 -0
  686. package/translations/es-pa.yaml +2 -0
  687. package/translations/fr-fr.yaml +2 -0
  688. package/translations/mn-mn.yaml +2 -0
  689. package/translations/pt-br.yaml +2 -0
  690. package/translations/ru-ru.yaml +2 -0
  691. package/server/src/Http/Controllers/Api/v1/OrganizationController.php +0 -45
  692. package/server/tests/DeviceFilterTest.php +0 -45
  693. package/server/tests/LiveControllerViewportTest.php +0 -60
@@ -54,7 +54,7 @@ class CustomerController extends Controller
54
54
  {
55
55
  $mode = $request->input('mode', 'email');
56
56
  $identity = $request->input('identity');
57
- $isEmail = Utils::isEmail($identity);
57
+ $isEmail = $this->isEmail($identity);
58
58
 
59
59
  if ($mode === 'email' && !$isEmail) {
60
60
  return response()->apiError('Invalid email provided for identity.');
@@ -64,7 +64,7 @@ class CustomerController extends Controller
64
64
  $identity = static::phone($identity);
65
65
  }
66
66
 
67
- $sessionCompany = session('company');
67
+ $sessionCompany = $this->sessionCompany();
68
68
  if (!$sessionCompany) {
69
69
  return response()->apiError('No company resolved from API credential.', 500);
70
70
  }
@@ -80,14 +80,12 @@ class CustomerController extends Controller
80
80
  // template references `$user->name`). Look up — or create — the User
81
81
  // before sending. `create()` later backfills password + remaining fields
82
82
  // on this same row when the customer confirms the code.
83
- $subject = $isEmail
84
- ? User::where('email', $identity)->whereNull('deleted_at')->withoutGlobalScopes()->first()
85
- : User::where('phone', $identity)->whereNull('deleted_at')->withoutGlobalScopes()->first();
83
+ $subject = $this->findActiveUserByIdentity($identity, $isEmail ? 'email' : 'phone');
86
84
 
87
85
  if (!$subject) {
88
86
  // `password` and `type` are guarded on User; assign type after create
89
87
  // via setUserType (saves the row).
90
- $subject = User::create([
88
+ $subject = $this->createUser([
91
89
  'company_uuid' => $sessionCompany,
92
90
  'name' => $providedName !== '' ? $providedName : $identity,
93
91
  'email' => $isEmail ? $identity : null,
@@ -108,13 +106,13 @@ class CustomerController extends Controller
108
106
 
109
107
  try {
110
108
  if ($mode === 'email') {
111
- VerificationCode::generateEmailVerificationFor($subject, 'fleetops_create_customer', [
109
+ $this->generateEmailVerification($subject, 'fleetops_create_customer', [
112
110
  'subject' => config('app.name') . ' verification code',
113
111
  'messageCallback' => fn ($verification) => 'Your ' . config('app.name') . ' verification code is ' . $verification->code,
114
112
  'meta' => $meta,
115
113
  ]);
116
114
  } else {
117
- VerificationCode::generateSmsVerificationFor($subject, 'fleetops_create_customer', [
115
+ $this->generateSmsVerification($subject, 'fleetops_create_customer', [
118
116
  'messageCallback' => fn ($verification) => 'Your ' . config('app.name') . ' verification code is ' . $verification->code,
119
117
  'meta' => $meta,
120
118
  ]);
@@ -135,22 +133,22 @@ class CustomerController extends Controller
135
133
  {
136
134
  $code = $request->input('code');
137
135
  $identity = $request->input('identity');
138
- $isEmail = Utils::isEmail($identity);
136
+ $isEmail = $this->isEmail($identity);
139
137
  if (!$isEmail) {
140
138
  $identity = static::phone($identity);
141
139
  }
142
140
 
143
141
  // Verify the code is one we sent for this identity.
144
- $verificationCode = VerificationCode::where([
142
+ $verificationCode = $this->verificationCodeExists([
145
143
  'code' => $code,
146
144
  'for' => 'fleetops_create_customer',
147
145
  'meta->identity' => $identity,
148
- ])->exists();
146
+ ]);
149
147
  if (!$verificationCode) {
150
148
  return response()->apiError('Invalid verification code provided.');
151
149
  }
152
150
 
153
- $sessionCompany = session('company');
151
+ $sessionCompany = $this->sessionCompany();
154
152
  if (!$sessionCompany) {
155
153
  return response()->apiError('No company resolved from API credential.', 500);
156
154
  }
@@ -158,15 +156,15 @@ class CustomerController extends Controller
158
156
  // Attach to existing User if one matches the identity, otherwise create one.
159
157
  $user = null;
160
158
  if ($isEmail) {
161
- $user = User::where('email', $identity)->whereNull('deleted_at')->withoutGlobalScopes()->first();
159
+ $user = $this->findActiveUserByIdentity($identity, 'email');
162
160
  } elseif (Str::startsWith($identity, '+')) {
163
- $user = User::where('phone', $identity)->whereNull('deleted_at')->withoutGlobalScopes()->first();
161
+ $user = $this->findActiveUserByIdentity($identity, 'phone');
164
162
  }
165
163
 
166
164
  if (!$user) {
167
165
  // `password` and `type` are guarded on User; assign them after create
168
166
  // (setUserType saves the type, setPasswordAttribute hashes plaintext).
169
- $user = User::create([
167
+ $user = $this->createUser([
170
168
  'company_uuid' => $sessionCompany,
171
169
  'name' => $request->input('name'),
172
170
  'email' => $isEmail ? $identity : $request->input('email'),
@@ -215,15 +213,15 @@ class CustomerController extends Controller
215
213
  // Handle photo as either file id or base64 data.
216
214
  $photo = $request->input('photo');
217
215
  if ($photo) {
218
- if (Utils::isPublicId($photo)) {
219
- $file = File::where('public_id', $photo)->first();
216
+ if ($this->isPublicId($photo)) {
217
+ $file = $this->findFileByPublicId($photo);
220
218
  if ($file) {
221
219
  $input['photo_uuid'] = $file->uuid;
222
220
  }
223
221
  }
224
- if (Utils::isBase64String($photo)) {
222
+ if ($this->isBase64String($photo)) {
225
223
  $path = implode('/', ['uploads', $sessionCompany, 'customers']);
226
- $file = File::createFromBase64($photo, null, $path);
224
+ $file = $this->createFileFromBase64($photo, $path);
227
225
  if ($file) {
228
226
  $input['photo_uuid'] = $file->uuid;
229
227
  }
@@ -232,22 +230,22 @@ class CustomerController extends Controller
232
230
 
233
231
  // Reuse an existing customer-Contact for this user+company if one exists
234
232
  // (idempotent re-signup), otherwise create one.
235
- $contact = Contact::where([
233
+ $contact = $this->findCustomerContact([
236
234
  'company_uuid' => $sessionCompany,
237
235
  'user_uuid' => $user->uuid,
238
236
  'type' => 'customer',
239
- ])->first();
237
+ ]);
240
238
  if ($contact) {
241
239
  $contact->fill(array_filter($input, fn ($v) => $v !== null && $v !== ''))->save();
242
240
  } else {
243
241
  try {
244
- $contact = Contact::create($input);
242
+ $contact = $this->createContact($input);
245
243
  } catch (UserAlreadyExistsException $e) {
246
- $contact = Contact::where([
244
+ $contact = $this->findCustomerContact([
247
245
  'company_uuid' => $sessionCompany,
248
246
  'user_uuid' => $user->uuid,
249
247
  'type' => 'customer',
250
- ])->first();
248
+ ]);
251
249
  if (!$contact) {
252
250
  return response()->apiError($e->getMessage());
253
251
  }
@@ -272,10 +270,10 @@ class CustomerController extends Controller
272
270
  }
273
271
  }
274
272
 
275
- $token = $user->createToken($contact->uuid);
273
+ $token = $this->createCustomerToken($user, $contact);
276
274
  $contact->token = $token->plainTextToken;
277
275
 
278
- return new CustomerResource($contact);
276
+ return $this->customerResource($contact);
279
277
  }
280
278
 
281
279
  /**
@@ -293,7 +291,7 @@ class CustomerController extends Controller
293
291
  }
294
292
 
295
293
  if (is_string($input)) {
296
- return Place::where(['public_id' => $input, 'company_uuid' => $companyUuid])->first();
294
+ return $this->findPlaceByPublicId($input, $companyUuid);
297
295
  }
298
296
 
299
297
  if (!is_array($input)) {
@@ -309,7 +307,7 @@ class CustomerController extends Controller
309
307
  return null;
310
308
  }
311
309
 
312
- return Place::create(array_merge(
310
+ return $this->createPlace(array_merge(
313
311
  [
314
312
  'company_uuid' => $companyUuid,
315
313
  'owner_uuid' => $contact->uuid,
@@ -330,20 +328,18 @@ class CustomerController extends Controller
330
328
  return response()->apiError('Identity and password are required.', 400);
331
329
  }
332
330
 
333
- $user = User::where('email', $identity)
334
- ->orWhere('phone', static::phone($identity))
335
- ->first();
331
+ $user = $this->findUserForLogin($identity);
336
332
 
337
- if (!$user || !$user->password || !Hash::check($password, $user->password)) {
333
+ if (!$user || !$user->password || !$this->passwordMatches($password, $user->password)) {
338
334
  return response()->apiError('Authentication failed using credentials provided.', 401);
339
335
  }
340
336
 
341
- $sessionCompany = session('company');
337
+ $sessionCompany = $this->sessionCompany();
342
338
  if (!$sessionCompany) {
343
339
  return response()->apiError('No company resolved from API credential.', 500);
344
340
  }
345
341
 
346
- $contact = Contact::firstOrCreate(
342
+ $contact = $this->firstOrCreateCustomerContact(
347
343
  [
348
344
  'user_uuid' => $user->uuid,
349
345
  'company_uuid' => $sessionCompany,
@@ -356,10 +352,10 @@ class CustomerController extends Controller
356
352
  ]
357
353
  );
358
354
 
359
- $token = $user->createToken($contact->uuid);
355
+ $token = $this->createCustomerToken($user, $contact);
360
356
  $contact->token = $token->plainTextToken;
361
357
 
362
- return new CustomerResource($contact);
358
+ return $this->customerResource($contact);
363
359
  }
364
360
 
365
361
  /**
@@ -369,13 +365,13 @@ class CustomerController extends Controller
369
365
  {
370
366
  $phone = static::phone($request->input('phone') ?? $request->input('identity'));
371
367
 
372
- $user = User::where('phone', $phone)->whereNull('deleted_at')->withoutGlobalScopes()->first();
368
+ $user = $this->findActiveUserByIdentity($phone, 'phone');
373
369
  if (!$user) {
374
370
  return response()->apiError('No customer with this phone number found.');
375
371
  }
376
372
 
377
373
  try {
378
- VerificationCode::generateSmsVerificationFor($user, 'fleetops_customer_login', [
374
+ $this->generateSmsVerification($user, 'fleetops_customer_login', [
379
375
  'messageCallback' => fn ($verification) => 'Your ' . config('app.name') . ' verification code is ' . $verification->code,
380
376
  ]);
381
377
 
@@ -383,7 +379,7 @@ class CustomerController extends Controller
383
379
  } catch (\Throwable $e) {
384
380
  if ($user->email) {
385
381
  try {
386
- VerificationCode::generateEmailVerificationFor($user, 'fleetops_customer_login', [
382
+ $this->generateEmailVerification($user, 'fleetops_customer_login', [
387
383
  'subject' => config('app.name') . ' verification code',
388
384
  'messageCallback' => fn ($verification) => 'Your ' . config('app.name') . ' verification code is ' . $verification->code,
389
385
  ]);
@@ -403,30 +399,30 @@ class CustomerController extends Controller
403
399
  */
404
400
  public function verifyCode(Request $request)
405
401
  {
406
- $identity = Utils::isEmail($request->input('identity')) ? $request->input('identity') : static::phone($request->input('identity'));
402
+ $identity = $this->isEmail($request->input('identity')) ? $request->input('identity') : static::phone($request->input('identity'));
407
403
  $code = $request->input('code');
408
404
  $for = $request->input('for', 'fleetops_customer_login');
409
405
 
410
406
  if ($for === 'fleetops_create_customer') {
411
- return $this->create($request);
407
+ return $this->create(CreateCustomerRequest::createFrom($request));
412
408
  }
413
409
 
414
- $user = User::where('phone', $identity)->orWhere('email', $identity)->first();
410
+ $user = $this->findUserForVerification($identity);
415
411
  if (!$user) {
416
412
  return response()->apiError('Unable to verify code.');
417
413
  }
418
414
 
419
- $verificationCode = VerificationCode::where([
415
+ $verificationCode = $this->verificationCodeExists([
420
416
  'subject_uuid' => $user->uuid,
421
417
  'code' => $code,
422
418
  'for' => $for,
423
- ])->exists();
419
+ ]);
424
420
  if (!$verificationCode) {
425
421
  return response()->apiError('Invalid verification code.');
426
422
  }
427
423
 
428
- $sessionCompany = session('company');
429
- $contact = Contact::firstOrCreate(
424
+ $sessionCompany = $this->sessionCompany();
425
+ $contact = $this->firstOrCreateCustomerContact(
430
426
  [
431
427
  'user_uuid' => $user->uuid,
432
428
  'company_uuid' => $sessionCompany,
@@ -439,10 +435,10 @@ class CustomerController extends Controller
439
435
  ]
440
436
  );
441
437
 
442
- $token = $user->createToken($contact->uuid);
438
+ $token = $this->createCustomerToken($user, $contact);
443
439
  $contact->token = $token->plainTextToken;
444
440
 
445
- return new CustomerResource($contact);
441
+ return $this->customerResource($contact);
446
442
  }
447
443
 
448
444
  /**
@@ -455,10 +451,8 @@ class CustomerController extends Controller
455
451
  return response()->apiError('Identity is required.', 400);
456
452
  }
457
453
 
458
- $isEmail = Utils::isEmail($identity);
459
- $user = $isEmail
460
- ? User::where('email', $identity)->first()
461
- : User::where('phone', static::phone($identity))->first();
454
+ $isEmail = $this->isEmail($identity);
455
+ $user = $this->findUserByIdentity($isEmail ? $identity : static::phone($identity), $isEmail ? 'email' : 'phone');
462
456
 
463
457
  if (!$user) {
464
458
  // Don't leak account existence — return success regardless.
@@ -468,13 +462,13 @@ class CustomerController extends Controller
468
462
  $meta = ['identity' => $isEmail ? $identity : static::phone($identity)];
469
463
  try {
470
464
  if ($isEmail) {
471
- VerificationCode::generateEmailVerificationFor($user, 'fleetops_customer_password_reset', [
465
+ $this->generateEmailVerification($user, 'fleetops_customer_password_reset', [
472
466
  'subject' => config('app.name') . ' password reset',
473
467
  'messageCallback' => fn ($v) => 'Your ' . config('app.name') . ' password reset code is ' . $v->code,
474
468
  'meta' => $meta,
475
469
  ]);
476
470
  } else {
477
- VerificationCode::generateSmsVerificationFor($user, 'fleetops_customer_password_reset', [
471
+ $this->generateSmsVerification($user, 'fleetops_customer_password_reset', [
478
472
  'messageCallback' => fn ($v) => 'Your ' . config('app.name') . ' password reset code is ' . $v->code,
479
473
  'meta' => $meta,
480
474
  ]);
@@ -501,21 +495,19 @@ class CustomerController extends Controller
501
495
  return response()->apiError('Password must be at least 8 characters.', 400);
502
496
  }
503
497
 
504
- $isEmail = Utils::isEmail($identity);
498
+ $isEmail = $this->isEmail($identity);
505
499
  $needle = $isEmail ? $identity : static::phone($identity);
506
500
 
507
- $verificationCode = VerificationCode::where([
501
+ $verificationCode = $this->findVerificationCode([
508
502
  'code' => $code,
509
503
  'for' => 'fleetops_customer_password_reset',
510
504
  'meta->identity' => $needle,
511
- ])->first();
505
+ ]);
512
506
  if (!$verificationCode) {
513
507
  return response()->apiError('Invalid reset code.');
514
508
  }
515
509
 
516
- $user = $isEmail
517
- ? User::where('email', $needle)->first()
518
- : User::where('phone', $needle)->first();
510
+ $user = $this->findUserByIdentity($needle, $isEmail ? 'email' : 'phone');
519
511
  if (!$user) {
520
512
  return response()->apiError('Account not found.');
521
513
  }
@@ -524,7 +516,7 @@ class CustomerController extends Controller
524
516
  $user->password = $password;
525
517
  $user->save();
526
518
  // Invalidate all existing sessions for this user after a password reset.
527
- $user->tokens()->delete();
519
+ $this->deleteUserTokens($user);
528
520
  $verificationCode->delete();
529
521
 
530
522
  return response()->json(['status' => 'ok']);
@@ -539,12 +531,12 @@ class CustomerController extends Controller
539
531
  */
540
532
  public function me()
541
533
  {
542
- $customer = CustomerAuth::current();
534
+ $customer = $this->currentCustomer();
543
535
  if (!$customer) {
544
536
  return response()->apiError('Not authenticated.', 401);
545
537
  }
546
538
 
547
- return new CustomerResource($customer);
539
+ return $this->customerResource($customer);
548
540
  }
549
541
 
550
542
  /**
@@ -552,7 +544,7 @@ class CustomerController extends Controller
552
544
  */
553
545
  public function updateMe(UpdateContactRequest $request)
554
546
  {
555
- $customer = CustomerAuth::current();
547
+ $customer = $this->currentCustomer();
556
548
  if (!$customer) {
557
549
  return response()->apiError('Not authenticated.', 401);
558
550
  }
@@ -565,15 +557,15 @@ class CustomerController extends Controller
565
557
  // Photo handling.
566
558
  $photo = $request->input('photo');
567
559
  if ($photo) {
568
- if (Utils::isPublicId($photo)) {
569
- $file = File::where('public_id', $photo)->first();
560
+ if ($this->isPublicId($photo)) {
561
+ $file = $this->findFileByPublicId($photo);
570
562
  if ($file) {
571
563
  $input['photo_uuid'] = $file->uuid;
572
564
  }
573
565
  }
574
- if (Utils::isBase64String($photo)) {
575
- $path = implode('/', ['uploads', session('company'), 'customers']);
576
- $file = File::createFromBase64($photo, null, $path);
566
+ if ($this->isBase64String($photo)) {
567
+ $path = implode('/', ['uploads', $this->sessionCompany(), 'customers']);
568
+ $file = $this->createFileFromBase64($photo, $path);
577
569
  if ($file) {
578
570
  $input['photo_uuid'] = $file->uuid;
579
571
  }
@@ -597,11 +589,11 @@ class CustomerController extends Controller
597
589
  'phone' => $input['phone'] ?? null,
598
590
  ], fn ($v) => $v !== null);
599
591
  if (!empty($userUpdate)) {
600
- User::where('uuid', $customer->user_uuid)->update($userUpdate);
592
+ $this->updateUserByUuid($customer->user_uuid, $userUpdate);
601
593
  }
602
594
  }
603
595
 
604
- return new CustomerResource($customer->fresh());
596
+ return $this->customerResource($customer->fresh());
605
597
  }
606
598
 
607
599
  /**
@@ -609,13 +601,13 @@ class CustomerController extends Controller
609
601
  */
610
602
  public function logout(Request $request)
611
603
  {
612
- $customer = CustomerAuth::current();
604
+ $customer = $this->currentCustomer();
613
605
  if (!$customer) {
614
606
  return response()->apiError('Not authenticated.', 401);
615
607
  }
616
608
 
617
609
  $tokenString = $request->header(CustomerAuth::HEADER);
618
- $accessToken = $tokenString ? \Laravel\Sanctum\PersonalAccessToken::findToken($tokenString) : null;
610
+ $accessToken = $tokenString ? $this->findAccessToken($tokenString) : null;
619
611
  if ($accessToken) {
620
612
  $accessToken->delete();
621
613
  }
@@ -628,14 +620,14 @@ class CustomerController extends Controller
628
620
  */
629
621
  public function logoutAll()
630
622
  {
631
- $customer = CustomerAuth::current();
623
+ $customer = $this->currentCustomer();
632
624
  if (!$customer || !$customer->user_uuid) {
633
625
  return response()->apiError('Not authenticated.', 401);
634
626
  }
635
627
 
636
- $user = User::where('uuid', $customer->user_uuid)->first();
628
+ $user = $this->findUserByUuid($customer->user_uuid);
637
629
  if ($user) {
638
- $user->tokens()->delete();
630
+ $this->deleteUserTokens($user);
639
631
  }
640
632
 
641
633
  return response()->json(['status' => 'ok']);
@@ -646,18 +638,18 @@ class CustomerController extends Controller
646
638
  */
647
639
  public function orders(Request $request)
648
640
  {
649
- $customer = CustomerAuth::current();
641
+ $customer = $this->currentCustomer();
650
642
  if (!$customer) {
651
643
  return response()->apiError('Not authenticated.', 401);
652
644
  }
653
645
 
654
- $results = Order::queryWithRequest($request, function (&$query) use ($customer) {
646
+ $results = $this->queryOrders($request, function (&$query) use ($customer) {
655
647
  $query->where('customer_uuid', $customer->uuid)
656
648
  ->whereNull('deleted_at')
657
649
  ->withoutGlobalScopes();
658
650
  });
659
651
 
660
- return OrderResource::collection($results);
652
+ return $this->orderResourceCollection($results);
661
653
  }
662
654
 
663
655
  /**
@@ -665,13 +657,13 @@ class CustomerController extends Controller
665
657
  */
666
658
  public function findOrder(string $id)
667
659
  {
668
- $customer = CustomerAuth::current();
660
+ $customer = $this->currentCustomer();
669
661
  if (!$customer) {
670
662
  return response()->apiError('Not authenticated.', 401);
671
663
  }
672
664
 
673
665
  try {
674
- $order = Order::findRecordOrFail($id);
666
+ $order = $this->findOrderOrFail($id);
675
667
  } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
676
668
  return response()->apiError('Order not found.', 404);
677
669
  }
@@ -680,7 +672,7 @@ class CustomerController extends Controller
680
672
  return response()->apiError('Order not found.', 404);
681
673
  }
682
674
 
683
- return new OrderResource($order);
675
+ return $this->orderResource($order);
684
676
  }
685
677
 
686
678
  /**
@@ -699,19 +691,18 @@ class CustomerController extends Controller
699
691
  */
700
692
  public function createOrder(CreateCustomerOrderRequest $request)
701
693
  {
702
- $customer = CustomerAuth::current();
694
+ $customer = $this->currentCustomer();
703
695
  if (!$customer) {
704
696
  return response()->apiError('Not authenticated.', 401);
705
697
  }
706
698
 
707
- $sessionCompany = session('company');
699
+ $sessionCompany = $this->sessionCompany();
708
700
  if (!$sessionCompany) {
709
701
  return response()->apiError('No company resolved from API credential.', 500);
710
702
  }
711
703
 
712
704
  // Resolve the order config for this order. Mirrors OrderController::create.
713
- $orderConfig = OrderConfig::resolveFromIdentifier($request->only(['type', 'order_config']))
714
- ?: OrderConfig::where('company_uuid', $sessionCompany)->first();
705
+ $orderConfig = $this->resolveOrderConfig($request, $sessionCompany);
715
706
  if (!$orderConfig) {
716
707
  return response()->apiError('No order config available for this company.', 422);
717
708
  }
@@ -725,7 +716,7 @@ class CustomerController extends Controller
725
716
  $payloadInput = (array) $request->input('payload');
726
717
  $payloadUuid = $this->buildPayloadFromInput($payloadInput, $sessionCompany)->uuid;
727
718
  } elseif ($request->isString('payload')) {
728
- $payloadUuid = Utils::getUuid('payloads', [
719
+ $payloadUuid = $this->getUuid('payloads', [
729
720
  'public_id' => $request->input('payload'),
730
721
  'company_uuid' => $sessionCompany,
731
722
  ]);
@@ -736,10 +727,10 @@ class CustomerController extends Controller
736
727
  }
737
728
  }
738
729
 
739
- $order = Order::create([
730
+ $order = $this->createOrderRecord([
740
731
  'company_uuid' => $sessionCompany,
741
732
  'customer_uuid' => $customer->uuid,
742
- 'customer_type' => Utils::getModelClassName('contact'),
733
+ 'customer_type' => $this->getModelClassName('contact'),
743
734
  'payload_uuid' => $payloadUuid,
744
735
  'order_config_uuid' => $orderConfig->uuid,
745
736
  'type' => $orderConfig->key,
@@ -753,12 +744,12 @@ class CustomerController extends Controller
753
744
  // If the customer picked a ServiceQuote up front, consume it now to
754
745
  // lock the pricing onto the order's PurchaseRate (mirrors how
755
746
  // OrderController::create handles `service_quote`).
756
- $serviceQuote = ServiceQuote::resolveFromRequest($request);
747
+ $serviceQuote = $this->resolveServiceQuote($request);
757
748
  if ($serviceQuote instanceof ServiceQuote) {
758
749
  $order->purchaseServiceQuote($serviceQuote);
759
750
  }
760
751
 
761
- return new OrderResource($order->fresh(['payload', 'payload.pickup', 'payload.dropoff', 'payload.entities']));
752
+ return $this->orderResource($order->fresh(['payload', 'payload.pickup', 'payload.dropoff', 'payload.entities']));
762
753
  }
763
754
 
764
755
  /**
@@ -769,7 +760,7 @@ class CustomerController extends Controller
769
760
  */
770
761
  protected function buildPayloadFromInput(array $payloadInput, string $companyUuid): Payload
771
762
  {
772
- $payload = new Payload();
763
+ $payload = $this->newPayload();
773
764
  $entities = data_get($payloadInput, 'entities', []);
774
765
  $waypoints = data_get($payloadInput, 'waypoints', []);
775
766
  $pickup = data_get($payloadInput, 'pickup');
@@ -810,16 +801,16 @@ class CustomerController extends Controller
810
801
  */
811
802
  public function places(Request $request)
812
803
  {
813
- $customer = CustomerAuth::current();
804
+ $customer = $this->currentCustomer();
814
805
  if (!$customer) {
815
806
  return response()->apiError('Not authenticated.', 401);
816
807
  }
817
808
 
818
- $results = Place::queryWithRequest($request, function (&$query) use ($customer) {
809
+ $results = $this->queryPlaces($request, function (&$query) use ($customer) {
819
810
  $query->where('owner_uuid', $customer->uuid);
820
811
  });
821
812
 
822
- return PlaceResource::collection($results);
813
+ return $this->placeResourceCollection($results);
823
814
  }
824
815
 
825
816
  /**
@@ -827,12 +818,12 @@ class CustomerController extends Controller
827
818
  */
828
819
  public function registerDevice(Request $request)
829
820
  {
830
- $customer = CustomerAuth::current();
821
+ $customer = $this->currentCustomer();
831
822
  if (!$customer) {
832
823
  return response()->apiError('Not authenticated.', 401);
833
824
  }
834
825
 
835
- $device = UserDevice::firstOrCreate(
826
+ $device = $this->firstOrCreateDevice(
836
827
  [
837
828
  'token' => $request->input('token'),
838
829
  'platform' => $request->input('platform', $request->input('os')),
@@ -855,6 +846,214 @@ class CustomerController extends Controller
855
846
  | Helpers
856
847
  * ============================================================ */
857
848
 
849
+ protected function isEmail(?string $identity): bool
850
+ {
851
+ return Utils::isEmail($identity);
852
+ }
853
+
854
+ protected function isPublicId(?string $value): bool
855
+ {
856
+ return Utils::isPublicId($value);
857
+ }
858
+
859
+ protected function isBase64String(?string $value): bool
860
+ {
861
+ return Utils::isBase64String($value);
862
+ }
863
+
864
+ protected function sessionCompany(): ?string
865
+ {
866
+ return session('company');
867
+ }
868
+
869
+ protected function currentCustomer(): ?Contact
870
+ {
871
+ return CustomerAuth::current();
872
+ }
873
+
874
+ protected function findActiveUserByIdentity(string $identity, string $column): ?User
875
+ {
876
+ return User::where($column, $identity)->whereNull('deleted_at')->withoutGlobalScopes()->first();
877
+ }
878
+
879
+ protected function findUserByIdentity(string $identity, string $column): ?User
880
+ {
881
+ return User::where($column, $identity)->first();
882
+ }
883
+
884
+ protected function findUserForLogin(string $identity): ?User
885
+ {
886
+ return User::where('email', $identity)
887
+ ->orWhere('phone', static::phone($identity))
888
+ ->first();
889
+ }
890
+
891
+ protected function findUserForVerification(string $identity): ?User
892
+ {
893
+ return User::where('phone', $identity)->orWhere('email', $identity)->first();
894
+ }
895
+
896
+ protected function findUserByUuid(string $uuid): ?User
897
+ {
898
+ return User::where('uuid', $uuid)->first();
899
+ }
900
+
901
+ protected function createUser(array $attributes): User
902
+ {
903
+ return User::create($attributes);
904
+ }
905
+
906
+ protected function passwordMatches(string $password, string $hash): bool
907
+ {
908
+ return Hash::check($password, $hash);
909
+ }
910
+
911
+ protected function generateEmailVerification(User $user, string $for, array $options): mixed
912
+ {
913
+ return VerificationCode::generateEmailVerificationFor($user, $for, $options);
914
+ }
915
+
916
+ protected function generateSmsVerification(User $user, string $for, array $options): mixed
917
+ {
918
+ return VerificationCode::generateSmsVerificationFor($user, $for, $options);
919
+ }
920
+
921
+ protected function verificationCodeExists(array $attributes): bool
922
+ {
923
+ return VerificationCode::where($attributes)->exists();
924
+ }
925
+
926
+ protected function findVerificationCode(array $attributes): mixed
927
+ {
928
+ return VerificationCode::where($attributes)->first();
929
+ }
930
+
931
+ protected function findFileByPublicId(string $publicId): mixed
932
+ {
933
+ return File::where('public_id', $publicId)->first();
934
+ }
935
+
936
+ protected function createFileFromBase64(string $contents, string $path): mixed
937
+ {
938
+ return File::createFromBase64($contents, null, $path);
939
+ }
940
+
941
+ protected function findCustomerContact(array $attributes): ?Contact
942
+ {
943
+ return Contact::where($attributes)->first();
944
+ }
945
+
946
+ protected function createContact(array $attributes): Contact
947
+ {
948
+ return Contact::create($attributes);
949
+ }
950
+
951
+ protected function firstOrCreateCustomerContact(array $attributes, array $values): Contact
952
+ {
953
+ return Contact::firstOrCreate($attributes, $values);
954
+ }
955
+
956
+ protected function createCustomerToken(User $user, Contact $contact): mixed
957
+ {
958
+ return $user->createToken($contact->uuid);
959
+ }
960
+
961
+ protected function findPlaceByPublicId(string $publicId, string $companyUuid): ?Place
962
+ {
963
+ return Place::where(['public_id' => $publicId, 'company_uuid' => $companyUuid])->first();
964
+ }
965
+
966
+ protected function createPlace(array $attributes): Place
967
+ {
968
+ return Place::create($attributes);
969
+ }
970
+
971
+ protected function updateUserByUuid(string $uuid, array $attributes): mixed
972
+ {
973
+ return User::where('uuid', $uuid)->update($attributes);
974
+ }
975
+
976
+ protected function findAccessToken(string $token): mixed
977
+ {
978
+ return \Laravel\Sanctum\PersonalAccessToken::findToken($token);
979
+ }
980
+
981
+ protected function deleteUserTokens(User $user): void
982
+ {
983
+ $user->tokens()->delete();
984
+ }
985
+
986
+ protected function queryOrders(Request $request, callable $callback): mixed
987
+ {
988
+ return Order::queryWithRequest($request, $callback);
989
+ }
990
+
991
+ protected function findOrderOrFail(string $id): Order
992
+ {
993
+ return Order::findRecordOrFail($id);
994
+ }
995
+
996
+ protected function resolveOrderConfig(CreateCustomerOrderRequest $request, string $companyUuid): ?OrderConfig
997
+ {
998
+ return OrderConfig::resolveFromIdentifier($request->only(['type', 'order_config']))
999
+ ?: OrderConfig::where('company_uuid', $companyUuid)->first();
1000
+ }
1001
+
1002
+ protected function getUuid(array|string $table, array $where, array $options = []): mixed
1003
+ {
1004
+ return Utils::getUuid($table, $where, $options);
1005
+ }
1006
+
1007
+ protected function getModelClassName(?string $table): ?string
1008
+ {
1009
+ return Utils::getModelClassName($table);
1010
+ }
1011
+
1012
+ protected function createOrderRecord(array $attributes): Order
1013
+ {
1014
+ return Order::create($attributes);
1015
+ }
1016
+
1017
+ protected function resolveServiceQuote(CreateCustomerOrderRequest $request): mixed
1018
+ {
1019
+ return ServiceQuote::resolveFromRequest($request);
1020
+ }
1021
+
1022
+ protected function newPayload(): Payload
1023
+ {
1024
+ return new Payload();
1025
+ }
1026
+
1027
+ protected function queryPlaces(Request $request, callable $callback): mixed
1028
+ {
1029
+ return Place::queryWithRequest($request, $callback);
1030
+ }
1031
+
1032
+ protected function firstOrCreateDevice(array $attributes, array $values): mixed
1033
+ {
1034
+ return UserDevice::firstOrCreate($attributes, $values);
1035
+ }
1036
+
1037
+ protected function customerResource(Contact $contact): mixed
1038
+ {
1039
+ return new CustomerResource($contact);
1040
+ }
1041
+
1042
+ protected function orderResource(Order $order): mixed
1043
+ {
1044
+ return new OrderResource($order);
1045
+ }
1046
+
1047
+ protected function orderResourceCollection(mixed $results): mixed
1048
+ {
1049
+ return OrderResource::collection($results);
1050
+ }
1051
+
1052
+ protected function placeResourceCollection(mixed $results): mixed
1053
+ {
1054
+ return PlaceResource::collection($results);
1055
+ }
1056
+
858
1057
  /**
859
1058
  * Normalize a phone number to international format (with leading `+`).
860
1059
  */