@fleetbase/fleetops-engine 0.6.38 → 0.6.40

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 (432) 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 +43 -38
  25. package/addon/components/layout/fleet-ops-sidebar.js +103 -24
  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 +1088 -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 +52 -0
  117. package/addon/components/vehicle/form.hbs +51 -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 +79 -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 +4 -2
  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 +53 -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 +38 -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/migrations/2026_04_14_000001_drop_redundant_capacity_columns_from_payloads_table.php +42 -0
  358. package/server/migrations/2026_04_14_000002_rename_capacity_columns_on_vehicles_table.php +48 -0
  359. package/server/resources/views/mail/maintenance-schedule-reminder.blade.php +59 -0
  360. package/server/resources/views/mail/work-order-dispatched.blade.php +67 -0
  361. package/server/src/Auth/Schemas/FleetOps.php +44 -0
  362. package/server/src/Console/Commands/ProcessMaintenanceTriggers.php +150 -0
  363. package/server/src/Console/Commands/SendMaintenanceReminders.php +128 -0
  364. package/server/src/Http/Controllers/Api/v1/OrderController.php +15 -2
  365. package/server/src/Http/Controllers/Api/v1/VehicleController.php +18 -2
  366. package/server/src/Http/Controllers/Internal/v1/DriverController.php +1 -0
  367. package/server/src/Http/Controllers/Internal/v1/EquipmentController.php +27 -0
  368. package/server/src/Http/Controllers/Internal/v1/LiveController.php +9 -2
  369. package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +165 -0
  370. package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +304 -0
  371. package/server/src/Http/Controllers/Internal/v1/ManifestController.php +138 -0
  372. package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +975 -0
  373. package/server/src/Http/Controllers/Internal/v1/OrderController.php +42 -0
  374. package/server/src/Http/Controllers/Internal/v1/PartController.php +27 -0
  375. package/server/src/Http/Controllers/Internal/v1/SettingController.php +118 -0
  376. package/server/src/Http/Controllers/Internal/v1/Traits/DriverSchedulingTrait.php +214 -0
  377. package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +68 -0
  378. package/server/src/Http/Resources/v1/Driver.php +1 -0
  379. package/server/src/Http/Resources/v1/Maintenance.php +138 -0
  380. package/server/src/Http/Resources/v1/MaintenanceSchedule.php +137 -0
  381. package/server/src/Http/Resources/v1/Orchestrator/Order.php +116 -0
  382. package/server/src/Http/Resources/v1/Order.php +7 -4
  383. package/server/src/Http/Resources/v1/Waypoint.php +7 -0
  384. package/server/src/Http/Resources/v1/WorkOrder.php +136 -0
  385. package/server/src/Imports/EquipmentImport.php +32 -0
  386. package/server/src/Imports/MaintenanceImport.php +32 -0
  387. package/server/src/Imports/MaintenanceScheduleImport.php +32 -0
  388. package/server/src/Imports/PartImport.php +32 -0
  389. package/server/src/Imports/WorkOrderImport.php +32 -0
  390. package/server/src/Jobs/ProcessAllocationJob.php +119 -0
  391. package/server/src/Listeners/HandleDeliveryCompletion.php +47 -0
  392. package/server/src/Listeners/NotifyDriverOnShiftChange.php +63 -0
  393. package/server/src/Mail/MaintenanceScheduleReminder.php +68 -0
  394. package/server/src/Mail/WorkOrderDispatched.php +58 -0
  395. package/server/src/Models/Asset.php +2 -2
  396. package/server/src/Models/Device.php +1 -1
  397. package/server/src/Models/Driver.php +82 -4
  398. package/server/src/Models/Equipment.php +62 -2
  399. package/server/src/Models/Maintenance.php +127 -9
  400. package/server/src/Models/MaintenanceSchedule.php +353 -0
  401. package/server/src/Models/Manifest.php +214 -0
  402. package/server/src/Models/ManifestStop.php +162 -0
  403. package/server/src/Models/Order.php +70 -0
  404. package/server/src/Models/OrderConfig.php +5 -2
  405. package/server/src/Models/Part.php +69 -3
  406. package/server/src/Models/Place.php +1 -1
  407. package/server/src/Models/Sensor.php +1 -1
  408. package/server/src/Models/ServiceQuote.php +1 -1
  409. package/server/src/Models/Vehicle.php +18 -1
  410. package/server/src/Models/Warranty.php +1 -1
  411. package/server/src/Models/Waypoint.php +7 -1
  412. package/server/src/Models/WorkOrder.php +122 -12
  413. package/server/src/Notifications/DriverShiftChanged.php +110 -0
  414. package/server/src/Observers/WorkOrderObserver.php +107 -0
  415. package/server/src/Orchestration/Contracts/OrchestrationEngineInterface.php +63 -0
  416. package/server/src/Orchestration/Engines/DriverAssignmentEngine.php +265 -0
  417. package/server/src/Orchestration/Engines/GreedyOrchestrationEngine.php +155 -0
  418. package/server/src/Orchestration/Engines/RouteSequencingEngine.php +272 -0
  419. package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +192 -0
  420. package/server/src/Orchestration/OrchestrationEngineRegistry.php +83 -0
  421. package/server/src/Orchestration/Support/OrchestrationPayloadBuilder.php +380 -0
  422. package/server/src/Providers/EventServiceProvider.php +7 -1
  423. package/server/src/Providers/FleetOpsServiceProvider.php +42 -15
  424. package/server/src/routes.php +65 -4
  425. package/translations/ar-ae.yml +44 -12
  426. package/translations/bg-bg.yaml +51 -10
  427. package/translations/en-us.yaml +444 -1
  428. package/translations/fr-fr.yaml +51 -10
  429. package/translations/mn-mn.yaml +51 -10
  430. package/translations/pt-br.yaml +51 -10
  431. package/translations/ru-ru.yaml +51 -10
  432. package/translations/vi-vn.yaml +48 -12
