@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
@@ -3,6 +3,8 @@
3
3
  namespace Fleetbase\FleetOps\Models;
4
4
 
5
5
  use Fleetbase\Casts\Json;
6
+ use Fleetbase\FleetOps\Casts\Point;
7
+ use Fleetbase\LaravelMysqlSpatial\Eloquent\SpatialTrait;
6
8
  use Fleetbase\Models\Alert;
7
9
  use Fleetbase\Models\Company;
8
10
  use Fleetbase\Models\Model;
@@ -35,6 +37,7 @@ class DeviceEvent extends Model
35
37
  use LogsActivity;
36
38
  use HasMetaAttributes;
37
39
  use Searchable;
40
+ use SpatialTrait;
38
41
 
39
42
  /**
40
43
  * The database table used by the model.
@@ -55,14 +58,14 @@ class DeviceEvent extends Model
55
58
  *
56
59
  * @var array
57
60
  */
58
- protected $searchableColumns = ['event_type', 'message', 'public_id'];
61
+ protected $searchableColumns = ['event_type', 'message', 'ident', 'code', 'provider', 'public_id'];
59
62
 
60
63
  /**
61
64
  * The attributes that can be used for filtering.
62
65
  *
63
66
  * @var array
64
67
  */
65
- protected $filterParams = ['event_type', 'severity', 'device_uuid'];
68
+ protected $filterParams = ['event_type', 'severity', 'device_uuid', 'provider', 'code'];
66
69
 
67
70
  /**
68
71
  * The attributes that are mass assignable.
@@ -73,10 +76,12 @@ class DeviceEvent extends Model
73
76
  'company_uuid',
74
77
  'device_uuid',
75
78
  'payload',
79
+ 'data',
76
80
  'meta',
77
81
  'location',
78
82
  'event_type',
79
83
  'severity',
84
+ 'message',
80
85
  'ident',
81
86
  'protocol',
82
87
  'provider',
@@ -86,6 +91,8 @@ class DeviceEvent extends Model
86
91
  'reason',
87
92
  'comment',
88
93
  'resolved_at',
94
+ 'occurred_at',
95
+ 'processed_at',
89
96
  'slug',
90
97
  ];
91
98
 
@@ -108,6 +115,13 @@ class DeviceEvent extends Model
108
115
  */
109
116
  protected $hidden = ['device'];
110
117
 
118
+ /**
119
+ * The attributes that are spatial columns.
120
+ *
121
+ * @var array
122
+ */
123
+ protected $spatialFields = ['location'];
124
+
111
125
  /**
112
126
  * The attributes that should be cast to native types.
113
127
  *
@@ -115,8 +129,12 @@ class DeviceEvent extends Model
115
129
  */
116
130
  protected $casts = [
117
131
  'payload' => Json::class,
132
+ 'data' => Json::class,
118
133
  'meta' => Json::class,
134
+ 'location' => Point::class,
119
135
  'resolved_at' => 'datetime',
136
+ 'occurred_at' => 'datetime',
137
+ 'processed_at' => 'datetime',
120
138
  ];
121
139
 
122
140
  /**
@@ -145,7 +163,26 @@ class DeviceEvent extends Model
145
163
  */
146
164
  public function getActivitylogOptions(): LogOptions
147
165
  {
148
- return LogOptions::defaults()->logAll();
166
+ return LogOptions::defaults()
167
+ ->logOnly([
168
+ 'company_uuid',
169
+ 'device_uuid',
170
+ 'event_type',
171
+ 'severity',
172
+ 'message',
173
+ 'ident',
174
+ 'protocol',
175
+ 'provider',
176
+ 'mileage',
177
+ 'state',
178
+ 'code',
179
+ 'reason',
180
+ 'comment',
181
+ 'resolved_at',
182
+ 'occurred_at',
183
+ 'processed_at',
184
+ ])
185
+ ->logOnlyDirty();
149
186
  }
150
187
 
151
188
  public function company(): BelongsTo
@@ -196,7 +196,7 @@ class Driver extends Model
196
196
  *
197
197
  * @var array
198
198
  */
