@fleetbase/fleetops-engine 0.6.38 → 0.6.39

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 (429) hide show
  1. package/addon/components/activity/form.hbs +2 -12
  2. package/addon/components/activity/logic-builder.hbs +1 -1
  3. package/addon/components/custom-entity/form.hbs +4 -20
  4. package/addon/components/device/form.hbs +3 -15
  5. package/addon/components/device/panel-header.hbs +13 -2
  6. package/addon/components/driver/details.hbs +33 -2
  7. package/addon/components/driver/form.hbs +42 -0
  8. package/addon/components/driver/panel-header.hbs +8 -1
  9. package/addon/components/driver/schedule.hbs +115 -76
  10. package/addon/components/driver/schedule.js +349 -157
  11. package/addon/components/driver-onboard-settings.hbs +2 -8
  12. package/addon/components/entity-field-editing-settings.hbs +2 -5
  13. package/addon/components/equipment/card.hbs +49 -0
  14. package/addon/components/equipment/card.js +6 -0
  15. package/addon/components/equipment/details.hbs +83 -44
  16. package/addon/components/equipment/form.hbs +111 -41
  17. package/addon/components/equipment/form.js +78 -10
  18. package/addon/components/equipment/panel-header.hbs +36 -0
  19. package/addon/components/equipment/panel-header.js +2 -0
  20. package/addon/components/fleet/driver-listing.hbs +3 -1
  21. package/addon/components/fleet/vehicle-listing.hbs +4 -7
  22. package/addon/components/fleet-panel/vehicle-listing.hbs +1 -6
  23. package/addon/components/fuel-report/form.hbs +1 -5
  24. package/addon/components/layout/fleet-ops-sidebar.hbs +40 -36
  25. package/addon/components/layout/fleet-ops-sidebar.js +61 -10
  26. package/addon/components/maintenance/cost-panel.hbs +176 -0
  27. package/addon/components/maintenance/cost-panel.js +241 -0
  28. package/addon/components/maintenance/details.hbs +123 -60
  29. package/addon/components/maintenance/form.hbs +138 -78
  30. package/addon/components/maintenance/form.js +131 -6
  31. package/addon/components/maintenance/panel-header.hbs +31 -0
  32. package/addon/components/maintenance/panel-header.js +2 -0
  33. package/addon/components/maintenance-schedule/details.hbs +260 -0
  34. package/addon/components/maintenance-schedule/details.js +158 -0
  35. package/addon/components/maintenance-schedule/form.hbs +287 -0
  36. package/addon/components/maintenance-schedule/form.js +199 -0
  37. package/addon/components/map/container.hbs +1 -1
  38. package/addon/components/map/drawer/device-event-listing.hbs +1 -1
  39. package/addon/components/map/drawer/driver-listing.hbs +1 -6
  40. package/addon/components/map/drawer/place-listing.hbs +1 -6
  41. package/addon/components/map/drawer/vehicle-listing.hbs +1 -6
  42. package/addon/components/map/drawer.hbs +8 -1
  43. package/addon/components/map/leaflet-live-map.hbs +2 -1
  44. package/addon/components/map/toolbar/visibility-control-panel.hbs +1 -1
  45. package/addon/components/map/toolbar.hbs +4 -29
  46. package/addon/components/modals/add-driver-shift.hbs +155 -0
  47. package/addon/components/modals/add-driver-shift.js +210 -0
  48. package/addon/components/modals/bulk-assign-orders.hbs +67 -0
  49. package/addon/components/modals/driver-shift.hbs +43 -0
  50. package/addon/components/modals/driver-shift.js +56 -0
  51. package/addon/components/modals/entity-form.hbs +5 -28
  52. package/addon/components/modals/orchestrator-import.hbs +351 -0
  53. package/addon/components/modals/orchestrator-import.js +807 -0
  54. package/addon/components/modals/order-config-new-status.hbs +1 -5
  55. package/addon/components/modals/scheduling-conflict.hbs +47 -0
  56. package/addon/components/modals/scheduling-conflict.js +53 -0
  57. package/addon/components/modals/send-work-order.hbs +91 -0
  58. package/addon/components/modals/send-work-order.js +3 -0
  59. package/addon/components/modals/service-area-form.hbs +1 -6
  60. package/addon/components/modals/set-driver-availability.hbs +50 -0
  61. package/addon/components/modals/set-driver-availability.js +57 -0
  62. package/addon/components/modals/update-order-activity.hbs +13 -9
  63. package/addon/components/modals/user-form.hbs +1 -5
  64. package/addon/components/modals/vehicle-form.hbs +17 -102
  65. package/addon/components/modals/vendor-form.hbs +15 -82
  66. package/addon/components/orchestrator/card-fields-settings.hbs +76 -0
  67. package/addon/components/orchestrator/card-fields-settings.js +134 -0
  68. package/addon/components/orchestrator/order-pool.hbs +264 -0
  69. package/addon/components/orchestrator/order-pool.js +394 -0
  70. package/addon/components/orchestrator/phase-builder.hbs +162 -0
  71. package/addon/components/orchestrator/phase-builder.js +162 -0
  72. package/addon/components/orchestrator/plan-viewer.hbs +278 -0
  73. package/addon/components/orchestrator/plan-viewer.js +342 -0
  74. package/addon/components/orchestrator/resource-panel.hbs +301 -0
  75. package/addon/components/orchestrator/resource-panel.js +106 -0
  76. package/addon/components/orchestrator-workbench.hbs +318 -0
  77. package/addon/components/orchestrator-workbench.js +1087 -0
  78. package/addon/components/order/details/custom-fields.hbs +10 -1
  79. package/addon/components/order/details/detail.hbs +37 -2
  80. package/addon/components/order/details/detail.js +0 -1
  81. package/addon/components/order/details/integrated-vendor-details.hbs +4 -4
  82. package/addon/components/order/details/notes.hbs +1 -7
  83. package/addon/components/order/details/route.hbs +1 -5
  84. package/addon/components/order/form/details.hbs +44 -10
  85. package/addon/components/order/form/details.js +57 -0
  86. package/addon/components/order/form/notes.hbs +1 -7
  87. package/addon/components/order/form/payload.hbs +1 -7
  88. package/addon/components/order/form/route.hbs +3 -15
  89. package/addon/components/order/header.hbs +1 -7
  90. package/addon/components/order/route-editor.hbs +4 -25
  91. package/addon/components/order/schedule-card.hbs +102 -95
  92. package/addon/components/order/schedule-card.js +8 -3
  93. package/addon/components/order-config-manager/details.hbs +2 -10
  94. package/addon/components/order-config-manager/entities.hbs +1 -7
  95. package/addon/components/order-config-manager.hbs +1 -6
  96. package/addon/components/part/card.hbs +49 -0
  97. package/addon/components/part/card.js +6 -0
  98. package/addon/components/part/details.hbs +102 -56
  99. package/addon/components/part/form.hbs +131 -56
  100. package/addon/components/part/form.js +78 -11
  101. package/addon/components/part/panel-header.hbs +36 -0
  102. package/addon/components/part/panel-header.js +2 -0
  103. package/addon/components/place/form.hbs +1 -7
  104. package/addon/components/sensor/details.hbs +1 -1
  105. package/addon/components/sensor/form.hbs +5 -3
  106. package/addon/components/sensor/panel-header.hbs +8 -1
  107. package/addon/components/service-area/form.hbs +1 -6
  108. package/addon/components/service-rate/form.hbs +12 -60
  109. package/addon/components/telematic/form.hbs +6 -2
  110. package/addon/components/vehicle/details/maintenance-history.hbs +42 -0
  111. package/addon/components/vehicle/details/maintenance-history.js +32 -0
  112. package/addon/components/vehicle/details/schedules.hbs +40 -0
  113. package/addon/components/vehicle/details/schedules.js +32 -0
  114. package/addon/components/vehicle/details/work-orders.hbs +42 -0
  115. package/addon/components/vehicle/details/work-orders.js +32 -0
  116. package/addon/components/vehicle/details.hbs +30 -0
  117. package/addon/components/vehicle/form.hbs +39 -0
  118. package/addon/components/vehicle/panel-header.hbs +19 -49
  119. package/addon/components/warranty/details.hbs +3 -2
  120. package/addon/components/warranty/form.hbs +3 -17
  121. package/addon/components/work-order/details.hbs +135 -40
  122. package/addon/components/work-order/form.hbs +178 -45
  123. package/addon/components/work-order/form.js +197 -4
  124. package/addon/components/work-order/panel-header.hbs +31 -0
  125. package/addon/components/work-order/panel-header.js +2 -0
  126. package/addon/controllers/connectivity/devices/index/details.js +1 -1
  127. package/addon/controllers/maintenance/equipment/index/details/index.js +0 -1
  128. package/addon/controllers/maintenance/equipment/index/details.js +36 -1
  129. package/addon/controllers/maintenance/equipment/index/edit.js +56 -1
  130. package/addon/controllers/maintenance/equipment/index/new.js +32 -1
  131. package/addon/controllers/maintenance/equipment/index.js +127 -113
  132. package/addon/controllers/maintenance/maintenances/index/details/index.js +3 -0
  133. package/addon/controllers/maintenance/maintenances/index/details.js +54 -0
  134. package/addon/controllers/maintenance/maintenances/index/edit.js +68 -0
  135. package/addon/controllers/maintenance/maintenances/index/new.js +34 -0
  136. package/addon/controllers/maintenance/maintenances/index.js +191 -0
  137. package/addon/controllers/maintenance/parts/index/details/index.js +0 -1
  138. package/addon/controllers/maintenance/parts/index/details.js +36 -1
  139. package/addon/controllers/maintenance/parts/index/edit.js +56 -1
  140. package/addon/controllers/maintenance/parts/index/new.js +32 -1
  141. package/addon/controllers/maintenance/parts/index.js +135 -113
  142. package/addon/controllers/maintenance/schedules/index/details.js +115 -0
  143. package/addon/controllers/maintenance/schedules/index/edit.js +41 -0
  144. package/addon/controllers/maintenance/schedules/index/new.js +33 -0
  145. package/addon/controllers/maintenance/schedules/index.js +280 -0
  146. package/addon/controllers/maintenance/work-orders/index/details.js +41 -1
  147. package/addon/controllers/maintenance/work-orders/index/edit.js +67 -1
  148. package/addon/controllers/maintenance/work-orders/index/new.js +43 -1
  149. package/addon/controllers/maintenance/work-orders/index.js +105 -113
  150. package/addon/controllers/management/drivers/index/details.js +6 -1
  151. package/addon/controllers/management/vehicles/index/details.js +65 -0
  152. package/addon/controllers/management/vehicles/index.js +18 -0
  153. package/addon/controllers/operations/orchestrator.js +10 -0
  154. package/addon/controllers/operations/orders/index.js +6 -0
  155. package/addon/controllers/operations/scheduler/fleet-schedule.js +341 -0
  156. package/addon/controllers/operations/scheduler/index.js +799 -275
  157. package/addon/controllers/operations/scheduler.js +21 -0
  158. package/addon/controllers/settings/orchestrator.js +70 -0
  159. package/addon/controllers/settings/scheduling.js +155 -0
  160. package/addon/extension.js +19 -0
  161. package/addon/instance-initializers/register-vroom-allocation.js +27 -0
  162. package/addon/models/maintenance-schedule.js +61 -0
  163. package/addon/routes/maintenance/equipment/index/details.js +27 -1
  164. package/addon/routes/maintenance/equipment/index/edit.js +27 -1
  165. package/addon/routes/maintenance/maintenances/index/details/index.js +3 -0
  166. package/addon/routes/maintenance/maintenances/index/details.js +29 -0
  167. package/addon/routes/maintenance/maintenances/index/edit.js +29 -0
  168. package/addon/routes/maintenance/maintenances/index/new.js +3 -0
  169. package/addon/routes/maintenance/maintenances/index.js +23 -0
  170. package/addon/routes/maintenance/maintenances.js +3 -0
  171. package/addon/routes/maintenance/parts/index/details.js +27 -1
  172. package/addon/routes/maintenance/parts/index/edit.js +27 -1
  173. package/addon/routes/maintenance/schedules/index/details/index.js +2 -0
  174. package/addon/routes/maintenance/schedules/index/details/work-orders.js +11 -0
  175. package/addon/routes/maintenance/schedules/index/details.js +25 -0
  176. package/addon/routes/maintenance/schedules/index/edit.js +25 -0
  177. package/addon/routes/maintenance/schedules/index/new.js +2 -0
  178. package/addon/routes/maintenance/schedules/index.js +21 -0
  179. package/addon/routes/maintenance/schedules.js +2 -0
  180. package/addon/routes/maintenance/work-orders/index/details.js +27 -1
  181. package/addon/routes/maintenance/work-orders/index/edit.js +27 -1
  182. package/addon/routes/management/vehicles/index/details/maintenance-history.js +3 -0
  183. package/addon/routes/management/vehicles/index/details/schedules.js +3 -0
  184. package/addon/routes/management/vehicles/index/details/work-orders.js +3 -0
  185. package/addon/routes/operations/orchestrator.js +23 -0
  186. package/addon/routes/operations/scheduler/fleet-schedule.js +28 -0
  187. package/addon/routes/operations/scheduler/index.js +48 -26
  188. package/addon/routes/operations/scheduler.js +14 -1
  189. package/addon/routes/settings/orchestrator.js +27 -0
  190. package/addon/routes/settings/scheduling.js +3 -0
  191. package/addon/routes.js +31 -1
  192. package/addon/services/driver-actions.js +40 -7
  193. package/addon/services/driver-scheduling.js +4 -1
  194. package/addon/services/equipment-actions.js +15 -5
  195. package/addon/services/leaflet-map-manager.js +14 -6
  196. package/addon/services/maintenance-actions.js +17 -14
  197. package/addon/services/maintenance-schedule-actions.js +118 -0
  198. package/addon/services/orchestration-engine-interface.js +49 -0
  199. package/addon/services/orchestration-engine.js +74 -0
  200. package/addon/services/order-actions.js +15 -0
  201. package/addon/services/order-allocation.js +116 -0
  202. package/addon/services/part-actions.js +12 -2
  203. package/addon/services/scheduling.js +316 -0
  204. package/addon/services/vehicle-actions.js +70 -7
  205. package/addon/services/vroom-allocation-engine.js +45 -0
  206. package/addon/services/work-order-actions.js +80 -0
  207. package/addon/styles/fleetops-engine.css +1658 -0
  208. package/addon/templates/analytics/reports/index/edit.hbs +1 -1
  209. package/addon/templates/analytics/reports/index/new.hbs +1 -1
  210. package/addon/templates/application.hbs +6 -1
  211. package/addon/templates/connectivity/devices/index/details/events.hbs +0 -1
  212. package/addon/templates/connectivity/devices.hbs +0 -1
  213. package/addon/templates/connectivity/events/index/details.hbs +0 -1
  214. package/addon/templates/connectivity/events.hbs +0 -1
  215. package/addon/templates/connectivity/sensors.hbs +0 -1
  216. package/addon/templates/connectivity/telematics/index/details/devices.hbs +0 -1
  217. package/addon/templates/connectivity/telematics/index/details/events.hbs +0 -1
  218. package/addon/templates/connectivity/telematics/index/details/sensors.hbs +0 -1
  219. package/addon/templates/connectivity/telematics.hbs +0 -1
  220. package/addon/templates/connectivity/tracking.hbs +0 -1
  221. package/addon/templates/connectivity.hbs +0 -1
  222. package/addon/templates/maintenance/equipment/index/details/index.hbs +1 -2
  223. package/addon/templates/maintenance/equipment/index/details.hbs +15 -2
  224. package/addon/templates/maintenance/equipment/index/edit.hbs +12 -2
  225. package/addon/templates/maintenance/equipment/index/new.hbs +1 -2
  226. package/addon/templates/maintenance/equipment/index.hbs +48 -13
  227. package/addon/templates/maintenance/equipment.hbs +0 -1
  228. package/addon/templates/maintenance/maintenances/index/details/index.hbs +1 -0
  229. package/addon/templates/maintenance/maintenances/index/details.hbs +15 -0
  230. package/addon/templates/maintenance/maintenances/index/edit.hbs +12 -0
  231. package/addon/templates/maintenance/maintenances/index/new.hbs +11 -0
  232. package/addon/templates/maintenance/maintenances/index.hbs +14 -0
  233. package/addon/templates/maintenance/maintenances.hbs +1 -0
  234. package/addon/templates/maintenance/parts/index/details/index.hbs +1 -2
  235. package/addon/templates/maintenance/parts/index/details.hbs +15 -2
  236. package/addon/templates/maintenance/parts/index/edit.hbs +12 -2
  237. package/addon/templates/maintenance/parts/index/new.hbs +1 -2
  238. package/addon/templates/maintenance/parts/index.hbs +48 -13
  239. package/addon/templates/maintenance/parts.hbs +0 -1
  240. package/addon/templates/maintenance/schedules/index/details/index.hbs +1 -0
  241. package/addon/templates/maintenance/schedules/index/details/work-orders.hbs +39 -0
  242. package/addon/templates/maintenance/schedules/index/details.hbs +14 -0
  243. package/addon/templates/maintenance/schedules/index/edit.hbs +12 -0
  244. package/addon/templates/maintenance/schedules/index/new.hbs +11 -0
  245. package/addon/templates/maintenance/schedules/index.hbs +40 -0
  246. package/addon/templates/maintenance/schedules.hbs +1 -0
  247. package/addon/templates/maintenance/work-orders/index/details.hbs +2 -1
  248. package/addon/templates/maintenance/work-orders/index/edit.hbs +2 -4
  249. package/addon/templates/maintenance/work-orders/index/new.hbs +1 -2
  250. package/addon/templates/maintenance/work-orders.hbs +0 -1
  251. package/addon/templates/management/contacts/customers/edit.hbs +1 -2
  252. package/addon/templates/management/contacts/customers/new.hbs +1 -2
  253. package/addon/templates/management/contacts/customers.hbs +1 -1
  254. package/addon/templates/management/contacts/index/edit.hbs +1 -2
  255. package/addon/templates/management/contacts/index/new.hbs +1 -2
  256. package/addon/templates/management/drivers/index/details/orders.hbs +0 -1
  257. package/addon/templates/management/drivers/index/edit.hbs +1 -2
  258. package/addon/templates/management/drivers/index/new.hbs +1 -2
  259. package/addon/templates/management/fleets/index/edit.hbs +1 -2
  260. package/addon/templates/management/fleets/index/new.hbs +1 -2
  261. package/addon/templates/management/fleets/index.hbs +1 -2
  262. package/addon/templates/management/fuel-reports/index/edit.hbs +1 -2
  263. package/addon/templates/management/fuel-reports/index/new.hbs +1 -2
  264. package/addon/templates/management/fuel-reports/index.hbs +1 -2
  265. package/addon/templates/management/issues/index/edit.hbs +1 -2
  266. package/addon/templates/management/issues/index/new.hbs +1 -2
  267. package/addon/templates/management/issues/index.hbs +1 -2
  268. package/addon/templates/management/places/index/details/activity.hbs +0 -1
  269. package/addon/templates/management/places/index/details/comments.hbs +0 -1
  270. package/addon/templates/management/places/index/details/documents.hbs +0 -1
  271. package/addon/templates/management/places/index/details/map.hbs +0 -1
  272. package/addon/templates/management/places/index/details/operations.hbs +0 -1
  273. package/addon/templates/management/places/index/details/performance.hbs +0 -1
  274. package/addon/templates/management/places/index/details/rules.hbs +0 -1
  275. package/addon/templates/management/vehicles/index/details/equipment.hbs +0 -1
  276. package/addon/templates/management/vehicles/index/details/maintenance-history.hbs +2 -0
  277. package/addon/templates/management/vehicles/index/details/schedules.hbs +2 -0
  278. package/addon/templates/management/vehicles/index/details/work-orders.hbs +2 -0
  279. package/addon/templates/management/vehicles/index/details.hbs +1 -1
  280. package/addon/templates/management/vehicles/index/edit.hbs +1 -2
  281. package/addon/templates/management/vehicles/index/new.hbs +1 -2
  282. package/addon/templates/management/vendors/index/edit.hbs +1 -2
  283. package/addon/templates/management/vendors/index/new.hbs +1 -2
  284. package/addon/templates/management/vendors/index.hbs +1 -2
  285. package/addon/templates/management/vendors/integrated.hbs +1 -2
  286. package/addon/templates/operations/orchestrator.hbs +1 -0
  287. package/addon/templates/operations/orders/index.hbs +6 -1
  288. package/addon/templates/operations/scheduler/fleet-schedule.hbs +41 -0
  289. package/addon/templates/operations/scheduler/index.hbs +147 -88
  290. package/addon/templates/operations/scheduler.hbs +7 -1
  291. package/addon/templates/settings/avatars.hbs +1 -1
  292. package/addon/templates/settings/orchestrator.hbs +65 -0
  293. package/addon/templates/settings/payments/index.hbs +1 -5
  294. package/addon/templates/settings/scheduling.hbs +82 -0
  295. package/addon/utils/create-full-calendar-event-from-order.js +52 -14
  296. package/addon/utils/create-full-calendar-event-from-schedule-item.js +50 -0
  297. package/addon/utils/fleet-ops-options.js +254 -0
  298. package/addon/utils/route-colors.js +99 -0
  299. package/addon/utils/to-calendar-date.js +70 -0
  300. package/app/components/driver/schedule.js +1 -0
  301. package/app/components/maintenance/cost-panel.js +1 -0
  302. package/app/components/maintenance/panel-header.js +1 -0
  303. package/app/components/maintenance-schedule/details.js +1 -0
  304. package/app/components/maintenance-schedule/form.js +1 -0
  305. package/app/components/modals/add-driver-shift.js +1 -0
  306. package/app/components/modals/bulk-assign-orders.js +1 -0
  307. package/app/components/modals/driver-shift.js +1 -0
  308. package/app/components/modals/orchestrator-import.js +1 -0
  309. package/app/components/modals/scheduling-conflict.js +1 -0
  310. package/app/components/modals/send-work-order.js +1 -0
  311. package/app/components/modals/set-driver-availability.js +1 -0
  312. package/app/components/orchestrator/card-fields-settings.js +1 -0
  313. package/app/components/orchestrator/order-pool.js +1 -0
  314. package/app/components/orchestrator/phase-builder.js +1 -0
  315. package/app/components/orchestrator/plan-viewer.js +1 -0
  316. package/app/components/orchestrator/resource-panel.js +1 -0
  317. package/app/components/orchestrator-workbench.js +1 -0
  318. package/app/components/vehicle/details/maintenance-history.js +1 -0
  319. package/app/components/vehicle/details/schedules.js +1 -0
  320. package/app/components/vehicle/details/work-orders.js +1 -0
  321. package/app/controllers/operations/orchestrator.js +1 -0
  322. package/app/controllers/settings/orchestrator.js +1 -0
  323. package/app/controllers/settings/scheduling.js +1 -0
  324. package/app/routes/operations/orchestrator.js +1 -0
  325. package/app/routes/settings/orchestrator.js +1 -0
  326. package/app/routes/settings/scheduling.js +1 -0
  327. package/app/services/maintenance-schedule-actions.js +1 -0
  328. package/app/services/orchestration-engine-interface.js +1 -0
  329. package/app/services/orchestration-engine.js +1 -0
  330. package/app/services/order-allocation.js +1 -0
  331. package/app/services/scheduling.js +1 -0
  332. package/app/services/vroom-allocation-engine.js +1 -0
  333. package/app/templates/settings/scheduling.js +1 -0
  334. package/app/utils/create-full-calendar-event-from-schedule-item.js +1 -0
  335. package/app/utils/route-colors.js +1 -0
  336. package/composer.json +5 -3
  337. package/extension.json +1 -1
  338. package/package.json +6 -5
  339. package/server/config/fleetops.php +20 -1
  340. package/server/migrations/2025_08_28_054927_create_parts_table.php +2 -2
  341. package/server/migrations/2025_08_28_054932_add_public_id_to_maintenance_tables.php +45 -0
  342. package/server/migrations/2025_09_01_000001_create_maintenance_schedules_table.php +88 -0
  343. package/server/migrations/2026_04_01_000001_fix_monetary_columns_in_parts_table.php +48 -0
  344. package/server/migrations/2026_04_01_000003_add_photo_uuid_to_equipment_and_parts_tables.php +61 -0
  345. package/server/migrations/2026_04_01_000004_add_public_id_to_equipments_table.php +38 -0
  346. package/server/migrations/2026_04_01_000005_add_missing_columns_to_parts_table.php +67 -0
  347. package/server/migrations/2026_04_04_000001_add_reminder_offsets_to_maintenance_schedules.php +44 -0
  348. package/server/migrations/2026_04_08_000001_add_orchestrator_columns_to_vehicles_table.php +58 -0
  349. package/server/migrations/2026_04_08_000002_add_orchestrator_columns_to_drivers_table.php +41 -0
  350. package/server/migrations/2026_04_08_000003_add_orchestrator_columns_to_orders_table.php +38 -0
  351. package/server/migrations/2026_04_08_000004_add_orchestrator_columns_to_payloads_table.php +41 -0
  352. package/server/migrations/2026_04_08_000005_add_orchestrator_columns_to_waypoints_table.php +38 -0
  353. package/server/migrations/2026_04_09_000001_create_manifests_table.php +48 -0
  354. package/server/migrations/2026_04_09_000002_create_manifest_stops_table.php +48 -0
  355. package/server/migrations/2026_04_09_000003_add_manifest_uuid_to_orders_table.php +28 -0
  356. package/server/migrations/2026_04_13_000001_add_pod_notes_columns_to_waypoints_table.php +39 -0
  357. package/server/resources/views/mail/maintenance-schedule-reminder.blade.php +59 -0
  358. package/server/resources/views/mail/work-order-dispatched.blade.php +67 -0
  359. package/server/src/Auth/Schemas/FleetOps.php +44 -0
  360. package/server/src/Console/Commands/ProcessMaintenanceTriggers.php +150 -0
  361. package/server/src/Console/Commands/SendMaintenanceReminders.php +128 -0
  362. package/server/src/Http/Controllers/Internal/v1/DriverController.php +1 -0
  363. package/server/src/Http/Controllers/Internal/v1/EquipmentController.php +27 -0
  364. package/server/src/Http/Controllers/Internal/v1/LiveController.php +9 -2
  365. package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +165 -0
  366. package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +304 -0
  367. package/server/src/Http/Controllers/Internal/v1/ManifestController.php +138 -0
  368. package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +975 -0
  369. package/server/src/Http/Controllers/Internal/v1/OrderController.php +42 -0
  370. package/server/src/Http/Controllers/Internal/v1/PartController.php +27 -0
  371. package/server/src/Http/Controllers/Internal/v1/SettingController.php +118 -0
  372. package/server/src/Http/Controllers/Internal/v1/Traits/DriverSchedulingTrait.php +214 -0
  373. package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +68 -0
  374. package/server/src/Http/Resources/v1/Driver.php +1 -0
  375. package/server/src/Http/Resources/v1/Maintenance.php +138 -0
  376. package/server/src/Http/Resources/v1/MaintenanceSchedule.php +137 -0
  377. package/server/src/Http/Resources/v1/Orchestrator/Order.php +116 -0
  378. package/server/src/Http/Resources/v1/Order.php +7 -4
  379. package/server/src/Http/Resources/v1/Waypoint.php +7 -0
  380. package/server/src/Http/Resources/v1/WorkOrder.php +136 -0
  381. package/server/src/Imports/EquipmentImport.php +32 -0
  382. package/server/src/Imports/MaintenanceImport.php +32 -0
  383. package/server/src/Imports/MaintenanceScheduleImport.php +32 -0
  384. package/server/src/Imports/PartImport.php +32 -0
  385. package/server/src/Imports/WorkOrderImport.php +32 -0
  386. package/server/src/Jobs/ProcessAllocationJob.php +119 -0
  387. package/server/src/Listeners/HandleDeliveryCompletion.php +47 -0
  388. package/server/src/Listeners/NotifyDriverOnShiftChange.php +63 -0
  389. package/server/src/Mail/MaintenanceScheduleReminder.php +68 -0
  390. package/server/src/Mail/WorkOrderDispatched.php +58 -0
  391. package/server/src/Models/Asset.php +2 -2
  392. package/server/src/Models/Device.php +1 -1
  393. package/server/src/Models/Driver.php +82 -4
  394. package/server/src/Models/Equipment.php +62 -2
  395. package/server/src/Models/Maintenance.php +127 -9
  396. package/server/src/Models/MaintenanceSchedule.php +353 -0
  397. package/server/src/Models/Manifest.php +214 -0
  398. package/server/src/Models/ManifestStop.php +162 -0
  399. package/server/src/Models/Order.php +70 -0
  400. package/server/src/Models/OrderConfig.php +5 -2
  401. package/server/src/Models/Part.php +69 -3
  402. package/server/src/Models/Payload.php +7 -2
  403. package/server/src/Models/Place.php +1 -1
  404. package/server/src/Models/Sensor.php +1 -1
  405. package/server/src/Models/ServiceQuote.php +1 -1
  406. package/server/src/Models/Vehicle.php +20 -1
  407. package/server/src/Models/Warranty.php +1 -1
  408. package/server/src/Models/Waypoint.php +7 -1
  409. package/server/src/Models/WorkOrder.php +122 -12
  410. package/server/src/Notifications/DriverShiftChanged.php +110 -0
  411. package/server/src/Observers/WorkOrderObserver.php +107 -0
  412. package/server/src/Orchestration/Contracts/OrchestrationEngineInterface.php +63 -0
  413. package/server/src/Orchestration/Engines/DriverAssignmentEngine.php +265 -0
  414. package/server/src/Orchestration/Engines/GreedyOrchestrationEngine.php +155 -0
  415. package/server/src/Orchestration/Engines/RouteSequencingEngine.php +272 -0
  416. package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +192 -0
  417. package/server/src/Orchestration/OrchestrationEngineRegistry.php +83 -0
  418. package/server/src/Orchestration/Support/OrchestrationPayloadBuilder.php +290 -0
  419. package/server/src/Providers/EventServiceProvider.php +7 -1
  420. package/server/src/Providers/FleetOpsServiceProvider.php +42 -15
  421. package/server/src/routes.php +65 -4
  422. package/translations/ar-ae.yml +44 -12
  423. package/translations/bg-bg.yaml +51 -10
  424. package/translations/en-us.yaml +444 -1
  425. package/translations/fr-fr.yaml +51 -10
  426. package/translations/mn-mn.yaml +51 -10
  427. package/translations/pt-br.yaml +51 -10
  428. package/translations/ru-ru.yaml +51 -10
  429. package/translations/vi-vn.yaml +48 -12
