@fleetbase/fleetops-engine 0.6.51 → 0.6.53

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 (396) hide show
  1. package/README.md +0 -2
  2. package/addon/components/cell/telematic-provider.hbs +16 -0
  3. package/addon/components/cell/telematic-provider.js +36 -0
  4. package/addon/components/cell/telematic-status.hbs +1 -0
  5. package/addon/components/cell/telematic-status.js +39 -0
  6. package/addon/components/device/manager.hbs +5 -6
  7. package/addon/components/device/manager.js +12 -15
  8. package/addon/components/driver/details.hbs +1 -1
  9. package/addon/components/fleet/vehicle-listing.js +1 -0
  10. package/addon/components/fuel-integration/form.hbs +200 -0
  11. package/addon/components/fuel-integration/form.js +242 -0
  12. package/addon/components/fuel-integration/hub.hbs +154 -0
  13. package/addon/components/fuel-integration/hub.js +165 -0
  14. package/addon/components/fuel-integration/matching-priority.hbs +76 -0
  15. package/addon/components/fuel-integration/matching-priority.js +145 -0
  16. package/addon/components/fuel-report/details.hbs +13 -1
  17. package/addon/components/issue/details.hbs +3 -57
  18. package/addon/components/issue/details.js +0 -96
  19. package/addon/components/layout/fleet-ops-sidebar/operations-monitor.hbs +201 -0
  20. package/addon/components/layout/fleet-ops-sidebar/operations-monitor.js +589 -0
  21. package/addon/components/layout/fleet-ops-sidebar.hbs +19 -233
  22. package/addon/components/layout/fleet-ops-sidebar.js +287 -376
  23. package/addon/components/maintenance-schedule/form.js +1 -0
  24. package/addon/components/map/drawer/device-event-listing.hbs +12 -2
  25. package/addon/components/map/drawer/driver-listing.hbs +14 -1
  26. package/addon/components/map/drawer/place-listing.hbs +14 -1
  27. package/addon/components/map/drawer/position-listing.hbs +12 -2
  28. package/addon/components/map/drawer/vehicle-listing.hbs +14 -1
  29. package/addon/components/modals/assigned-orders.hbs +40 -0
  30. package/addon/components/modals/attach-device.hbs +4 -3
  31. package/addon/components/modals/attach-telematic-device.hbs +25 -0
  32. package/addon/components/modals/attach-telematic-device.js +3 -0
  33. package/addon/components/modals/driver-assign-order.hbs +7 -58
  34. package/addon/components/modals/driver-assign-vehicle.hbs +10 -2
  35. package/addon/components/modals/fleet-assign-driver.hbs +18 -0
  36. package/addon/components/modals/fleet-assign-driver.js +3 -0
  37. package/addon/components/modals/fleet-assign-vehicle.hbs +18 -0
  38. package/addon/components/modals/fleet-assign-vehicle.js +3 -0
  39. package/addon/components/modals/telematic-connection-diagnostics.hbs +75 -0
  40. package/addon/components/modals/telematic-connection-diagnostics.js +287 -0
  41. package/addon/components/modals/vehicle-details.hbs +6 -1
  42. package/addon/components/modals/vehicle-form.hbs +8 -1
  43. package/addon/components/order/card.hbs +106 -0
  44. package/addon/components/order/card.js +257 -0
  45. package/addon/components/order/form/payload.js +3 -1
  46. package/addon/components/order/form/service-rate.hbs +2 -0
  47. package/addon/components/service-rate/form.hbs +3 -2
  48. package/addon/components/telematic/details.hbs +98 -87
  49. package/addon/components/telematic/details.js +230 -1
  50. package/addon/components/telematic/form.hbs +303 -72
  51. package/addon/components/telematic/form.js +519 -3
  52. package/addon/components/telematic/hub.hbs +149 -0
  53. package/addon/components/telematic/hub.js +142 -0
  54. package/addon/components/telematic/settings.hbs +152 -0
  55. package/addon/components/telematic/settings.js +45 -0
  56. package/addon/components/telematic/tab-empty-state.hbs +29 -0
  57. package/addon/components/telematic/tab-empty-state.js +33 -0
  58. package/addon/components/vehicle/details.hbs +6 -1
  59. package/addon/components/vehicle/form.hbs +2 -1
  60. package/addon/components/widget/fuel-providers.hbs +43 -0
  61. package/addon/components/widget/fuel-providers.js +27 -0
  62. package/addon/controllers/connectivity/devices/index/details.js +27 -1
  63. package/addon/controllers/connectivity/devices/index.js +18 -1
  64. package/addon/controllers/connectivity/fuel-providers/details/sync.js +18 -0
  65. package/addon/controllers/connectivity/fuel-providers/details/transactions.js +24 -0
  66. package/addon/controllers/connectivity/fuel-providers/details.js +69 -0
  67. package/addon/controllers/connectivity/fuel-providers/edit.js +24 -0
  68. package/addon/controllers/connectivity/fuel-providers/index.js +177 -0
  69. package/addon/controllers/connectivity/fuel-providers/new.js +37 -0
  70. package/addon/controllers/connectivity/telematics/details/attachments.js +247 -0
  71. package/addon/controllers/connectivity/telematics/details/devices.js +368 -0
  72. package/addon/controllers/connectivity/telematics/details/events.js +244 -0
  73. package/addon/controllers/connectivity/telematics/details/index.js +3 -0
  74. package/addon/controllers/connectivity/telematics/details/logs.js +43 -0
  75. package/addon/controllers/connectivity/telematics/details/sensors.js +270 -0
  76. package/addon/controllers/connectivity/telematics/details.js +149 -0
  77. package/addon/controllers/connectivity/telematics/{index/edit.js → edit.js} +15 -4
  78. package/addon/controllers/connectivity/telematics/index.js +25 -5
  79. package/addon/controllers/connectivity/telematics/{index/new.js → new.js} +8 -2
  80. package/addon/controllers/maintenance/index.js +100 -0
  81. package/addon/controllers/management/drivers/index/details.js +78 -1
  82. package/addon/controllers/management/drivers/index.js +39 -0
  83. package/addon/controllers/management/fleets/index/details.js +23 -1
  84. package/addon/controllers/management/fleets/index.js +6 -1
  85. package/addon/controllers/management/fuel-reports/index.js +37 -1
  86. package/addon/controllers/management/fuel-transactions/index/details.js +70 -0
  87. package/addon/controllers/management/fuel-transactions/index.js +240 -0
  88. package/addon/controllers/management/index.js +88 -0
  89. package/addon/controllers/management/vehicles/index/details.js +32 -0
  90. package/addon/controllers/management/vehicles/index.js +26 -0
  91. package/addon/controllers/operations/orders/index.js +4 -0
  92. package/addon/controllers/settings/index.js +142 -0
  93. package/addon/controllers/settings/payments/index.js +5 -0
  94. package/addon/extension.js +31 -0
  95. package/addon/routes/analytics/index.js +3 -0
  96. package/addon/routes/connectivity/devices/index.js +3 -0
  97. package/addon/routes/connectivity/fuel-providers/details/index.js +7 -0
  98. package/addon/routes/connectivity/fuel-providers/details/matching.js +7 -0
  99. package/addon/routes/connectivity/fuel-providers/details/settings.js +7 -0
  100. package/addon/routes/connectivity/fuel-providers/details/sync.js +18 -0
  101. package/addon/routes/connectivity/fuel-providers/details/transactions.js +14 -0
  102. package/addon/routes/connectivity/fuel-providers/details.js +18 -0
  103. package/addon/routes/connectivity/fuel-providers/edit.js +18 -0
  104. package/addon/routes/connectivity/fuel-providers/index.js +20 -0
  105. package/addon/routes/connectivity/fuel-providers/new.js +3 -0
  106. package/addon/routes/connectivity/fuel-providers.js +3 -0
  107. package/addon/routes/connectivity/telematics/details/attachments.js +28 -0
  108. package/addon/routes/connectivity/telematics/details/devices.js +30 -0
  109. package/addon/routes/connectivity/telematics/details/events.js +33 -0
  110. package/addon/routes/connectivity/telematics/details/index.js +3 -0
  111. package/addon/routes/connectivity/telematics/details/logs.js +17 -0
  112. package/addon/routes/connectivity/telematics/details/sensors.js +29 -0
  113. package/addon/routes/connectivity/telematics/{index/details.js → details.js} +1 -1
  114. package/addon/routes/connectivity/telematics/{index/edit.js → edit.js} +1 -1
  115. package/addon/routes/connectivity/telematics/new.js +3 -0
  116. package/addon/routes/maintenance/index.js +3 -0
  117. package/addon/routes/maintenance/work-orders/index.js +2 -0
  118. package/addon/routes/management/drivers/index/details/activity.js +3 -0
  119. package/addon/routes/management/fuel-reports/index.js +2 -0
  120. package/addon/routes/management/fuel-transactions/index/details.js +18 -0
  121. package/addon/routes/management/fuel-transactions/index.js +21 -0
  122. package/addon/routes/management/fuel-transactions.js +3 -0
  123. package/addon/routes/settings/index.js +3 -0
  124. package/addon/routes.js +28 -9
  125. package/addon/services/device-actions.js +64 -1
  126. package/addon/services/device-event-actions.js +12 -1
  127. package/addon/services/driver-actions.js +147 -11
  128. package/addon/services/fleet-actions.js +66 -1
  129. package/addon/services/fuel-integration-actions.js +31 -0
  130. package/addon/services/issue-actions.js +1 -1
  131. package/addon/services/telematic-actions.js +9 -3
  132. package/addon/services/vehicle-actions.js +125 -0
  133. package/addon/styles/fleetops-engine.css +2237 -162
  134. package/addon/templates/analytics/index.hbs +14 -0
  135. package/addon/templates/analytics/reports/index.hbs +19 -1
  136. package/addon/templates/connectivity/devices/index.hbs +19 -1
  137. package/addon/templates/connectivity/events/index.hbs +16 -1
  138. package/addon/templates/connectivity/fuel-providers/details/index.hbs +38 -0
  139. package/addon/templates/connectivity/fuel-providers/details/matching.hbs +13 -0
  140. package/addon/templates/connectivity/fuel-providers/details/settings.hbs +11 -0
  141. package/addon/templates/connectivity/fuel-providers/details/sync.hbs +48 -0
  142. package/addon/templates/connectivity/fuel-providers/details/transactions.hbs +21 -0
  143. package/addon/templates/connectivity/fuel-providers/details.hbs +51 -0
  144. package/addon/templates/connectivity/fuel-providers/edit.hbs +24 -0
  145. package/addon/templates/connectivity/fuel-providers/index.hbs +12 -0
  146. package/addon/templates/connectivity/fuel-providers/new.hbs +22 -0
  147. package/addon/templates/connectivity/fuel-providers.hbs +1 -0
  148. package/addon/templates/connectivity/sensors/index.hbs +19 -1
  149. package/addon/templates/connectivity/telematics/details/attachments.hbs +163 -0
  150. package/addon/templates/connectivity/telematics/details/devices.hbs +88 -0
  151. package/addon/templates/connectivity/telematics/details/events.hbs +101 -0
  152. package/addon/templates/connectivity/telematics/{index/details → details}/index.hbs +0 -1
  153. package/addon/templates/connectivity/telematics/details/logs.hbs +69 -0
  154. package/addon/templates/connectivity/telematics/details/sensors.hbs +88 -0
  155. package/addon/templates/connectivity/telematics/details.hbs +53 -0
  156. package/addon/templates/connectivity/telematics/edit.hbs +27 -0
  157. package/addon/templates/connectivity/telematics/index.hbs +6 -8
  158. package/addon/templates/connectivity/telematics/new.hbs +24 -0
  159. package/addon/templates/maintenance/equipment/index.hbs +19 -1
  160. package/addon/templates/maintenance/index.hbs +113 -0
  161. package/addon/templates/maintenance/maintenances/index.hbs +15 -1
  162. package/addon/templates/maintenance/parts/index.hbs +19 -1
  163. package/addon/templates/maintenance/schedules/index.hbs +19 -1
  164. package/addon/templates/maintenance/work-orders/index.hbs +19 -1
  165. package/addon/templates/management/contacts/customers.hbs +15 -1
  166. package/addon/templates/management/contacts/index.hbs +19 -1
  167. package/addon/templates/management/drivers/index/details/activity.hbs +1 -0
  168. package/addon/templates/management/drivers/index.hbs +19 -1
  169. package/addon/templates/management/fleets/index.hbs +19 -1
  170. package/addon/templates/management/fuel-reports/index.hbs +19 -1
  171. package/addon/templates/management/fuel-transactions/index/details.hbs +73 -0
  172. package/addon/templates/management/fuel-transactions/index.hbs +58 -0
  173. package/addon/templates/management/fuel-transactions.hbs +1 -0
  174. package/addon/templates/management/index.hbs +109 -73
  175. package/addon/templates/management/issues/index.hbs +19 -1
  176. package/addon/templates/management/places/index.hbs +19 -1
  177. package/addon/templates/management/vehicles/index.hbs +19 -1
  178. package/addon/templates/management/vendors/index.hbs +19 -1
  179. package/addon/templates/management/vendors/integrated.hbs +13 -1
  180. package/addon/templates/operations/orders/index.hbs +19 -1
  181. package/addon/templates/operations/service-rates/index.hbs +19 -1
  182. package/addon/templates/settings/index.hbs +83 -0
  183. package/addon/templates/settings/payments/index.hbs +15 -1
  184. package/addon/templates/settings/routing.hbs +2 -2
  185. package/addon/utils/fleet-ops-options.js +3 -0
  186. package/app/components/cell/telematic-provider.js +1 -0
  187. package/app/components/cell/telematic-status.js +1 -0
  188. package/app/components/fuel-integration/form.js +1 -0
  189. package/app/components/fuel-integration/hub.js +1 -0
  190. package/app/components/fuel-integration/matching-priority.js +1 -0
  191. package/app/components/modals/assigned-orders.js +1 -0
  192. package/app/components/modals/attach-telematic-device.js +1 -0
  193. package/app/components/modals/fleet-assign-driver.js +1 -0
  194. package/app/components/modals/fleet-assign-vehicle.js +1 -0
  195. package/app/components/modals/telematic-connection-diagnostics.js +1 -0
  196. package/app/components/order/card.js +1 -0
  197. package/app/components/telematic/hub.js +1 -0
  198. package/app/components/telematic/settings.js +1 -0
  199. package/app/components/telematic/tab-empty-state.js +1 -0
  200. package/app/components/widget/fuel-providers.js +1 -0
  201. package/app/controllers/connectivity/fuel-providers/details/sync.js +1 -0
  202. package/app/controllers/connectivity/{telematics/index/details/devices.js → fuel-providers/details/transactions.js} +1 -1
  203. package/app/controllers/connectivity/{telematics/index → fuel-providers}/details.js +1 -1
  204. package/app/controllers/connectivity/{telematics/index → fuel-providers}/edit.js +1 -1
  205. package/app/controllers/connectivity/{telematics/index/details → fuel-providers}/index.js +1 -1
  206. package/app/controllers/connectivity/{telematics/index → fuel-providers}/new.js +1 -1
  207. package/app/controllers/connectivity/telematics/details/attachments.js +1 -0
  208. package/app/controllers/connectivity/telematics/details/devices.js +1 -0
  209. package/app/controllers/connectivity/telematics/details/events.js +1 -0
  210. package/app/controllers/connectivity/telematics/details/index.js +1 -0
  211. package/app/controllers/connectivity/telematics/details/logs.js +1 -0
  212. package/app/controllers/connectivity/telematics/details/sensors.js +1 -0
  213. package/app/controllers/connectivity/telematics/details.js +1 -0
  214. package/app/controllers/connectivity/telematics/edit.js +1 -0
  215. package/app/controllers/connectivity/telematics/new.js +1 -0
  216. package/app/controllers/maintenance/index.js +1 -0
  217. package/app/controllers/management/fuel-transactions/index/details.js +1 -0
  218. package/app/controllers/management/fuel-transactions/index.js +1 -0
  219. package/app/controllers/management/index.js +1 -0
  220. package/app/controllers/settings/index.js +1 -0
  221. package/app/routes/analytics/index.js +1 -0
  222. package/app/routes/connectivity/{telematics/index → fuel-providers}/details/index.js +1 -1
  223. package/app/routes/connectivity/{telematics/index/details/events.js → fuel-providers/details/matching.js} +1 -1
  224. package/app/routes/connectivity/fuel-providers/details/settings.js +1 -0
  225. package/app/routes/connectivity/fuel-providers/details/sync.js +1 -0
  226. package/app/routes/connectivity/{telematics/index/details/devices.js → fuel-providers/details/transactions.js} +1 -1
  227. package/app/routes/connectivity/{telematics/index → fuel-providers}/details.js +1 -1
  228. package/app/routes/connectivity/{telematics/index → fuel-providers}/edit.js +1 -1
  229. package/app/routes/connectivity/fuel-providers/index.js +1 -0
  230. package/app/routes/connectivity/{telematics/index → fuel-providers}/new.js +1 -1
  231. package/app/routes/connectivity/fuel-providers.js +1 -0
  232. package/app/routes/connectivity/telematics/details/attachments.js +1 -0
  233. package/app/routes/connectivity/telematics/details/devices.js +1 -0
  234. package/app/routes/connectivity/telematics/details/events.js +1 -0
  235. package/app/routes/connectivity/telematics/details/index.js +1 -0
  236. package/app/routes/connectivity/telematics/details/logs.js +1 -0
  237. package/app/routes/connectivity/telematics/details/sensors.js +1 -0
  238. package/app/routes/connectivity/telematics/details.js +1 -0
  239. package/app/routes/connectivity/telematics/edit.js +1 -0
  240. package/app/routes/connectivity/telematics/new.js +1 -0
  241. package/app/routes/maintenance/index.js +1 -0
  242. package/app/routes/management/drivers/index/details/activity.js +1 -0
  243. package/app/routes/management/fuel-transactions/index/details.js +1 -0
  244. package/app/routes/management/fuel-transactions/index.js +1 -0
  245. package/app/routes/management/fuel-transactions.js +1 -0
  246. package/app/routes/settings/index.js +1 -0
  247. package/app/services/fuel-integration-actions.js +1 -0
  248. package/app/templates/analytics/index.js +1 -0
  249. package/app/templates/connectivity/{telematics/index → fuel-providers}/details/index.js +1 -1
  250. package/app/templates/connectivity/{telematics/index/details/events.js → fuel-providers/details/matching.js} +1 -1
  251. package/app/templates/connectivity/fuel-providers/details/settings.js +1 -0
  252. package/app/templates/connectivity/fuel-providers/details/sync.js +1 -0
  253. package/app/templates/connectivity/{telematics/index/details/devices.js → fuel-providers/details/transactions.js} +1 -1
  254. package/app/templates/connectivity/{telematics/index → fuel-providers}/details.js +1 -1
  255. package/app/templates/connectivity/{telematics/index → fuel-providers}/edit.js +1 -1
  256. package/app/templates/connectivity/fuel-providers/index.js +1 -0
  257. package/app/templates/connectivity/{telematics/index → fuel-providers}/new.js +1 -1
  258. package/app/templates/connectivity/fuel-providers.js +1 -0
  259. package/app/templates/connectivity/telematics/details/attachments.js +1 -0
  260. package/app/templates/connectivity/telematics/details/devices.js +1 -0
  261. package/app/templates/connectivity/telematics/details/events.js +1 -0
  262. package/app/templates/connectivity/telematics/details/index.js +1 -0
  263. package/app/templates/connectivity/telematics/details/logs.js +1 -0
  264. package/app/templates/connectivity/telematics/details/sensors.js +1 -0
  265. package/app/templates/connectivity/telematics/details.js +1 -0
  266. package/app/templates/connectivity/telematics/edit.js +1 -0
  267. package/app/templates/connectivity/telematics/new.js +1 -0
  268. package/app/templates/maintenance/index.js +1 -0
  269. package/app/templates/management/drivers/index/details/activity.js +1 -0
  270. package/app/templates/management/fuel-transactions/index/details.js +1 -0
  271. package/app/templates/management/fuel-transactions/index.js +1 -0
  272. package/app/templates/management/fuel-transactions.js +1 -0
  273. package/app/templates/management/index.js +1 -0
  274. package/app/templates/settings/index.js +1 -0
  275. package/assets/images/telematics/providers/afaqy.webp +0 -0
  276. package/assets/images/telematics/providers/default.webp +0 -0
  277. package/assets/images/telematics/providers/flespi.webp +0 -0
  278. package/assets/images/telematics/providers/geotab.webp +0 -0
  279. package/assets/images/telematics/providers/safee.webp +0 -0
  280. package/assets/images/telematics/providers/samsara.webp +0 -0
  281. package/composer.json +1 -1
  282. package/extension.json +1 -1
  283. package/package.json +4 -4
  284. package/server/config/fuel-providers.php +42 -0
  285. package/server/config/telematics.php +139 -130
  286. package/server/migrations/2026_06_06_000001_harden_device_events_telematics_contract.php +59 -0
  287. package/server/migrations/2026_06_08_000001_create_fuel_provider_connections_table.php +37 -0
  288. package/server/migrations/2026_06_08_000002_create_fuel_provider_transactions_table.php +53 -0
  289. package/server/migrations/2026_06_08_000003_create_fuel_provider_sync_runs_table.php +40 -0
  290. package/server/migrations/2026_06_10_000001_add_fuel_card_number_to_vehicles_table.php +25 -0
  291. package/server/migrations/2026_06_10_000002_add_vehicle_identity_columns_to_fuel_provider_transactions_table.php +39 -0
  292. package/server/migrations/2026_06_15_000001_normalize_device_attachable_vehicle_morph_types.php +30 -0
  293. package/server/src/Console/Commands/FixInvalidPolymorphicRelationTypeNamespaces.php +1 -0
  294. package/server/src/Contracts/FuelProvider.php +30 -0
  295. package/server/src/Contracts/TelematicProviderDescriptor.php +3 -1
  296. package/server/src/Events/FuelProviderTransactionImported.php +17 -0
  297. package/server/src/Events/FuelProviderTransactionMatched.php +17 -0
  298. package/server/src/Events/FuelProviderTransactionUnmatched.php +17 -0
  299. package/server/src/Events/FuelReportCreatedFromProvider.php +18 -0
  300. package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +6 -0
  301. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +140 -2
  302. package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +44 -0
  303. package/server/src/Http/Controllers/Internal/v1/DriverController.php +158 -7
  304. package/server/src/Http/Controllers/Internal/v1/FuelProviderConnectionController.php +124 -0
  305. package/server/src/Http/Controllers/Internal/v1/FuelProviderSyncRunController.php +10 -0
  306. package/server/src/Http/Controllers/Internal/v1/FuelProviderTransactionController.php +76 -0
  307. package/server/src/Http/Controllers/Internal/v1/HubController.php +300 -0
  308. package/server/src/Http/Controllers/Internal/v1/SearchController.php +506 -0
  309. package/server/src/Http/Controllers/Internal/v1/SensorController.php +1 -1
  310. package/server/src/Http/Controllers/Internal/v1/TelematicController.php +179 -16
  311. package/server/src/Http/Controllers/Internal/v1/VehicleController.php +249 -0
  312. package/server/src/Http/Controllers/TelematicWebhookController.php +103 -19
  313. package/server/src/Http/Filter/DeviceFilter.php +74 -0
  314. package/server/src/Http/Filter/DriverFilter.php +6 -0
  315. package/server/src/Http/Filter/FuelProviderConnectionFilter.php +33 -0
  316. package/server/src/Http/Filter/FuelProviderSyncRunFilter.php +28 -0
  317. package/server/src/Http/Filter/FuelProviderTransactionFilter.php +59 -0
  318. package/server/src/Http/Filter/FuelReportFilter.php +10 -0
  319. package/server/src/Http/Filter/VehicleFilter.php +6 -0
  320. package/server/src/Http/Resources/v1/Driver.php +15 -0
  321. package/server/src/Http/Resources/v1/FuelProviderConnection.php +30 -0
  322. package/server/src/Http/Resources/v1/FuelProviderSyncRun.php +36 -0
  323. package/server/src/Http/Resources/v1/FuelProviderTransaction.php +54 -0
  324. package/server/src/Http/Resources/v1/FuelReport.php +28 -22
  325. package/server/src/Http/Resources/v1/Index/Driver.php +26 -20
  326. package/server/src/Http/Resources/v1/Index/Vehicle.php +29 -22
  327. package/server/src/Http/Resources/v1/Vehicle.php +17 -0
  328. package/server/src/Http/Resources/v1/VehicleWithoutDriver.php +2 -0
  329. package/server/src/Jobs/SyncFuelProviderTransactionsJob.php +57 -0
  330. package/server/src/Jobs/SyncTelematicDevicesJob.php +105 -17
  331. package/server/src/Jobs/TestTelematicConnectionJob.php +9 -22
  332. package/server/src/Models/Asset.php +2 -1
  333. package/server/src/Models/Contact.php +2 -1
  334. package/server/src/Models/Device.php +27 -4
  335. package/server/src/Models/DeviceEvent.php +40 -3
  336. package/server/src/Models/Driver.php +3 -2
  337. package/server/src/Models/Equipment.php +2 -1
  338. package/server/src/Models/Fleet.php +2 -1
  339. package/server/src/Models/FuelProviderConnection.php +60 -0
  340. package/server/src/Models/FuelProviderSyncRun.php +58 -0
  341. package/server/src/Models/FuelProviderTransaction.php +119 -0
  342. package/server/src/Models/FuelReport.php +16 -1
  343. package/server/src/Models/Part.php +2 -1
  344. package/server/src/Models/Sensor.php +21 -4
  345. package/server/src/Models/ServiceRate.php +39 -2
  346. package/server/src/Models/Vehicle.php +14 -2
  347. package/server/src/Models/Vendor.php +2 -1
  348. package/server/src/Providers/FleetOpsServiceProvider.php +20 -0
  349. package/server/src/Support/Analytics/FuelProviderSummary.php +42 -0
  350. package/server/src/Support/FuelProviders/FuelProviderDescriptor.php +55 -0
  351. package/server/src/Support/FuelProviders/FuelProviderRegistry.php +75 -0
  352. package/server/src/Support/FuelProviders/FuelProviderService.php +447 -0
  353. package/server/src/Support/FuelProviders/Providers/AbstractFuelProvider.php +98 -0
  354. package/server/src/Support/FuelProviders/Providers/PetroAppFuelProvider.php +167 -0
  355. package/server/src/Support/Telematics/Providers/AbstractProvider.php +27 -6
  356. package/server/src/Support/Telematics/Providers/AfaqyProvider.php +105 -38
  357. package/server/src/Support/Telematics/Providers/FlespiProvider.php +1 -0
  358. package/server/src/Support/Telematics/Providers/GeotabProvider.php +1 -0
  359. package/server/src/Support/Telematics/Providers/SafeeProvider.php +32 -22
  360. package/server/src/Support/Telematics/Providers/SamsaraProvider.php +3 -1
  361. package/server/src/Support/Telematics/TelematicService.php +340 -21
  362. package/server/src/routes.php +50 -4
  363. package/server/tests/FuelProviderRegistryTest.php +416 -0
  364. package/server/tests/HubRoutesTest.php +62 -0
  365. package/server/tests/ServiceRateAlgorithmWeightVariablesTest.php +44 -0
  366. package/server/tests/TelematicsHardeningTest.php +359 -0
  367. package/server/tests/VehicleDriverAssignmentTest.php +51 -0
  368. package/translations/ar-ae.yml +23 -1
  369. package/translations/bg-bg.yaml +72 -0
  370. package/translations/en-us.yaml +83 -0
  371. package/translations/es-pa.yaml +72 -0
  372. package/translations/fr-fr.yaml +72 -0
  373. package/translations/mn-mn.yaml +72 -0
  374. package/translations/pt-br.yaml +72 -0
  375. package/translations/ru-ru.yaml +72 -0
  376. package/translations/vi-vn.yaml +98 -1
  377. package/addon/controllers/connectivity/telematics/index/details/devices.js +0 -3
  378. package/addon/controllers/connectivity/telematics/index/details/events.js +0 -3
  379. package/addon/controllers/connectivity/telematics/index/details/index.js +0 -3
  380. package/addon/controllers/connectivity/telematics/index/details/sensors.js +0 -3
  381. package/addon/controllers/connectivity/telematics/index/details.js +0 -24
  382. package/addon/routes/connectivity/telematics/index/details/devices.js +0 -3
  383. package/addon/routes/connectivity/telematics/index/details/events.js +0 -3
  384. package/addon/routes/connectivity/telematics/index/details/index.js +0 -3
  385. package/addon/routes/connectivity/telematics/index/details/sensors.js +0 -3
  386. package/addon/routes/connectivity/telematics/index/new.js +0 -3
  387. package/addon/templates/connectivity/telematics/index/details/devices.hbs +0 -1
  388. package/addon/templates/connectivity/telematics/index/details/events.hbs +0 -1
  389. package/addon/templates/connectivity/telematics/index/details/sensors.hbs +0 -1
  390. package/addon/templates/connectivity/telematics/index/details.hbs +0 -14
  391. package/addon/templates/connectivity/telematics/index/edit.hbs +0 -12
  392. package/addon/templates/connectivity/telematics/index/new.hbs +0 -12
  393. package/app/controllers/connectivity/telematics/index/details/events.js +0 -1
  394. package/app/controllers/connectivity/telematics/index/details/sensors.js +0 -1
  395. package/app/routes/connectivity/telematics/index/details/sensors.js +0 -1
  396. package/app/templates/connectivity/telematics/index/details/sensors.js +0 -1
