@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
@@ -1036,4 +1036,46 @@ class OrderController extends FleetOpsController
1036
1036
 
1037
1037
  return new OrderResource($order);
1038
1038
  }
1039
+
1040
+ /**
1041
+ * Schedule an order: set scheduled_at and optionally assign a driver.
1042
+ * This endpoint intentionally does NOT trigger dispatch or change the
1043
+ * order status, so it is safe to call from the scheduler UI.
1044
+ *
1045
+ * @return \Illuminate\Http\Response
1046
+ */
1047
+ public function scheduleOrder(Request $request)
1048
+ {
1049
+ $orderId = $request->input('order');
1050
+ $scheduledAt = $request->input('scheduled_at');
1051
+ $driverId = $request->input('driver_id');
1052
+
1053
+ $order = Order::findById($orderId);
1054
+ if (!$order) {
1055
+ return response()->error('No order found to schedule.');
1056
+ }
1057
+
1058
+ if ($scheduledAt) {
1059
+ $order->scheduled_at = \Carbon\Carbon::parse($scheduledAt);
1060
+ }
1061
+
1062
+ if ($driverId) {
1063
+ // Resolve by uuid or public_id
1064
+ $driver = Driver::where('uuid', $driverId)
1065
+ ->orWhere('public_id', $driverId)
1066
+ ->first();
1067
+ if ($driver) {
1068
+ $order->driver_assigned_uuid = $driver->uuid;
1069
+ }
1070
+ }
1071
+
1072
+ $order->saveQuietly();
1073
+
1074
+ return response()->json([
1075
+ 'status' => 'OK',
1076
+ 'message' => 'Order scheduled',
1077
+ 'order' => $order->uuid,
1078
+ 'scheduled_at' => $order->scheduled_at,
1079
+ ]);
1080
+ }
1039
1081
  }
@@ -3,6 +3,9 @@
3
3
  namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
4
4
 
5
5
  use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
6
+ use Fleetbase\FleetOps\Imports\PartImport;
7
+ use Fleetbase\Http\Requests\ImportRequest;
8
+ use Maatwebsite\Excel\Facades\Excel;
6
9
 
7
10
  class PartController extends FleetOpsController
8
11
  {
@@ -12,4 +15,28 @@ class PartController extends FleetOpsController
12
15
  * @var string
13
16
  */
14
17
  public $resource = 'part';
18
+
19
+ /**
20
+ * Process import files (excel, csv) into Part records.
21
+ *
22
+ * @return \Illuminate\Http\Response
23
+ */
24
+ public function import(ImportRequest $request)
25
+ {
26
+ $disk = $request->input('disk', config('filesystems.default'));
27
+ $files = $request->resolveFilesFromIds();
28
+ $importedCount = 0;
29
+
30
+ foreach ($files as $file) {
31
+ try {
32
+ $import = new PartImport();
33
+ Excel::import($import, $file->path, $disk);
34
+ $importedCount += $import->imported;
35
+ } catch (\Throwable $e) {
36
+ return response()->error('Invalid file, unable to process.');
37
+ }
38
+ }
39
+
40
+ return response()->json(['status' => 'ok', 'message' => 'Import completed', 'imported' => $importedCount]);
41
+ }
15
42
  }
@@ -210,4 +210,122 @@ class SettingController extends Controller
210
210
 
211
211
  return response()->json($routingSettings);
212
212
  }