@@ -0,0 +1,119 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Jobs;
4
+
5
+ use Fleetbase\FleetOps\Models\Driver;
6
+ use Fleetbase\FleetOps\Models\Order;
7
+ use Fleetbase\FleetOps\Models\Vehicle;
8
+ use Fleetbase\FleetOps\Orchestration\OrchestrationEngineRegistry;
9
+ use Fleetbase\Models\Setting;
10
+ use Illuminate\Bus\Queueable;
11
+ use Illuminate\Contracts\Queue\ShouldQueue;
12
+ use Illuminate\Foundation\Bus\Dispatchable;
13
+ use Illuminate\Queue\InteractsWithQueue;
14
+ use Illuminate\Queue\SerializesModels;
15
+ use Illuminate\Support\Facades\Log;
16
+
17
+ /**
18
+ * ProcessAllocationJob.
19
+ *
20
+ * Dispatched asynchronously when auto-allocation is triggered (e.g. on order
21
+ * creation or on delivery completion when auto_reallocate_on_complete is
22
+ * enabled). The job runs the active allocation engine and commits all
23
+ * assignments automatically.
24
+ *
25
+ * The job is idempotent — if an order has already been assigned by the time
26
+ * the job runs, it is silently skipped.
27
+ *
28
+ * @example Dispatching from a listener:
29
+ * ProcessAllocationJob::dispatch($companyUuid, $orderIds);
30
+ */
31
+ class ProcessAllocationJob implements ShouldQueue
32
+ {
33
+ use Dispatchable;
34
+ use InteractsWithQueue;
35
+ use Queueable;
36
+ use SerializesModels;
37
+
38
+ /**
39
+ * Maximum number of retry attempts before the job is marked as failed.
40
+ */
41
+ public int $tries = 3;
42
+
43
+ /**
44
+ * @param string $companyUuid the company to run allocation for
45
+ * @param array $orderIds Optional list of order public_ids to allocate.
46
+ * If empty, all unassigned orders are used.
47
+ */
48
+ public function __construct(
49
+ protected string $companyUuid,
50
+ protected array $orderIds = [],
51
+ ) {
52
+ }
53
+
54
+ public function handle(OrchestrationEngineRegistry $registry): void
55
+ {
56
+ $ordersQuery = Order::where('company_uuid', $this->companyUuid)
57
+ ->whereNull('driver_assigned_uuid')
58
+ ->whereNotIn('status', ['completed', 'cancelled'])
59
+ ->with(['payload.dropoff', 'payload.waypoints']);
60
+
61
+ if (!empty($this->orderIds)) {
62
+ $ordersQuery->whereIn('public_id', $this->orderIds);
63
+ }
64
+
65
+ $orders = $ordersQuery->get();
66
+
67
+ if ($orders->isEmpty()) {
68
+ Log::info("[ProcessAllocationJob] No unassigned orders for company {$this->companyUuid}.");
69
+
70
+ return;
71
+ }
72
+
73
+ $vehicles = Vehicle::where('company_uuid', $this->companyUuid)
74
+ ->with(['driver' => fn ($q) => $q->where('online', true)])
75
+ ->get()
76
+ ->filter(fn ($v) => $v->driver !== null);
77
+
78
+ if ($vehicles->isEmpty()) {
79
+ Log::info("[ProcessAllocationJob] No available vehicles for company {$this->companyUuid}.");
80
+
81
+ return;
82
+ }
83
+
84
+ $engineId = Setting::lookup('fleetops.orchestrator_engine', 'greedy');
85
+ $engine = $registry->resolve($engineId);
86
+
87
+ $result = $engine->allocate($orders, $vehicles, [
88
+ 'max_travel_time' => Setting::lookup('fleetops.allocation_max_travel_time', 3600),
89
+ 'balance_workload' => Setting::lookup('fleetops.allocation_balance_workload', false),
90
+ ]);
91
+
92
+ foreach ($result['assignments'] as $assignment) {
93
+ $order = Order::where('public_id', $assignment['order_id'])->first();
94
+ $driver = Driver::where('public_id', $assignment['driver_id'])->first();
95
+
96
+ if (!$order || !$driver) {
97
+ continue;
98
+ }
99
+
100
+ // Skip if already assigned (idempotency guard)
101
+ if ($order->driver_assigned_uuid) {
102
+ continue;
103
+ }
104
+
105
+ $order->driver_assigned_uuid = $driver->uuid;
106
+ $order->save();
107
+ $order->firstDispatchWithActivity();
108
+ }
109
+
110
+ Log::info(
111
+ sprintf(
112
+ '[ProcessAllocationJob] Committed %d assignments, %d unassigned for company %s.',
113
+ count($result['assignments']),
114
+ count($result['unassigned']),
115
+ $this->companyUuid
116
+ )
117
+ );
118
+ }
119
+ }
@@ -0,0 +1,47 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Listeners;
4
+
5
+ use Fleetbase\FleetOps\Events\OrderCompleted;
6
+ use Fleetbase\FleetOps\Jobs\ProcessAllocationJob;
7
+ use Fleetbase\Models\Setting;
8
+ use Illuminate\Contracts\Queue\ShouldQueue;
9
+
10
+ /**
11
+ * HandleDeliveryCompletion.
12
+ *
13
+ * Listens for the OrderCompleted event and dispatches a new allocation run
14
+ * when the 'auto_reallocate_on_complete' setting is enabled.
15
+ *
16
+ * This closes the re-allocation loop: as drivers complete deliveries and
17
+ * become available, the engine automatically picks up the next batch of
18
+ * unassigned orders without dispatcher intervention.
19
+ *
20
+ * The listener is registered in EventServiceProvider alongside the existing
21
+ * HandleOrderDispatched and HandleOrderReady listeners.
22
+ */
23
+ class HandleDeliveryCompletion implements ShouldQueue
24
+ {
25
+ /**
26
+ * Handle the OrderCompleted event.
27
+ */
28
+ public function handle(OrderCompleted $event): void
29
+ {
30
+ $order = $event->order ?? null;
31
+
32
+ if (!$order) {
33
+ return;
34
+ }
35
+
36
+ $companyUuid = $order->company_uuid;
37
+
38
+ // Only re-allocate if the setting is enabled for this company
39
+ if (!Setting::lookup('fleetops.auto_reallocate_on_complete', false)) {
40
+ return;
41
+ }
42
+
43
+ // Dispatch the allocation job asynchronously so it does not block
44
+ // the order completion response.
45
+ ProcessAllocationJob::dispatch($companyUuid);
46
+ }
47
+ }
@@ -0,0 +1,63 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Listeners;
4
+
5
+ use Fleetbase\FleetOps\Models\Driver;
6
+ use Fleetbase\FleetOps\Notifications\DriverShiftChanged;
7
+ use Fleetbase\Models\Schedule;
8
+ use Fleetbase\Models\ScheduleItem;
9
+ use Fleetbase\Models\Setting;
10
+ use Illuminate\Contracts\Queue\ShouldQueue;
11
+ use Illuminate\Queue\InteractsWithQueue;
12
+
13
+ /**
14
+ * Listener: NotifyDriverOnShiftChange.
15
+ *
16
+ * Fires after a ScheduleItem is created or updated. Checks the company-level
17
+ * `notify_drivers_on_shift_change` scheduling setting and, if enabled, sends
18
+ * a DriverShiftChanged mail notification to the driver who owns the schedule.
19
+ */
20
+ class NotifyDriverOnShiftChange implements ShouldQueue
21
+ {
22
+ use InteractsWithQueue;
23
+
24
+ /**
25
+ * Handle the event.
26
+ *
27
+ * @param object $event Either ScheduleItemCreated or ScheduleItemUpdated
28
+ */
29
+ public function handle($event): void
30
+ {
31
+ /** @var ScheduleItem $scheduleItem */
32
+ $scheduleItem = $event->scheduleItem ?? null;
33
+ if (!$scheduleItem instanceof ScheduleItem) {
34
+ return;
35
+ }
36
+
37
+ // Load the parent schedule to find the subject (driver)
38
+ /** @var Schedule|null $schedule */
39
+ $schedule = $scheduleItem->schedule()->with('subject')->first();
40
+ if (!$schedule) {
41
+ return;
42
+ }
43
+
44
+ // Only proceed if the subject is a Driver
45
+ $subject = $schedule->subject;
46
+ if (!$subject instanceof Driver) {
47
+ return;
48
+ }
49
+
50
+ // Check the company-level scheduling setting
51
+ $settings = Setting::lookupFromCompany('fleet-ops.scheduling-settings', []);
52
+ $shouldNotify = (bool) data_get($settings, 'notify_drivers_on_shift_change', false);
53
+ if (!$shouldNotify) {
54
+ return;
55
+ }
56
+
57
+ // Determine if this is a new shift or an update
58
+ $isNew = $event instanceof \Fleetbase\Events\ScheduleItemCreated;
59
+
60
+ // Send the notification to the driver
61
+ $subject->notify(new DriverShiftChanged($scheduleItem, $isNew));
62
+ }
63
+ }
@@ -0,0 +1,68 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Mail;
4
+
5
+ use Fleetbase\FleetOps\Models\MaintenanceSchedule;
6
+ use Illuminate\Bus\Queueable;
7
+ use Illuminate\Mail\Mailable;
8
+ use Illuminate\Mail\Mailables\Content;
9
+ use Illuminate\Mail\Mailables\Envelope;
10
+ use Illuminate\Queue\SerializesModels;
11
+
12
+ class MaintenanceScheduleReminder extends Mailable
13
+ {
14
+ use Queueable;
15
+ use SerializesModels;
16
+
17
+ /**
18
+ * The maintenance schedule this reminder is for.
19
+ */
20
+ public MaintenanceSchedule $schedule;
21
+
22
+ /**
23
+ * How many days before the due date this reminder is firing.
24
+ */
25
+ public int $offsetDays;
26
+
27
+ /**
28
+ * Create a new message instance.
29
+ */
30
+ public function __construct(MaintenanceSchedule $schedule, int $offsetDays)
31
+ {
32
+ $this->schedule = $schedule;
33
+ $this->offsetDays = $offsetDays;
34
+ }
35
+
36
+ /**
37
+ * Get the message envelope.
38
+ */
39
+ public function envelope(): Envelope
40
+ {
41
+ $subject = 'Maintenance Reminder: ' . $this->schedule->name;
42
+
43
+ if ($this->schedule->subject) {
44
+ $assetName = $this->schedule->subject->name
45
+ ?? $this->schedule->subject->display_name
46
+ ?? $this->schedule->subject->public_id;
47
+ $subject .= ' — ' . $assetName;
48
+ }
49
+
50
+ return new Envelope(subject: $subject);
51
+ }
52
+
53
+ /**
54
+ * Get the message content definition.
55
+ */
56
+ public function content(): Content
57
+ {
58
+ return new Content(
59
+ markdown: 'fleetops::mail.maintenance-schedule-reminder',
60
+ with: [
61
+ 'schedule' => $this->schedule,
62
+ 'assignee' => $this->schedule->defaultAssignee,
63
+ 'subject' => $this->schedule->subject,
64
+ 'offsetDays' => $this->offsetDays,
65
+ ]
66
+ );
67
+ }
68
+ }
@@ -0,0 +1,58 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Mail;
4
+
5
+ use Fleetbase\FleetOps\Models\WorkOrder;
6
+ use Illuminate\Bus\Queueable;
7
+ use Illuminate\Mail\Mailable;
8
+ use Illuminate\Mail\Mailables\Content;
9
+ use Illuminate\Mail\Mailables\Envelope;
10
+ use Illuminate\Queue\SerializesModels;
11
+
12
+ class WorkOrderDispatched extends Mailable
13
+ {
14
+ use Queueable;
15
+ use SerializesModels;
16
+
17
+ /**
18
+ * The work order being dispatched.
19
+ */
20
+ public WorkOrder $workOrder;
21
+
22
+ /**
23
+ * Create a new message instance.
24
+ */
25
+ public function __construct(WorkOrder $workOrder)
26
+ {
27
+ $this->workOrder = $workOrder;
28
+ }
29
+
30
+ /**
31
+ * Get the message envelope.
32
+ */
33
+ public function envelope(): Envelope
34
+ {
35
+ $subject = 'Work Order #' . $this->workOrder->public_id;
36
+
37
+ if ($this->workOrder->subject) {
38
+ $subject .= ': ' . $this->workOrder->subject;
39
+ }
40
+
41
+ return new Envelope(subject: $subject);
42
+ }
43
+
44
+ /**
45
+ * Get the message content definition.
46
+ */
47
+ public function content(): Content
48
+ {
49
+ return new Content(
50
+ markdown: 'fleetops::mail.work-order-dispatched',
51
+ with: [
52
+ 'workOrder' => $this->workOrder,
53
+ 'assignee' => $this->workOrder->assignee,
54
+ 'target' => $this->workOrder->target,
55
+ ]
56
+ );
57
+ }
58
+ }
@@ -210,12 +210,12 @@ class Asset extends Model
210
210
 