@@ -0,0 +1,214 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Models;
4
+
5
+ use Fleetbase\Casts\Json;
6
+ use Fleetbase\Models\Model;
7
+ use Fleetbase\Traits\HasApiModelBehavior;
8
+ use Fleetbase\Traits\HasInternalId;
9
+ use Fleetbase\Traits\HasMetaAttributes;
10
+ use Fleetbase\Traits\HasPublicId;
11
+ use Fleetbase\Traits\HasUuid;
12
+ use Fleetbase\Traits\Searchable;
13
+ use Fleetbase\Traits\TracksApiCredential;
14
+ use Illuminate\Database\Eloquent\Relations\BelongsTo;
15
+ use Illuminate\Database\Eloquent\Relations\HasMany;
16
+ use Illuminate\Database\Eloquent\SoftDeletes;
17
+
18
+ /**
19
+ * Manifest.
20
+ *
21
+ * Represents a committed delivery plan for a specific vehicle and (optionally)
22
+ * driver. Generated by the Orchestrator commit step. Each Manifest contains an
23
+ * ordered list of ManifestStops representing the physical locations to visit.
24
+ *
25
+ * Status lifecycle:
26
+ * draft → active → in_progress → completed
27
+ * ↘ cancelled
28
+ */
29
+ class Manifest extends Model
30
+ {
31
+ use HasUuid;
32
+ use HasPublicId;
33
+ use HasInternalId;
34
+ use HasMetaAttributes;
35
+ use HasApiModelBehavior;
36
+ use TracksApiCredential;
37
+ use Searchable;
38
+ use SoftDeletes;
39
+
40
+ /**
41
+ * The database table used by the model.
42
+ */
43
+ protected $table = 'manifests';
44
+
45
+ /**
46
+ * The type of public ID to generate.
47
+ */
48
+ protected $publicIdType = 'manifest';
49
+
50
+ /**
51
+ * Columns that can be searched.
52
+ */
53
+ protected $searchableColumns = ['public_id', 'internal_id'];
54
+
55
+ /**
56
+ * Mass-assignable attributes.
57
+ */
58
+ protected $fillable = [
59
+ 'company_uuid',
60
+ 'driver_uuid',
61
+ 'vehicle_uuid',
62
+ 'status',
63
+ 'scheduled_date',
64
+ 'started_at',
65
+ 'completed_at',
66
+ 'total_distance_m',
67
+ 'total_duration_s',
68
+ 'stop_count',
69
+ 'notes',
70
+ 'meta',
71
+ ];
72
+
73
+ /**
74
+ * Attribute casts.
75
+ */
76
+ protected $casts = [
77
+ 'meta' => Json::class,
78
+ 'scheduled_date' => 'date',
79
+ 'started_at' => 'datetime',
80
+ 'completed_at' => 'datetime',
81
+ ];
82
+
83
+ /**
84
+ * Attributes appended to the model's JSON representation.
85
+ */
86
+ protected $appends = [
87
+ 'driver_name',
88
+ 'vehicle_name',
89
+ 'completed_stops',
90
+ 'pending_stops',
91
+ ];
92
+
93
+ // ── Relationships ─────────────────────────────────────────────────────────
94
+
95
+ /**
96
+ * The driver assigned to this manifest.
97
+ */
98
+ public function driver(): BelongsTo
99
+ {
100
+ return $this->belongsTo(Driver::class, 'driver_uuid', 'uuid');
101
+ }
102
+
103
+ /**
104
+ * The vehicle assigned to this manifest.
105
+ */
106
+ public function vehicle(): BelongsTo
107
+ {
108
+ return $this->belongsTo(Vehicle::class, 'vehicle_uuid', 'uuid');
109
+ }
110
+
111
+ /**
112
+ * The ordered list of stops in this manifest.
113
+ */
114
+ public function stops(): HasMany
115
+ {
116
+ return $this->hasMany(ManifestStop::class, 'manifest_uuid', 'uuid')
117
+ ->orderBy('sequence');
118
+ }
119
+
120
+ /**
121
+ * The orders associated with this manifest (through stops).
122
+ */
123
+ public function orders(): HasMany
124
+ {
125
+ return $this->hasMany(Order::class, 'manifest_uuid', 'uuid');
126
+ }
127
+
128
+ // ── Computed Attributes ───────────────────────────────────────────────────
129
+
130
+ public function getDriverNameAttribute(): ?string
131
+ {
132
+ return $this->driver?->name;
133
+ }
134
+
135
+ public function getVehicleNameAttribute(): ?string
136
+ {
137
+ return $this->vehicle?->display_name;
138
+ }
139
+
140
+ public function getCompletedStopsAttribute(): int
141
+ {
142
+ return $this->stops()->where('status', 'completed')->count();
143
+ }
144
+
145
+ public function getPendingStopsAttribute(): int
146
+ {
147
+ return $this->stops()->whereIn('status', ['pending', 'arrived'])->count();
148
+ }
149
+
150
+ // ── Scopes ────────────────────────────────────────────────────────────────
151
+
152
+ public function scopeForCompany($query, string $companyUuid)
153
+ {
154
+ return $query->where('company_uuid', $companyUuid);
155
+ }
156
+
157
+ public function scopeActive($query)
158
+ {
159
+ return $query->whereIn('status', ['active', 'in_progress']);
160
+ }
161
+
162
+ public function scopeForDriver($query, string $driverUuid)
163
+ {
164
+ return $query->where('driver_uuid', $driverUuid);
165
+ }
166
+
167
+ public function scopeForVehicle($query, string $vehicleUuid)
168
+ {
169
+ return $query->where('vehicle_uuid', $vehicleUuid);
170
+ }
171
+
172
+ // ── Business Logic ────────────────────────────────────────────────────────
173
+
174
+ /**
175
+ * Mark the manifest as in_progress and record the start time.
176
+ */
177
+ public function start(): self
178
+ {
179
+ $this->update(['status' => 'in_progress', 'started_at' => now()]);
180
+
181
+ return $this;
182
+ }
183
+
184
+ /**
185
+ * Mark the manifest as completed and record the completion time.
186
+ */
187
+ public function complete(): self
188
+ {
189
+ $this->update(['status' => 'completed', 'completed_at' => now()]);
190
+
191
+ return $this;
192
+ }
193
+
194
+ /**
195
+ * Cancel the manifest.
196
+ */
197
+ public function cancel(): self
198
+ {
199
+ $this->update(['status' => 'cancelled']);
200
+
201
+ return $this;
202
+ }
203
+
204
+ /**
205
+ * Check whether all stops are completed and auto-complete the manifest.
206
+ */
207
+ public function checkAndAutoComplete(): void
208
+ {
209
+ $pendingCount = $this->stops()->whereIn('status', ['pending', 'arrived'])->count();
210
+ if ($pendingCount === 0 && $this->status === 'in_progress') {
211
+ $this->complete();
212
+ }
213
+ }
214
+ }
@@ -0,0 +1,162 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Models;
4
+
5
+ use Fleetbase\Casts\Json;
6
+ use Fleetbase\Models\Model;
7
+ use Fleetbase\Traits\HasApiModelBehavior;
8
+ use Fleetbase\Traits\HasMetaAttributes;
9
+ use Fleetbase\Traits\HasPublicId;
10
+ use Fleetbase\Traits\HasUuid;
11
+ use Fleetbase\Traits\TracksApiCredential;
12
+ use Illuminate\Database\Eloquent\Relations\BelongsTo;
13
+ use Illuminate\Database\Eloquent\SoftDeletes;
14
+
15
+ /**
16
+ * ManifestStop.
17
+ *
18
+ * Represents a single physical stop within a Manifest. Each stop links to:
19
+ * - The parent Manifest
20
+ * - The Order being fulfilled at this stop
21
+ * - The Place (physical address) to visit
22
+ * - Optionally, the specific Waypoint within the order's Payload
23
+ *
24
+ * The sequence field holds the VROOM-optimised stop order (1-indexed).
25
+ */
26
+ class ManifestStop extends Model
27
+ {
28
+ use HasUuid;
29
+ use HasPublicId;
30
+ use HasMetaAttributes;
31
+ use HasApiModelBehavior;
32
+ use TracksApiCredential;
33
+ use SoftDeletes;
34
+
35
+ /**
36
+ * The database table used by the model.
37
+ */
38
+ protected $table = 'manifest_stops';
39
+
40
+ /**
41
+ * The type of public ID to generate.
42
+ */
43
+ protected $publicIdType = 'mstop';
44
+
45
+ /**
46
+ * Mass-assignable attributes.
47
+ */
48
+ protected $fillable = [
49
+ 'manifest_uuid',
50
+ 'order_uuid',
51
+ 'place_uuid',
52
+ 'waypoint_uuid',
53
+ 'status',
54
+ 'sequence',
55
+ 'estimated_arrival',
56
+ 'actual_arrival',
57
+ 'distance_from_prev_m',
58
+ 'duration_from_prev_s',
59
+ 'meta',
60
+ ];
61
+
62
+ /**
63
+ * Attribute casts.
64
+ */
65
+ protected $casts = [
66
+ 'meta' => Json::class,
67
+ 'estimated_arrival' => 'datetime',
68
+ 'actual_arrival' => 'datetime',
69
+ 'sequence' => 'integer',
70
+ 'distance_from_prev_m' => 'integer',
71
+ 'duration_from_prev_s' => 'integer',
72
+ ];
73
+
74
+ /**
75
+ * Attributes appended to the model's JSON representation.
76
+ */
77
+ protected $appends = [
78
+ 'tracking_number',
79
+ 'address',
80
+ ];
81
+
82
+ // ── Relationships ─────────────────────────────────────────────────────────
83
+
84
+ /**
85
+ * The parent manifest.
86
+ */
87
+ public function manifest(): BelongsTo
88
+ {
89
+ return $this->belongsTo(Manifest::class, 'manifest_uuid', 'uuid');
90
+ }
91
+
92
+ /**
93
+ * The order this stop fulfils.
94
+ */
95
+ public function order(): BelongsTo
96
+ {
97
+ return $this->belongsTo(Order::class, 'order_uuid', 'uuid')
98
+ ->with(['trackingNumber', 'payload.dropoff']);
99
+ }
100
+
101
+ /**
102
+ * The physical Place to visit.
103
+ */
104
+ public function place(): BelongsTo
105
+ {
106
+ return $this->belongsTo(Place::class, 'place_uuid', 'uuid');
107
+ }
108
+
109
+ /**
110
+ * The specific Waypoint within the order payload (nullable).
111
+ */
112
+ public function waypoint(): BelongsTo
113
+ {
114
+ return $this->belongsTo(Waypoint::class, 'waypoint_uuid', 'uuid');
115
+ }
116
+
117
+ // ── Computed Attributes ───────────────────────────────────────────────────
118
+
119
+ public function getTrackingNumberAttribute(): ?string
120
+ {
121
+ return $this->order?->trackingNumber?->tracking_number;
122
+ }
123
+
124
+ public function getAddressAttribute(): ?string
125
+ {
126
+ return $this->place?->address ?? $this->order?->payload?->dropoff?->address;
127
+ }
128
+
129
+ // ── Business Logic ────────────────────────────────────────────────────────
130
+
131
+ /**
132
+ * Mark this stop as arrived and record the actual arrival time.
133
+ */
134
+ public function markArrived(): self
135
+ {
136
+ $this->update(['status' => 'arrived', 'actual_arrival' => now()]);
137
+
138
+ return $this;
139
+ }
140
+
141
+ /**
142
+ * Mark this stop as completed and trigger manifest auto-completion check.
143
+ */
144
+ public function markCompleted(): self
145
+ {
146
+ $this->update(['status' => 'completed']);
147
+ $this->manifest?->checkAndAutoComplete();
148
+
149
+ return $this;
150
+ }
151
+
152
+ /**
153
+ * Mark this stop as skipped.
154
+ */
155
+ public function markSkipped(): self
156
+ {
157
+ $this->update(['status' => 'skipped']);
158
+ $this->manifest?->checkAndAutoComplete();
159
+
160
+ return $this;
161
+ }
162
+ }
@@ -120,6 +120,13 @@ class Order extends Model
120
120
  'notes',
