@fleetbase/fleetops-engine 0.6.50 → 0.6.52

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 (494) hide show
  1. package/README.md +183 -67
  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/contact/panel-header.hbs +11 -48
  7. package/addon/components/customer/details.hbs +1 -2
  8. package/addon/components/customer/form.hbs +63 -51
  9. package/addon/components/customer/form.js +27 -1
  10. package/addon/components/customer/orders.hbs +48 -0
  11. package/addon/components/customer/orders.js +67 -5
  12. package/addon/components/device/manager.hbs +5 -6
  13. package/addon/components/device/manager.js +12 -15
  14. package/addon/components/driver/details.hbs +1 -1
  15. package/addon/components/driver/form.hbs +1 -1
  16. package/addon/components/fleet/vehicle-listing.js +1 -0
  17. package/addon/components/fuel-integration/form.hbs +200 -0
  18. package/addon/components/fuel-integration/form.js +242 -0
  19. package/addon/components/fuel-integration/hub.hbs +154 -0
  20. package/addon/components/fuel-integration/hub.js +165 -0
  21. package/addon/components/fuel-integration/matching-priority.hbs +76 -0
  22. package/addon/components/fuel-integration/matching-priority.js +145 -0
  23. package/addon/components/fuel-report/details.hbs +13 -1
  24. package/addon/components/home/getting-started-guidance.hbs +113 -0
  25. package/addon/components/home/getting-started-guidance.js +107 -0
  26. package/addon/components/issue/details/comments.hbs +3 -0
  27. package/addon/components/issue/details/comments.js +3 -0
  28. package/addon/components/issue/details/correspondence.hbs +9 -0
  29. package/addon/components/issue/details/correspondence.js +83 -0
  30. package/addon/components/issue/details/documents.hbs +69 -0
  31. package/addon/components/issue/details/documents.js +85 -0
  32. package/addon/components/issue/details.hbs +166 -59
  33. package/addon/components/issue/details.js +149 -0
  34. package/addon/components/issue/form.hbs +19 -1
  35. package/addon/components/issue/panel-header.hbs +43 -0
  36. package/addon/components/issue/panel-header.js +22 -0
  37. package/addon/components/issue/timeline.hbs +40 -0
  38. package/addon/components/issue/timeline.js +45 -0
  39. package/addon/components/layout/fleet-ops-sidebar.js +20 -2
  40. package/addon/components/leaflet-tracking-marker.js +3 -0
  41. package/addon/components/map/drawer/device-event-listing.hbs +12 -2
  42. package/addon/components/map/drawer/driver-listing.hbs +14 -1
  43. package/addon/components/map/drawer/place-listing.hbs +14 -1
  44. package/addon/components/map/drawer/position-listing.hbs +12 -2
  45. package/addon/components/map/drawer/position-listing.js +3 -0
  46. package/addon/components/map/drawer/vehicle-listing.hbs +14 -1
  47. package/addon/components/map/leaflet-live-map.hbs +2 -2
  48. package/addon/components/map/leaflet-live-map.js +17 -0
  49. package/addon/components/map/order-list-overlay.hbs +4 -4
  50. package/addon/components/modals/assigned-orders.hbs +40 -0
  51. package/addon/components/modals/attach-device.hbs +4 -3
  52. package/addon/components/modals/attach-telematic-device.hbs +25 -0
  53. package/addon/components/modals/attach-telematic-device.js +3 -0
  54. package/addon/components/modals/convert-customer-to-vendor.hbs +30 -0
  55. package/addon/components/modals/convert-customer-to-vendor.js +55 -0
  56. package/addon/components/modals/driver-assign-order.hbs +7 -58
  57. package/addon/components/modals/driver-assign-vehicle.hbs +10 -2
  58. package/addon/components/modals/fleet-assign-driver.hbs +18 -0
  59. package/addon/components/modals/fleet-assign-driver.js +3 -0
  60. package/addon/components/modals/fleet-assign-vehicle.hbs +18 -0
  61. package/addon/components/modals/fleet-assign-vehicle.js +3 -0
  62. package/addon/components/modals/issue-assign.hbs +20 -0
  63. package/addon/components/modals/issue-assign.js +49 -0
  64. package/addon/components/modals/issue-close.hbs +30 -0
  65. package/addon/components/modals/issue-close.js +73 -0
  66. package/addon/components/modals/issue-status.hbs +20 -0
  67. package/addon/components/modals/issue-status.js +43 -0
  68. package/addon/components/modals/reset-customer-credentials.js +12 -6
  69. package/addon/components/modals/telematic-connection-diagnostics.hbs +75 -0
  70. package/addon/components/modals/telematic-connection-diagnostics.js +287 -0
  71. package/addon/components/modals/update-order-activity.hbs +51 -17
  72. package/addon/components/modals/update-order-activity.js +59 -5
  73. package/addon/components/modals/vehicle-details.hbs +6 -1
  74. package/addon/components/modals/vehicle-form.hbs +8 -1
  75. package/addon/components/order/card.hbs +106 -0
  76. package/addon/components/order/card.js +257 -0
  77. package/addon/components/order/details/activity.js +2 -2
  78. package/addon/components/order/details/proof.hbs +40 -38
  79. package/addon/components/order/details/proof.js +31 -4
  80. package/addon/components/order/details.hbs +5 -5
  81. package/addon/components/order/details.js +19 -1
  82. package/addon/components/order/form/service-rate.hbs +2 -0
  83. package/addon/components/order/header.hbs +1 -1
  84. package/addon/components/route-list.hbs +0 -12
  85. package/addon/components/service-rate/details.hbs +1 -1
  86. package/addon/components/service-rate/form.hbs +4 -3
  87. package/addon/components/service-rate/form.js +4 -0
  88. package/addon/components/telematic/details.hbs +98 -87
  89. package/addon/components/telematic/details.js +230 -1
  90. package/addon/components/telematic/form.hbs +303 -72
  91. package/addon/components/telematic/form.js +519 -3
  92. package/addon/components/telematic/hub.hbs +149 -0
  93. package/addon/components/telematic/hub.js +142 -0
  94. package/addon/components/telematic/settings.hbs +152 -0
  95. package/addon/components/telematic/settings.js +45 -0
  96. package/addon/components/telematic/tab-empty-state.hbs +29 -0
  97. package/addon/components/telematic/tab-empty-state.js +33 -0
  98. package/addon/components/vehicle/details.hbs +6 -1
  99. package/addon/components/vehicle/form.hbs +2 -1
  100. package/addon/components/vendor/personnel-manager.hbs +166 -0
  101. package/addon/components/vendor/personnel-manager.js +143 -0
  102. package/addon/components/widget/fuel-providers.hbs +43 -0
  103. package/addon/components/widget/fuel-providers.js +27 -0
  104. package/addon/components/widget/live-fleet.hbs +1 -0
  105. package/addon/components/widget/live-fleet.js +2 -7
  106. package/addon/components/widget/revenue-trend.hbs +1 -1
  107. package/addon/components/widget/revenue-trend.js +75 -2
  108. package/addon/controllers/connectivity/devices/index/details.js +27 -1
  109. package/addon/controllers/connectivity/devices/index.js +14 -0
  110. package/addon/controllers/connectivity/fuel-providers/details/sync.js +18 -0
  111. package/addon/controllers/connectivity/fuel-providers/details/transactions.js +24 -0
  112. package/addon/controllers/connectivity/fuel-providers/details.js +69 -0
  113. package/addon/controllers/connectivity/fuel-providers/edit.js +24 -0
  114. package/addon/controllers/connectivity/fuel-providers/index.js +177 -0
  115. package/addon/controllers/connectivity/fuel-providers/new.js +37 -0
  116. package/addon/controllers/connectivity/telematics/details/attachments.js +247 -0
  117. package/addon/controllers/connectivity/telematics/details/devices.js +368 -0
  118. package/addon/controllers/connectivity/telematics/details/events.js +244 -0
  119. package/addon/controllers/connectivity/telematics/details/index.js +3 -0
  120. package/addon/controllers/connectivity/telematics/details/logs.js +43 -0
  121. package/addon/controllers/connectivity/telematics/details/sensors.js +270 -0
  122. package/addon/controllers/connectivity/telematics/details.js +149 -0
  123. package/addon/controllers/connectivity/telematics/{index/edit.js → edit.js} +15 -4
  124. package/addon/controllers/connectivity/telematics/index.js +25 -5
  125. package/addon/controllers/connectivity/telematics/{index/new.js → new.js} +8 -2
  126. package/addon/controllers/management/contacts/customers/details.js +31 -13
  127. package/addon/controllers/management/contacts/customers.js +16 -5
  128. package/addon/controllers/management/contacts/index/details.js +31 -13
  129. package/addon/controllers/management/contacts/index.js +7 -0
  130. package/addon/controllers/management/drivers/index/details.js +78 -1
  131. package/addon/controllers/management/drivers/index.js +39 -0
  132. package/addon/controllers/management/fleets/index/details.js +23 -1
  133. package/addon/controllers/management/fleets/index.js +6 -1
  134. package/addon/controllers/management/fuel-reports/index.js +37 -1
  135. package/addon/controllers/management/fuel-transactions/index/details.js +70 -0
  136. package/addon/controllers/management/fuel-transactions/index.js +240 -0
  137. package/addon/controllers/management/issues/index/details.js +52 -6
  138. package/addon/controllers/management/vehicles/index/details.js +32 -0
  139. package/addon/controllers/management/vehicles/index.js +26 -0
  140. package/addon/controllers/management/vendors/index/details.js +4 -0
  141. package/addon/controllers/operations/orders/index/details.js +11 -3
  142. package/addon/controllers/operations/orders/index.js +5 -1
  143. package/addon/controllers/settings/payments/index.js +5 -0
  144. package/addon/extension.js +29 -12
  145. package/addon/helpers/format-duration.js +1 -38
  146. package/addon/initializers/load-leaflet-assets.js +5 -6
  147. package/addon/initializers/patch-ember-leaflet-tooltip-layer.js +51 -0
  148. package/addon/routes/connectivity/fuel-providers/details/index.js +7 -0
  149. package/addon/routes/connectivity/fuel-providers/details/matching.js +7 -0
  150. package/addon/routes/connectivity/fuel-providers/details/settings.js +7 -0
  151. package/addon/routes/connectivity/fuel-providers/details/sync.js +18 -0
  152. package/addon/routes/connectivity/fuel-providers/details/transactions.js +14 -0
  153. package/addon/routes/connectivity/fuel-providers/details.js +18 -0
  154. package/addon/routes/connectivity/fuel-providers/edit.js +18 -0
  155. package/addon/routes/connectivity/fuel-providers/index.js +20 -0
  156. package/addon/routes/connectivity/fuel-providers/new.js +3 -0
  157. package/addon/routes/connectivity/fuel-providers.js +3 -0
  158. package/addon/routes/connectivity/telematics/details/attachments.js +28 -0
  159. package/addon/routes/connectivity/telematics/details/devices.js +30 -0
  160. package/addon/routes/connectivity/telematics/details/events.js +33 -0
  161. package/addon/routes/connectivity/telematics/details/index.js +3 -0
  162. package/addon/routes/connectivity/telematics/details/logs.js +17 -0
  163. package/addon/routes/connectivity/telematics/details/sensors.js +29 -0
  164. package/addon/routes/connectivity/telematics/{index/details.js → details.js} +1 -1
  165. package/addon/routes/connectivity/telematics/{index/edit.js → edit.js} +1 -1
  166. package/addon/routes/connectivity/telematics/new.js +3 -0
  167. package/addon/routes/management/drivers/index/details/activity.js +3 -0
  168. package/addon/routes/management/fuel-reports/index.js +2 -0
  169. package/addon/routes/management/fuel-transactions/index/details.js +18 -0
  170. package/addon/routes/management/fuel-transactions/index.js +21 -0
  171. package/addon/routes/management/fuel-transactions.js +3 -0
  172. package/addon/routes/management/issues/index/details.js +1 -1
  173. package/addon/routes.js +29 -9
  174. package/addon/services/contact-actions.js +231 -1
  175. package/addon/services/device-actions.js +64 -1
  176. package/addon/services/device-event-actions.js +12 -1
  177. package/addon/services/driver-actions.js +147 -11
  178. package/addon/services/fleet-actions.js +66 -1
  179. package/addon/services/fuel-integration-actions.js +31 -0
  180. package/addon/services/getting-started.js +44 -0
  181. package/addon/services/issue-actions.js +72 -1
  182. package/addon/services/leaflet-map-manager.js +2 -0
  183. package/addon/services/map-adapter/leaflet.js +19 -0
  184. package/addon/services/service-areas.js +3 -0
  185. package/addon/services/telematic-actions.js +9 -3
  186. package/addon/services/vehicle-actions.js +125 -0
  187. package/addon/styles/fleetops-engine.css +1313 -1
  188. package/addon/templates/analytics/reports/index.hbs +19 -1
  189. package/addon/templates/connectivity/devices/index.hbs +19 -1
  190. package/addon/templates/connectivity/events/index.hbs +16 -1
  191. package/addon/templates/connectivity/fuel-providers/details/index.hbs +38 -0
  192. package/addon/templates/connectivity/fuel-providers/details/matching.hbs +13 -0
  193. package/addon/templates/connectivity/fuel-providers/details/settings.hbs +11 -0
  194. package/addon/templates/connectivity/fuel-providers/details/sync.hbs +48 -0
  195. package/addon/templates/connectivity/fuel-providers/details/transactions.hbs +21 -0
  196. package/addon/templates/connectivity/fuel-providers/details.hbs +51 -0
  197. package/addon/templates/connectivity/fuel-providers/edit.hbs +24 -0
  198. package/addon/templates/connectivity/fuel-providers/index.hbs +12 -0
  199. package/addon/templates/connectivity/fuel-providers/new.hbs +22 -0
  200. package/addon/templates/connectivity/fuel-providers.hbs +1 -0
  201. package/addon/templates/connectivity/sensors/index.hbs +19 -1
  202. package/addon/templates/connectivity/telematics/details/attachments.hbs +163 -0
  203. package/addon/templates/connectivity/telematics/details/devices.hbs +88 -0
  204. package/addon/templates/connectivity/telematics/details/events.hbs +101 -0
  205. package/addon/templates/connectivity/telematics/{index/details → details}/index.hbs +0 -1
  206. package/addon/templates/connectivity/telematics/details/logs.hbs +69 -0
  207. package/addon/templates/connectivity/telematics/details/sensors.hbs +88 -0
  208. package/addon/templates/connectivity/telematics/details.hbs +53 -0
  209. package/addon/templates/connectivity/telematics/edit.hbs +27 -0
  210. package/addon/templates/connectivity/telematics/index.hbs +6 -8
  211. package/addon/templates/connectivity/telematics/new.hbs +24 -0
  212. package/addon/templates/maintenance/equipment/index.hbs +19 -1
  213. package/addon/templates/maintenance/maintenances/index.hbs +15 -1
  214. package/addon/templates/maintenance/parts/index.hbs +19 -1
  215. package/addon/templates/maintenance/schedules/index.hbs +19 -1
  216. package/addon/templates/maintenance/work-orders/index.hbs +19 -1
  217. package/addon/templates/management/contacts/customers/details.hbs +1 -1
  218. package/addon/templates/management/contacts/customers.hbs +15 -1
  219. package/addon/templates/management/contacts/index/details.hbs +1 -1
  220. package/addon/templates/management/contacts/index.hbs +19 -1
  221. package/addon/templates/management/contacts.hbs +2 -2
  222. package/addon/templates/management/drivers/index/details/activity.hbs +1 -0
  223. package/addon/templates/management/drivers/index.hbs +19 -1
  224. package/addon/templates/management/fleets/index.hbs +19 -1
  225. package/addon/templates/management/fuel-reports/index.hbs +19 -1
  226. package/addon/templates/management/fuel-transactions/index/details.hbs +73 -0
  227. package/addon/templates/management/fuel-transactions/index.hbs +58 -0
  228. package/addon/templates/management/fuel-transactions.hbs +1 -0
  229. package/addon/templates/management/issues/index/details/index.hbs +3 -1
  230. package/addon/templates/management/issues/index/details.hbs +3 -2
  231. package/addon/templates/management/issues/index.hbs +19 -1
  232. package/addon/templates/management/places/index.hbs +19 -1
  233. package/addon/templates/management/vehicles/index.hbs +19 -1
  234. package/addon/templates/management/vendors/index/details/personnel.hbs +1 -2
  235. package/addon/templates/management/vendors/index.hbs +19 -1
  236. package/addon/templates/management/vendors/integrated.hbs +13 -1
  237. package/addon/templates/operations/orders/index/details/index.hbs +2 -2
  238. package/addon/templates/operations/orders/index.hbs +20 -2
  239. package/addon/templates/operations/service-rates/index/edit.hbs +1 -0
  240. package/addon/templates/operations/service-rates/index/new.hbs +1 -0
  241. package/addon/templates/operations/service-rates/index.hbs +19 -1
  242. package/addon/templates/settings/payments/index.hbs +15 -1
  243. package/addon/templates/settings/payments/onboard.hbs +8 -8
  244. package/addon/utils/fleet-ops-options.js +3 -0
  245. package/addon/utils/leaflet-draw-namespace-guard.js +22 -0
  246. package/addon/utils/leaflet-plugin-loader.js +219 -0
  247. package/addon/utils/setup-customer-portal.js +4 -64
  248. package/app/components/cell/telematic-provider.js +1 -0
  249. package/app/components/cell/telematic-status.js +1 -0
  250. package/app/components/fuel-integration/form.js +1 -0
  251. package/app/components/fuel-integration/hub.js +1 -0
  252. package/app/components/fuel-integration/matching-priority.js +1 -0
  253. package/app/components/home/getting-started-guidance.js +1 -0
  254. package/app/components/issue/details/comments.js +1 -0
  255. package/app/components/issue/details/correspondence.js +1 -0
  256. package/app/components/issue/details/documents.js +1 -0
  257. package/app/components/issue/panel-header.js +1 -0
  258. package/app/components/modals/assigned-orders.js +1 -0
  259. package/app/components/modals/attach-telematic-device.js +1 -0
  260. package/app/components/modals/convert-customer-to-vendor.js +1 -0
  261. package/app/components/modals/fleet-assign-driver.js +1 -0
  262. package/app/components/modals/fleet-assign-vehicle.js +1 -0
  263. package/app/components/modals/issue-assign.js +1 -0
  264. package/app/components/modals/issue-close.js +1 -0
  265. package/app/components/modals/issue-status.js +1 -0
  266. package/app/components/modals/telematic-connection-diagnostics.js +1 -0
  267. package/app/components/order/card.js +1 -0
  268. package/app/components/telematic/hub.js +1 -0
  269. package/app/components/telematic/settings.js +1 -0
  270. package/app/components/telematic/tab-empty-state.js +1 -0
  271. package/app/components/vendor/personnel-manager.js +1 -0
  272. package/app/components/widget/fuel-providers.js +1 -0
  273. package/app/controllers/connectivity/fuel-providers/details/sync.js +1 -0
  274. package/app/controllers/connectivity/{telematics/index/details/devices.js → fuel-providers/details/transactions.js} +1 -1
  275. package/app/controllers/connectivity/{telematics/index → fuel-providers}/details.js +1 -1
  276. package/app/controllers/connectivity/{telematics/index → fuel-providers}/edit.js +1 -1
  277. package/app/controllers/connectivity/{telematics/index/details → fuel-providers}/index.js +1 -1
  278. package/app/controllers/connectivity/{telematics/index → fuel-providers}/new.js +1 -1
  279. package/app/controllers/connectivity/telematics/details/attachments.js +1 -0
  280. package/app/controllers/connectivity/telematics/details/devices.js +1 -0
  281. package/app/controllers/connectivity/telematics/details/events.js +1 -0
  282. package/app/controllers/connectivity/telematics/details/index.js +1 -0
  283. package/app/controllers/connectivity/telematics/details/logs.js +1 -0
  284. package/app/controllers/connectivity/telematics/details/sensors.js +1 -0
  285. package/app/controllers/connectivity/telematics/details.js +1 -0
  286. package/app/controllers/connectivity/telematics/edit.js +1 -0
  287. package/app/controllers/connectivity/telematics/new.js +1 -0
  288. package/app/controllers/management/fuel-transactions/index/details.js +1 -0
  289. package/app/controllers/management/fuel-transactions/index.js +1 -0
  290. package/app/helpers/format-duration.js +1 -1
  291. package/app/routes/connectivity/{telematics/index → fuel-providers}/details/index.js +1 -1
  292. package/app/routes/connectivity/{telematics/index/details/events.js → fuel-providers/details/matching.js} +1 -1
  293. package/app/routes/connectivity/fuel-providers/details/settings.js +1 -0
  294. package/app/routes/connectivity/fuel-providers/details/sync.js +1 -0
  295. package/app/routes/connectivity/{telematics/index/details/devices.js → fuel-providers/details/transactions.js} +1 -1
  296. package/app/routes/connectivity/{telematics/index → fuel-providers}/details.js +1 -1
  297. package/app/routes/connectivity/{telematics/index → fuel-providers}/edit.js +1 -1
  298. package/app/routes/connectivity/fuel-providers/index.js +1 -0
  299. package/app/routes/connectivity/{telematics/index → fuel-providers}/new.js +1 -1
  300. package/app/routes/connectivity/fuel-providers.js +1 -0
  301. package/app/routes/connectivity/telematics/details/attachments.js +1 -0
  302. package/app/routes/connectivity/telematics/details/devices.js +1 -0
  303. package/app/routes/connectivity/telematics/details/events.js +1 -0
  304. package/app/routes/connectivity/telematics/details/index.js +1 -0
  305. package/app/routes/connectivity/telematics/details/logs.js +1 -0
  306. package/app/routes/connectivity/telematics/details/sensors.js +1 -0
  307. package/app/routes/connectivity/telematics/details.js +1 -0
  308. package/app/routes/connectivity/telematics/edit.js +1 -0
  309. package/app/routes/connectivity/telematics/new.js +1 -0
  310. package/app/routes/management/drivers/index/details/activity.js +1 -0
  311. package/app/routes/management/fuel-transactions/index/details.js +1 -0
  312. package/app/routes/management/fuel-transactions/index.js +1 -0
  313. package/app/routes/management/fuel-transactions.js +1 -0
  314. package/app/services/fuel-integration-actions.js +1 -0
  315. package/app/services/getting-started.js +1 -0
  316. package/app/templates/connectivity/{telematics/index → fuel-providers}/details/index.js +1 -1
  317. package/app/templates/connectivity/{telematics/index/details/events.js → fuel-providers/details/matching.js} +1 -1
  318. package/app/templates/connectivity/fuel-providers/details/settings.js +1 -0
  319. package/app/templates/connectivity/fuel-providers/details/sync.js +1 -0
  320. package/app/templates/connectivity/{telematics/index/details/devices.js → fuel-providers/details/transactions.js} +1 -1
  321. package/app/templates/connectivity/{telematics/index → fuel-providers}/details.js +1 -1
  322. package/app/templates/connectivity/{telematics/index → fuel-providers}/edit.js +1 -1
  323. package/app/templates/connectivity/fuel-providers/index.js +1 -0
  324. package/app/templates/connectivity/{telematics/index → fuel-providers}/new.js +1 -1
  325. package/app/templates/connectivity/fuel-providers.js +1 -0
  326. package/app/templates/connectivity/telematics/details/attachments.js +1 -0
  327. package/app/templates/connectivity/telematics/details/devices.js +1 -0
  328. package/app/templates/connectivity/telematics/details/events.js +1 -0
  329. package/app/templates/connectivity/telematics/details/index.js +1 -0
  330. package/app/templates/connectivity/telematics/details/logs.js +1 -0
  331. package/app/templates/connectivity/telematics/details/sensors.js +1 -0
  332. package/app/templates/connectivity/telematics/details.js +1 -0
  333. package/app/templates/connectivity/telematics/edit.js +1 -0
  334. package/app/templates/connectivity/telematics/new.js +1 -0
  335. package/app/templates/management/drivers/index/details/activity.js +1 -0
  336. package/app/templates/management/fuel-transactions/index/details.js +1 -0
  337. package/app/templates/management/fuel-transactions/index.js +1 -0
  338. package/app/templates/management/fuel-transactions.js +1 -0
  339. package/app/utils/leaflet-draw-namespace-guard.js +1 -0
  340. package/app/utils/leaflet-plugin-loader.js +1 -0
  341. package/assets/images/telematics/providers/afaqy.webp +0 -0
  342. package/assets/images/telematics/providers/default.webp +0 -0
  343. package/assets/images/telematics/providers/flespi.webp +0 -0
  344. package/assets/images/telematics/providers/geotab.webp +0 -0
  345. package/assets/images/telematics/providers/safee.webp +0 -0
  346. package/assets/images/telematics/providers/samsara.webp +0 -0
  347. package/composer.json +1 -1
  348. package/extension.json +1 -1
  349. package/package.json +5 -5
  350. package/server/config/fuel-providers.php +42 -0
  351. package/server/config/telematics.php +139 -130
  352. package/server/migrations/2026_05_31_000001_add_portal_fields_to_vendor_personnels_table.php +30 -0
  353. package/server/migrations/2026_06_03_000000_ensure_tags_column_on_issues_table.php +31 -0
  354. package/server/migrations/2026_06_03_000001_add_order_uuid_to_issues_table.php +25 -0
  355. package/server/migrations/2026_06_04_000001_backfill_order_transaction_subjects.php +39 -0
  356. package/server/migrations/2026_06_04_000002_backfill_order_transaction_directions.php +24 -0
  357. package/server/migrations/2026_06_06_000001_harden_device_events_telematics_contract.php +59 -0
  358. package/server/migrations/2026_06_08_000001_create_fuel_provider_connections_table.php +37 -0
  359. package/server/migrations/2026_06_08_000002_create_fuel_provider_transactions_table.php +53 -0
  360. package/server/migrations/2026_06_08_000003_create_fuel_provider_sync_runs_table.php +40 -0
  361. package/server/migrations/2026_06_10_000001_add_fuel_card_number_to_vehicles_table.php +25 -0
  362. package/server/migrations/2026_06_10_000002_add_vehicle_identity_columns_to_fuel_provider_transactions_table.php +39 -0
  363. package/server/resources/views/mail/customer-credentials.blade.php +16 -13
  364. package/server/src/Contracts/FuelProvider.php +30 -0
  365. package/server/src/Contracts/TelematicProviderDescriptor.php +3 -1
  366. package/server/src/Events/FuelProviderTransactionImported.php +17 -0
  367. package/server/src/Events/FuelProviderTransactionMatched.php +17 -0
  368. package/server/src/Events/FuelProviderTransactionUnmatched.php +17 -0
  369. package/server/src/Events/FuelReportCreatedFromProvider.php +18 -0
  370. package/server/src/Expansions/UserFilterExpansion.php +28 -0
  371. package/server/src/Http/Controllers/Api/v1/IssueController.php +2 -0
  372. package/server/src/Http/Controllers/Api/v1/OrderController.php +26 -25
  373. package/server/src/Http/Controllers/Api/v1/PlaceController.php +10 -58
  374. package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +6 -0
  375. package/server/src/Http/Controllers/Internal/v1/ContactController.php +135 -0
  376. package/server/src/Http/Controllers/Internal/v1/CustomerController.php +116 -6
  377. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +76 -2
  378. package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +44 -0
  379. package/server/src/Http/Controllers/Internal/v1/DriverController.php +158 -7
  380. package/server/src/Http/Controllers/Internal/v1/FuelProviderConnectionController.php +124 -0
  381. package/server/src/Http/Controllers/Internal/v1/FuelProviderSyncRunController.php +10 -0
  382. package/server/src/Http/Controllers/Internal/v1/FuelProviderTransactionController.php +76 -0
  383. package/server/src/Http/Controllers/Internal/v1/GettingStartedController.php +17 -0
  384. package/server/src/Http/Controllers/Internal/v1/IssueController.php +251 -0
  385. package/server/src/Http/Controllers/Internal/v1/OrderController.php +172 -97
  386. package/server/src/Http/Controllers/Internal/v1/PlaceController.php +10 -68
  387. package/server/src/Http/Controllers/Internal/v1/SensorController.php +1 -1
  388. package/server/src/Http/Controllers/Internal/v1/TelematicController.php +178 -15
  389. package/server/src/Http/Controllers/Internal/v1/VehicleController.php +165 -0
  390. package/server/src/Http/Controllers/Internal/v1/VendorController.php +89 -0
  391. package/server/src/Http/Controllers/TelematicWebhookController.php +103 -19
  392. package/server/src/Http/Filter/FuelProviderConnectionFilter.php +33 -0
  393. package/server/src/Http/Filter/FuelProviderSyncRunFilter.php +28 -0
  394. package/server/src/Http/Filter/FuelProviderTransactionFilter.php +59 -0
  395. package/server/src/Http/Filter/FuelReportFilter.php +10 -0
  396. package/server/src/Http/Requests/CreateIssueRequest.php +4 -0
  397. package/server/src/Http/Requests/UpdateIssueRequest.php +4 -0
  398. package/server/src/Http/Resources/v1/Driver.php +15 -0
  399. package/server/src/Http/Resources/v1/FuelProviderConnection.php +30 -0
  400. package/server/src/Http/Resources/v1/FuelProviderSyncRun.php +36 -0
  401. package/server/src/Http/Resources/v1/FuelProviderTransaction.php +54 -0
  402. package/server/src/Http/Resources/v1/FuelReport.php +28 -22
  403. package/server/src/Http/Resources/v1/Index/Driver.php +26 -20
  404. package/server/src/Http/Resources/v1/Index/Order.php +12 -9
  405. package/server/src/Http/Resources/v1/Index/Vehicle.php +29 -22
  406. package/server/src/Http/Resources/v1/Issue.php +25 -0
  407. package/server/src/Http/Resources/v1/Order.php +20 -18
  408. package/server/src/Http/Resources/v1/Vehicle.php +17 -0
  409. package/server/src/Http/Resources/v1/VehicleWithoutDriver.php +2 -0
  410. package/server/src/Jobs/SyncFuelProviderTransactionsJob.php +57 -0
  411. package/server/src/Jobs/SyncTelematicDevicesJob.php +36 -6
  412. package/server/src/Jobs/TestTelematicConnectionJob.php +9 -22
  413. package/server/src/Mail/CustomerCredentialsMail.php +5 -6
  414. package/server/src/Models/Asset.php +2 -1
  415. package/server/src/Models/Contact.php +32 -52
  416. package/server/src/Models/Device.php +27 -4
  417. package/server/src/Models/DeviceEvent.php +40 -3
  418. package/server/src/Models/Driver.php +2 -1
  419. package/server/src/Models/Equipment.php +2 -1
  420. package/server/src/Models/Fleet.php +2 -1
  421. package/server/src/Models/FuelProviderConnection.php +60 -0
  422. package/server/src/Models/FuelProviderSyncRun.php +58 -0
  423. package/server/src/Models/FuelProviderTransaction.php +119 -0
  424. package/server/src/Models/FuelReport.php +16 -1
  425. package/server/src/Models/Issue.php +47 -6
  426. package/server/src/Models/Order.php +33 -6
  427. package/server/src/Models/Part.php +2 -1
  428. package/server/src/Models/Sensor.php +21 -4
  429. package/server/src/Models/ServiceArea.php +1 -1
  430. package/server/src/Models/ServiceRate.php +39 -2
  431. package/server/src/Models/Vehicle.php +14 -2
  432. package/server/src/Models/Vendor.php +2 -1
  433. package/server/src/Models/VendorPersonnel.php +10 -1
  434. package/server/src/Models/Zone.php +1 -1
  435. package/server/src/Observers/PurchaseRateObserver.php +20 -0
  436. package/server/src/Observers/ZoneObserver.php +56 -0
  437. package/server/src/Providers/FleetOpsServiceProvider.php +11 -0
  438. package/server/src/Support/Analytics/FuelProviderSummary.php +42 -0
  439. package/server/src/Support/Analytics/TopDrivers.php +9 -1
  440. package/server/src/Support/FuelProviders/FuelProviderDescriptor.php +55 -0
  441. package/server/src/Support/FuelProviders/FuelProviderRegistry.php +75 -0
  442. package/server/src/Support/FuelProviders/FuelProviderService.php +447 -0
  443. package/server/src/Support/FuelProviders/Providers/AbstractFuelProvider.php +98 -0
  444. package/server/src/Support/FuelProviders/Providers/PetroAppFuelProvider.php +167 -0
  445. package/server/src/Support/GettingStarted.php +144 -0
  446. package/server/src/Support/PlaceSearch.php +282 -0
  447. package/server/src/Support/ResolvesOrderServiceStops.php +22 -12
  448. package/server/src/Support/Telematics/Providers/AbstractProvider.php +27 -6
  449. package/server/src/Support/Telematics/Providers/AfaqyProvider.php +55 -26
  450. package/server/src/Support/Telematics/Providers/FlespiProvider.php +1 -0
  451. package/server/src/Support/Telematics/Providers/GeotabProvider.php +1 -0
  452. package/server/src/Support/Telematics/Providers/SafeeProvider.php +32 -22
  453. package/server/src/Support/Telematics/Providers/SamsaraProvider.php +3 -1
  454. package/server/src/Support/Telematics/TelematicService.php +340 -21
  455. package/server/src/routes.php +74 -5
  456. package/server/tests/AnalyticsRoutesTest.php +8 -0
  457. package/server/tests/CustomerContactIdentitySafetyTest.php +41 -0
  458. package/server/tests/DriverVehicleStatusDefaultTest.php +2 -2
  459. package/server/tests/FuelProviderRegistryTest.php +416 -0
  460. package/server/tests/GettingStartedStatusTest.php +21 -0
  461. package/server/tests/OrderActivityFlowRegressionTest.php +116 -0
  462. package/server/tests/ServiceAreaZoneApiShapeTest.php +44 -0
  463. package/server/tests/ServiceRateAlgorithmWeightVariablesTest.php +44 -0
  464. package/server/tests/TelematicsHardeningTest.php +268 -0
  465. package/server/tests/VehicleDriverAssignmentTest.php +51 -0
  466. package/translations/ar-ae.yml +31 -0
  467. package/translations/bg-bg.yaml +81 -0
  468. package/translations/en-us.yaml +94 -0
  469. package/translations/es-pa.yaml +81 -0
  470. package/translations/fr-fr.yaml +81 -0
  471. package/translations/mn-mn.yaml +81 -0
  472. package/translations/pt-br.yaml +81 -0
  473. package/translations/ru-ru.yaml +81 -0
  474. package/translations/vi-vn.yaml +106 -0
  475. package/addon/controllers/connectivity/telematics/index/details/devices.js +0 -3
  476. package/addon/controllers/connectivity/telematics/index/details/events.js +0 -3
  477. package/addon/controllers/connectivity/telematics/index/details/index.js +0 -3
  478. package/addon/controllers/connectivity/telematics/index/details/sensors.js +0 -3
  479. package/addon/controllers/connectivity/telematics/index/details.js +0 -24
  480. package/addon/routes/connectivity/telematics/index/details/devices.js +0 -3
  481. package/addon/routes/connectivity/telematics/index/details/events.js +0 -3
  482. package/addon/routes/connectivity/telematics/index/details/index.js +0 -3
  483. package/addon/routes/connectivity/telematics/index/details/sensors.js +0 -3
  484. package/addon/routes/connectivity/telematics/index/new.js +0 -3
  485. package/addon/templates/connectivity/telematics/index/details/devices.hbs +0 -1
  486. package/addon/templates/connectivity/telematics/index/details/events.hbs +0 -1
  487. package/addon/templates/connectivity/telematics/index/details/sensors.hbs +0 -1
  488. package/addon/templates/connectivity/telematics/index/details.hbs +0 -14
  489. package/addon/templates/connectivity/telematics/index/edit.hbs +0 -12
  490. package/addon/templates/connectivity/telematics/index/new.hbs +0 -12
  491. package/app/controllers/connectivity/telematics/index/details/events.js +0 -1
  492. package/app/controllers/connectivity/telematics/index/details/sensors.js +0 -1
  493. package/app/routes/connectivity/telematics/index/details/sensors.js +0 -1
  494. package/app/templates/connectivity/telematics/index/details/sensors.js +0 -1