211
211
  public function assignedTo(): MorphTo
212
212
  {
213
- return $this->morphTo();
213
+ return $this->morphTo(__FUNCTION__, 'assigned_to_type', 'assigned_to_uuid');
214
214
  }
215
215
 
216
216
  public function operator(): MorphTo
217
217
  {
218
- return $this->morphTo();
218
+ return $this->morphTo(__FUNCTION__, 'operator_type', 'operator_uuid');
219
219
  }
220
220
 
221
221
  public function category(): BelongsTo
@@ -220,7 +220,7 @@ class Device extends Model
220
220
 
221
221
  public function attachable(): MorphTo
222
222
  {
223
- return $this->morphTo();
223
+ return $this->morphTo(__FUNCTION__, 'attachable_type', 'attachable_uuid');
224
224
  }
225
225
 
226
226
  public function events(): HasMany
@@ -11,6 +11,9 @@ use Fleetbase\LaravelMysqlSpatial\Eloquent\SpatialTrait;
11
11
  use Fleetbase\LaravelMysqlSpatial\Types\Point as SpatialPoint;
12
12
  use Fleetbase\Models\File;
13
13
  use Fleetbase\Models\Model;
14
+ use Fleetbase\Models\Schedule;
15
+ use Fleetbase\Models\ScheduleAvailability;
16
+ use Fleetbase\Models\ScheduleItem;
14
17
  use Fleetbase\Models\User;
