@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
@@ -3,46 +3,147 @@ import { tracked } from '@glimmer/tracking';
3
3
  import { inject as service } from '@ember/service';
4
4
  import { action } from '@ember/object';
5
5
  import { task } from 'ember-concurrency';
6
+ import { startOfWeek, endOfWeek, addWeeks, subWeeks, formatISO, addDays, format, isSameDay, startOfDay } from 'date-fns';
6
7
 
7
8
  /**
8
9
  * Driver::Schedule Component
9
10
  *
10
- * Displays and manages a driver's schedule from their detail page.
11
- * Includes HOS compliance tracking, upcoming shifts, and availability management.
11
+ * Displays and manages a driver's schedule from their detail panel.
12
+ *
13
+ * Architecture:
14
+ * - A Driver has one or more Schedule records (containers, subject_type='driver')
15
+ * - Each Schedule is materialised into ScheduleItem records by the daily
16
+ * MaterializeSchedulesJob (RRULE → concrete shifts for 60-day window)
17
+ * - Deviations are tracked as ScheduleException records (time off, sick leave, etc.)
18
+ *
19
+ * This component:
20
+ * 1. Loads the driver's primary Schedule (or creates one on first use)
21
+ * 2. Loads materialised ScheduleItem records for the next 4 weeks
22
+ * 3. Loads pending/approved ScheduleException records
23
+ * 4. Provides actions to add shifts (single or recurring), request time off, and
24
+ * manage exceptions
12
25
  *
13
26
  * @example
14
- * <Driver::Schedule @resource={{@model}} />
27
+ * <Driver::Schedule @resource={{@driver}} />
15
28
  */