213
+
214
+ /**
215
+ * Retrieve driver scheduling settings for the current company.
216
+ *
217
+ * @return \Illuminate\Http\JsonResponse
218
+ */
219
+ public function getSchedulingSettings()
220
+ {
221
+ $defaults = [
222
+ 'horizon_days' => 60,
223
+ 'default_shift_duration' => 8,
224
+ 'hos_daily_limit' => 11,
225
+ 'hos_weekly_limit' => 70,
226
+ 'auto_activate_schedule' => true,
227
+ 'notify_drivers_on_shift_change' => false,
228
+ ];
229
+ $settings = Setting::lookupFromCompany('fleet-ops.scheduling-settings', $defaults);
230
+
231
+ return response()->json($settings);
232
+ }
233
+
234
+ /**
235
+ * Save driver scheduling settings for the current company.
236
+ *
237
+ * @return \Illuminate\Http\JsonResponse
238
+ */
239
+ public function saveSchedulingSettings(Request $request)
240
+ {
241
+ $settings = [
242
+ 'horizon_days' => (int) $request->input('horizon_days', 60),
243
+ 'default_shift_duration' => (int) $request->input('default_shift_duration', 8),
244
+ 'hos_daily_limit' => (int) $request->input('hos_daily_limit', 11),
245
+ 'hos_weekly_limit' => (int) $request->input('hos_weekly_limit', 70),
246
+ 'auto_activate_schedule' => (bool) $request->input('auto_activate_schedule', true),
247
+ 'notify_drivers_on_shift_change' => (bool) $request->input('notify_drivers_on_shift_change', false),
248
+ ];
249
+ Setting::configureCompany('fleet-ops.scheduling-settings', $settings);
250
+
251
+ return response()->json($settings);
252
+ }
253
+
254
+ /**
255
+ * Retrieve order allocation settings for the current company.
256
+ *
257
+ * @return \Illuminate\Http\JsonResponse
258
+ */
259
+ public function getOrchestratorSettings()
260
+ {
261
+ $defaults = [
262
+ 'allocation_engine' => 'vroom',
263
+ 'auto_allocate_on_create' => false,
264
+ 'auto_reallocate_on_complete' => false,
265
+ 'max_travel_time_seconds' => 3600,
266
+ 'balance_workload' => false,
267
+ ];
268
+ $settings = Setting::lookupFromCompany('fleet-ops.allocation-settings', $defaults);
269
+
270
+ return response()->json($settings);
271
+ }
272
+
273
+ /**
274
+ * Save order allocation settings for the current company.
275
+ *
276
+ * @return \Illuminate\Http\JsonResponse
277
+ */
278
+ public function saveOrchestratorSettings(Request $request)
279
+ {
280
+ $settings = [
281
+ 'allocation_engine' => $request->input('allocation_engine', 'vroom'),
282
+ 'auto_allocate_on_create' => (bool) $request->input('auto_allocate_on_create', false),
283
+ 'auto_reallocate_on_complete' => (bool) $request->input('auto_reallocate_on_complete', false),
284
+ 'max_travel_time_seconds' => (int) $request->input('max_travel_time_seconds', 3600),
285
+ 'balance_workload' => (bool) $request->input('balance_workload', false),
286
+ ];
287
+ Setting::configureCompany('fleet-ops.allocation-settings', $settings);
288
+
289
+ return response()->json($settings);
290
+ }
291
+
292
+ /**
293
+ * Retrieve orchestrator order card field settings for the current company.
294
+ *
295
+ * @return \Illuminate\Http\JsonResponse
296
+ */
297
+ public function getOrchestratorCardFields()
298
+ {
299
+ $defaults = [
300
+ 'standard' => ['tracking', 'status', 'scheduled_at', 'customer', 'dropoff'],
301
+ 'byConfig' => (object) [],
302
+ 'meta' => [],
303
+ ];
304
+ $settings = Setting::lookupFromCompany('fleet-ops.orchestrator-card-fields', $defaults);
305
+
306
+ return response()->json(['settings' => $settings]);
307
+ }
308
+
309
+ /**
310
+ * Save orchestrator order card field settings for the current company.
311
+ *
312
+ * @return \Illuminate\Http\JsonResponse
313
+ */
314
+ public function saveOrchestratorCardFields(Request $request)
315
+ {
316
+ $settings = $request->input('settings', []);
317
+
318
+ $normalized = [
319
+ 'standard' => $settings['standard'] ?? ['tracking', 'status', 'scheduled_at', 'customer', 'dropoff'],
320
+ 'byConfig' => $settings['byConfig'] ?? [],
321
+ 'meta' => $settings['meta'] ?? [],
322
+ ];
323
+ Setting::configureCompany('fleet-ops.orchestrator-card-fields', $normalized);
324
+
325
+ return response()->json([
326
+ 'status' => 'ok',
327
+ 'message' => 'Orchestrator card fields saved.',
328
+ 'settings' => $normalized,
329
+ ]);
330
+ }
213
331
  }