121
121
  'type',
122
122
  'status',
123
+ // Orchestrator
124
+ 'orchestrator_priority',
125
+ 'required_skills',
126
+ 'time_window_start',
127
+ 'time_window_end',
128
+ // Manifest (set by orchestrator commit)
129
+ 'manifest_uuid',
123
130
  ];
124
131
 
125
132
  /**
@@ -205,6 +212,11 @@ class Order extends Model
205
212
  'scheduled_at' => 'datetime',
206
213
  'dispatched_at' => 'datetime',
207
214
  'started_at' => 'datetime',
215
+ // Orchestrator
216
+ 'required_skills' => Json::class,
217
+ 'time_window_start' => 'datetime',
218
+ 'time_window_end' => 'datetime',
219
+ 'orchestrator_priority' => 'integer',
208
220
  ];
209
221
 
210
222
  /**
@@ -623,6 +635,64 @@ class Order extends Model
623
635
  $this->attributes['status'] = is_string($status) ? Str::snake($status) : 'created';
624
636
  }
625
637
 
638
+ /**
639
+ * Normalise the date portion of time_window_start on write.
640
+ *
641
+ * If the incoming value has a Unix-epoch date (1970-01-01) — which happens
642
+ * when a caller supplies a time-only string such as "09:00:00" or when the
643
+ * client-side picker emits a time without a date — the date portion is
644
+ * replaced with the order's scheduled_at date, falling back to created_at,
645
+ * and finally to now(). If the value already carries a meaningful date it
646
+ * is stored as-is, so callers that supply a full datetime are never
647
+ * overridden.
648
+ */
649
+ public function setTimeWindowStartAttribute($value): void
650
+ {
651
+ $this->attributes['time_window_start'] = $this->normaliseTimeWindowValue($value);
652
+ }
653
+
654
+ /**
655
+ * Normalise the date portion of time_window_end on write.
656
+ *
657
+ * @see setTimeWindowStartAttribute()
658
+ */
659
+ public function setTimeWindowEndAttribute($value): void
660
+ {
661
+ $this->attributes['time_window_end'] = $this->normaliseTimeWindowValue($value);
662
+ }
663
+
664
+ /**
665
+ * Resolve a time-window value to a full datetime string, injecting the
666
+ * order's reference date (scheduled_at ?? created_at ?? now) when the
667
+ * supplied value has no meaningful date of its own.
668
+ *
669
+ * @param mixed $value Anything Carbon::parse() can accept, or null
670
+ *
671
+ * @return string|null MySQL-formatted datetime string, or null
672
+ */
673
+ protected function normaliseTimeWindowValue($value): ?string
674
+ {
675
+ if ($value === null || $value === '') {
676
+ return null;
677
+ }
678
+
679
+ $parsed = Carbon::parse($value);
680
+
681
+ // When the date portion is the Unix epoch the caller sent a time-only
682
+ // value (e.g. "09:00:00"). Inject the order's reference date.
683
+ if ($parsed->year === 1970 && $parsed->month === 1 && $parsed->day === 1) {
684
+ $ref = isset($this->attributes['scheduled_at']) && $this->attributes['scheduled_at']
685
+ ? Carbon::parse($this->attributes['scheduled_at'])
686
+ : (isset($this->attributes['created_at']) && $this->attributes['created_at']
687
+ ? Carbon::parse($this->attributes['created_at'])
688
+ : Carbon::now());
689
+
690
+ $parsed->setDate($ref->year, $ref->month, $ref->day);
691
+ }
692
+
693
+ return $parsed->toDateTimeString();
694
+ }
695
+
626
696
  /**
627
697
  * Checks if a driver is assigned to the order.
628
698
  *
@@ -175,11 +175,14 @@ class OrderConfig extends Model
175
175
  }
176
176
 
177
177
  /**
178
- * @return \Illuminate\Database\Eloquent\Relations\HasMany
178
+ * Get all custom fields defined for this order config.
179
+ * CustomField uses a polymorphic subject relationship (subject_uuid / subject_type).
180
+ *
181
+ * @return \Illuminate\Database\Eloquent\Relations\MorphMany
179
182
  */