@@ -14,7 +14,11 @@ use Fleetbase\Traits\HasCustomFields;
14
14
  use Fleetbase\Traits\HasPublicId;
15
15
  use Fleetbase\Traits\HasUuid;
16
16
  use Fleetbase\Traits\TracksApiCredential;
17
+ use Illuminate\Database\Eloquent\Relations\BelongsTo;
18
+ use Illuminate\Database\Eloquent\Relations\HasMany;
17
19
  use Illuminate\Support\Str;
20
+ use Spatie\Activitylog\LogOptions;
21
+ use Spatie\Activitylog\Traits\LogsActivity;
18
22
 
19
23
  class Issue extends Model
20
24
  {
@@ -24,6 +28,7 @@ class Issue extends Model
24
28
  use SpatialTrait;
25
29
  use HasApiModelBehavior;
26
30
  use HasApiModelCache;
31
+ use LogsActivity;
27
32
  use HasCustomFields;
28
33
 
29
34
  /**
@@ -60,6 +65,7 @@ class Issue extends Model
60
65
  'assigned_to_uuid',
61
66
  'vehicle_uuid',
62
67
  'driver_uuid',
68
+ 'order_uuid',
63
69
  'issue_id',
64
70
  'location',
65
71
  'category',
@@ -106,6 +112,31 @@ class Issue extends Model
106
112
  */
107
113
  protected $appends = ['driver_name', 'vehicle_name', 'assignee_name', 'reporter_name'];
108
114
 
115
+ /**
116
+ * Get the activity log options for the model.
117
+ */
118
+ public function getActivitylogOptions(): LogOptions
119
+ {
120
+ return LogOptions::defaults()
121
+ ->logOnly([
122
+ 'title',
123
+ 'report',
124
+ 'status',
125
+ 'priority',
126
+ 'assigned_to_uuid',
127
+ 'vehicle_uuid',
128
+ 'driver_uuid',
129
+ 'order_uuid',
130
+ 'type',
131
+ 'category',
132
+ 'tags',
133
+ 'resolved_at',
134
+ 'meta',
135
+ ])
136
+ ->logOnlyDirty()
137
+ ->dontSubmitEmptyLogs();
138
+ }
139
+
109
140
  /**
110
141
  * The attributes excluded from the model's JSON form.
111
142
  *
@@ -114,7 +145,7 @@ class Issue extends Model
114
145
  protected $hidden = [];
115
146
 
116
147
  /**
117
- * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
148
+ * @return BelongsTo
118
149
  */
119
150
  public function reportedBy()
120
151
  {
@@ -122,7 +153,7 @@ class Issue extends Model
122
153
  }
123
154
 
124
155
  /**
125
- * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
156
+ * @return BelongsTo
126
157
  */
127
158
  public function reporter()
128
159
  {
@@ -130,7 +161,7 @@ class Issue extends Model
130
161
  }
131
162
 
132
163
  /**
133
- * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
164
+ * @return BelongsTo
134
165
  */
135
166
  public function assignedTo()
136
167
  {
@@ -138,7 +169,7 @@ class Issue extends Model
138
169
  }
139
170
 
140
171
  /**
141
- * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
172
+ * @return BelongsTo
142
173
  */
143
174
  public function assignee()
144
175
  {
@@ -146,7 +177,7 @@ class Issue extends Model
146
177
  }
147
178
 
148
179
  /**
149
- * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
180
+ * @return BelongsTo
150
181
  */
151
182
  public function vehicle()
152
183
  {
@@ -154,13 +185,23 @@ class Issue extends Model
154
185
  }
155
186
 
156
187
  /**
157
- * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
188
+ * @return BelongsTo
158
189
  */
159
190
  public function driver()
160
191
  {
161
192
  return $this->belongsTo(Driver::class);
162
193
  }
163
194
 
195
+ public function order(): BelongsTo
196
+ {
197
+ return $this->belongsTo(Order::class, 'order_uuid', 'uuid')->without(['comments', 'files']);
198
+ }
199
+
200
+ public function files(): HasMany
201
+ {
202
+ return $this->hasMany(\Fleetbase\Models\File::class, 'subject_uuid', 'uuid')->latest();
203
+ }
204
+
164
205
  /**
165
206
  * Set the title attribute for the Issue model.
166
207
  *
@@ -169,6 +169,7 @@ class Order extends Model
169
169
  'tracking',
170
170
  'total_entities',
171
171
  'transaction_amount',
172
+ 'transaction_currency',
172
173
  'customer_name',
173
174
  'customer_phone',
174
175
  'facilitator_name',
@@ -508,6 +509,16 @@ class Order extends Model
508
509
  return data_get($this, 'transaction.amount');
509
510
  }
510
511
 
512
+ /**
513
+ * The transaction amount for the order.
514
+ *
515
+ * @return string
516
+ */
517
+ public function getTransactionCurrencyAttribute()
518
+ {
519
+ return data_get($this, 'transaction.currency');
520
+ }
521
+
511
522
  /**
512
523
  * The customer name for the order.
513
524
  *
@@ -1143,7 +1154,17 @@ class Order extends Model
1143
1154
  $this->setRelation('purchaseRate', $purchaseRate);
1144
1155
 
1145
1156
  if ($purchaseRate->transaction_uuid) {
1146
- $this->setRelation('transaction', Transaction::where('uuid', $purchaseRate->transaction_uuid)->first());
1157
+ $transaction = Transaction::where('uuid', $purchaseRate->transaction_uuid)->first();
1158
+ if ($transaction instanceof Transaction) {
1159
+ $transaction->update([
1160
+ 'subject_uuid' => $this->uuid,
1161
+ 'subject_type' => static::class,
1162
+ 'context_uuid' => $purchaseRate->uuid,
1163
+ 'context_type' => PurchaseRate::class,
1164
+ 'direction' => Transaction::DIRECTION_CREDIT,
1165
+ ]);
1166
+ $this->setRelation('transaction', $transaction);
1167
+ }
1147
1168
  }
1148
1169
 
1149
1170
  if (
@@ -1176,12 +1197,17 @@ class Order extends Model
1176
1197
  'company_uuid' => session('company', $this->company_uuid),
1177
1198
  'customer_uuid' => $this->customer_uuid,
1178
1199
  'customer_type' => $this->customer_type,
1200
+ 'subject_uuid' => $this->uuid,
1201
+ 'subject_type' => static::class,
1202
+ 'context_uuid' => $this->uuid,
1203
+ 'context_type' => static::class,
1179
1204
  'gateway_transaction_id' => Transaction::generateNumber(),
1180
1205
  'gateway' => 'internal',
1181
1206
  'amount' => 0,
1182
1207
  'currency' => Utils::getCompanyTransactionCurrency($this->company ?? $this->company_uuid),
1183
1208
  'description' => 'Dispatch order',
1184
1209
  'type' => 'dispatch',
1210
+ 'direction' => Transaction::DIRECTION_CREDIT,
1185
1211
  'status' => 'success',
1186
1212
  ]);
1187
1213
 
@@ -1379,8 +1405,9 @@ class Order extends Model
1379
1405
  *
1380
1406
  * The process involves the following steps:
1381
1407
  * 1. Creating a new Activity instance with the 'completed' code and relevant details.
1382
- * 2. Notifying that the order has been completed via `notifyCompleted`.
1383
- * 3. Updating the order's activity with the new 'completed' activity through `updateActivity`.
1408
+ * 2. Updating the order's activity with the new 'completed' activity through `updateActivity`,
1409
+ * which applies and persists the 'completed' status.
1410
+ * 3. Notifying that the order has been completed via `notifyCompleted`.
1384
1411
  *
1385
1412
  * @param Proof|null $proof Optional. Additional proof or details for the activity update.
1386
1413
  *
@@ -1388,15 +1415,15 @@ class Order extends Model
1388
1415
  */
1389
1416
  public function complete(?Proof $proof = null): self
1390
1417
  {
1391
- $this->notifyCompleted();
1392
-
1393
1418
  $doesntHaveCompletedActivity = TrackingStatus::where(['tracking_number_uuid' => $this->tracking_number_uuid, 'code' => 'COMPLETED'])->doesntExist();
1394
1419
  if ($doesntHaveCompletedActivity) {
1395
1420
  $activity = $this->config()->getCompletedActivity();
1396
1421
 
1397
- return $this->updateActivity($activity, $proof);
1422
+ $this->updateActivity($activity, $proof);
1398
1423
  }
1399
1424
 
1425
+ $this->notifyCompleted();
1426
+
1400
1427
  return $this;
1401
1428
  }
1402
1429
 
@@ -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
@@ -123,7 +123,7 @@ class ServiceArea extends Model
123
123
  */
124
124
  public function zones()
125
125
  {
126
- return $this->hasMany(Zone::class)->without(['serviceArea']);
126
+ return $this->hasMany(Zone::class, 'service_area_uuid', 'uuid')->without(['serviceArea']);
127
127
  }
128
128
 
129
129
  /**
@@ -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
  /**
@@ -3,6 +3,7 @@
3
3
  namespace Fleetbase\FleetOps\Models;
4
4
 
5
5
  use Fleetbase\Models\Model;
6
+ use Fleetbase\Models\User;
6
7
  use Fleetbase\Traits\HasUuid;
7
8
  use Illuminate\Database\Eloquent\Relations\BelongsTo;
8
9
 
@@ -22,7 +23,7 @@ class VendorPersonnel extends Model
22
23
  *
23
24
  * @var array
24
25
  */
25
- protected $fillable = ['vendor_uuid', 'contact_uuid'];
26
+ protected $fillable = ['vendor_uuid', 'contact_uuid', 'role', 'status', 'invited_by_uuid'];
26
27
 
27
28
  /**
28
29
  * These attributes that can be queried.
@@ -60,4 +61,12 @@ class VendorPersonnel extends Model
60
61
  {
61
62
  return $this->belongsTo(Contact::class);
62
63
  }
64
+
65
+ /**
66
+ * The Fleetbase user who invited this personnel.
67
+ */
68
+ public function invitedBy(): BelongsTo
69
+ {
70
+ return $this->belongsTo(User::class, 'invited_by_uuid');
71
+ }
63
72
  }