@@ -0,0 +1,214 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1\Traits;
4
+
5
+ use Fleetbase\FleetOps\Models\Driver;
6
+ use Fleetbase\Models\Schedule;
7
+ use Illuminate\Http\JsonResponse;
8
+ use Illuminate\Http\Request;
9
+ use Illuminate\Support\Facades\DB;
10
+
11
+ /**
12
+ * DriverSchedulingTrait.
13
+ *
14
+ * Provides scheduling-related controller methods for the DriverController.
15
+ * These methods expose the core-api scheduling relationships (ScheduleItem,
16
+ * ScheduleAvailability) through FleetOps-specific driver endpoints.
17
+ *
18
+ * Routes:
19
+ * GET /int/v1/drivers/{id}/schedule-items
20
+ * GET /int/v1/drivers/{id}/availabilities
21
+ * GET /int/v1/drivers/{id}/hos-status
22
+ * GET /int/v1/drivers/{id}/active-shift
23
+ *
24
+ * The {id} parameter accepts either the driver's UUID or public_id.
25
+ */
26
+ trait DriverSchedulingTrait
27
+ {
28
+ /**
29
+ * Regulatory HOS defaults used when no per-schedule override is configured.
30
+ * These match the US FMCSA 11-hour / 70-hour rules as a sensible baseline.
31
+ */
32
+ private const HOS_DEFAULT_DAILY_LIMIT = 11;
33
+ private const HOS_DEFAULT_WEEKLY_LIMIT = 70;
34
+
35
+ /**
36
+ * Resolve a Driver by UUID or public_id, throwing 404 if not found.
37
+ */
38
+ private function resolveDriver(string $id): Driver
39
+ {
40
+ return Driver::where('uuid', $id)
41
+ ->orWhere('public_id', $id)
42
+ ->firstOrFail();
43
+ }
44
+
45
+ /**
46
+ * Return all ScheduleItem records assigned to this driver.
47
+ * Supports optional date range filtering via start_at and end_at query params.
48
+ *
49
+ * GET /int/v1/drivers/{id}/schedule-items
50
+ */
51
+ public function scheduleItems(string $id, Request $request): JsonResponse
52
+ {
53
+ $driver = $this->resolveDriver($id);
54
+ $query = $driver->scheduleItems();
55
+
56
+ if ($request->filled('start_at')) {
57
+ $query->where('start_at', '>=', $request->input('start_at'));
58
+ }
59
+ if ($request->filled('end_at')) {
60
+ $query->where('end_at', '<=', $request->input('end_at'));
61
+ }
62
+
63
+ return response()->json(['data' => $query->orderBy('start_at')->get()]);
64
+ }
65
+
66
+ /**
67
+ * Return all ScheduleAvailability records for this driver.
68
+ * Supports optional date range filtering via start_at and end_at query params.
69
+ *
70
+ * GET /int/v1/drivers/{id}/availabilities
71
+ */
72
+ public function availabilities(string $id, Request $request): JsonResponse
73
+ {
74
+ $driver = $this->resolveDriver($id);
75
+ $query = $driver->availabilities();
76
+
77
+ if ($request->filled('start_at')) {
78
+ $query->where('start_at', '>=', $request->input('start_at'));
79
+ }
80
+ if ($request->filled('end_at')) {
81
+ $query->where('end_at', '<=', $request->input('end_at'));
82
+ }
83
+
84
+ return response()->json(['data' => $query->orderBy('start_at')->get()]);
85
+ }
86
+
87
+ /**
88
+ * Return the driver's Hours of Service (HOS) status.
89
+ *
90
+ * ## Data source
91
+ *
92
+ * The `hos_source` field on the driver's active Schedule determines how
93
+ * driving hours are accumulated:
94
+ *
95
+ * - `schedule` (default): Hours are derived from the driver's ScheduleItem
96
+ * records. Any shift whose `start_at` is in the past (i.e. has already
97
+ * started) is counted. For ongoing shifts (no `end_at` or end_at > NOW()),
98
+ * elapsed time up to NOW() is used. This gives a meaningful "hours
99
+ * scheduled/worked so far" reading immediately, without requiring
100
+ * clock-in/clock-out or telematics data.
101
+ *
102
+ * - `telematics` (future): Accumulated from GPS movement data.
103
+ * - `manual` (future): Manually logged by a dispatcher.
104
+ *
105
+ * ## Limits
106
+ *
107
+ * Limits are resolved in priority order:
108
+ * 1. Per-schedule `hos_daily_limit` / `hos_weekly_limit` (if set on the Schedule)
109
+ * 2. Hard-coded regulatory defaults: 11h daily / 70h weekly (US FMCSA baseline)
110
+ *
111
+ * GET /int/v1/drivers/{id}/hos-status
112
+ */
113
+ public function hosStatus(string $id): JsonResponse
114
+ {
115
+ $driver = $this->resolveDriver($id);
116
+
117
+ // ── Resolve the driver's active schedule ──────────────────────────────
118
+ /** @var Schedule|null $schedule */
119
+ $schedule = $driver->schedules()
120
+ ->where('status', 'active')
121
+ ->latest('created_at')
122
+ ->first();
123
+
124
+ // ── Determine HOS limits (per-schedule → global default) ──────────────
125
+ $dailyLimit = ($schedule && $schedule->hos_daily_limit)
126
+ ? (int) $schedule->hos_daily_limit
127
+ : self::HOS_DEFAULT_DAILY_LIMIT;
128
+
129
+ $weeklyLimit = ($schedule && $schedule->hos_weekly_limit)
130
+ ? (int) $schedule->hos_weekly_limit
131
+ : self::HOS_DEFAULT_WEEKLY_LIMIT;
132
+
133
+ // ── Determine HOS source ──────────────────────────────────────────────
134
+ $hosSource = $schedule ? ($schedule->hos_source ?? 'schedule') : 'schedule';
135
+
136
+ // ── Calculate hours based on source ───────────────────────────────────
137
+ [$dailyHours, $weeklyHours] = match ($hosSource) {
138
+ // Future sources (telematics, manual) will be added here
139
+ default => $this->calculateHosFromSchedule($driver),
140
+ };
141
+
142
+ return response()->json([
143
+ 'daily_hours' => $dailyHours,
144
+ 'weekly_hours' => $weeklyHours,
145
+ 'daily_limit' => $dailyLimit,
146
+ 'weekly_limit' => $weeklyLimit,
147
+ 'hos_source' => $hosSource,
148
+ 'is_compliant' => $dailyHours < $dailyLimit && $weeklyHours < $weeklyLimit,
149
+ ]);
150
+ }
151
+
152
+ /**
153
+ * Calculate HOS hours from the driver's ScheduleItem records.
154
+ *
155
+ * Counts all shifts whose `start_at` is in the past (i.e. the shift has
156
+ * already started). For ongoing shifts (end_at is null or in the future),
157
+ * elapsed time up to NOW() is used via LEAST(COALESCE(end_at, NOW()), NOW()).
158
+ *
159
+ * Cancelled shifts are excluded. All other statuses (scheduled, in_progress,
160
+ * completed) are included — a shift that has started counts toward HOS
161
+ * regardless of whether it has been formally marked completed.
162
+ *
163
+ * @return array{float, float} [dailyHours, weeklyHours]
164
+ */
165
+ private function calculateHosFromSchedule(Driver $driver): array
166
+ {
167
+ $now = now();
168
+ $startOfDay = $now->copy()->startOfDay();
169
+ $startOfWeek = $now->copy()->startOfWeek();
170
+
171
+ // Duration expression: elapsed minutes from shift start to MIN(end_at, NOW()).
172
+ // This caps ongoing shifts at the current moment so future time is never counted.
173
+ $durationExpr = DB::raw(
174
+ 'TIMESTAMPDIFF(MINUTE, start_at, LEAST(COALESCE(end_at, NOW()), NOW()))'
175
+ );
176
+
177
+ // Daily: shifts that started today and have already begun
178
+ $dailyMinutes = $driver->scheduleItems()
179
+ ->where('start_at', '>=', $startOfDay)
180
+ ->where('start_at', '<=', $now)
181
+ ->where('status', '!=', 'cancelled')
182
+ ->sum($durationExpr);
183
+
184
+ // Weekly: shifts that started this week and have already begun
185
+ $weeklyMinutes = $driver->scheduleItems()
186
+ ->where('start_at', '>=', $startOfWeek)
187
+ ->where('start_at', '<=', $now)
188
+ ->where('status', '!=', 'cancelled')
189
+ ->sum($durationExpr);
190
+
191
+ return [
192
+ round((float) $dailyMinutes / 60, 1),
193
+ round((float) $weeklyMinutes / 60, 1),
194
+ ];
195
+ }
196
+
197
+ /**
198
+ * Return the driver's currently active shift for today.
199
+ * Used by OrchestrationPayloadBuilder to inject time_window constraints.
200
+ *
201
+ * GET /int/v1/drivers/{id}/active-shift
202
+ */
203
+ public function activeShift(string $id): JsonResponse
204
+ {
205
+ $driver = $this->resolveDriver($id);
206
+ $shift = $driver->activeShiftFor(now());
207
+
208
+ if (!$shift) {
209
+ return response()->json(['data' => null]);
210
+ }
211
+
212
+ return response()->json(['data' => $shift]);
213
+ }
214
+ }
@@ -3,6 +3,13 @@
3
3
  namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