199
- protected $filterParams = ['vendor', 'facilitator', 'customer', 'fleet', 'photo_uuid', 'avatar_uuid', 'avatar_value'];
199
+ protected $filterParams = ['vendor', 'facilitator', 'customer', 'fleet', 'vehicle', 'photo_uuid', 'avatar_uuid', 'avatar_value'];
200
200
 
201
201
  /**
202
202
  * The session-agnostic columns for the model.
@@ -220,7 +220,8 @@ class Driver extends Model
220
220
  {
221
221
  return SlugOptions::create()
222
222
  ->generateSlugsFrom('drivers_license_number')
223
- ->saveSlugsTo('slug');
223
+ ->saveSlugsTo('slug')
224
+ ->doNotGenerateSlugsOnUpdate();
224
225
  }
225
226
 
226
227
  /**
@@ -155,7 +155,8 @@ class Equipment extends Model
155
155
  {
156
156
  return SlugOptions::create()
157
157
  ->generateSlugsFrom(['name', 'code'])
158
- ->saveSlugsTo('slug');
158
+ ->saveSlugsTo('slug')
159
+ ->doNotGenerateSlugsOnUpdate();
159
160
  }
160
161
 
161
162
  /**
@@ -66,7 +66,8 @@ class Fleet extends Model
66
66
  {
67
67
  return SlugOptions::create()
68
68
  ->generateSlugsFrom('name')
69
- ->saveSlugsTo('slug');
69
+ ->saveSlugsTo('slug')
70
+ ->doNotGenerateSlugsOnUpdate();
70
71
  }
71
72
 
72
73
  /**
@@ -0,0 +1,60 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Models;
4
+
5
+ use Fleetbase\Casts\Json;
6
+ use Fleetbase\Models\Model;
7
+ use Fleetbase\Traits\HasApiModelBehavior;
8
+ use Fleetbase\Traits\HasPublicId;
9
+ use Fleetbase\Traits\HasUuid;
10
+ use Fleetbase\Traits\Searchable;
11
+ use Fleetbase\Traits\TracksApiCredential;
12
+ use Illuminate\Database\Eloquent\Relations\HasMany;
13
+
14
+ class FuelProviderConnection extends Model
15
+ {
16
+ use HasUuid;
17
+ use HasPublicId;
18
+ use TracksApiCredential;
19
+ use HasApiModelBehavior;
20
+ use Searchable;
21
+
22
+ protected $table = 'fuel_provider_connections';
23
+ protected $publicIdType = 'fuel_provider_connection';
24
+ protected $searchableColumns = ['public_id', 'name', 'provider', 'status', 'environment'];
25
+ protected $filterParams = ['provider', 'status', 'environment'];
26
+
27
+ protected $fillable = [
28
+ 'company_uuid',
29
+ 'provider',
30
+ 'name',
31
+ 'environment',
32
+ 'status',
33
+ 'credentials',
34
+ 'sync_settings',
35
+ 'last_sync_state',
36
+ 'last_synced_at',
37
+ 'last_tested_at',
38
+ 'last_error',
39
+ 'meta',
40
+ ];
41
+
42
+ protected $casts = [
43
+ 'credentials' => Json::class,
44
+ 'sync_settings' => Json::class,
45
+ 'last_sync_state' => Json::class,
46
+ 'last_synced_at' => 'datetime',
47
+ 'last_tested_at' => 'datetime',
48
+ 'meta' => Json::class,
49
+ ];
50
+
51
+ public function transactions(): HasMany
52
+ {
53
+ return $this->hasMany(FuelProviderTransaction::class, 'fuel_provider_connection_uuid', 'uuid');
54
+ }
55
+
56
+ public function syncRuns(): HasMany
57
+ {
58
+ return $this->hasMany(FuelProviderSyncRun::class, 'fuel_provider_connection_uuid', 'uuid');
59
+ }
60
+ }
@@ -0,0 +1,58 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Models;
4
+
5
+ use Fleetbase\Casts\Json;
6
+ use Fleetbase\Models\Model;
7
+ use Fleetbase\Traits\HasApiModelBehavior;
8
+ use Fleetbase\Traits\HasPublicId;
9
+ use Fleetbase\Traits\HasUuid;
10
+ use Fleetbase\Traits\Searchable;
11
+ use Illuminate\Database\Eloquent\Relations\BelongsTo;
12
+
13
+ class FuelProviderSyncRun extends Model
14
+ {
15
+ use HasUuid;
16
+ use HasPublicId;
17
+ use HasApiModelBehavior;
18
+ use Searchable;
19
+
20
+ protected $table = 'fuel_provider_sync_runs';
21
+ protected $publicIdType = 'fuel_provider_sync_run';
22
+ protected $searchableColumns = ['public_id', 'provider', 'status'];
23
+ protected $filterParams = ['provider', 'status', 'connection'];
24
+
25
+ protected $fillable = [
26
+ 'company_uuid',
27
+ 'fuel_provider_connection_uuid',
28
+ 'provider',
29
+ 'status',
30
+ 'from',
31
+ 'to',
32
+ 'imported',
33
+ 'matched',
34
+ 'unmatched',
35
+ 'fuel_reports_created',
36
+ 'liters',
37
+ 'amount',
38
+ 'started_at',
39
+ 'finished_at',
40
+ 'error',
41
+ 'summary',
42
+ 'meta',
43
+ ];
44
+
45
+ protected $casts = [
46
+ 'from' => 'datetime',
47
+ 'to' => 'datetime',
48
+ 'started_at' => 'datetime',
49
+ 'finished_at' => 'datetime',
50
+ 'summary' => Json::class,
51
+ 'meta' => Json::class,
52
+ ];
53
+
54
+ public function connection(): BelongsTo
55
+ {
56
+ return $this->belongsTo(FuelProviderConnection::class, 'fuel_provider_connection_uuid', 'uuid');
57
+ }
58
+ }
@@ -0,0 +1,119 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Models;
4
+
5
+ use Fleetbase\Casts\Json;
6
+ use Fleetbase\LaravelMysqlSpatial\Types\Point;
7
+ use Fleetbase\Models\Model;
8
+ use Fleetbase\Traits\HasApiModelBehavior;
9
+ use Fleetbase\Traits\HasPublicId;
10
+ use Fleetbase\Traits\HasUuid;
11
+ use Fleetbase\Traits\Searchable;
12
+ use Illuminate\Database\Eloquent\Relations\BelongsTo;
13
+
14
+ class FuelProviderTransaction extends Model
15
+ {
16
+ use HasUuid;
17
+ use HasPublicId;
18
+ use HasApiModelBehavior;
19
+ use Searchable;
20
+
21
+ protected $table = 'fuel_provider_transactions';
22
+ protected $publicIdType = 'fuel_provider_transaction';
23
+ protected $searchableColumns = ['public_id', 'provider', 'provider_transaction_id', 'vehicle_card_id', 'internal_number', 'plate_number', 'vin', 'serial_number', 'call_sign', 'station_name', 'trip_number'];
24
+ protected $filterParams = ['provider', 'sync_status', 'vehicle', 'driver', 'order', 'fuel_report', 'connection'];
25
+
26
+ protected $fillable = [
27
+ 'company_uuid',
28
+ 'fuel_provider_connection_uuid',
29
+ 'fuel_report_uuid',
30
+ 'vehicle_uuid',
31
+ 'driver_uuid',
32
+ 'order_uuid',
33
+ 'provider',
34
+ 'provider_transaction_id',
35
+ 'provider_vehicle_id',
36
+ 'vehicle_card_id',
37
+ 'internal_number',
38
+ 'structure_number',
39
+ 'plate_number',
40
+ 'vin',
41
+ 'serial_number',
42
+ 'call_sign',
43
+ 'trip_number',
44
+ 'station_name',
45
+ 'station_latitude',
46
+ 'station_longitude',
47
+ 'transaction_at',
48
+ 'volume',
49
+ 'metric_unit',
50
+ 'amount',
51
+ 'currency',
52
+ 'odometer',
53
+ 'sync_status',
54
+ 'matched_at',
55
+ 'normalized_payload',
56
+ 'raw_payload',
57
+ 'meta',
58
+ ];
59
+
60
+ protected $casts = [
61
+ 'transaction_at' => 'datetime',
62
+ 'matched_at' => 'datetime',
63
+ 'normalized_payload' => Json::class,
64
+ 'raw_payload' => Json::class,
65
+ 'meta' => Json::class,
66
+ ];
67
+
68
+ protected $appends = ['vehicle_name', 'driver_name', 'fuel_report_id', 'station_location'];
69
+ protected $hidden = ['vehicle', 'driver', 'fuelReport'];
70
+
71
+ public function connection(): BelongsTo
72
+ {
73
+ return $this->belongsTo(FuelProviderConnection::class, 'fuel_provider_connection_uuid', 'uuid');
74
+ }
75
+
76
+ public function fuelReport(): BelongsTo
77
+ {
78
+ return $this->belongsTo(FuelReport::class, 'fuel_report_uuid', 'uuid');
79
+ }
80
+
81
+ public function vehicle(): BelongsTo
82
+ {
83
+ return $this->belongsTo(Vehicle::class, 'vehicle_uuid', 'uuid');
84
+ }
85
+
86
+ public function driver(): BelongsTo
87
+ {
88
+ return $this->belongsTo(Driver::class, 'driver_uuid', 'uuid');
89
+ }
90
+
91
+ public function order(): BelongsTo
92
+ {
93
+ return $this->belongsTo(Order::class, 'order_uuid', 'uuid');
94
+ }
95
+
96
+ public function getVehicleNameAttribute(): ?string
97
+ {
98
+ return data_get($this, 'vehicle.display_name');
99
+ }
100
+
101
+ public function getDriverNameAttribute(): ?string
102
+ {
103
+ return data_get($this, 'driver.name');
104
+ }
105
+
106
+ public function getFuelReportIdAttribute(): ?string
107
+ {
108
+ return data_get($this, 'fuelReport.public_id');
109
+ }
110
+
111
+ public function getStationLocationAttribute(): ?Point
112
+ {
113
+ if (!$this->station_latitude || !$this->station_longitude) {
114
+ return null;
115
+ }
116
+
117
+ return new Point($this->station_latitude, $this->station_longitude);
118
+ }
119
+ }
@@ -91,7 +91,7 @@ class FuelReport extends Model
91
91
  *
92
92
  * @var array
93
93
  */