@@ -118,7 +118,7 @@ class Zone extends Model
118
118
  */
119
119
  public function serviceArea()
120
120
  {
121
- return $this->belongsTo(ServiceArea::class);
121
+ return $this->belongsTo(ServiceArea::class, 'service_area_uuid', 'uuid');
122
122
  }
123
123
 
124
124
  /**
@@ -2,6 +2,7 @@
2
2
 
3
3
  namespace Fleetbase\FleetOps\Observers;
4
4
 
5
+ use Fleetbase\FleetOps\Models\Order;
5
6
  use Fleetbase\FleetOps\Models\PurchaseRate;
6
7
  use Fleetbase\FleetOps\Support\Utils;
7
8
  use Fleetbase\Models\Company;
@@ -18,7 +19,12 @@ class PurchaseRateObserver
18
19
  */
19
20
  public function creating(PurchaseRate $purchaseRate)
20
21
  {
22
+ if (!$purchaseRate->uuid) {
23
+ $purchaseRate->uuid = PurchaseRate::generateUuid();
24
+ }
25
+
21
26
  $purchaseRate->load(['serviceQuote.items', 'serviceQuote.serviceRate']);
27
+ $order = $this->resolveOrder($purchaseRate);
22
28
 
23
29
  // get company
24
30
  $company = Company::where('uuid', session('company', $purchaseRate->company_uuid))->first();
@@ -32,12 +38,17 @@ class PurchaseRateObserver
32
38
  'company_uuid' => session('company', $purchaseRate->company_uuid),
33
39
  'customer_uuid' => $purchaseRate->customer_uuid,
34
40
  'customer_type' => $purchaseRate->customer_type,
41
+ 'subject_uuid' => $order?->uuid,
42
+ 'subject_type' => $order ? Order::class : null,
43
+ 'context_uuid' => $purchaseRate->uuid,
44
+ 'context_type' => PurchaseRate::class,
35
45
  'gateway_transaction_id' => $purchaseRate->getMeta('transaction_id', Transaction::generateNumber()),
36
46
  'gateway' => 'internal',
37
47
  'amount' => data_get($purchaseRate, 'serviceQuote.amount', 0),
38
48
  'currency' => $currency,
39
49
  'description' => 'Dispatch order',
40
50
  'type' => 'dispatch',
51
+ 'direction' => Transaction::DIRECTION_CREDIT,
41
52
  'status' => 'success',
42
53
  ]);