4
4
 
5
5
  use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
6
+ use Fleetbase\FleetOps\Imports\WorkOrderImport;
7
+ use Fleetbase\FleetOps\Mail\WorkOrderDispatched;
8
+ use Fleetbase\FleetOps\Models\WorkOrder;
9
+ use Fleetbase\Http\Requests\ImportRequest;
10
+ use Illuminate\Http\JsonResponse;
11
+ use Illuminate\Support\Facades\Mail;
12
+ use Maatwebsite\Excel\Facades\Excel;
6
13
 
7
14
  class WorkOrderController extends FleetOpsController
8
15
  {
@@ -12,4 +19,65 @@ class WorkOrderController extends FleetOpsController
12
19
  * @var string
13
20
  */
14
21
  public $resource = 'work-order';
22
+
23
+ /**
24
+ * Process import files (excel, csv) into WorkOrder records.
25
+ *
26
+ * @return \Illuminate\Http\Response
27
+ */
28
+ public function import(ImportRequest $request)
29
+ {
30
+ $disk = $request->input('disk', config('filesystems.default'));
31
+ $files = $request->resolveFilesFromIds();
32
+ $importedCount = 0;
33
+
34
+ foreach ($files as $file) {
35
+ try {
36
+ $import = new WorkOrderImport();
37
+ Excel::import($import, $file->path, $disk);
38
+ $importedCount += $import->imported;
39
+ } catch (\Throwable $e) {
40
+ return response()->error('Invalid file, unable to process.');
41
+ }
42
+ }
43
+
44
+ return response()->json(['status' => 'ok', 'message' => 'Import completed', 'imported' => $importedCount]);
45
+ }
46
+
47
+ /**
48
+ * Send a work order email to the assigned vendor.
49
+ * POST /work-orders/{id}/send.
50
+ */
51
+ public function sendEmail(string $id): JsonResponse
52
+ {
53
+ $workOrder = WorkOrder::where('uuid', $id)
54
+ ->orWhere('public_id', $id)
55
+ ->with(['assignee', 'target'])
56
+ ->firstOrFail();
57
+
58
+ // Resolve recipient email from the assignee (vendor or contact)
59
+ $assignee = $workOrder->assignee;
60
+
61
+ if (!$assignee) {
62
+ return response()->json(['error' => 'This work order has no assigned vendor.'], 422);
63
+ }
64
+
65
+ $email = $assignee->email ?? null;
66
+
67
+ if (!$email) {
68
+ return response()->json(['error' => 'The assigned vendor has no email address on file.'], 422);
69
+ }
70
+
71
+ Mail::to($email)->send(new WorkOrderDispatched($workOrder));
72
+
73
+ activity('work_order_sent')
74
+ ->performedOn($workOrder)
75
+ ->withProperties(['sent_to' => $email])
76
+ ->log('Work order emailed to vendor');
77
+
78
+ return response()->json([
79
+ 'status' => 'ok',
80
+ 'message' => 'Work order successfully sent to ' . $email,
81
+ ]);
82
+ }
15
83
  }