15
18
  use Fleetbase\Traits\HasApiModelBehavior;
16
19
  use Fleetbase\Traits\HasApiModelCache;
@@ -25,6 +28,8 @@ use Illuminate\Database\Eloquent\Builder;
25
28
  use Illuminate\Database\Eloquent\Relations\BelongsTo;
26
29
  use Illuminate\Database\Eloquent\Relations\HasMany;
27
30
  use Illuminate\Database\Eloquent\Relations\HasManyThrough;
31
+ use Illuminate\Database\Eloquent\Relations\MorphMany;
32
+ use Illuminate\Database\Eloquent\Relations\MorphOne;
28
33
  use Illuminate\Notifications\Notifiable;
29
34
  use Illuminate\Support\Arr;
30
35
  use Illuminate\Support\Collection;
@@ -105,6 +110,12 @@ class Driver extends Model
105
110
  'slug',
106
111
  'status',
107
112
  'meta,',
113
+ // Orchestrator
114
+ 'skills',
115
+ 'max_travel_time',
116
+ 'max_distance',
117
+ 'time_window_start',
118
+ 'time_window_end',
108
119
  ];
109
120
 
110
121
  /**
@@ -127,9 +138,13 @@ class Driver extends Model
127
138
  * @var array
128
139
  */
129
140
  protected $casts = [
130
- 'location' => Point::class,
131
- 'online' => 'boolean',
132
- 'meta' => Json::class,
141
+ 'location' => Point::class,
142
+ 'online' => 'boolean',
143
+ 'meta' => Json::class,
144
+ // Orchestrator
145
+ 'skills' => Json::class,
146
+ 'max_travel_time' => 'integer',
147
+ 'max_distance' => 'integer',
133
148
  ];