43
54
 
@@ -56,4 +67,13 @@ class PurchaseRateObserver
56
67
  $purchaseRate->transaction_uuid = $transaction->uuid;
57
68
  $purchaseRate->status = $purchaseRate->status ?: Transaction::STATUS_SUCCESS;
58
69
  }
70
+
71
+ protected function resolveOrder(PurchaseRate $purchaseRate): ?Order
72
+ {
73
+ if (!$purchaseRate->payload_uuid) {
74
+ return null;
75
+ }
76
+
77
+ return Order::where('payload_uuid', $purchaseRate->payload_uuid)->first();
78
+ }
59
79
  }
@@ -0,0 +1,56 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Observers;
4
+
5
+ use Fleetbase\FleetOps\Models\ServiceArea;
6
+ use Fleetbase\FleetOps\Models\Zone;
7
+
8
+ class ZoneObserver
9
+ {
10
+ /**
11
+ * Handle the Zone "created" event.
12
+ */
13
+ public function created(Zone $zone): void
14
+ {
15
+ $this->invalidateServiceAreaCache($zone);
16
+ }
17
+
18
+ /**
19
+ * Handle the Zone "updated" event.
20
+ */
21
+ public function updated(Zone $zone): void
22
+ {
23
+ $this->invalidateServiceAreaCache($zone, $zone->getOriginal('service_area_uuid'));
24
+ $this->invalidateServiceAreaCache($zone);
25
+ }
26
+
27
+ /**
28
+ * Handle the Zone "deleted" event.
29
+ */
30
+ public function deleted(Zone $zone): void
31
+ {
32
+ $this->invalidateServiceAreaCache($zone);
33
+ }
34
+
35
+ /**
36
+ * Handle the Zone "restored" event.
37
+ */
38
+ public function restored(Zone $zone): void
39
+ {
40
+ $this->invalidateServiceAreaCache($zone);
41
+ }
42
+
43
+ /**
44
+ * Invalidate service area API cache because service area responses embed zones.
45
+ */
46
+ protected function invalidateServiceAreaCache(Zone $zone, ?string $serviceAreaUuid = null): void
47
+ {
48
+ $serviceAreaUuid ??= $zone->service_area_uuid;
49
+ if (!$serviceAreaUuid) {
50
+ return;
51
+ }
52
+
53
+ ServiceArea::invalidateApiCacheManually($zone->company_uuid);
54
+ ServiceArea::invalidateApiCacheManually();
55
+ }
56
+ }
@@ -29,6 +29,7 @@ class FleetOpsServiceProvider extends CoreServiceProvider
29
29
  \Fleetbase\FleetOps\Models\ServiceRate::class => \Fleetbase\FleetOps\Observers\ServiceRateObserver::class,