@@ -0,0 +1,30 @@
1
+ <?php
2
+
3
+ use Fleetbase\FleetOps\Models\Vehicle;
4
+ use Illuminate\Database\Migrations\Migration;
5
+ use Illuminate\Support\Facades\DB;
6
+ use Illuminate\Support\Facades\Schema;
7
+
8
+ return new class extends Migration {
9
+ public function up(): void
10
+ {
11
+ if (!Schema::hasTable('devices') || !Schema::hasColumn('devices', 'attachable_type') || !Schema::hasColumn('devices', 'attachable_uuid')) {
12
+ return;
13
+ }
14
+
15
+ DB::table('devices')
16
+ ->whereNotNull('attachable_uuid')
17
+ ->whereIn('attachable_type', [
18
+ 'Fleetbase\\Models\\Vehicle',
19
+ '\\Fleetbase\\Models\\Vehicle',
20
+ ])
21
+ ->update([
22
+ 'attachable_type' => Vehicle::class,
23
+ ]);
24
+ }
25
+
26
+ public function down(): void
27
+ {
28
+ // Intentionally do not restore invalid legacy morph class names.
29
+ }
30
+ };
@@ -37,6 +37,7 @@ class FixInvalidPolymorphicRelationTypeNamespaces extends Command
37
37
  ['model' => \Fleetbase\FleetOps\Models\Place::class, 'columns' => ['owner_type']],