134
149
 
135
150
  /**
@@ -300,6 +315,69 @@ class Driver extends Model
300
315
  return $this->hasMany(\Fleetbase\Models\UserDevice::class, 'user_uuid', 'user_uuid');
301
316
  }
302
317
 
318
+ /**
319
+ * Get all schedules assigned to this driver.
320
+ * The driver acts as the polymorphic `subject` on the Schedule model.
321
+ */
322
+ public function schedules(): MorphMany
323
+ {
324
+ // Explicit FK columns required — Fleetbase uses *_uuid not *_id
325
+ return $this->morphMany(Schedule::class, 'subject', 'subject_type', 'subject_uuid');
326
+ }
327
+
328
+ /**
329
+ * Get all individual schedule items (shifts) assigned to this driver.
330
+ * The driver acts as the polymorphic `assignee` on the ScheduleItem model.
331
+ */
332
+ public function scheduleItems(): MorphMany
333
+ {
334
+ // Explicit FK columns required — Fleetbase uses *_uuid not *_id
335
+ return $this->morphMany(ScheduleItem::class, 'assignee', 'assignee_type', 'assignee_uuid');
336
+ }
337
+
338
+ /**
339
+ * The driver's current active shift — the ScheduleItem whose window
340
+ * contains the current timestamp and whose status is 'scheduled' or 'active'.
341
+ *
342
+ * Exposed as an eager-loadable MorphOne so the order scheduler route can
343
+ * request it via with: ['currentShift'] without triggering an N+1 query.
344
+ * The FullCalendar resource timeline uses this to render shift-window
345
+ * background events for each driver resource row.
346
+ */
347
+ public function currentShift(): MorphOne
348
+ {
349
+ return $this->morphOne(ScheduleItem::class, 'assignee', 'assignee_type', 'assignee_uuid')
350
+ ->whereIn('status', ['scheduled', 'active'])
351
+ ->where('start_at', '<=', now())
352
+ ->where('end_at', '>=', now())
353
+ ->latest('start_at');
354
+ }
355
+
356
+ /**
357
+ * Get the active schedule item (shift) for a given date.
358
+ * Used by OrchestrationPayloadBuilder to inject time_window constraints.
359
+ */
360
+ public function activeShiftFor(?\DateTimeInterface $date = null): ?ScheduleItem
361
+ {
362
+ $date = $date ?? now();
363
+
364
+ return $this->scheduleItems()
365
+ ->whereDate('start_at', $date)
366
+ ->whereIn('status', ['pending', 'active'])
367
+ ->orderBy('start_at')
368
+ ->first();
369
+ }
370
+
371
+ /**
372
+ * Get all availability records (time-off, preferred hours) for this driver.
373
+ * The driver acts as the polymorphic `subject` on the ScheduleAvailability model.
374
+ */
375
+ public function availabilities(): MorphMany
376
+ {
377
+ // Explicit FK columns required — Fleetbase uses *_uuid not *_id
378
+ return $this->morphMany(ScheduleAvailability::class, 'subject', 'subject_type', 'subject_uuid');
379
+ }
380
+
303
381
  /**
304
382
  * Get avatar url.
305
383
  */