180
183
  public function customFields()
181
184
  {
182
- return $this->belongsTo(\Fleetbase\Models\CustomField::class);
185
+ return $this->morphMany(\Fleetbase\Models\CustomField::class, 'subject', 'subject_type', 'subject_uuid');
183
186
  }
184
187
 
185
188
  /**
@@ -3,7 +3,9 @@
3
3
  namespace Fleetbase\FleetOps\Models;
4
4
 
5
5
  use Fleetbase\Casts\Json;
6
+ use Fleetbase\Casts\Money;
6
7
  use Fleetbase\Casts\PolymorphicType;
8
+ use Fleetbase\FleetOps\Support\Utils;
7
9
  use Fleetbase\FleetOps\Traits\Maintainable;
8
10
  use Fleetbase\Models\Alert;
9
11
  use Fleetbase\Models\File;
@@ -88,6 +90,7 @@ class Part extends Model
88
90
  'quantity_on_hand',
89
91
  'unit_cost',
90
92
  'msrp',
93
+ 'currency',
91
94
  'asset_type',
92
95
  'asset_uuid',
93
96
  'type',
@@ -126,8 +129,9 @@ class Part extends Model
126
129
  */
127
130
  protected $casts = [
128
131
  'quantity_on_hand' => 'integer',
129
- 'unit_cost' => 'decimal:2',
130
- 'msrp' => 'decimal:2',
132
+ // Money values
133
+ 'unit_cost' => Money::class,
134
+ 'msrp' => Money::class,
131
135
  'specs' => Json::class,
132
136
  'meta' => Json::class,
133
137
  'asset_type' => PolymorphicType::class,
@@ -199,7 +203,7 @@ class Part extends Model
199
203
 
200
204
  public function asset(): MorphTo
201
205
  {
202
- return $this->morphTo();
206
+ return $this->morphTo(__FUNCTION__, 'asset_type', 'asset_uuid');
203
207
  }
204
208
 
205
209
  /**
@@ -501,4 +505,66 @@ class Part extends Model
501
505
 
502
506
  return $quantity * ($price ?? 0);
503
507
  }
508
+
509
+ /**
510
+ * Create a Part instance from an import row.
511
+ *
512
+ * Monetary values (unit_cost, msrp) must be supplied in cents (integers).
513
+ * The Money cast will strip non-numeric characters before storage.
514
+ *
515
+ * @param array $row Associative array from the import spreadsheet
516
+ * @param bool $saveInstance Whether to persist the record immediately
517
+ */
518
+ public static function createFromImport(array $row, bool $saveInstance = false): Part
519
+ {
520
+ $row = array_filter($row);
521
+
522
+ $sku = Utils::or($row, ['sku', 'part_number', 'internal_id']);
523
+ $name = Utils::or($row, ['name', 'part_name']);
524
+ $type = Utils::or($row, ['type', 'part_type'], 'consumable');
525
+ $status = Utils::or($row, ['status'], 'in_stock');
526
+ $manufacturer = Utils::or($row, ['manufacturer', 'make', 'brand']);
527
+ $model = Utils::or($row, ['model', 'part_model']);
528
+ $serialNumber = Utils::or($row, ['serial_number', 'serial']);
529
+ $barcode = Utils::or($row, ['barcode']);
530
+ $description = Utils::or($row, ['description']);
531
+ $quantityOnHand = Utils::or($row, ['quantity_on_hand', 'quantity', 'qty']);
532
+ $unitCost = Utils::or($row, ['unit_cost', 'cost']);
533
+ $msrp = Utils::or($row, ['msrp', 'retail_price']);
534
+ $currency = Utils::or($row, ['currency'], 'USD');
535
+ $vendorName = Utils::or($row, ['vendor_name', 'vendor', 'supplier']);
536
+
537
+ $part = new static([
538
+ 'company_uuid' => session('company'),
539
+ 'sku' => $sku,
540
+ 'name' => $name,
541
+ 'type' => $type,
542
+ 'status' => $status,
543
+ 'manufacturer' => $manufacturer,
544
+ 'model' => $model,
545
+ 'serial_number' => $serialNumber,
546
+ 'barcode' => $barcode,
547
+ 'description' => $description,
548
+ 'quantity_on_hand' => $quantityOnHand ? (int) $quantityOnHand : 0,
549
+ 'unit_cost' => $unitCost,
550
+ 'msrp' => $msrp,
551
+ 'currency' => strtoupper($currency ?? 'USD'),
552
+ ]);
553
+
554
+ // Attempt to resolve vendor by name
555
+ if ($vendorName) {
556
+ $vendor = Vendor::where('company_uuid', session('company'))
557
+ ->where('name', 'like', '%' . $vendorName . '%')
558
+ ->first();
559
+ if ($vendor) {
560
+ $part->vendor_uuid = $vendor->uuid;
561
+ }
562
+ }
563
+
564
+ if ($saveInstance === true) {
565
+ $part->save();
566
+ }
567
+
568
+ return $part;
569
+ }
504
570
  }