38
38
  ['model' => \Fleetbase\FleetOps\Models\Entity::class, 'columns' => ['customer_type']],
39
39
  ['model' => \Fleetbase\FleetOps\Models\PurchaseRate::class, 'columns' => ['customer_type']],
40
+ ['model' => \Fleetbase\FleetOps\Models\Device::class, 'columns' => ['attachable_type']],
40
41
  ];
41
42
 
42
43
  foreach ($models as $modelConfig) {
@@ -0,0 +1,30 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Contracts;
4
+
5
+ use Fleetbase\FleetOps\Models\FuelProviderConnection;
6
+ use Illuminate\Support\Carbon;
7
+ use Illuminate\Support\Collection;
8
+
9
+ interface FuelProvider
10
+ {
11
+ public function key(): string;
12
+
13
+ public function name(): string;
14
+
15
+ public function authenticate(FuelProviderConnection $connection): array;
16
+
17
+ public function testConnection(FuelProviderConnection $connection): array;
18
+
19
+ public function listVehicles(FuelProviderConnection $connection, array $options = []): Collection;
20
+
21
+ public function listTransactions(FuelProviderConnection $connection, Carbon $from, Carbon $to, array $options = []): Collection;
22
+
23
+ public function listStations(FuelProviderConnection $connection, array $options = []): Collection;
24
+
25
+ public function pushTrip(FuelProviderConnection $connection, array $trip): array;
26
+
27
+ public function syncVehicle(FuelProviderConnection $connection, array $vehicle): array;
28
+
29
+ public function webhookPayloadToTransaction(FuelProviderConnection $connection, array $payload): ?array;
30
+ }
@@ -12,6 +12,8 @@ use Fleetbase\FleetOps\Support\Utils;
12
12
  */
13
13
  class TelematicProviderDescriptor
14
14
  {
15
+ public const DEFAULT_ICON = '/engines-dist/images/telematics/providers/default.webp';
16
+
15
17
  public string $key;
16
18
  public string $label;
17
19
  public string $type; // 'native' or 'custom'
@@ -33,7 +35,7 @@ class TelematicProviderDescriptor
33
35
  $this->label = $data['label'];
34
36
  $this->type = $data['type'] ?? 'native';
35
37
  $this->driverClass = $data['driver_class'] ?? null;
36
- $this->icon = $data['icon'] ?? null;
38
+ $this->icon = $data['icon'] ?? self::DEFAULT_ICON;
37
39
  $this->description = $data['description'] ?? null;
38
40
  $this->docsUrl = $data['docs_url'] ?? null;
39
41
  $this->requiredFields = $data['required_fields'] ?? [];
@@ -0,0 +1,17 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Events;
4
+
5
+ use Fleetbase\FleetOps\Models\FuelProviderTransaction;
6
+ use Illuminate\Foundation\Events\Dispatchable;
7
+ use Illuminate\Queue\SerializesModels;
8
+
9
+ class FuelProviderTransactionImported
10
+ {
11
+ use Dispatchable;
12
+ use SerializesModels;
13
+
14
+ public function __construct(public FuelProviderTransaction $transaction)
15
+ {
16
+ }
17
+ }
@@ -0,0 +1,17 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Events;
4
+
5
+ use Fleetbase\FleetOps\Models\FuelProviderTransaction;
6
+ use Illuminate\Foundation\Events\Dispatchable;
7
+ use Illuminate\Queue\SerializesModels;
8
+
9
+ class FuelProviderTransactionMatched
10
+ {
11
+ use Dispatchable;
12
+ use SerializesModels;
13
+
14
+ public function __construct(public FuelProviderTransaction $transaction)
15
+ {
16
+ }
17
+ }
@@ -0,0 +1,17 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Events;
4
+
5
+ use Fleetbase\FleetOps\Models\FuelProviderTransaction;
6
+ use Illuminate\Foundation\Events\Dispatchable;
7
+ use Illuminate\Queue\SerializesModels;
8
+
9
+ class FuelProviderTransactionUnmatched
10
+ {
11
+ use Dispatchable;
12
+ use SerializesModels;
13
+
14
+ public function __construct(public FuelProviderTransaction $transaction)
15
+ {
16
+ }
17
+ }
@@ -0,0 +1,18 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Events;
4
+
5
+ use Fleetbase\FleetOps\Models\FuelProviderTransaction;
6
+ use Fleetbase\FleetOps\Models\FuelReport;
7
+ use Illuminate\Foundation\Events\Dispatchable;
8
+ use Illuminate\Queue\SerializesModels;
9
+
10
+ class FuelReportCreatedFromProvider
11
+ {
12
+ use Dispatchable;
13
+ use SerializesModels;
14
+
15
+ public function __construct(public FuelProviderTransaction $transaction, public FuelReport $fuelReport)
16
+ {
17
+ }
18
+ }
@@ -4,6 +4,7 @@ namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
4
4
 
5
5
  use Fleetbase\FleetOps\Support\Analytics\AbstractAnalytics;
6
6
  use Fleetbase\FleetOps\Support\Analytics\FuelEfficiency;
7
+ use Fleetbase\FleetOps\Support\Analytics\FuelProviderSummary;
7
8
  use Fleetbase\FleetOps\Support\Analytics\GeofenceViolations;
8
9
  use Fleetbase\FleetOps\Support\Analytics\IssuesInsights;
9
10
  use Fleetbase\FleetOps\Support\Analytics\LiveFleet;
@@ -64,6 +65,11 @@ class AnalyticsController extends Controller
64
65
  return $this->run($request, FuelEfficiency::class, defaultDays: 90);
65
66
  }
66
67
 
68
+ public function fuelProviders(Request $request)
69
+ {
70
+ return $this->run($request, FuelProviderSummary::class, defaultDays: 30);
71
+ }
72
+
67
73
  public function issuesInsights(Request $request)
68
74
  {
69
75
  return $this->run($request, IssuesInsights::class);
@@ -3,6 +3,11 @@
3
3
  namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
4
4
 
5
5
  use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
6
+ use Fleetbase\FleetOps\Models\Device;
7
+ use Fleetbase\FleetOps\Models\Vehicle;
8
+ use Illuminate\Http\JsonResponse;
9
+ use Illuminate\Http\Request;
10
+ use Illuminate\Support\Facades\Log;
6
11
 
7
12
  class DeviceController extends FleetOpsController
8
13
  {
@@ -21,7 +26,23 @@ class DeviceController extends FleetOpsController
21
26
  */
22
27
  public static function onQueryRecord($query, $request): void
23
28
  {
24
- $query->with(['telematic', 'warranty']);
29
+ $query->with(['telematic', 'warranty', 'attachable']);
30
+
31
+ if ($request->filled('attachment_state')) {
32
+ match ($request->input('attachment_state')) {
33
+ 'attached' => $query->whereNotNull('attachable_uuid'),
34
+ 'unattached' => $query->whereNull('attachable_uuid'),
35
+ default => null,
36
+ };
37
+ }
38
+
39
+ if ($request->filled('vehicle')) {
40
+ $query->where('attachable_uuid', $request->input('vehicle'));
41
+ }
42
+
43
+ if ($request->filled('device_id')) {
44
+ $query->where('device_id', 'like', '%' . $request->input('device_id') . '%');
45
+ }
25
46
  }
26
47
 
27
48
  /**
@@ -32,6 +53,123 @@ class DeviceController extends FleetOpsController
32
53
  */
33
54
  public static function onFindRecord($query, $request): void
34
55
  {
35
- $query->with(['telematic', 'warranty']);
56
+ $query->with(['telematic', 'warranty', 'attachable']);
57
+ }
58
+
59
+ /**
60
+ * Attach a device to a supported FleetOps resource.
61
+ */
62
+ public function attach(Request $request, string $id): JsonResponse
63
+ {
64
+ $request->validate([
65
+ 'vehicle' => 'required_without:attachable_uuid|nullable|string',
66
+ ]);
67
+
68
+ $vehicleId = $request->input('vehicle') ?? $request->input('attachable_uuid');
69
+ $device = $this->resolveDevice($id);
70
+ $vehicle = $this->resolveVehicle($vehicleId);
71
+
72
+ if (!$device) {
73
+ $this->logDeviceAttachmentLookupFailure('attach', 'device', $id, $vehicleId);
74
+
75
+ return response()->error('Device not found or not available for this organization.', 404);
76
+ }
77
+
78
+ if (!$vehicle) {
79
+ $this->logDeviceAttachmentLookupFailure('attach', 'vehicle', $id, $vehicleId);
80
+
81
+ return response()->error('Vehicle not found or not available for this organization.', 404);
82
+ }
83
+
84
+ try {
85
+ $device->attachTo($vehicle);
86
+ $device->load(['telematic', 'warranty', 'attachable']);
87
+ } catch (\Throwable $e) {
88
+ $this->logDeviceAttachmentFailure('attach', $device, $vehicle, $e);
89
+
90
+ return response()->error('Unable to attach device to vehicle. Please try again or contact support.', 500);
91
+ }
92
+
93
+ return response()->json([
94
+ 'status' => 'ok',
95
+ 'device' => $device,
96
+ ]);
97
+ }
98
+
99
+ /**
100
+ * Detach a device from its current FleetOps resource.
101
+ */
102
+ public function detach(string $id): JsonResponse
103
+ {
104
+ $device = $this->resolveDevice($id);
105
+
106
+ if (!$device) {
107
+ $this->logDeviceAttachmentLookupFailure('detach', 'device', $id, null);
108
+
109
+ return response()->error('Device not found or not available for this organization.', 404);
110
+ }
111
+
112
+ try {
113
+ $device->detach();
114
+ $device->load(['telematic', 'warranty', 'attachable']);
115
+ } catch (\Throwable $e) {
116
+ $this->logDeviceAttachmentFailure('detach', $device, null, $e);
117
+
118
+ return response()->error('Unable to detach device from vehicle. Please try again or contact support.', 500);
119
+ }
120
+
121
+ return response()->json([
122
+ 'status' => 'ok',
123
+ 'device' => $device,
124
+ ]);
125
+ }
126
+
127
+ protected function resolveDevice(string $id): ?Device
128
+ {
129
+ return Device::where(function ($query) use ($id) {
130
+ $query->where('uuid', $id)->orWhere('public_id', $id);
131
+ })
132
+ ->where('company_uuid', session('company'))
133
+ ->first();
134
+ }
135
+
136
+ protected function resolveVehicle(?string $id): ?Vehicle
137
+ {
138
+ if (!$id) {
139
+ return null;
140
+ }
141
+
142
+ return Vehicle::where(function ($query) use ($id) {
143
+ $query->where('uuid', $id)->orWhere('public_id', $id);
144
+ })
145
+ ->where('company_uuid', session('company'))
146
+ ->first();
147
+ }
148
+
149
+ protected function logDeviceAttachmentLookupFailure(string $action, string $missingResource, string $deviceId, ?string $vehicleId): void
150
+ {
151
+ Log::warning('Device attachment lookup failed', [
152
+ 'action' => $action,
153
+ 'missing_resource' => $missingResource,
154
+ 'device_id' => $deviceId,
155
+ 'vehicle_id' => $vehicleId,
156
+ 'company_uuid' => session('company'),
157
+ 'request_id' => request()->headers->get('X-Request-ID') ?? request()->headers->get('X-Correlation-ID'),
158
+ ]);
159
+ }
160
+
161
+ protected function logDeviceAttachmentFailure(string $action, Device $device, ?Vehicle $vehicle, \Throwable $exception): void
162
+ {
163
+ Log::error('Device attachment failed', [
164
+ 'action' => $action,
165
+ 'device_uuid' => $device->uuid,
166
+ 'device_id' => $device->public_id,
167
+ 'vehicle_uuid' => $vehicle?->uuid,
168
+ 'vehicle_id' => $vehicle?->public_id,
169
+ 'company_uuid' => session('company'),
170
+ 'request_id' => request()->headers->get('X-Request-ID') ?? request()->headers->get('X-Correlation-ID'),
171
+ 'exception_class' => get_class($exception),
172
+ 'exception' => $exception->getMessage(),
173
+ ]);
36
174
  }
37
175
  }
@@ -3,6 +3,8 @@
3
3
  namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
4
4
 
5
5
  use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
6
+ use Fleetbase\FleetOps\Models\DeviceEvent;
7
+ use Illuminate\Http\JsonResponse;
6
8
 
7
9
  class DeviceEventController extends FleetOpsController
8
10
  {
@@ -12,4 +14,46 @@ class DeviceEventController extends FleetOpsController
12
14
  * @var string
13
15
  */
14
16
  public $resource = 'device-event';
17
+
18
+ /**
19
+ * Query callback when querying record.
20
+ *
21
+ * @param \Illuminate\Database\Query\Builder $query
22
+ * @param Request $request
23
+ */
24
+ public static function onQueryRecord($query, $request): void
25
+ {
26
+ $query->with(['device']);
27
+
28
+ if ($request->filled('telematic')) {
29
+ $query->whereHas('device', function ($deviceQuery) use ($request) {
30
+ $deviceQuery->where('telematic_uuid', $request->input('telematic'));
31
+ });
32
+ }
33
+
34
+ if ($request->filled('processed')) {
35
+ match ($request->input('processed')) {
36
+ 'processed' => $query->whereNotNull('processed_at'),
37
+ 'unprocessed' => $query->whereNull('processed_at'),
38
+ default => null,
39
+ };
40
+ }
41
+ }
42
+
43
+ public function markProcessed(string $id): JsonResponse
44
+ {
45
+ $deviceEvent = DeviceEvent::where('company_uuid', session('company'))
46
+ ->where(function ($query) use ($id) {
47
+ $query->where('uuid', $id)->orWhere('public_id', $id);
48
+ })
49
+ ->firstOrFail();
50
+
51
+ $processed = $deviceEvent->markAsProcessed();
52
+
53
+ return response()->json([
54
+ 'status' => 'ok',
55
+ 'message' => $processed ? 'Event marked processed.' : 'Event was already processed.',
56
+ 'device_event' => $deviceEvent->fresh(),
57
+ ]);
58
+ }
15
59
  }
@@ -6,12 +6,13 @@ use Fleetbase\Exceptions\FleetbaseRequestValidationException;
6
6
  use Fleetbase\FleetOps\Exports\DriverExport;
7
7
  use Fleetbase\FleetOps\Http\Controllers\Api\v1\DriverController as ApiDriverController;
8
8
  use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
9
- use Fleetbase\FleetOps\Http\Requests\Internal\AssignOrderRequest;
10
9
  use Fleetbase\FleetOps\Http\Requests\Internal\CreateDriverRequest;
11
10
  use Fleetbase\FleetOps\Http\Requests\Internal\UpdateDriverRequest;
11
+ use Fleetbase\FleetOps\Http\Resources\v1\Index\Order as IndexOrderResource;
12
12
  use Fleetbase\FleetOps\Imports\DriverImport;
13
13
  use Fleetbase\FleetOps\Models\Driver;
14
14
  use Fleetbase\FleetOps\Models\Order;
15
+ use Fleetbase\FleetOps\Models\Vehicle;
15
16
  use Fleetbase\FleetOps\Support\Utils;
16
17
  use Fleetbase\Http\Requests\ExportRequest;
17
18
  use Fleetbase\Http\Requests\ImportRequest;
@@ -21,6 +22,7 @@ use Fleetbase\Models\User;
21
22
  use Fleetbase\Models\VerificationCode;
22
23
  use Fleetbase\Support\Auth;
23
24
  use Illuminate\Database\QueryException;
25
+ use Illuminate\Http\JsonResponse;
24
26
  use Illuminate\Http\Request;
25
27
  use Illuminate\Support\Facades\DB;
26
28
  use Illuminate\Support\Facades\Validator;
@@ -303,7 +305,7 @@ class DriverController extends FleetOpsController
303
305
  function (&$request, &$driver, &$input) {
304
306
  $driver->load(['user'])->guard(['user_uuid']);
305
307
  $input = collect($input);
306
- $userInput = $input->only(['name', 'password', 'email', 'phone', 'avatar_uuid'])->toArray();
308
+ $userInput = $input->only(['name', 'password', 'email', 'phone', 'avatar_uuid'])->reject(fn ($value) => $value === null)->toArray();
307
309
  // handle `photo_uuid`
308
310
  if (isset($input['photo_uuid']) && Str::isUuid($input['photo_uuid'])) {
309
311
  $userInput['avatar_uuid'] = $input['photo_uuid'];
@@ -312,9 +314,8 @@ class DriverController extends FleetOpsController
312
314
 
313
315
  // Update driver user details
314
316
  $driverUser = $driver->getUser();
315
- if ($driverUser) {
317
+ if ($driverUser && !empty($userInput)) {
316
318
  $driverUser->update($userInput);
317
- $input['slug'] = $driverUser->slug;
318
319
  }
319
320
 
320
321
  // Flush cache
@@ -396,10 +397,18 @@ class DriverController extends FleetOpsController
396
397
  *
397
398
  * @return \Illuminate\Http\Response $response
398
399
  */
399
- public function assignOrder(AssignOrderRequest $request)
400
+ public function assignOrder(Request $request, ?string $id = null)
400
401
  {
401
- $driver = Driver::where('public_id', $request->driver)->first();
402
- $order = Order::where('public_id', $request->order)->first();
402
+ $request->validate([
403
+ 'driver' => ($id ? 'nullable' : 'required') . '|string',
404
+ 'order' => 'required|string',
405
+ ]);
406
+
407
+ $driverIdentifier = $id ?? $request->input('driver');
408
+ $orderIdentifier = $request->input('order');
409
+
410
+ $driver = $this->findDriver($driverIdentifier);
411
+ $order = $this->findOrder($orderIdentifier);
403
412
 
404
413
  if ($order->hasDriverAssigned) {
405
414
  return response()->error('A driver is already assigned to this order.');
@@ -410,13 +419,155 @@ class DriverController extends FleetOpsController
410
419
  }
411
420
 
412
421
  $order->assignDriver($driver);
422
+ $driver->update(['current_job_uuid' => $order->uuid]);
413
423
 
414
424
  return response()->json([
415
425
  'status' => 'ok',
416
426
  'message' => 'Driver assigned',
427
+ 'driver' => $driver->fresh(['vehicle', 'currentOrder']),
428
+ 'order' => $order->fresh(['driverAssigned']),
429
+ ]);
430
+ }
431
+
432
+ public function assignedOrders(string $id): JsonResponse
433
+ {
434
+ $driver = $this->findDriver($id);
435
+ $orders = Order::where('driver_assigned_uuid', $driver->uuid)
436
+ ->where('company_uuid', session('company'))
437
+ ->with(['payload', 'trackingNumber', 'orderConfig', 'driverAssigned', 'vehicleAssigned'])
438
+ ->orderByRaw('uuid = ? desc', [$driver->current_job_uuid])
439
+ ->latest()
440
+ ->get();
441
+
442
+ return response()->json([
443
+ 'status' => 'ok',
444
+ 'driver' => $driver->fresh(['vehicle', 'currentOrder']),
445
+ 'orders' => IndexOrderResource::collection($orders)->resolve(),
446
+ 'current' => $driver->current_job_uuid,
447
+ 'count' => $orders->count(),
448
+ ]);
449
+ }
450
+
451
+ public function unassignOrders(Request $request, string $id): JsonResponse
452
+ {
453
+ $request->validate([
454
+ 'orders' => 'required|array|min:1',
455
+ 'orders.*' => 'required|string',
456
+ ]);
457
+
458
+ $driver = $this->findDriver($id);
459
+ $ids = collect($request->input('orders'))->filter()->unique()->values();
460
+ $orders = Order::where('driver_assigned_uuid', $driver->uuid)
461
+ ->where('company_uuid', session('company'))
462
+ ->where(function ($query) use ($ids) {
463
+ $query->whereIn('uuid', $ids)->orWhereIn('public_id', $ids);
464
+ })
465
+ ->get();
466
+
467
+ if ($orders->isEmpty()) {
468
+ return response()->error('No assigned orders were selected for this driver.');
469
+ }
470
+
471
+ DB::transaction(function () use ($driver, $orders): void {
472
+ Order::whereIn('uuid', $orders->pluck('uuid'))->update([
473
+ 'driver_assigned_uuid' => null,
474
+ 'updated_at' => now(),
475
+ ]);
476
+
477
+ if ($driver->current_job_uuid && $orders->contains('uuid', $driver->current_job_uuid)) {
478
+ $driver->update(['current_job_uuid' => null]);
479
+ }
480
+ });
481
+
482
+ return response()->json([
483
+ 'status' => 'ok',
484
+ 'message' => 'Driver unassigned from selected orders.',
485
+ 'driver' => $driver->fresh(['vehicle', 'currentOrder']),
486
+ 'orders' => IndexOrderResource::collection($orders->fresh(['driverAssigned', 'vehicleAssigned']))->resolve(),
487
+ 'count' => $orders->count(),
488
+ ]);
489
+ }
490
+
491
+ public function unassignOrder(string $id): JsonResponse
492
+ {
493
+ $driver = $this->findDriver($id);
494
+ $order = Order::where('driver_assigned_uuid', $driver->uuid)
495
+ ->where('company_uuid', session('company'))
496
+ ->first() ?? $driver->getCurrentOrder();
497
+
498
+ if ($order) {
499
+ $order->update(['driver_assigned_uuid' => null]);
500
+ }
501
+
502
+ $driver->unassignCurrentJob();
503
+
504
+ return response()->json([
505
+ 'status' => 'ok',
506
+ 'message' => 'Driver unassigned from order.',
507
+ 'driver' => $driver->fresh(['vehicle', 'currentOrder']),
508
+ 'order' => $order?->fresh(['driverAssigned']),
417
509
  ]);
418
510
  }
419
511
 
512
+ public function assignVehicle(Request $request, string $id): JsonResponse
513
+ {
514
+ $request->validate(['vehicle' => 'required|string']);
515
+
516
+ $driver = $this->findDriver($id);
517
+ $vehicle = $this->findVehicle($request->input('vehicle'));
518
+
519
+ $driver->assignVehicle($vehicle);
520
+
521
+ return response()->json([
522
+ 'status' => 'ok',
523
+ 'message' => 'Vehicle assigned to driver.',
524
+ 'driver' => $driver->fresh(['vehicle', 'currentOrder']),
525
+ 'vehicle' => $vehicle->fresh(['driver']),
526
+ ]);
527
+ }
528
+
529
+ public function unassignVehicle(string $id): JsonResponse
530
+ {
531
+ $driver = $this->findDriver($id);
532
+ $vehicle = $driver->vehicle;
533
+
534
+ $driver->update(['vehicle_uuid' => null]);
535
+
536
+ return response()->json([
537
+ 'status' => 'ok',
538
+ 'message' => 'Vehicle unassigned from driver.',
539
+ 'driver' => $driver->fresh(['vehicle', 'currentOrder']),
540
+ 'vehicle' => $vehicle?->fresh(['driver']),
541
+ ]);
542
+ }
543
+
544
+ protected function findDriver(?string $id): Driver
545
+ {
546
+ return Driver::where(function ($query) use ($id) {
547
+ $query->where('uuid', $id)->orWhere('public_id', $id);
548
+ })
549
+ ->where('company_uuid', session('company'))
550
+ ->firstOrFail();
551
+ }
552
+
553
+ protected function findOrder(?string $id): Order
554
+ {
555
+ return Order::where(function ($query) use ($id) {
556
+ $query->where('uuid', $id)->orWhere('public_id', $id);
557
+ })
558
+ ->where('company_uuid', session('company'))
559
+ ->firstOrFail();
560
+ }
561
+
562
+ protected function findVehicle(?string $id): Vehicle
563
+ {
564
+ return Vehicle::where(function ($query) use ($id) {
565
+ $query->where('uuid', $id)->orWhere('public_id', $id);
566
+ })
567
+ ->where('company_uuid', session('company'))
568
+ ->firstOrFail();
569
+ }
570
+
420
571
  /**
421
572
  * Update drivers geolocation data.
422
573
  *