@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
@@ -36,9 +36,7 @@ class Geocoding
36
36
  */
37
37
  public static function geocode(string $searchQuery, $latitude = null, $longitude = null): Collection
38
38
  {
39
- $httpClient = new Client();
40
- $provider = new GoogleMaps($httpClient, null, config('services.google_maps.api_key', env('GOOGLE_MAPS_API_KEY')));
41
- $geocoder = new StatefulGeocoder($provider, 'en');
39
+ $geocoder = static::makeGeocoder();
42
40
 
43
41
  try {
44
42
  if ($latitude && $longitude) {
@@ -57,7 +55,7 @@ class Geocoding
57
55
 
58
56
  return collect($geoResults->all())->map(
59
57
  function ($googleAddress) {
60
- return Place::createFromGoogleAddress($googleAddress);
58
+ return static::makePlaceFromGoogleAddress($googleAddress);
61
59
  }
62
60
  )->values();
63
61
  } catch (\Exception $e) {
@@ -81,10 +79,6 @@ class Geocoding
81
79
  */
82
80
  public static function reverseFromQuery(string $searchQuery, $latitude, $longitude): Collection
83
81
  {
84
- $httpClient = new Client();
85
- $provider = new GoogleMaps($httpClient, null, config('services.google_maps.api_key', env('GOOGLE_MAPS_API_KEY')));
86
- $geocoder = new StatefulGeocoder($provider, 'en');
87
-
88
82
  if (empty($searchQuery)) {
89
83
  return collect();
90
84
  }
@@ -93,6 +87,8 @@ class Geocoding
93
87
  return collect();
94
88
  }
95
89
 
90
+ $geocoder = static::makeGeocoder();
91
+
96
92
  try {
97
93
  $geoResults = $geocoder->reverseQuery(
98
94
  ReverseQuery::fromCoordinates($latitude, $longitude)
@@ -103,7 +99,7 @@ class Geocoding
103
99
 
104
100
  return collect($geoResults->all())->map(
105
101
  function ($googleAddress) {
106
- return Place::createFromGoogleAddress($googleAddress);
102
+ return static::makePlaceFromGoogleAddress($googleAddress);
107
103
  }
108
104
  )->values();
109
105
  } catch (\Exception $e) {
@@ -127,14 +123,12 @@ class Geocoding
127
123
  */
128
124
  public static function reverseFromCoordinates($latitude, $longitude, ?string $searchQuery = null): Collection
129
125
  {
130
- $httpClient = new Client();
131
- $provider = new GoogleMaps($httpClient, null, config('services.google_maps.api_key', env('GOOGLE_MAPS_API_KEY')));
132
- $geocoder = new StatefulGeocoder($provider, 'en');
133
-
134
126
  if (empty($latitude) && empty($longitude)) {
135
127
  return collect();
136
128
  }
137
129
 
130
+ $geocoder = static::makeGeocoder();
131
+
138
132
  try {
139
133
  if ($searchQuery) {
140
134
  $geoResults = $geocoder->reverseQuery(
@@ -153,7 +147,7 @@ class Geocoding
153
147
 
154
148
  return collect($geoResults->all())->map(
155
149
  function ($googleAddress) {
156
- return Place::createFromGoogleAddress($googleAddress);
150
+ return static::makePlaceFromGoogleAddress($googleAddress);
157
151
  }
158
152
  )->values();
159
153
  } catch (\Exception $e) {
@@ -216,4 +210,48 @@ class Geocoding
216
210
  {
217
211
  return Utils::notEmpty(config('services.google_maps.api_key'));
218
212
  }
213
+
214
+ /**
215
+ * The language geocoding results are returned in — Google's `language`
216
+ * parameter, e.g. `en`, `ru`, `es`.
217
+ */
218
+ public static function getLocale(): string
219
+ {
220
+ // `?:` rather than a config() default: the settings table stores this
221
+ // key, so it exists-but-empty on installs that never filled it in, and
222
+ // config()'s default only applies when the key is absent entirely.
223
+ return config('services.google_maps.locale') ?: env('GOOGLE_MAPS_LOCALE', 'en');
224
+ }
225
+
226
+ /**
227
+ * The region requests are biased towards — Google's `region` parameter.
228
+ * This is a ccTLD (`us`, `ru`, `sg`), not a language code, and is a
229
+ * separate concern from the locale above.
230
+ */
231
+ public static function getRegion(): ?string
232
+ {
233
+ return config('services.google_maps.region') ?: env('GOOGLE_MAPS_REGION', 'us');
234
+ }
235
+
236
+ protected static function makeGeocoder(): object
237
+ {
238
+ // Allow an alternative geocoder (or test double) to be injected
239
+ // through the container without constructing a live HTTP client.
240
+ if (app()->bound('fleetops.geocoder')) {
241
+ return app('fleetops.geocoder');
242
+ }
243
+
244
+ // Region biases which results rank highest; locale controls the
245
+ // language they come back in. Applying both here covers every caller
246
+ // rather than each construction site repeating them.
247
+ $httpClient = new Client();
248
+ $provider = new GoogleMaps($httpClient, static::getRegion(), config('services.google_maps.api_key', env('GOOGLE_MAPS_API_KEY')));
249
+
250
+ return new StatefulGeocoder($provider, static::getLocale());
251
+ }
252
+
253
+ protected static function makePlaceFromGoogleAddress($googleAddress): Place
254
+ {
255
+ return Place::createFromGoogleAddress($googleAddress);
256
+ }
219
257
  }
@@ -70,16 +70,7 @@ class GeofenceIntersectionService
70
70
  // - ST_Contains performs the precise polygon containment check
71
71
  // on the reduced candidate set (accurate, no index needed).
72
72
  // ----------------------------------------------------------------
73
- $insideZones = Zone::where('company_uuid', $companyUuid)
74
- ->whereNotNull('border')
75
- ->where(function ($q) {
76
- $q->where('trigger_on_entry', true)
77
- ->orWhere('trigger_on_exit', true)
78
- ->orWhereNotNull('dwell_threshold_minutes');
79
- })
80
- ->whereRaw('MBRContains(`border`, ST_GeomFromText(?))', [$wkt])
81
- ->whereRaw('ST_Contains(`border`, ST_GeomFromText(?))', [$wkt])
82
- ->get();
73
+ $insideZones = $this->insideZones($companyUuid, $wkt);
83
74
 
84
75
  // ----------------------------------------------------------------
85
76
  // 2. Find all Service Areas the driver is currently inside.
@@ -87,16 +78,7 @@ class GeofenceIntersectionService
87
78
  // Service areas use MultiPolygon borders, so we use
88
79
  // ST_Contains which handles both Polygon and MultiPolygon.
89
80
  // ----------------------------------------------------------------
90
- $insideServiceAreas = ServiceArea::where('company_uuid', $companyUuid)
91
- ->whereNotNull('border')
92
- ->where(function ($q) {
93
- $q->where('trigger_on_entry', true)
94
- ->orWhere('trigger_on_exit', true)
95
- ->orWhereNotNull('dwell_threshold_minutes');
96
- })
97
- ->whereRaw('MBRContains(`border`, ST_GeomFromText(?))', [$wkt])
98
- ->whereRaw('ST_Contains(`border`, ST_GeomFromText(?))', [$wkt])
99
- ->get();
81
+ $insideServiceAreas = $this->insideServiceAreas($companyUuid, $wkt);
100
82
 
101
83
  // Merge into a unified collection with a type discriminator
102
84
  $currentlyInside = collect()
@@ -108,10 +90,7 @@ class GeofenceIntersectionService
108
90
  // ----------------------------------------------------------------
109
91
  // 3. Load the driver's current geofence state records.
110
92
  // ----------------------------------------------------------------
111
- $currentStates = DB::table($stateTable)
112
- ->where($subjectColumn, $subjectUuid)
113
- ->get()
114
- ->keyBy('geofence_uuid');
93
+ $currentStates = $this->currentSubjectStates($stateTable, $subjectColumn, $subjectUuid);
115
94
 
116
95
  // ----------------------------------------------------------------
117
96
  // 4. Detect ENTRIES: geofences the driver is now inside but
@@ -136,9 +115,7 @@ class GeofenceIntersectionService
136
115
  // ----------------------------------------------------------------
137
116
  foreach ($currentStates as $geofenceUuid => $state) {
138
117
  if ($state->is_inside && !in_array($geofenceUuid, $currentlyInsideUuids)) {
139
- $geofence = $state->geofence_type === 'service_area'
140
- ? ServiceArea::where('uuid', $geofenceUuid)->first()
141
- : Zone::where('uuid', $geofenceUuid)->first();
118
+ $geofence = $this->findGeofence($state->geofence_type, $geofenceUuid);
142
119
 
143
120
  if ($geofence) {
144
121
  $crossings[] = [
@@ -153,6 +130,49 @@ class GeofenceIntersectionService
153
130
  return $crossings;
154
131
  }
155
132
 
133
+ protected function insideZones(string $companyUuid, string $wkt)
134
+ {
135
+ return Zone::where('company_uuid', $companyUuid)
136
+ ->whereNotNull('border')
137
+ ->where(function ($q) {
138
+ $q->where('trigger_on_entry', true)
139
+ ->orWhere('trigger_on_exit', true)
140
+ ->orWhereNotNull('dwell_threshold_minutes');
141
+ })
142
+ ->whereRaw('MBRContains(`border`, ST_GeomFromText(?))', [$wkt])
143
+ ->whereRaw('ST_Contains(`border`, ST_GeomFromText(?))', [$wkt])
144
+ ->get();
145
+ }
146
+
147
+ protected function insideServiceAreas(string $companyUuid, string $wkt)
148
+ {
149
+ return ServiceArea::where('company_uuid', $companyUuid)
150
+ ->whereNotNull('border')
151
+ ->where(function ($q) {
152
+ $q->where('trigger_on_entry', true)
153
+ ->orWhere('trigger_on_exit', true)
154
+ ->orWhereNotNull('dwell_threshold_minutes');
155
+ })
156
+ ->whereRaw('MBRContains(`border`, ST_GeomFromText(?))', [$wkt])
157
+ ->whereRaw('ST_Contains(`border`, ST_GeomFromText(?))', [$wkt])
158
+ ->get();
159
+ }
160
+
161
+ protected function currentSubjectStates(string $stateTable, string $subjectColumn, string $subjectUuid)
162
+ {
163
+ return DB::table($stateTable)
164
+ ->where($subjectColumn, $subjectUuid)
165
+ ->get()
166
+ ->keyBy('geofence_uuid');
167
+ }
168
+
169
+ protected function findGeofence(string $geofenceType, string $geofenceUuid)
170
+ {
171
+ return $geofenceType === 'service_area'
172
+ ? ServiceArea::where('uuid', $geofenceUuid)->first()
173
+ : Zone::where('uuid', $geofenceUuid)->first();
174
+ }
175
+
156
176
  /**
157
177
  * Check if a driver is currently recorded as inside a specific geofence.
158
178
  *
@@ -19,7 +19,7 @@ class LiveOrderQuery
19
19
  $withRelations = $options['with_relations'] ?? false;
20
20
  $applyPermissions = $options['apply_permissions'] ?? true;
21
21
 
22
- $query = Order::where('company_uuid', $companyUuid)
22
+ $query = static::newOrderQuery($companyUuid)
23
23
  ->whereHas('payload', function ($query) {
24
24
  $query->where(function ($q) {
25
25
  $q->whereHas('waypoints');
@@ -72,4 +72,9 @@ class LiveOrderQuery
72
72
 
73
73
  return $query;
74
74
  }
75
+
76
+ protected static function newOrderQuery(string $companyUuid): Builder
77
+ {
78
+ return Order::where('company_uuid', $companyUuid);
79
+ }
75
80
  }
@@ -10,7 +10,8 @@ use Illuminate\Support\Facades\Schema;
10
10
 
11
11
  class ActiveRevenueQuery
12
12
  {
13
- public const ACTIVE_STATUSES = [Transaction::STATUS_SUCCESS];
13
+ public const ACTIVE_STATUSES = ['success'];
14
+ public const CREDIT_DIRECTION = 'credit';
14
15
  public const INACTIVE_TRANSACTION_STATUSES = ['pending', 'failed', 'cancelled', 'canceled', 'void', 'voided', 'expired', 'reversed', 'refunded', 'ignored'];
15
16
  public const INACTIVE_ORDER_STATUSES = ['canceled', 'cancelled', 'order_canceled'];
16
17
  public const INACTIVE_INVOICE_STATUSES = ['void', 'voided', 'cancelled', 'canceled'];
@@ -20,7 +21,7 @@ class ActiveRevenueQuery
20
21
  $query = Transaction::query()
21
22
  ->where('company_uuid', $company->uuid)
22
23
  ->where('currency', $currency)
23
- ->where('direction', Transaction::DIRECTION_CREDIT)
24
+ ->where('direction', self::CREDIT_DIRECTION)
24
25
  ->whereIn('status', self::ACTIVE_STATUSES)
25
26
  ->whereNotIn('status', self::INACTIVE_TRANSACTION_STATUSES)
26
27
  ->whereNull('deleted_at')
@@ -13,7 +13,7 @@ class FuelCostsMetric extends MoneyMetric
13
13
 
14
14
  protected function query(?\DateTimeInterface $start, ?\DateTimeInterface $end)
15
15
  {
16
- $query = FuelReport::where('company_uuid', $this->company->uuid)
16
+ $query = $this->fuelReportQuery($this->company->uuid)
17
17
  ->where('currency', $this->currency());
18
18
 
19
19
  if ($start && $end) {
@@ -27,4 +27,9 @@ class FuelCostsMetric extends MoneyMetric
27
27
  {
28
28
  return (float) $query->sum('amount');
29
29
  }
30
+
31
+ protected function fuelReportQuery(string $companyUuid)
32
+ {
33
+ return FuelReport::where('company_uuid', $companyUuid);
34
+ }
30
35
  }
@@ -381,9 +381,14 @@ trait ResolvesOrderServiceStops
381
381
  'location' => Utils::parsePointToWkt($this->serviceStopLocationPoint($place)),
382
382
  ], $place);
383
383
 
384
+ // Unreachable: insertGetUuid() only returns false when the underlying
385
+ // insert returns false, which Laravel's forced PDO::ERRMODE_EXCEPTION
386
+ // never does — the insert either succeeds or throws.
387
+ // @codeCoverageIgnoreStart
384
388
  if (!$trackingNumberUuid) {
385
389
  return null;
386
390
  }
391
+ // @codeCoverageIgnoreEnd
387
392
 
388
393
  DB::table($payload->getTable())->where('uuid', $payload->uuid)->update([$column => $trackingNumberUuid]);
389
394
  $payload->{$column} = $trackingNumberUuid;
@@ -415,9 +420,14 @@ trait ResolvesOrderServiceStops
415
420
  $trackingNumber->status_uuid = $activityId;
416
421
  }
417
422
 
423
+ // Unreachable: endpointServiceStopTrackingNumber() always hands back a
424
+ // freshly queried TrackingNumber, and TrackingNumber declares no $with,
425
+ // so the status relation is never already loaded here.
426
+ // @codeCoverageIgnoreStart
418
427
  if ($trackingNumber->relationLoaded('status')) {
419
428
  $trackingNumber->unsetRelation('status');
420
429
  }
430
+ // @codeCoverageIgnoreEnd
421
431
 
422
432
  return $activityId ?: null;
423
433
  }
@@ -34,14 +34,14 @@ class GeotabProvider extends AbstractProvider
34
34
  */
35
35
  protected function authenticate(): void
36
36
  {
37
- $response = Http::post($this->baseUrl, [
37
+ $response = $this->postGeotab([
38
38
  'method' => 'Authenticate',
39
39
  'params' => [
40
40
  'database' => $this->credentials['database'],
41
41
  'userName' => $this->credentials['username'],
42
42
  'password' => $this->credentials['password'],
43
43
  ],
44
- ])->json();
44
+ ]);
45
45
 
46
46
  if (isset($response['result']['credentials']['sessionId'])) {
47
47
  $this->sessionId = $response['result']['credentials']['sessionId'];
@@ -223,10 +223,15 @@ class GeotabProvider extends AbstractProvider
223
223
  'sessionId' => $this->sessionId,
224
224
  ];
225
225
 
226
- return Http::post($this->baseUrl, [
226
+ return $this->postGeotab([
227
227
  'method' => $method,
228
228
  'params' => $params,
229
- ])->json() ?? [];
229
+ ]) ?? [];
230
+ }
231
+
232
+ protected function postGeotab(array $payload): ?array
233
+ {
234
+ return Http::post($this->baseUrl, $payload)->json();
230
235
  }
231
236
 
232
237
  protected function fetchLatestLogRecords(array $devices, array $options = []): array
@@ -271,12 +271,20 @@ class Utils extends FleetbaseUtils
271
271
  try {
272
272
  $coordinates = Point::fromJson($coordinatesJson);
273
273
  } catch (\Throwable $e) {
274
+ // Both fallbacks carry a GeoJSON coordinate value, so they are
275
+ // read as GeoJSON first: pointFromGeoJson() maps [lng, lat],
276
+ // whereas recursing hands the pair to the positional array
277
+ // reader below, which takes index 0 as the latitude. Nested
278
+ // values (a Polygon or LineString ring rather than a single
279
+ // pair) yield null there and still fall through to it.
274
280
  if ($coordinatesInGeoJson) {
275
- return static::getPointFromMixed($coordinatesInGeoJson);
281
+ return static::pointFromGeoJsonCoordinates($coordinatesInGeoJson)
282
+ ?? static::getPointFromMixed($coordinatesInGeoJson);
276
283
  }
277
284
 
278
285
  if ($coordinatesInGeoJsonFeature) {
279
- return static::getPointFromMixed($coordinatesInGeoJsonFeature);
286
+ return static::pointFromGeoJsonCoordinates($coordinatesInGeoJsonFeature)
287
+ ?? static::getPointFromMixed($coordinatesInGeoJsonFeature);
280
288
  }
281
289
  }
282
290
  }
@@ -492,7 +500,7 @@ class Utils extends FleetbaseUtils
492
500
  $coordinates = null;
493
501
  }
494
502
 
495
- if (preg_match('/LatLng\(([^,]+),\s*([^)]+)\)/', $coordinates, $matches)) {
503
+ if (is_string($coordinates) && preg_match('/LatLng\(([^,]+),\s*([^)]+)\)/', $coordinates, $matches)) {
496
504
  $coords = [
497
505
  floatval($matches[1]),
498
506
  floatval($matches[2]),
@@ -501,20 +509,20 @@ class Utils extends FleetbaseUtils
501
509
  $coordinates = null;
502
510
  }
503
511
 
504
- if (Str::contains($coordinates, ',')) {
512
+ if (is_string($coordinates) && Str::contains($coordinates, ',')) {
505
513
  $coords = explode(',', $coordinates);
506
514
  }
507
515
 
508
- if (Str::contains($coordinates, '|')) {
516
+ if (is_string($coordinates) && Str::contains($coordinates, '|')) {
509
517
  $coords = explode('|', $coordinates);
510
518
  }
511
519
 
512
- if (Str::contains($coordinates, ' ')) {
520
+ if (is_string($coordinates) && Str::contains($coordinates, ' ')) {
513
521
  $coords = explode(' ', $coordinates);
514
522
  }
515
523
 
516
- $latitude = $coords[0];
517
- $longitude = $coords[1];
524
+ $latitude = $coords[0] ?? null;
525
+ $longitude = $coords[1] ?? null;
518
526
 
519
527
  if (is_numeric($latitude) && is_numeric($longitude)) {
520
528
  $coordinates = new Point((float) $latitude, (float) $longitude);
@@ -701,6 +709,19 @@ class Utils extends FleetbaseUtils
701
709
  return new Point((float) $latitude, (float) $longitude);
702
710
  }
703
711
 
712
+ /**
713
+ * Resolve a bare GeoJSON `coordinates` value — an `[longitude, latitude]`
714
+ * pair — into a Point, without the surrounding envelope.
715
+ *
716
+ * Returns null for anything that is not a usable pair, including the nested
717
+ * rings a Polygon or LineString carries, so callers can fall through to
718
+ * their own handling.
719
+ */
720
+ protected static function pointFromGeoJsonCoordinates($coordinates): ?Point
721
+ {
722
+ return static::pointFromGeoJson(['type' => 'Point', 'coordinates' => $coordinates]);
723
+ }
724
+
704
725
  /**
705
726
  * Converts a point to a WKT (Well-Known Text) representation for SQL insert.
706
727
  *
@@ -1162,9 +1183,13 @@ class Utils extends FleetbaseUtils
1162
1183
 
1163
1184
  $feature = collect($globe->features)->first(
1164
1185
  function ($feature) use ($country) {
1186
+ // Every feature in the bundled resources/data/globe.json carries
1187
+ // both codes, so this only guards against future data changes.
1188
+ // @codeCoverageIgnoreStart
1165
1189
  if (!isset($feature->properties->ISO_A3) || !isset($feature->properties->ISO_A2)) {
1166
1190
  return false;
1167
1191
  }
1192
+ // @codeCoverageIgnoreEnd
1168
1193
 
1169
1194
  return strtolower($feature->properties->ISO_A3) === $country || strtolower($feature->properties->ISO_A2) === $country;
1170
1195
  }
@@ -1199,8 +1224,10 @@ class Utils extends FleetbaseUtils
1199
1224
  $radius = ($meters * 1000) / 6378137;
1200
1225
  // create circle coordinates
1201
1226
  $coords = collect();
1202
- // loop through the array and write path linestrings
1203
- for ($i = 0; $i <= 360; $i += 3) {
1227
+ // loop through the array and write path linestrings — stop short of 360
1228
+ // so the ring is closed explicitly below rather than by re-computing the
1229
+ // 0 degree vertex, which produced a duplicated point
1230
+ for ($i = 0; $i < 360; $i += 3) {
1204
1231
  $radial = deg2rad($i);
1205
1232
  $lat_rad = asin(sin($latitude) * cos($radius) + cos($latitude) * sin($radius) * cos($radial));
1206
1233
  $dlon_rad = atan2(sin($radial) * sin($radius) * cos($latitude), cos($radius) - sin($latitude) * sin($lat_rad));
@@ -1261,9 +1288,80 @@ class Utils extends FleetbaseUtils
1261
1288
  */
1262
1289
  public static function getCentroidFromGeosPolygon(\Brick\Geo\Polygon $polygon): \Brick\Geo\Point
1263
1290
  {
1264
- $geometryEngine = new \Brick\Geo\Engine\GEOSEngine();
1291
+ return static::resolveGeometryEngine()->centroid($polygon);
1292
+ }
1293
+
1294
+ /**
1295
+ * Resolve the configured geometry engine, preferring the registry so
1296
+ * alternative engines (or test doubles) can be injected without the
1297
+ * GEOS extension.
1298
+ */
1299
+ /**
1300
+ * Determine whether the active database connection speaks SQLite.
1301
+ */
1302
+ protected static function isSqliteConnection(): bool
1303
+ {
1304
+ try {
1305
+ $connection = DB::connection();
1306
+ } catch (\Throwable $e) {
1307
+ return false;
1308
+ }
1309
+
1310
+ return $connection instanceof \Illuminate\Database\SQLiteConnection
1311
+ || ($connection && $connection->getDriverName() === 'sqlite');
1312
+ }
1313
+
1314
+ /**
1315
+ * Build a driver-aware SQL expression for whole-second differences
1316
+ * between two datetime expressions.
1317
+ */
1318
+ public static function sqlSecondsDiff(string $start, string $end): string
1319
+ {
1320
+ if (static::isSqliteConnection()) {
1321
+ return "CAST(ROUND((julianday($end) - julianday($start)) * 86400) AS INTEGER)";
1322
+ }
1265
1323
 
1266
- return $geometryEngine->centroid($polygon);
1324
+ return "TIMESTAMPDIFF(SECOND, $start, $end)";
1325
+ }
1326
+
1327
+ /**
1328
+ * Build a driver-aware SQL expression for whole-minute differences
1329
+ * between two datetime expressions.
1330
+ */
1331
+ public static function sqlMinutesDiff(string $start, string $end): string
1332
+ {
1333
+ if (static::isSqliteConnection()) {
1334
+ return "CAST(ROUND((julianday($end) - julianday($start)) * 1440) AS INTEGER)";
1335
+ }
1336
+
1337
+ return "TIMESTAMPDIFF(MINUTE, $start, $end)";
1338
+ }
1339
+
1340
+ /**
1341
+ * Driver-aware SQL expression for the current timestamp.
1342
+ */
1343
+ public static function sqlNow(): string
1344
+ {
1345
+ return static::isSqliteConnection() ? "datetime('now')" : 'NOW()';
1346
+ }
1347
+
1348
+ /**
1349
+ * Driver-aware SQL scalar minimum of two expressions.
1350
+ */
1351
+ public static function sqlLeast(string $first, string $second): string
1352
+ {
1353
+ $function = static::isSqliteConnection() ? 'MIN' : 'LEAST';
1354
+
1355
+ return "$function($first, $second)";
1356
+ }
1357
+
1358
+ public static function resolveGeometryEngine(): \Brick\Geo\Engine\GeometryEngine
1359
+ {
1360
+ if (\Brick\Geo\Engine\GeometryEngineRegistry::has()) {
1361
+ return \Brick\Geo\Engine\GeometryEngineRegistry::get();
1362
+ }
1363
+
1364
+ return new \Brick\Geo\Engine\GEOSEngine();
1267
1365
  }
1268
1366
 
1269
1367
  /**
@@ -1275,9 +1373,7 @@ class Utils extends FleetbaseUtils
1275
1373
  */
1276
1374
  public static function getCentroidFromGeosMultiPolygon(\Brick\Geo\MultiPolygon $multiPolygon): \Brick\Geo\Point
1277
1375
  {
1278
- $geometryEngine = new \Brick\Geo\Engine\GEOSEngine();
1279
-
1280
- return $geometryEngine->centroid($multiPolygon);
1376
+ return static::resolveGeometryEngine()->centroid($multiPolygon);
1281
1377
  }
1282
1378
 
1283
1379
  /**
@@ -1489,8 +1585,18 @@ class Utils extends FleetbaseUtils
1489
1585
  return $activity && $activity instanceof Activity && !empty($activity->code);
1490
1586
  }
1491
1587
 
1492
- public static function fixPhone(string $phone): string
1588
+ /**
1589
+ * Normalize a phone number to E.164-ish form by ensuring a leading `+`.
1590
+ *
1591
+ * Import rows frequently omit a phone column entirely, so a missing
1592
+ * number is passed through untouched rather than becoming a bare `+`.
1593
+ */
1594
+ public static function fixPhone(?string $phone): ?string
1493
1595
  {
1596
+ if ($phone === null || $phone === '') {
1597
+ return $phone;
1598
+ }
1599
+
1494
1600
  if (!Str::startsWith($phone, '+')) {
1495
1601
  $phone = '+' . $phone;
1496
1602
  }
@@ -113,6 +113,11 @@ class GoogleRoutesTrackingProvider implements TrackingProviderInterface
113
113
 
114
114
  protected function apiKey(): ?string
115
115
  {
116
- return config('services.google_maps.api_key') ?: env('GOOGLE_MAPS_API_KEY');
116
+ $configuredKey = config('services.google_maps.api_key');
117
+ if ($configuredKey) {
118
+ return $configuredKey;
119
+ }
120
+
121
+ return class_exists(\PhpOption\Option::class) ? env('GOOGLE_MAPS_API_KEY') : null;
117
122
  }
118
123
  }
@@ -29,12 +29,7 @@ class OsrmTrackingProvider implements TrackingProviderInterface
29
29
 
30
30
  public function track(TrackingContext $context, TrackingOptions $options): TrackingProviderResult
31
31
  {
32
- $response = OSRM::getRouteFromPoints($context->routePoints(), [
33
- 'overview' => 'full',
34
- 'geometries' => 'polyline',
35
- 'steps' => 'false',
36
- 'annotations' => 'false',
37
- ]);
32
+ $response = $this->routeResponse($context);
38
33
 
39
34
  if (data_get($response, 'code') !== 'Ok') {
40
35
  throw new \RuntimeException('OSRM did not return a routable response.');
@@ -68,4 +63,14 @@ class OsrmTrackingProvider implements TrackingProviderInterface
68
63
  raw: $route
69
64
  );
70
65
  }
66
+
67
+ protected function routeResponse(TrackingContext $context): array
68
+ {
69
+ return OSRM::getRouteFromPoints($context->routePoints(), [
70
+ 'overview' => 'full',
71
+ 'geometries' => 'polyline',
72
+ 'steps' => 'false',
73
+ 'annotations' => 'false',
74
+ ]);
75
+ }
71
76
  }
@@ -6,7 +6,6 @@ use Fleetbase\FleetOps\Tracking\Contracts\TrackingProviderInterface;
6
6
  use Illuminate\Support\Arr;
7
7
  use Illuminate\Support\Facades\Cache;
8
8
  use Illuminate\Support\Facades\Log;
9
- use Illuminate\Support\Str;
10
9
 
11
10
  class TrackingProviderManager
12
11
  {
@@ -33,7 +32,7 @@ class TrackingProviderManager
33
32
  $result = $this->trackWithProviderCache($provider, $context, $options);
34
33
  $result->warnings = array_values(array_unique([...$warnings, ...$result->warnings]));
35
34
 
36
- if (Str::snake($result->provider) !== Str::snake((string) $options->provider)) {
35
+ if (TrackingProviderRegistry::normalizeKey($result->provider) !== TrackingProviderRegistry::normalizeKey($options->provider)) {
37
36
  $result->warnings[] = 'fallback_used';
38
37
  }
39
38
 
@@ -62,7 +61,7 @@ class TrackingProviderManager
62
61
 
63
62
  return collect([$provider, ...$fallbacks])
64
63
  ->filter()
65
- ->map(fn ($key) => Str::snake($key))
64
+ ->map(fn ($key) => TrackingProviderRegistry::normalizeKey($key))
66
65
  ->unique()
67
66
  ->values()
68
67
  ->all();