16
29
  export default class DriverScheduleComponent extends Component {
17
- @service driverScheduling;
18
30
  @service notifications;
19
31
  @service modalsManager;
20
32
  @service store;
33
+ @service fetch;
34
+ @service intl;
35
+
36
+ @tracked schedule = null;
21
37
  @tracked scheduleItems = [];
22
38
  @tracked upcomingShifts = [];
39
+ @tracked exceptions = [];
23
40
  @tracked hosStatus = null;
24
- @tracked availability = [];
25
- @tracked timeOffRequests = [];
26
- @tracked selectedItem = null;
41
+ /** Anchor date for the 7-day calendar view — start of the displayed week */
42
+ @tracked calendarAnchor = startOfDay(new Date());
27
43
 
28
- get scheduleActionButtons() {
29
- return [
30
- {
31
- type: 'default',
32
- text: 'Request Time Off',
33
- icon: 'calendar-times',
34
- iconPrefix: 'fas',
35
- permission: 'fleet-ops update driver',
36
- onClick: this.requestTimeOff,
37
- },
38
- ];
44
+ constructor() {
45
+ super(...arguments);
46
+ this.loadDriverSchedule.perform();
47
+ this.loadHOSStatus.perform();
48
+ }
49
+
50
+ // ── Date window helpers ───────────────────────────────────────────────────
51
+
52
+ get startDate() {
53
+ return formatISO(startOfWeek(new Date(), { weekStartsOn: 1 }));
54
+ }
55
+
56
+ get endDate() {
57
+ return formatISO(addWeeks(endOfWeek(new Date(), { weekStartsOn: 1 }), 4));
58
+ }
59
+
60
+ get weekRangeLabel() {
61
+ const start = this.calendarAnchor;
62
+ const end = addDays(start, 6);
63
+ if (format(start, 'MMM') === format(end, 'MMM')) {
64
+ return `${format(start, 'MMM d')} – ${format(end, 'd, yyyy')}`;
65
+ }
66
+ return `${format(start, 'MMM d')} – ${format(end, 'MMM d, yyyy')}`;
67
+ }
68
+
69
+ @action prevWeek() {
70
+ this.calendarAnchor = subWeeks(this.calendarAnchor, 1);
71
+ }
72
+
73
+ @action nextWeek() {
74
+ this.calendarAnchor = addWeeks(this.calendarAnchor, 1);
39
75
  }
40
76
 
77
+ // ── Derived state ─────────────────────────────────────────────────────────
78
+
79
+ get hosComplianceBadge() {
80
+ if (!this.hosStatus) {
81
+ return { color: 'gray', label: 'Unknown' };
82
+ }
83
+ const { daily_hours, weekly_hours } = this.hosStatus;
84
+ if (daily_hours >= 11 || weekly_hours >= 70) {
85
+ return { color: 'red', label: 'At Limit' };
86
+ }
87
+ if (daily_hours >= 9 || weekly_hours >= 60) {
88
+ return { color: 'yellow', label: 'Approaching Limit' };
89
+ }
90
+ return { color: 'green', label: 'Compliant' };
91
+ }
92
+
93
+ get pendingExceptions() {
94
+ return this.exceptions.filter((e) => e.status === 'pending');
95
+ }
96
+
97
+ get approvedExceptions() {
98
+ return this.exceptions.filter((e) => e.status === 'approved');
99
+ }
100
+
101
+ /**
102
+ * Returns the Tailwind CSS classes for a shift status badge.
103
+ * Called directly from the template as {{this.shiftStatusClass status}}.
104
+ */
105
+ shiftStatusClass(status) {
106
+ const map = {
107
+ scheduled: 'bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-200',
108
+ in_progress: 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200',
109
+ completed: 'bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-400',
110
+ cancelled: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200',
111
+ };
112
+ return map[status] ?? 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200';
113
+ }
114
+
115
+ /**
116
+ * Returns 7 days starting from calendarAnchor with any shifts that fall
117
+ * on each day. Used to render the compact 7-day calendar grid.
118
+ * Navigate with prevWeek/nextWeek actions.
119
+ */
120
+ get weekDays() {
121
+ const anchor = this.calendarAnchor;
122
+ const today = startOfDay(new Date());
123
+ return Array.from({ length: 7 }, (_, i) => {
124
+ const day = addDays(anchor, i);
125
+ // Match items whose start_at falls on this calendar day (local time)
126
+ const shifts = this.scheduleItems.filter((item) => {
127
+ const itemDate = item.start_at instanceof Date ? item.start_at : new Date(item.start_at);
128
+ return isSameDay(itemDate, day);
129
+ });
130
+ return {
131
+ date: day,
132
+ label: format(day, 'EEE'),
133
+ dayNum: format(day, 'd'),
134
+ isToday: isSameDay(day, today),
135
+ shifts,
136
+ };
137
+ });
138
+ }
139
+
140
+ // ── Panel action buttons ──────────────────────────────────────────────────
141
+
41
142
  get shiftActionButtons() {
42
143
  return [
43
144
  {
44
145
  type: 'default',
45
- text: 'Add Shift',
146
+ text: this.intl.t('scheduler.add-shift'),
46
147
  icon: 'plus',
47
148
  iconPrefix: 'fas',
48
149
  permission: 'fleet-ops update driver',
@@ -51,217 +152,308 @@ export default class DriverScheduleComponent extends Component {
51
152
  ];
52
153
  }
53
154
 
54
- get availabilityActionButtons() {
155
+ get exceptionActionButtons() {
55
156
  return [
56
157
  {
57
158
  type: 'default',
58
- text: 'Set Availability',
59
- icon: 'clock',
159
+ text: this.intl.t('scheduler.request-time-off'),
160
+ icon: 'calendar-times',
60
161
  iconPrefix: 'fas',
61
162
  permission: 'fleet-ops update driver',
62
- onClick: this.setAvailability,
163
+ onClick: this.requestTimeOff,
63
164
  },
64
165
  ];
65
166
  }
66
167
 
67
- constructor() {
68
- super(...arguments);
69
- this.loadDriverSchedule.perform();
70
- this.loadHOSStatus.perform();
71
- this.loadAvailability.perform();
72
- }
168
+ // ── Data loading ──────────────────────────────────────────────────────────
73
169
 
74
170
  /**
75
- * Load driver schedule items
171
+ * Load the driver's primary Schedule container, then load its materialised
172
+ * ScheduleItems and ScheduleExceptions.
173
+ *
174
+ * If no Schedule exists yet for this driver, we create a draft one so the
175
+ * UI is always ready to accept shifts.
76
176
  */
77
177
  @task *loadDriverSchedule() {
78
178
  try {
79
- const items = yield this.driverScheduling.getScheduleItemsForAssignee.perform('driver', this.args.resource.id, {
80
- start_at: this.startDate,
81
- end_at: this.endDate,
179
+ // 1. Find or create the driver's primary schedule
180
+ const schedules = yield this.store.query('schedule', {
181
+ subject_type: 'fleet-ops:driver',
182
+ subject_uuid: this.args.resource.id,
183
+ limit: 1,
184
+ });
185
+
186
+ if (schedules.length > 0) {
187
+ this.schedule = schedules.firstObject;
188
+ } else {
189
+ const newSchedule = this.store.createRecord('schedule', {
190
+ subject_type: 'fleet-ops:driver',
191
+ subject_uuid: this.args.resource.id,
192
+ name: `${this.args.resource.name} Schedule`,
193
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
194
+ status: 'draft',
195
+ });
196
+ this.schedule = yield newSchedule.save();
197
+ }
198
+
199
+ // 2. Load materialised schedule items within the 4-week window
200
+ // Use _gte/_lte operator suffixes so the API applies range filtering
201
+ // (plain start_at/end_at would be treated as exact equality by the query builder)
202
+ const items = yield this.store.query('schedule-item', {
203
+ schedule_uuid: this.schedule.id,
204
+ start_at_gte: this.startDate,
205
+ end_at_lte: this.endDate,
82
206
  });
83
207
 
84
208
  this.scheduleItems = items.toArray();
85
- this.upcomingShifts = this.scheduleItems.filter((item) => new Date(item.start_at) > new Date()).slice(0, 5);
209
+ this.upcomingShifts = this.scheduleItems.filter((item) => new Date(item.start_at) >= new Date()).sort((a, b) => new Date(a.start_at) - new Date(b.start_at));
210
+
211
+ // 3. Load schedule exceptions
212
+ const exceptions = yield this.store.query('schedule-exception', {
213
+ schedule_uuid: this.schedule.id,
214
+ });
215
+ this.exceptions = exceptions.toArray();
86
216
  } catch (error) {
87
- console.error('Failed to load driver schedule:', error);
217
+ this.notifications.serverError(error);
88
218
  }
89
219
  }
90
220
 
91
221
  /**
92
- * Load HOS status for the driver
222
+ * Load HOS (Hours of Service) status from the FleetOps driver endpoint.
223
+ * Best-effort — if the endpoint is not yet implemented hosStatus stays null.
93
224
  */
94
225
  @task *loadHOSStatus() {
95
226
  try {
96
227
  const response = yield this.fetch.get(`drivers/${this.args.resource.id}/hos-status`);
97
228
  this.hosStatus = response;
98
- } catch (error) {
99
- console.error('Failed to load HOS status:', error);
229
+ } catch {
230
+ this.hosStatus = null;
100
231
  }
101
232
  }
102
233
 
103
- /**
104
- * Load driver availability
105
- */
106
- @task *loadAvailability() {
107
- try {
108
- const availability = yield this.store.query('schedule-availability', {
109
- subject_type: 'driver',
110
- subject_uuid: this.args.resource.id,
111
- start_at: this.startDate,
112
- end_at: this.endDate,
113
- });
114
-
115
- this.availability = availability.toArray();
116
- } catch (error) {
117
- console.error('Failed to load availability:', error);
118
- }
119
- }
234
+ // ── Shift management ──────────────────────────────────────────────────────
120
235
 
121
236
  /**
122
- * Get start date for schedule query (current week)
237
+ * Open the Add Shift modal.
238
+ *
239
+ * Two modes are supported:
240
+ * - Single shift: creates a ScheduleItem directly on the driver's Schedule
241
+ * - Recurring schedule: creates a ScheduleTemplate with an RRULE and
242
+ * triggers materialisation via the core-api schedule-templates/{id}/apply endpoint
123
243
  */
124
- get startDate() {
125
- const now = new Date();
126
- const dayOfWeek = now.getDay();
127
- const diff = now.getDate() - dayOfWeek;
128
- return new Date(now.setDate(diff)).toISOString();
129
- }
130
-
131
- /**
132
- * Get end date for schedule query (4 weeks out)
133
- */
134
- get endDate() {
135
- const now = new Date();
136
- return new Date(now.setDate(now.getDate() + 28)).toISOString();
137
- }
138
-
139
- /**
140
- * Get HOS compliance badge color
141
- */
142
- get hosComplianceBadge() {
143
- if (!this.hosStatus) {
144
- return { color: 'gray', text: 'Unknown' };
145
- }
146
-
147
- const { daily_hours, weekly_hours } = this.hosStatus;
148
-
149
- if (daily_hours >= 11 || weekly_hours >= 70) {
150
- return { color: 'red', text: 'At Limit' };
151
- }
244
+ @action
245
+ addShift() {
246
+ this.modalsManager.show('modals/add-driver-shift', {
247
+ title: this.intl.t('scheduler.add-shift'),
248
+ acceptButtonText: this.intl.t('scheduler.create-shift'),
249
+ acceptButtonIcon: 'plus',
250
+ drivers: [this.args.resource],
251
+ selectedDriver: this.args.resource,
252
+ confirm: async (modal) => {
253
+ modal.startLoading();
254
+ const options = modal.getOptions();
152
255
 
153
- if (daily_hours >= 9 || weekly_hours >= 60) {
154
- return { color: 'yellow', text: 'Approaching Limit' };
155
- }
256
+ try {
257
+ if (options.isRecurring) {
258
+ // Recurring mode: create a ScheduleTemplate then apply it
259
+ const template = this.store.createRecord('schedule-template', {
260
+ name: options.templateName || `${this.args.resource.name} Recurring Schedule`,
261
+ rrule: options.rrule,
262
+ start_time: options.shiftStartTime,
263
+ end_time: options.shiftEndTime,
264
+ break_start_time: options.breakStartTime || null,
265
+ break_end_time: options.breakEndTime || null,
266
+ color: options.templateColor || '#6366f1',
267
+ });
268
+ const savedTemplate = await template.save();
156
269
 
157
- return { color: 'green', text: 'Compliant' };
158
- }
270
+ await this.fetch.post(`schedule-templates/${savedTemplate.id}/apply`, {
271
+ subject_type: 'fleet-ops:driver',
272
+ subject_uuid: this.args.resource.id,
273
+ schedule_uuid: this.schedule.id,
274
+ effective_from: options.recurrenceStartDate || new Date().toISOString(),
275
+ effective_until: options.recurrenceEndDate || null,
276
+ });
159
277
 
160
- /**
161
- * Handle item click
162
- */
163
- @action
164
- handleItemClick(item) {
165
- this.selectedItem = item;
166
- this.modalsManager.show('modals/schedule-item-details', {
167
- item,
168
- onEdit: this.editScheduleItem,
169
- onDelete: this.deleteScheduleItem,
170
- });
171
- }
278
+ this.notifications.success(this.intl.t('scheduler.recurring-schedule-created'));
279
+ } else {
280
+ // Single shift mode: create a ScheduleItem directly
281
+ const scheduleItem = this.store.createRecord('schedule-item', {
282
+ schedule_uuid: this.schedule.id,
283
+ assignee_type: 'fleet-ops:driver',
284
+ assignee_uuid: this.args.resource.id,
285
+ title: options.title || null,
286
+ start_at: options.startAt,
287
+ end_at: options.endAt,
288
+ notes: options.notes || null,
289
+ status: 'scheduled',
290
+ });
291
+ await scheduleItem.save();
292
+ this.notifications.success(this.intl.t('scheduler.shift-created'));
293
+ }
172
294
 
173
- /**
174
- * Add new shift
175
- */
176
- @action
177
- addShift() {
178
- this.modalsManager.show('modals/add-shift', {
179
- driver: this.args.resource,
180
- onSave: this.handleShiftAdded,
295
+ await this.loadDriverSchedule.perform();
296
+ await this.loadHOSStatus.perform();
297
+ modal.done();
298
+ } catch (error) {
299
+ this.notifications.serverError(error);
300
+ modal.stopLoading();
301
+ }
302
+ },
181
303
  });
182
304
  }
183
305
 
184
306
  /**
185
- * Edit schedule item
307
+ * Open the Edit Shift modal for an existing ScheduleItem.
186
308
  */
187
309
  @action
188
- async editScheduleItem(item) {
189
- this.modalsManager.show('modals/edit-shift', {
310
+ editShift(item) {
311
+ this.modalsManager.show('modals/driver-shift', {
312
+ title: this.intl.t('scheduler.edit-shift'),
313
+ acceptButtonText: this.intl.t('common.save-changes'),
314
+ acceptButtonIcon: 'save',
190
315
  item,
191
- driver: this.args.resource,
192
- onSave: this.handleShiftUpdated,
316
+ confirm: async (modal) => {
317
+ modal.startLoading();
318
+ const options = modal.getOptions();
319
+ try {
320
+ item.setProperties({
321
+ title: options.title,
322
+ start_at: options.startAt,
323
+ end_at: options.endAt,
324
+ notes: options.notes,
325
+ });
326
+ await item.save();
327
+ this.notifications.success(this.intl.t('scheduler.shift-updated'));
328
+ await this.loadDriverSchedule.perform();
329
+ modal.done();
330
+ } catch (error) {
331
+ this.notifications.serverError(error);
332
+ modal.stopLoading();
333
+ }
334
+ },
193
335
  });
194
336
  }
195
337
 
196
338
  /**
197
- * Delete schedule item
198
- */
199
- @action
200
- async deleteScheduleItem(item) {
201
- if (confirm('Are you sure you want to delete this shift?')) {
202
- try {
203
- await this.driverScheduling.deleteScheduleItem.perform(item);
204
- await this.loadDriverSchedule.perform();
205
- } catch (error) {
206
- console.error('Failed to delete shift:', error);
207
- }
208
- }
209
- }
210
-
211
- /**
212
- * Handle shift added
339
+ * Delete a shift after inline confirmation.
213
340
  */
214
341
  @action
215
- async handleShiftAdded() {
216
- await this.loadDriverSchedule.perform();
217
- await this.loadHOSStatus.perform();
342
+ deleteShift(item) {
343
+ this.modalsManager.confirm({
344
+ title: this.intl.t('scheduler.delete-shift'),
345
+ body: this.intl.t('scheduler.delete-shift-confirm'),
346
+ acceptButtonText: this.intl.t('common.delete'),
347
+ acceptButtonScheme: 'danger',
348
+ confirm: async (modal) => {
349
+ modal.startLoading();
350
+ try {
351
+ await item.destroyRecord();
352
+ this.notifications.success(this.intl.t('scheduler.shift-deleted'));
353
+ await this.loadDriverSchedule.perform();
354
+ await this.loadHOSStatus.perform();
355
+ modal.done();
356
+ } catch (error) {
357
+ this.notifications.serverError(error);
358
+ modal.stopLoading();
359
+ }
360
+ },
361
+ });
218
362
  }
219
363
 
220
- /**
221
- * Handle shift updated
222
- */
223
- @action
224
- async handleShiftUpdated() {
225
- await this.loadDriverSchedule.perform();
226
- await this.loadHOSStatus.perform();
227
- }
364
+ // ── Exception management ──────────────────────────────────────────────────
228
365
 
229
366
  /**
230
- * Request time off
367
+ * Open the Request Time Off modal.
368
+ * Creates a ScheduleException with type='time_off' and status='pending'.
231
369
  */
232
370
  @action
233
371
  requestTimeOff() {
234
- this.modalsManager.show('modals/request-time-off', {
372
+ this.modalsManager.show('modals/set-driver-availability', {
373
+ title: this.intl.t('scheduler.request-time-off'),
374
+ acceptButtonText: this.intl.t('scheduler.submit-request'),
375
+ acceptButtonIcon: 'calendar-times',
235
376
  driver: this.args.resource,
236
- onSave: this.handleTimeOffRequested,
377
+ isAvailable: false,
378
+ confirm: async (modal) => {
379
+ modal.startLoading();
380
+ const options = modal.getOptions();
381
+ try {
382
+ const exception = this.store.createRecord('schedule-exception', {
383
+ schedule_uuid: this.schedule?.id,
384
+ subject_type: 'fleet-ops:driver',
385
+ subject_uuid: this.args.resource.id,
386
+ type: 'time_off',
387
+ status: 'pending',
388
+ start_at: options.startAt,
389
+ end_at: options.endAt,
390
+ reason: options.reason || null,
391
+ notes: options.notes || null,
392
+ });
393
+ await exception.save();
394
+ this.notifications.success(this.intl.t('scheduler.time-off-requested'));
395
+ await this.loadDriverSchedule.perform();
396
+ modal.done();
397
+ } catch (error) {
398
+ this.notifications.serverError(error);
399
+ modal.stopLoading();
400
+ }
401
+ },
237
402
  });
238
403
  }
239
404
 
240
405
  /**
241
- * Handle time off requested
406
+ * Approve a pending ScheduleException (manager action).
242
407
  */
243
408
  @action
244
- async handleTimeOffRequested() {
245
- await this.loadAvailability.perform();
246
- await this.loadDriverSchedule.perform();
409
+ async approveException(exception) {
410
+ try {
411
+ await this.fetch.post(`schedule-exceptions/${exception.id}/approve`);
412
+ exception.set('status', 'approved');
413
+ this.notifications.success(this.intl.t('scheduler.exception-approved'));
414
+ await this.loadDriverSchedule.perform();
415
+ } catch (error) {
416
+ this.notifications.serverError(error);
417
+ }
247
418
  }
248
419
 
249
420
  /**
250
- * Set availability
421
+ * Reject a pending ScheduleException (manager action).
251
422
  */
252
423
  @action
253
- setAvailability() {
254
- this.modalsManager.show('modals/set-availability', {
255
- driver: this.args.resource,
256
- onSave: this.handleAvailabilitySet,
257
- });
424
+ async rejectException(exception) {
425
+ try {
426
+ await this.fetch.post(`schedule-exceptions/${exception.id}/reject`);
427
+ exception.set('status', 'rejected');
428
+ this.notifications.success(this.intl.t('scheduler.exception-rejected'));
429
+ await this.loadDriverSchedule.perform();
430
+ } catch (error) {
431
+ this.notifications.serverError(error);
432
+ }
258
433
  }
259
434
 
260
435
  /**
261
- * Handle availability set
436
+ * Delete a ScheduleException record.
262
437
  */
263
438
  @action
264
- async handleAvailabilitySet() {
265
- await this.loadAvailability.perform();
439
+ deleteException(exception) {
440
+ this.modalsManager.confirm({
441
+ title: this.intl.t('scheduler.delete-exception'),
442
+ body: this.intl.t('scheduler.delete-exception-confirm'),
443
+ acceptButtonText: this.intl.t('common.delete'),
444
+ acceptButtonScheme: 'danger',
445
+ confirm: async (modal) => {
446
+ modal.startLoading();
447
+ try {
448
+ await exception.destroyRecord();
449
+ this.notifications.success(this.intl.t('scheduler.exception-deleted'));
450
+ await this.loadDriverSchedule.perform();
451
+ modal.done();
452
+ } catch (error) {
453
+ this.notifications.serverError(error);
454
+ modal.stopLoading();
455
+ }
456
+ },
457
+ });
266
458
  }
267
459
  }
@@ -11,10 +11,7 @@
11
11
  </div>
12
12
  </InputGroup>
13
13
  {{#if this.driverOnboardSettings.enableDriverOnboardFromApp}}
14
- <InputGroup
15
- @name={{t "driver-onboard-settings.select-onboard-method"}}
16
- @helpText={{t "driver-onboard-settings.select-onboard-method-help-text"}}
17
- >
14
+ <InputGroup @name={{t "driver-onboard-settings.select-onboard-method"}} @helpText={{t "driver-onboard-settings.select-onboard-method-help-text"}}>
18
15
  <Select
19
16
  class="w-full flex-1"
20
17
  @value={{this.driverOnboardSettings.driverOnboardAppMethod}}
@@ -41,10 +38,7 @@
41
38
  @onDataChanged={{this.onOnboardDocumentsChanged}}
42
39
  @addButtonText={{t "driver-onboard-settings.add-onboard-document"}}
43
40
  >
44
- <InputLabel
45
- @labelText={{t "driver-onboard-settings.required-onboard-documents"}}
46
- @helpText={{t "driver-onboard-settings.required-onboard-documents-help-text"}}
47
- />
41
+ <InputLabel @labelText={{t "driver-onboard-settings.required-onboard-documents"}} @helpText={{t "driver-onboard-settings.required-onboard-documents-help-text"}} />
48
42
  </ArrayInput>
49
43
  </InputGroup>
50
44
  {{/if}}
@@ -1,10 +1,7 @@
1
- <ContentPanel @title={{t "entity-field-editing-settings.entitiy-field-editing-settings"}} @open={{true}} @wrapperClass="bordered-classic">
1
+ <ContentPanel @title={{t "entity-field-editing-settings.entitiy-field-editing-settings"}} @open={{true}} @wrapperClass="bordered-classic">
2
2
  <OrderConfigManager @onConfigChanged={{this.onConfigChanged}} as |Action Context|>
3
3
  <div>
4
- <InputGroup
5
- @name={{t "entity-field-editing-settings.select-order-config"}}
6
- @helpText={{t "entity-field-editing-settings.select-order-config-help-text"}}
7
- >
4
+ <InputGroup @name={{t "entity-field-editing-settings.select-order-config"}} @helpText={{t "entity-field-editing-settings.select-order-config-help-text"}}>
8
5
  <DropdownButton
9
6
  class="order-config-select-button mr-2"
10
7
  @disabled={{not Context.configs}}