30
30
  \Fleetbase\FleetOps\Models\PurchaseRate::class => \Fleetbase\FleetOps\Observers\PurchaseRateObserver::class,
31
31
  \Fleetbase\FleetOps\Models\ServiceArea::class => \Fleetbase\FleetOps\Observers\ServiceAreaObserver::class,
32
+ \Fleetbase\FleetOps\Models\Zone::class => \Fleetbase\FleetOps\Observers\ZoneObserver::class,
32
33
  \Fleetbase\FleetOps\Models\TrackingNumber::class => \Fleetbase\FleetOps\Observers\TrackingNumberObserver::class,
33
34
  \Fleetbase\FleetOps\Models\Driver::class => \Fleetbase\FleetOps\Observers\DriverObserver::class,
34
35
  \Fleetbase\FleetOps\Models\Vehicle::class => \Fleetbase\FleetOps\Observers\VehicleObserver::class,
@@ -108,6 +109,15 @@ class FleetOpsServiceProvider extends CoreServiceProvider
108
109
  \Fleetbase\FleetOps\Tracking\TrackingProviderRegistry::class,
109
110
  fn () => new \Fleetbase\FleetOps\Tracking\TrackingProviderRegistry()
110
111
  );
112
+
113
+ // Register the fuel provider registry as a singleton so FleetOps core
114
+ // and third-party extensions can share fuel card and fuel billing
115
+ // providers. Extensions can register providers from their own service
116
+ // providers with callAfterResolving(FuelProviderRegistry::class, ...).
117
+ $this->app->singleton(
118
+ \Fleetbase\FleetOps\Support\FuelProviders\FuelProviderRegistry::class,
119
+ fn () => new \Fleetbase\FleetOps\Support\FuelProviders\FuelProviderRegistry()
120
+ );
111
121
  }