94
- protected $appends = ['vehicle_name', 'driver_name', 'reporter_name'];
94
+ protected $appends = ['vehicle_name', 'driver_name', 'reporter_name', 'source', 'provider', 'fuel_provider_transaction_uuid'];
95
95
 
96
96
  /**
97
97
  * The attributes excluded from the model's JSON form.
@@ -179,6 +179,21 @@ class FuelReport extends Model
179
179
  return data_get($this, 'reportedBy.name');
180
180
  }
181
181
 
182
+ public function getSourceAttribute(): ?string
183
+ {
184
+ return data_get($this, 'meta.source');
185
+ }
186
+
187
+ public function getProviderAttribute(): ?string
188
+ {
189
+ return data_get($this, 'meta.provider');
190
+ }
191
+
192
+ public function getFuelProviderTransactionUuidAttribute(): ?string
193
+ {
194
+ return data_get($this, 'meta.fuel_provider_transaction_uuid');
195
+ }
196
+
182
197
  public static function createFromImport(array $row, bool $saveInstance = false): FuelReport
183
198
  {
184
199
  // Filter array for null key values
@@ -165,7 +165,8 @@ class Part extends Model
165
165
  {
166
166
  return SlugOptions::create()
167
167
  ->generateSlugsFrom(['name', 'sku'])
168
- ->saveSlugsTo('slug');
168
+ ->saveSlugsTo('slug')
169
+ ->doNotGenerateSlugsOnUpdate();
169
170
  }
170
171
 
171
172
  /**
@@ -66,14 +66,14 @@ class Sensor extends Model
66
66
  *
67
67
  * @var array
68
68
  */