@@ -364,7 +442,7 @@ class Driver extends Model
364
442
  function ($option) {
365
443
  $key = str_replace(['.svg', '.png'], '', $option);
366
444
 
367
- return [$key => Utils::assetFromS3('static/driver-icons/' . $option)];
445
+ return [$key => Utils::assetFromFleetbase('static/driver-icons/' . $option)];
368
446
  }
369
447
  );
370
448
 
@@ -3,6 +3,8 @@
3
3
  namespace Fleetbase\FleetOps\Models;
4
4
 
5
5
  use Fleetbase\Casts\Json;
6
+ use Fleetbase\Casts\Money;
7
+ use Fleetbase\FleetOps\Support\Utils;
6
8
  use Fleetbase\Models\File;
7
9
  use Fleetbase\Models\Model;
8
10
  use Fleetbase\Models\User;
@@ -87,6 +89,7 @@ class Equipment extends Model
87
89
  'equipable_uuid',
88
90
  'purchased_at',
89
91
  'purchase_price',
92
+ 'currency',
90
93
  'meta',
91
94
  'slug',
92
95
  ];
@@ -119,7 +122,8 @@ class Equipment extends Model
119
122
  */
120
123
  protected $casts = [
121
124
  'purchased_at' => 'date',
122
- 'purchase_price' => 'decimal:2',
125
+ // Money values
126
+ 'purchase_price' => Money::class,
123
127
  'meta' => Json::class,
124
128
  ];