112
122
 
113
123
  /**
@@ -172,6 +182,7 @@ class FleetOpsServiceProvider extends CoreServiceProvider
172
182
  $this->loadViewsFrom(__DIR__ . '/../../resources/views', 'fleetops');
173
183
  $this->mergeConfigFrom(__DIR__ . '/../../config/fleetops.php', 'fleetops');
174
184
  $this->mergeConfigFrom(__DIR__ . '/../../config/telematics.php', 'telematics');
185
+ $this->mergeConfigFrom(__DIR__ . '/../../config/fuel-providers.php', 'fuel-providers');
175
186
  $this->mergeConfigFrom(__DIR__ . '/../../config/api.php', 'api');
176
187
  $this->mergeConfigFrom(__DIR__ . '/../../config/cache.stores.php', 'cache.stores');
177
188
  $this->mergeConfigFrom(__DIR__ . '/../../config/geocoder.php', 'geocoder');
@@ -0,0 +1,42 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Support\Analytics;
4
+
5
+ use Fleetbase\FleetOps\Models\FuelProviderConnection;
6
+ use Fleetbase\FleetOps\Models\FuelProviderTransaction;
7
+
8
+ class FuelProviderSummary extends AbstractAnalytics
9
+ {
10
+ public function get(): array
11
+ {
12
+ $transactions = FuelProviderTransaction::where('company_uuid', $this->company->uuid)
13
+ ->whereBetween('transaction_at', [$this->start, $this->end])
14
+ ->get();
15
+
16
+ $connections = FuelProviderConnection::where('company_uuid', $this->company->uuid)->get();
17
+
18
+ $byProvider = $transactions
19
+ ->groupBy('provider')
20
+ ->map(fn ($rows, $provider) => [
21
+ 'provider' => $provider,
22
+ 'transactions' => $rows->count(),
23
+ 'spend' => (int) $rows->sum('amount'),
24
+ 'volume' => (float) $rows->sum('volume'),
25
+ 'unmatched' => $rows->where('sync_status', 'unmatched')->count(),
26
+ ])
27
+ ->values();
28
+
29
+ return [
30
+ 'summary' => [
31
+ 'connections' => $connections->count(),
32
+ 'active_connections' => $connections->whereIn('status', ['connected', 'active'])->count(),
33
+ 'transactions' => $transactions->count(),
34
+ 'unmatched' => $transactions->where('sync_status', 'unmatched')->count(),
35
+ 'spend' => (int) $transactions->sum('amount'),
36
+ 'volume' => (float) $transactions->sum('volume'),
37
+ 'currency' => $transactions->first()?->currency ?? $this->companyCurrency(),
38
+ ],
39
+ 'providers' => $byProvider,
40
+ ];
41
+ }
42
+ }
@@ -38,7 +38,15 @@ class TopDrivers extends AbstractAnalytics
38
38
 
39
39
  $sortColumn = match ($this->sortBy) {
40
40
  'distance' => 'distance_m',
41
- 'on_time' => 'on_time_pct',
41
+ 'on_time' => 'CASE
42
+ WHEN SUM(CASE WHEN orders.scheduled_at IS NOT NULL THEN 1 ELSE 0 END) > 0
43
+ THEN SUM(CASE
44
+ WHEN orders.scheduled_at IS NOT NULL
45
+ AND TIMESTAMPDIFF(SECOND, orders.scheduled_at, orders.updated_at) <= 1800
46
+ THEN 1 ELSE 0 END)
47
+ / SUM(CASE WHEN orders.scheduled_at IS NOT NULL THEN 1 ELSE 0 END)
48
+ ELSE -1
49
+ END',
42
50
  default => 'orders_completed',
43
51
  };
44
52