69
- protected $searchableColumns = ['name', 'sensor_type', 'unit', 'public_id'];
69
+ protected $searchableColumns = ['name', 'type', 'internal_id', 'unit', 'public_id'];
70
70
 
71
71
  /**
72
72
  * The attributes that can be used for filtering.
73
73
  *
74
74
  * @var array
75
75
  */
76
- protected $filterParams = ['sensor_type', 'status', 'device_uuid', 'warranty_uuid', 'sensorable_type'];
76
+ protected $filterParams = ['type', 'sensor_type', 'status', 'device_uuid', 'warranty_uuid', 'sensorable_type', 'telematic_uuid'];
77
77
 
78
78
  /**
79
79
  * The attributes that are mass assignable.
@@ -178,7 +178,8 @@ class Sensor extends Model
178
178
  {
179
179
  return SlugOptions::create()
180
180
  ->generateSlugsFrom(['name', 'sensor_type'])
181
- ->saveSlugsTo('slug');
181
+ ->saveSlugsTo('slug')
182
+ ->doNotGenerateSlugsOnUpdate();
182
183
  }
183
184
 
184
185
  /**
@@ -186,7 +187,23 @@ class Sensor extends Model
186
187
  */
187
188
  public function getActivitylogOptions(): LogOptions
188
189
  {
189
- return LogOptions::defaults()->logAll();
190
+ return LogOptions::defaults()
191
+ ->logOnly([
192
+ 'company_uuid',
193
+ 'telematic_uuid',
194
+ 'device_uuid',
195
+ 'sensorable_uuid',
196
+ 'sensorable_type',
197
+ 'type',
198
+ 'sensor_type',
199
+ 'internal_id',
200
+ 'name',
201
+ 'unit',
202
+ 'last_value',
203
+ 'last_reading_at',
204
+ 'status',
205
+ ])
206
+ ->logOnlyDirty();
190
207
  }