@@ -235,7 +235,7 @@ class Place extends Model
235
235
  function ($option) {
236
236
  $key = str_replace(['.svg', '.png'], '', $option);
237
237
 
238
- return [$key => Utils::assetFromS3('static/place-icons/' . $option)];
238
+ return [$key => Utils::assetFromFleetbase('static/place-icons/' . $option)];
239
239
  }
240
240
  );
241
241
 
@@ -216,7 +216,7 @@ class Sensor extends Model
216
216
 
217
217
  public function sensorable(): MorphTo
218
218
  {
219
- return $this->morphTo();
219
+ return $this->morphTo(__FUNCTION__, 'sensorable_type', 'sensorable_uuid');
220
220
  }
221
221
 
222
222
  public function photo(): BelongsTo
@@ -121,7 +121,7 @@ class ServiceQuote extends Model
121
121
  return $this->belongsTo(IntegratedVendor::class);
122
122
  }
123
123
 
124
- public function getServiceRateNameAttribute(): string
124
+ public function getServiceRateNameAttribute(): ?string
125
125
  {
126
126
  return data_get($this, 'serviceRate.service_name');
127
127
  }
@@ -139,6 +139,7 @@ class Vehicle extends Model
139
139
  'type',
140
140
  'class',
141
141
  // Identifiers