125
129
 
@@ -184,7 +188,7 @@ class Equipment extends Model
184
188
 
185
189
  public function equipable(): MorphTo
186
190
  {
187
- return $this->morphTo();
191
+ return $this->morphTo(__FUNCTION__, 'equipable_type', 'equipable_uuid');
188
192
  }
189
193
 
190
194
  public function maintenances(): HasMany
@@ -480,4 +484,60 @@ class Equipment extends Model
480
484
 
481
485
  return null;
482
486
  }
487
+
488
+ /**
489
+ * Create an Equipment instance from an import row.
490
+ *
491
+ * Monetary values (purchase_price) must be supplied in cents (integers).
492
+ * The Money cast will strip non-numeric characters before storage.
493
+ *
494
+ * @param array $row Associative array from the import spreadsheet
495
+ * @param bool $saveInstance Whether to persist the record immediately
496
+ */
497
+ public static function createFromImport(array $row, bool $saveInstance = false): Equipment
498
+ {
499
+ $row = array_filter($row);
500
+
501
+ $name = Utils::or($row, ['name']);
502
+ $code = Utils::or($row, ['code', 'internal_id']);
503
+ $type = Utils::or($row, ['type'], 'equipment');
504
+ $status = Utils::or($row, ['status'], 'operational');
505
+ $serialNumber = Utils::or($row, ['serial_number', 'serial']);
506
+ $manufacturer = Utils::or($row, ['manufacturer', 'make', 'brand']);
507
+ $model = Utils::or($row, ['model', 'equipment_model']);
508
+ $purchasePrice = Utils::or($row, ['purchase_price', 'price', 'cost']);
509
+ $currency = Utils::or($row, ['currency'], 'USD');
510
+ $purchasedAt = Utils::or($row, ['purchased_at', 'purchase_date']);
511
+ $warrantyName = Utils::or($row, ['warranty_name', 'warranty']);
512
+
513
+ $equipment = new static([
514
+ 'company_uuid' => session('company'),
515
+ 'name' => $name,
516
+ 'code' => $code,
517
+ 'type' => $type,
518
+ 'status' => $status,
519
+ 'serial_number' => $serialNumber,
520
+ 'manufacturer' => $manufacturer,
521
+ 'model' => $model,
522
+ 'purchase_price' => $purchasePrice,
523
+ 'currency' => strtoupper($currency ?? 'USD'),
524
+ 'purchased_at' => $purchasedAt ? \Carbon\Carbon::parse($purchasedAt) : null,
525
+ ]);
526
+
527
+ // Attempt to resolve warranty by name
528
+ if ($warrantyName) {
529
+ $warranty = Warranty::where('company_uuid', session('company'))
530
+ ->where('name', 'like', '%' . $warrantyName . '%')
531
+ ->first();
532
+ if ($warranty) {
533
+ $equipment->warranty_uuid = $warranty->uuid;
534
+ }
535
+ }
536
+
537
+ if ($saveInstance === true) {
538
+ $equipment->save();
539
+ }
540
+
541
+ return $equipment;
542
+ }
483
543
  }