191
208
 
192
209
  public function telematic(): BelongsTo
@@ -1130,8 +1130,9 @@ class ServiceRate extends Model
1130
1130
  $stopCount = collect($stops)->filter()->count();
1131
1131
  $endpointCount = max(0, min($endpointCount, $stopCount));
1132
1132
  $waypointCount = max($stopCount - $endpointCount, 0);
1133
+ $weightVariables = $this->buildAlgorithmWeightVariables($entityCollection);
1133
1134
 
1134
- return Algo::normalizeVariables([
1135
+ return Algo::normalizeVariables(array_merge([
1135
1136
  'distance_m' => $totalDistance ?? 0,
1136
1137
  'time_s' => $totalTime ?? 0,
1137
1138
  'stops' => $stopCount,
@@ -1139,7 +1140,43 @@ class ServiceRate extends Model
1139
1140
  'parcels' => $entityCollection->where('type', 'parcel')->count(),
1140
1141
  'entities' => $entityCollection->count(),
1141
1142
  'base_fee' => Utils::numbersOnly($this->base_fee ?? 0),
1142
- ]);
1143
+ ], $weightVariables));
1144
+ }
1145
+
1146
+ protected function buildAlgorithmWeightVariables($entities): array
1147
+ {
1148
+ $weightKg = collect($entities)->sum(fn ($entity) => $this->normalizeEntityWeightToKilograms($entity));
1149
+
1150
+ return [
1151
+ 'weight' => $weightKg,
1152
+ 'weight_kg' => $weightKg,
1153
+ 'weight_g' => $weightKg * 1000,
1154
+ 'weight_lb' => $weightKg / 0.45359237,
1155
+ 'weight_oz' => $weightKg / 0.028349523125,
1156
+ 'weight_tonne' => $weightKg / 1000,
1157
+ 'weight_t' => $weightKg / 1000,
1158
+ ];
1159
+ }
1160
+
1161
+ protected function normalizeEntityWeightToKilograms($entity): float
1162
+ {
1163
+ $weight = data_get($entity, 'weight');
1164
+
1165
+ if ($weight === null || $weight === '' || !is_numeric($weight)) {
1166
+ return 0;
1167
+ }
1168
+
1169
+ $weight = (float) $weight;
1170
+ $unit = strtolower(trim((string) data_get($entity, 'weight_unit', 'kg')));
1171
+
1172
+ return match ($unit) {
1173
+ 'g', 'gram', 'grams' => $weight / 1000,
1174
+ 'oz', 'ounce', 'ounces' => $weight * 0.028349523125,
1175
+ 'lb', 'lbs', 'pound', 'pounds' => $weight * 0.45359237,
1176
+ 't', 'mt', 'tonne', 'tonnes', 'metric_ton',
1177
+ 'metric_tons' => $weight * 1000,
1178
+ default => $weight,
1179
+ };
1143
1180
  }