@@ -50,6 +50,7 @@ class Driver extends FleetbaseResource
50
50
  'jobs' => $this->whenLoaded('jobs', fn () => $this->getJobs()),
51
51
  'vendor' => $this->whenLoaded('vendor', fn () => new Vendor($this->vendor)),
52
52
  'fleets' => $this->whenLoaded('fleets', fn () => Fleet::collection($this->fleets()->without('drivers')->get())),
53
+ 'current_shift' => $this->whenLoaded('currentShift', fn () => $this->currentShift),
53
54
  'location' => $this->wasRecentlyCreated ? new Point(0, 0) : Utils::castPoint($this->location),
54
55
  'heading' => (int) data_get($this, 'heading', 0),
55
56
  'altitude' => (int) data_get($this, 'altitude', 0),
@@ -0,0 +1,138 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Http\Resources\v1;
4
+
5
+ use Fleetbase\FleetOps\Support\Utils;
6
+ use Fleetbase\Http\Resources\FleetbaseResource;
7
+ use Fleetbase\Support\Http;
8
+ use Illuminate\Support\Str;
9
+
10
+ class Maintenance extends FleetbaseResource
11
+ {
12
+ /**
13
+ * Transform the resource into an array.
14
+ *
15
+ * @param \Illuminate\Http\Request $request
16
+ *
17
+ * @return array
18
+ */
19
+ public function toArray($request)
20
+ {
21
+ return $this->withCustomFields([
22
+ 'id' => $this->when(Http::isInternalRequest(), $this->id, $this->public_id),
23
+ 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
24
+ 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
25
+ 'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid),
26
+ 'work_order_uuid' => $this->when(Http::isInternalRequest(), $this->work_order_uuid),
27
+ 'created_by_uuid' => $this->when(Http::isInternalRequest(), $this->created_by_uuid),
28
+ 'updated_by_uuid' => $this->when(Http::isInternalRequest(), $this->updated_by_uuid),
29
+ // Polymorphic maintainable
30
+ 'maintainable_uuid' => $this->when(Http::isInternalRequest(), $this->maintainable_uuid),
31
+ 'maintainable_type' => $this->when(Http::isInternalRequest(), $this->maintainable_type ? Utils::toEmberResourceType($this->maintainable_type) : null),
32
+ 'maintainable' => $this->whenLoaded('maintainable', function () {
33
+ return $this->setMaintainableType($this->transformMorphResource($this->maintainable));
34
+ }),
35
+ // Polymorphic performed_by
36
+ 'performed_by_uuid' => $this->when(Http::isInternalRequest(), $this->performed_by_uuid),
37
+ 'performed_by_type' => $this->when(Http::isInternalRequest(), $this->performed_by_type ? Utils::toEmberResourceType($this->performed_by_type) : null),
38
+ 'performed_by' => $this->whenLoaded('performedBy', function () {
39
+ return $this->setPerformedByType($this->transformMorphResource($this->performedBy));
40
+ }),
41
+ // Core attributes
42
+ 'type' => $this->type,
43
+ 'status' => $this->status,
44
+ 'priority' => $this->priority,
45
+ 'odometer' => $this->odometer,
46
+ 'engine_hours' => $this->engine_hours,
47
+ 'summary' => $this->summary,
48
+ 'notes' => $this->notes,
49
+ 'line_items' => data_get($this, 'line_items', []),
50
+ 'labor_cost' => $this->labor_cost,
51
+ 'parts_cost' => $this->parts_cost,
52
+ 'tax' => $this->tax,
53
+ 'total_cost' => $this->total_cost,
54
+ 'currency' => $this->currency,
55
+ 'attachments' => data_get($this, 'attachments', []),
56
+ 'meta' => data_get($this, 'meta', (object) []),
57
+ 'slug' => $this->slug,
58
+ // Computed
59
+ 'maintainable_name' => $this->maintainable_name,
60
+ 'work_order_subject' => $this->work_order_subject,
61
+ 'performed_by_name' => $this->performed_by_name,
62
+ 'duration_hours' => $this->duration_hours,
63
+ 'is_overdue' => $this->is_overdue,
64
+ 'days_until_due' => $this->days_until_due,
65
+ 'cost_breakdown' => $this->cost_breakdown,
66
+ // Dates
67
+ 'scheduled_at' => $this->scheduled_at,
68
+ 'started_at' => $this->started_at,
69
+ 'completed_at' => $this->completed_at,
70
+ 'updated_at' => $this->updated_at,
71
+ 'created_at' => $this->created_at,
72
+ ]);
73
+ }
74
+
75
+ /**
76
+ * Inject the abstract 'maintenance-subject' type into the embedded maintainable object
77
+ * so Ember Data can resolve the correct polymorphic model.
78
+ *
79
+ * subject_type must be the Ember Data model name for the concrete subtype,
80
+ * e.g. 'maintenance-subject-vehicle' or 'maintenance-subject-equipment'.
81
+ * We use the bare PHP class basename so we get 'vehicle' / 'equipment' rather
82
+ * than the full 'fleet-ops:vehicle' string that toEmberResourceType() would return.
83
+ */
84
+ protected function setMaintainableType(?array $resolved): ?array
85
+ {
86
+ if (empty($resolved)) {
87
+ return $resolved;
88
+ }
89
+
90
+ $bareSlug = Str::kebab(class_basename($this->maintainable_type ?? ''));
91
+
92
+ data_set($resolved, 'type', 'maintenance-subject-' . $bareSlug);
93
+ data_set($resolved, 'subject_type', 'maintenance-subject-' . $bareSlug);
94
+
95
+ return $resolved;
96
+ }
97
+
98
+ /**
99
+ * Inject the abstract 'facilitator' type into the embedded performed_by object
100
+ * so Ember Data can resolve the correct polymorphic model.
101
+ *
102
+ * facilitator_type must be the Ember Data model name for the concrete subtype,
103
+ * e.g. 'facilitator-vendor' or 'facilitator-contact'.
104
+ * We use the bare PHP class basename so we get 'vendor' / 'contact' rather
105
+ * than the full 'fleet-ops:vendor' string that toEmberResourceType() would return.
106
+ */
107
+ protected function setPerformedByType(?array $resolved): ?array
108
+ {
109
+ if (empty($resolved)) {
110
+ return $resolved;
111
+ }
112
+
113
+ $bareSlug = Str::kebab(class_basename($this->performed_by_type ?? ''));
114
+
115
+ data_set($resolved, 'type', 'facilitator-' . $bareSlug);
116
+ data_set($resolved, 'facilitator_type', 'facilitator-' . $bareSlug);
117
+
118
+ return $resolved;
119
+ }
120
+
121
+ /**
122
+ * Resolve the appropriate resource transformer for a polymorphic morph target
123
+ * and return its array representation.
124
+ */
125
+ protected function transformMorphResource($model): ?array
126
+ {
127
+ if (!$model) {
128
+ return null;
129
+ }
130
+
131
+ $resourceClass = \Fleetbase\Support\Find::httpResourceForModel($model);
132
+ if ($resourceClass) {
133
+ return (new $resourceClass($model))->resolve();
134
+ }
135
+
136
+ return (new \Illuminate\Http\Resources\Json\JsonResource($model))->resolve();
137
+ }
138
+ }