142
+ 'internal_id',
142
143
  'plate_number',
143
144
  'call_sign',
144
145
  'serial_number',
@@ -204,6 +205,15 @@ class Vehicle extends Model
204
205
  'slug',
205
206
  'purchased_at',
206
207
  'lease_expires_at',
208
+ // Orchestrator
209
+ 'skills',
210
+ 'payload_capacity_volume',
211
+ 'payload_capacity_pallets',
212
+ 'payload_capacity_parcels',
213
+ 'max_tasks',
214
+ 'time_window_start',
215
+ 'time_window_end',
216
+ 'return_to_depot',
207
217
  ];
208
218
 
209
219
  /**
@@ -295,6 +305,13 @@ class Vehicle extends Model
295
305
  'torque' => 'decimal:2',
296
306
  'gvwr' => 'decimal:2',
297
307
  'gcwr' => 'decimal:2',
308
+ // Orchestrator
309
+ 'skills' => Json::class,
310
+ 'payload_capacity_volume' => 'decimal:3',
311
+ 'payload_capacity_pallets' => 'integer',
312
+ 'payload_capacity_parcels' => 'integer',
313
+ 'max_tasks' => 'integer',
314
+ 'return_to_depot' => 'boolean',
298
315
  ];
299
316
 
300
317
  public function photo(): BelongsTo
@@ -561,7 +578,7 @@ class Vehicle extends Model
561
578
  function ($option) {
562
579
  $key = str_replace(['.svg', '.png'], '', $option);
563
580
 
564
- return [$key => Utils::assetFromS3('static/vehicle-icons/' . $option)];
581
+ return [$key => Utils::assetFromFleetbase('static/vehicle-icons/' . $option)];
565
582
  }
566
583
  );
567
584
 
@@ -164,7 +164,7 @@ class Warranty extends Model
164
164
 
165
165
  public function subject(): MorphTo
166
166
  {
167
- return $this->morphTo();
167
+ return $this->morphTo(__FUNCTION__, 'subject_type', 'subject_uuid');
168
168
  }
169
169
 
170
170
  /**