1144
1181
 
1145
1182
  protected function inferEndpointCountFromStops($stops = []): int
@@ -65,7 +65,7 @@ class Vehicle extends Model
65
65
  *
66
66
  * @var array
67
67
  */
68
- protected $searchableColumns = ['name', 'description', 'make', 'model', 'trim', 'model_type', 'body_type', 'body_sub_type', 'year', 'plate_number', 'vin', 'call_sign', 'public_id'];
68
+ protected $searchableColumns = ['name', 'description', 'make', 'model', 'trim', 'model_type', 'body_type', 'body_sub_type', 'year', 'internal_id', 'plate_number', 'vin', 'serial_number', 'call_sign', 'fuel_card_number', 'public_id'];
69
69
 
70
70
  /**
71
71
  * Attributes that is filterable on this model.
@@ -96,7 +96,8 @@ class Vehicle extends Model
96
96
  {
97
97
  return SlugOptions::create()
98
98
  ->generateSlugsFrom(['year', 'make', 'model', 'trim', 'plate_number'])
99
- ->saveSlugsTo('slug');
99
+ ->saveSlugsTo('slug')
100
+ ->doNotGenerateSlugsOnUpdate();
100
101
  }
101
102
 
102
103
  /**
@@ -142,6 +143,7 @@ class Vehicle extends Model
142
143
  'internal_id',
143
144
  'plate_number',
144
145
  'call_sign',
146
+ 'fuel_card_number',
145
147
  'serial_number',
146
148
  'vin',
147
149
  'vin_data',
@@ -701,8 +703,12 @@ class Vehicle extends Model
701
703
  $year = Utils::or($row, ['year', 'vehicle_year', 'build_year', 'release_year']);
702
704
  $trim = Utils::or($row, ['trim', 'vehicle_trim', 'brand_trim']);
703
705
  $type = Utils::or($row, ['type', 'vehicle_type'], 'vehicle');
706
+ $internalId = Utils::or($row, ['internal_id', 'internal_number', 'fleet_number', 'vehicle_number']);
704
707
  $plateNumber = Utils::or($row, ['plate_number', 'license_plate', 'license_place_number', 'vehicle_plate', 'registration_plate', 'tag_number', 'tail_number', 'head_number']);
705
708
  $vin = Utils::or($row, ['vin', 'vin_number', 'vin_id', 'vehicle_identification_number', 'serial_number']);
709
+ $serialNumber = Utils::or($row, ['serial_number', 'serial', 'vehicle_serial_number']);
710
+ $callSign = Utils::or($row, ['call_sign', 'callsign', 'call_number']);
711
+ $fuelCardNumber = Utils::or($row, ['fuel_card_number', 'fuel_card', 'fuel_card_id', 'vehicle_card_id', 'card_number']);
706
712
  $driverAssigned = Utils::or($row, ['driver', 'driver_name', 'driver_assigned', 'driver_assignee']);
707
713
 
708
714
  // Handle when only a vehicle name is provided
@@ -741,8 +747,12 @@ class Vehicle extends Model
741
747
  'model' => $model,
742
748
  'year' => $year,
743
749
  'trim' => $trim,
750
+ 'internal_id' => $internalId,
744
751
  'plate_number' => $plateNumber,
745
752
  'vin' => $vin,
753
+ 'serial_number' => $serialNumber,
754
+ 'call_sign' => $callSign,
755
+ 'fuel_card_number' => $fuelCardNumber,
746
756
  'type' => $type,
747
757
  'status' => 'available',
748
758
  'online' => 0,
@@ -769,10 +779,12 @@ class Vehicle extends Model
769
779
 
770
780
  return static::where(function ($query) use ($vehicleName) {
771
781
  $query->where('public_id', $vehicleName)
782
+ ->orWhere('internal_id', $vehicleName)
772
783
  ->orWhere('plate_number', $vehicleName)
773
784
  ->orWhere('vin', $vehicleName)
774
785
  ->orWhere('serial_number', $vehicleName)
775
786
  ->orWhere('call_sign', $vehicleName)
787
+ ->orWhere('fuel_card_number', $vehicleName)
776
788
  ->orWhereRaw("CONCAT(make, ' ', model, ' ', year) LIKE ?", ["%{$vehicleName}%"])
777
789
  ->orWhereRaw("CONCAT(year, ' ', make, ' ', model) LIKE ?", ["%{$vehicleName}%"]);
778
790
  })->first();
@@ -134,7 +134,8 @@ class Vendor extends Model
134
134
  {
135
135
  return SlugOptions::create()
136
136
  ->generateSlugsFrom('name')
137
- ->saveSlugsTo('slug');
137
+ ->saveSlugsTo('slug')
138
+ ->doNotGenerateSlugsOnUpdate();
138
139
  }
139
140
 
140
141
  /**
@@ -7,6 +7,7 @@ use Brick\Geo\Engine\GEOSEngine;
7
7
  use Fleetbase\Providers\CoreServiceProvider;
8
8
  use Fleetbase\Support\NotificationRegistry;
9
9
  use Fleetbase\Support\Utils;
10
+ use Illuminate\Database\Eloquent\Relations\Relation;
10
11
 
11
12
  if (!Utils::classExists(CoreServiceProvider::class)) {
12
13
  throw new \Exception('FleetOps cannot be loaded without `fleetbase/core-api` installed!');
@@ -109,6 +110,15 @@ class FleetOpsServiceProvider extends CoreServiceProvider
109
110
  \Fleetbase\FleetOps\Tracking\TrackingProviderRegistry::class,
110
111
  fn () => new \Fleetbase\FleetOps\Tracking\TrackingProviderRegistry()
111
112
  );
113
+
114
+ // Register the fuel provider registry as a singleton so FleetOps core
115
+ // and third-party extensions can share fuel card and fuel billing
116
+ // providers. Extensions can register providers from their own service
117
+ // providers with callAfterResolving(FuelProviderRegistry::class, ...).
118
+ $this->app->singleton(
119
+ \Fleetbase\FleetOps\Support\FuelProviders\FuelProviderRegistry::class,
120
+ fn () => new \Fleetbase\FleetOps\Support\FuelProviders\FuelProviderRegistry()
121
+ );
112
122
  }
113
123
 
114
124
  /**
@@ -120,6 +130,7 @@ class FleetOpsServiceProvider extends CoreServiceProvider
120
130
  */
121
131
  public function boot()
122
132
  {
133
+ $this->registerMorphMap();
123
134
  $this->registerObservers();
124
135
  $this->registerCommands();
125
136
  $this->scheduleCommands(function ($schedule) {
@@ -173,6 +184,7 @@ class FleetOpsServiceProvider extends CoreServiceProvider
173
184
  $this->loadViewsFrom(__DIR__ . '/../../resources/views', 'fleetops');
174
185
  $this->mergeConfigFrom(__DIR__ . '/../../config/fleetops.php', 'fleetops');
175
186
  $this->mergeConfigFrom(__DIR__ . '/../../config/telematics.php', 'telematics');
187
+ $this->mergeConfigFrom(__DIR__ . '/../../config/fuel-providers.php', 'fuel-providers');
176
188
  $this->mergeConfigFrom(__DIR__ . '/../../config/api.php', 'api');
177
189
  $this->mergeConfigFrom(__DIR__ . '/../../config/cache.stores.php', 'cache.stores');
178
190
  $this->mergeConfigFrom(__DIR__ . '/../../config/geocoder.php', 'geocoder');
@@ -184,6 +196,14 @@ class FleetOpsServiceProvider extends CoreServiceProvider
184
196
  }
185
197
  }
186
198
 
199
+ public function registerMorphMap(): void
200
+ {
201
+ Relation::morphMap([
202
+ 'Fleetbase\\Models\\Vehicle' => \Fleetbase\FleetOps\Models\Vehicle::class,
203
+ '\\Fleetbase\\Models\\Vehicle' => \Fleetbase\FleetOps\Models\Vehicle::class,
204
+ ]);
205
+ }
206
+
187
207
  public function registerNotifications()
188
208
  {
189
209
  // Register Notifications