@fleetbase/fleetops-engine 0.6.69 → 0.6.71

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 (324) hide show
  1. package/RELEASE.md +21 -14
  2. package/addon/components/admin/telematics-settings.hbs +143 -0
  3. package/addon/components/admin/telematics-settings.js +145 -0
  4. package/addon/components/fuel-integration/hub.hbs +1 -1
  5. package/addon/components/layout/fleet-ops-sidebar.js +37 -17
  6. package/addon/components/map/leaflet-live-map.hbs +4 -242
  7. package/addon/components/map/leaflet-live-map.js +2 -1
  8. package/addon/components/map/marker-card/driver.hbs +57 -0
  9. package/addon/components/map/marker-card/driver.js +3 -0
  10. package/addon/components/map/marker-card/vehicle.hbs +78 -0
  11. package/addon/components/map/marker-card/vehicle.js +3 -0
  12. package/addon/components/order/details/activity.hbs +8 -6
  13. package/addon/components/order/details/activity.js +9 -0
  14. package/addon/components/order/details.hbs +29 -0
  15. package/addon/components/order/details.js +26 -0
  16. package/addon/components/order/form/details.hbs +30 -4
  17. package/addon/components/order/form/details.js +46 -0
  18. package/addon/components/order/form/route.hbs +4 -2
  19. package/addon/components/order/form/route.js +11 -0
  20. package/addon/components/order/form.hbs +12 -0
  21. package/addon/components/order/form.js +21 -1
  22. package/addon/components/order/kanban.js +72 -0
  23. package/addon/components/order-config-manager/activity-flow.js +45 -10
  24. package/addon/components/order-config-manager/lifecycle.hbs +250 -0
  25. package/addon/components/order-config-manager/lifecycle.js +358 -0
  26. package/addon/components/order-config-manager.js +5 -1
  27. package/addon/components/telematic/hub.hbs +1 -1
  28. package/addon/components/widget/live-fleet.hbs +8 -40
  29. package/addon/controllers/analytics/reports/index.js +15 -1
  30. package/addon/controllers/connectivity/devices/index/details.js +1 -0
  31. package/addon/controllers/connectivity/devices/index.js +12 -2
  32. package/addon/controllers/connectivity/events/index.js +31 -1
  33. package/addon/controllers/connectivity/fuel-providers/index.js +6 -4
  34. package/addon/controllers/connectivity/sensors/index/details.js +1 -1
  35. package/addon/controllers/connectivity/sensors/index.js +41 -1
  36. package/addon/controllers/connectivity/telematics/index.js +4 -0
  37. package/addon/controllers/maintenance/equipment/index/details.js +2 -2
  38. package/addon/controllers/maintenance/equipment/index.js +36 -10
  39. package/addon/controllers/maintenance/inspection-forms/index.js +32 -12
  40. package/addon/controllers/maintenance/inspection-submissions/index/details.js +2 -1
  41. package/addon/controllers/maintenance/inspection-submissions/index.js +56 -10
  42. package/addon/controllers/maintenance/maintenances/index/details.js +2 -0
  43. package/addon/controllers/maintenance/maintenances/index.js +24 -1
  44. package/addon/controllers/maintenance/parts/index/details.js +2 -2
  45. package/addon/controllers/maintenance/parts/index.js +36 -9
  46. package/addon/controllers/maintenance/schedules/index.js +48 -6
  47. package/addon/controllers/maintenance/work-orders/index/details.js +3 -3
  48. package/addon/controllers/maintenance/work-orders/index.js +47 -9
  49. package/addon/controllers/management/contacts/customers.js +13 -0
  50. package/addon/controllers/management/contacts/index.js +47 -1
  51. package/addon/controllers/management/drivers/index/details.js +1 -0
  52. package/addon/controllers/management/drivers/index.js +36 -2
  53. package/addon/controllers/management/fleets/index/details.js +1 -0
  54. package/addon/controllers/management/fleets/index.js +43 -1
  55. package/addon/controllers/management/fuel-reports/index.js +26 -2
  56. package/addon/controllers/management/fuel-transactions/index.js +45 -7
  57. package/addon/controllers/management/issues/index/details.js +1 -0
  58. package/addon/controllers/management/issues/index.js +26 -2
  59. package/addon/controllers/management/places/index.js +40 -1
  60. package/addon/controllers/management/trailers/index/details.js +1 -0
  61. package/addon/controllers/management/trailers/index.js +50 -2
  62. package/addon/controllers/management/vehicles/index/details.js +1 -0
  63. package/addon/controllers/management/vehicles/index.js +37 -2
  64. package/addon/controllers/management/vendors/index.js +30 -2
  65. package/addon/controllers/operations/orders/index/details.js +61 -5
  66. package/addon/controllers/operations/orders/index.js +66 -4
  67. package/addon/controllers/operations/service-rates/index.js +18 -1
  68. package/addon/controllers/settings/index.js +13 -0
  69. package/addon/controllers/settings/telematics.js +113 -0
  70. package/addon/extension.js +70 -6
  71. package/addon/routes/analytics/index.js +14 -1
  72. package/addon/routes/analytics/reports/index/details.js +1 -1
  73. package/addon/routes/analytics/reports/index/edit.js +1 -1
  74. package/addon/routes/analytics/reports/index/new.js +14 -1
  75. package/addon/routes/analytics/reports.js +14 -1
  76. package/addon/routes/connectivity/devices/index/new.js +14 -1
  77. package/addon/routes/connectivity/devices.js +14 -1
  78. package/addon/routes/connectivity/events.js +14 -1
  79. package/addon/routes/connectivity/fuel-providers/details/transactions.js +12 -0
  80. package/addon/routes/connectivity/fuel-providers/details.js +9 -0
  81. package/addon/routes/connectivity/fuel-providers/edit.js +9 -0
  82. package/addon/routes/connectivity/fuel-providers/new.js +14 -1
  83. package/addon/routes/connectivity/fuel-providers.js +14 -1
  84. package/addon/routes/connectivity/sensors/index/new.js +14 -1
  85. package/addon/routes/connectivity/sensors.js +14 -1
  86. package/addon/routes/connectivity/telematics/new.js +14 -1
  87. package/addon/routes/connectivity/telematics.js +14 -1
  88. package/addon/routes/connectivity/tracking.js +14 -1
  89. package/addon/routes/maintenance/equipment/index/details.js +2 -2
  90. package/addon/routes/maintenance/equipment/index/edit.js +2 -2
  91. package/addon/routes/maintenance/equipment/index/new.js +14 -1
  92. package/addon/routes/maintenance/equipment.js +14 -1
  93. package/addon/routes/maintenance/index.js +14 -1
  94. package/addon/routes/maintenance/inspection-forms/index/details.js +10 -1
  95. package/addon/routes/maintenance/inspection-forms/index/edit.js +10 -1
  96. package/addon/routes/maintenance/inspection-forms/index/new.js +14 -1
  97. package/addon/routes/maintenance/inspection-forms.js +14 -1
  98. package/addon/routes/maintenance/inspection-submissions/index/details.js +10 -1
  99. package/addon/routes/maintenance/inspection-submissions/index/edit.js +10 -1
  100. package/addon/routes/maintenance/inspection-submissions/index/new.js +14 -1
  101. package/addon/routes/maintenance/inspection-submissions.js +14 -1
  102. package/addon/routes/maintenance/maintenances/index/details.js +2 -2
  103. package/addon/routes/maintenance/maintenances/index/edit.js +2 -2
  104. package/addon/routes/maintenance/maintenances/index/new.js +14 -1
  105. package/addon/routes/maintenance/maintenances.js +14 -1
  106. package/addon/routes/maintenance/parts/index/details.js +2 -2
  107. package/addon/routes/maintenance/parts/index/edit.js +2 -2
  108. package/addon/routes/maintenance/parts/index/new.js +14 -1
  109. package/addon/routes/maintenance/parts.js +14 -1
  110. package/addon/routes/maintenance/schedules/index/details.js +2 -2
  111. package/addon/routes/maintenance/schedules/index/edit.js +2 -2
  112. package/addon/routes/maintenance/schedules/index/new.js +15 -1
  113. package/addon/routes/maintenance/schedules.js +15 -1
  114. package/addon/routes/maintenance/work-orders/index/details.js +2 -2
  115. package/addon/routes/maintenance/work-orders/index/edit.js +2 -2
  116. package/addon/routes/maintenance/work-orders/index/new.js +14 -1
  117. package/addon/routes/maintenance/work-orders.js +14 -1
  118. package/addon/routes/management/fuel-transactions/index/details.js +9 -0
  119. package/addon/routes/management/fuel-transactions.js +14 -1
  120. package/addon/routes/management/index.js +13 -0
  121. package/addon/routes/management/trailers.js +16 -0
  122. package/addon/routes/management/vendors/integrated/details.js +14 -1
  123. package/addon/routes/management/vendors/integrated/edit.js +14 -1
  124. package/addon/routes/management/vendors/integrated/new.js +14 -1
  125. package/addon/routes/management/vendors/integrated.js +14 -1
  126. package/addon/routes/operations/orders/index/details.js +1 -0
  127. package/addon/routes/operations/orders.js +40 -1
  128. package/addon/routes/operations/routes/index/details.js +14 -1
  129. package/addon/routes/operations/routes/index/new.js +13 -0
  130. package/addon/routes/operations/routes.js +14 -1
  131. package/addon/routes/operations/service-rates/index/new.js +11 -0
  132. package/addon/routes/operations/service-rates.js +14 -1
  133. package/addon/routes/settings/avatars.js +14 -1
  134. package/addon/routes/settings/custom-fields.js +14 -1
  135. package/addon/routes/settings/map.js +14 -1
  136. package/addon/routes/settings/notifications.js +11 -0
  137. package/addon/routes/settings/orchestrator.js +1 -1
  138. package/addon/routes/settings/payments/index.js +1 -1
  139. package/addon/routes/settings/routing.js +14 -1
  140. package/addon/routes/settings/scheduling.js +14 -1
  141. package/addon/routes/settings/telematics.js +21 -0
  142. package/addon/routes/virtual.js +11 -0
  143. package/addon/routes.js +1 -0
  144. package/addon/services/contact-actions.js +1 -0
  145. package/addon/services/customer-actions.js +2 -1
  146. package/addon/services/device-actions.js +1 -0
  147. package/addon/services/device-event-actions.js +1 -0
  148. package/addon/services/driver-actions.js +4 -13
  149. package/addon/services/equipment-actions.js +1 -0
  150. package/addon/services/fleet-actions.js +1 -0
  151. package/addon/services/fuel-report-actions.js +1 -0
  152. package/addon/services/inspection-form-actions.js +1 -0
  153. package/addon/services/inspection-submission-actions.js +1 -0
  154. package/addon/services/integrated-vendor-actions.js +1 -0
  155. package/addon/services/issue-actions.js +1 -0
  156. package/addon/services/maintenance-actions.js +1 -0
  157. package/addon/services/maintenance-schedule-actions.js +2 -1
  158. package/addon/services/order-actions.js +7 -0
  159. package/addon/services/order-presentation.js +129 -0
  160. package/addon/services/part-actions.js +1 -0
  161. package/addon/services/place-actions.js +1 -0
  162. package/addon/services/sensor-actions.js +1 -0
  163. package/addon/services/service-area-actions.js +1 -0
  164. package/addon/services/service-rate-actions.js +1 -0
  165. package/addon/services/telematic-actions.js +1 -0
  166. package/addon/services/trailer-actions.js +4 -14
  167. package/addon/services/vehicle-actions.js +4 -13
  168. package/addon/services/vendor-actions.js +1 -0
  169. package/addon/services/work-order-actions.js +1 -0
  170. package/addon/services/zone-actions.js +1 -0
  171. package/addon/templates/analytics/reports/index/details.hbs +1 -0
  172. package/addon/templates/analytics/reports/index.hbs +1 -0
  173. package/addon/templates/connectivity/devices/index/details.hbs +1 -0
  174. package/addon/templates/connectivity/devices/index.hbs +1 -0
  175. package/addon/templates/connectivity/events/index.hbs +1 -0
  176. package/addon/templates/connectivity/sensors/index/details.hbs +1 -0
  177. package/addon/templates/connectivity/sensors/index.hbs +1 -0
  178. package/addon/templates/maintenance/equipment/index/details.hbs +1 -0
  179. package/addon/templates/maintenance/equipment/index.hbs +2 -0
  180. package/addon/templates/maintenance/inspection-forms/index/details.hbs +1 -0
  181. package/addon/templates/maintenance/inspection-forms/index.hbs +1 -0
  182. package/addon/templates/maintenance/inspection-submissions/index/details.hbs +1 -0
  183. package/addon/templates/maintenance/inspection-submissions/index.hbs +1 -0
  184. package/addon/templates/maintenance/maintenances/index/details.hbs +1 -0
  185. package/addon/templates/maintenance/maintenances/index.hbs +1 -0
  186. package/addon/templates/maintenance/parts/index/details.hbs +1 -0
  187. package/addon/templates/maintenance/parts/index.hbs +2 -0
  188. package/addon/templates/maintenance/schedules/index/details.hbs +1 -0
  189. package/addon/templates/maintenance/schedules/index.hbs +2 -0
  190. package/addon/templates/maintenance/work-orders/index/details.hbs +1 -0
  191. package/addon/templates/maintenance/work-orders/index.hbs +1 -0
  192. package/addon/templates/management/contacts/customers/details.hbs +1 -0
  193. package/addon/templates/management/contacts/customers.hbs +1 -0
  194. package/addon/templates/management/contacts/index/details.hbs +1 -0
  195. package/addon/templates/management/contacts/index.hbs +1 -0
  196. package/addon/templates/management/contacts.hbs +1 -0
  197. package/addon/templates/management/drivers/index/details.hbs +1 -0
  198. package/addon/templates/management/drivers/index.hbs +2 -0
  199. package/addon/templates/management/fleets/index/details.hbs +1 -0
  200. package/addon/templates/management/fleets/index.hbs +1 -0
  201. package/addon/templates/management/fuel-reports/index/details.hbs +1 -0
  202. package/addon/templates/management/fuel-reports/index.hbs +1 -0
  203. package/addon/templates/management/fuel-transactions/index.hbs +1 -0
  204. package/addon/templates/management/issues/index/details.hbs +1 -0
  205. package/addon/templates/management/issues/index.hbs +1 -0
  206. package/addon/templates/management/places/index/details.hbs +1 -0
  207. package/addon/templates/management/places/index.hbs +1 -0
  208. package/addon/templates/management/trailers/index/details.hbs +1 -0
  209. package/addon/templates/management/trailers/index.hbs +2 -0
  210. package/addon/templates/management/vehicles/index/details.hbs +1 -0
  211. package/addon/templates/management/vehicles/index.hbs +2 -0
  212. package/addon/templates/management/vendors/index/details.hbs +1 -0
  213. package/addon/templates/management/vendors/index.hbs +2 -0
  214. package/addon/templates/management/vendors/integrated.hbs +1 -0
  215. package/addon/templates/operations/orders/index/details.hbs +1 -0
  216. package/addon/templates/operations/orders/index.hbs +1 -0
  217. package/addon/templates/operations/service-rates/index/details.hbs +1 -0
  218. package/addon/templates/operations/service-rates/index.hbs +1 -0
  219. package/addon/templates/settings/telematics.hbs +70 -0
  220. package/addon/utils/normalize-order-config-flow.js +6 -1
  221. package/app/components/admin/telematics-settings.js +1 -0
  222. package/app/components/map/marker-card/driver.js +1 -0
  223. package/app/components/map/marker-card/vehicle.js +1 -0
  224. package/app/controllers/settings/telematics.js +1 -0
  225. package/app/routes/settings/telematics.js +1 -0
  226. package/app/services/order-presentation.js +1 -0
  227. package/app/templates/settings/telematics.js +1 -0
  228. package/composer.json +2 -2
  229. package/docs/AFAQY.md +1 -1
  230. package/docs/TELEMATICS_QUEUES.md +1 -1
  231. package/docs/TELEMETRY_ARCHITECTURE.md +72 -1
  232. package/extension.json +1 -1
  233. package/package.json +3 -3
  234. package/server/config/telemetry.php +12 -0
  235. package/server/migrations/2026_09_23_000001_add_retention_index_to_device_events.php +40 -0
  236. package/server/migrations/2026_09_23_000002_add_retention_index_to_positions.php +40 -0
  237. package/server/migrations/2026_09_23_000003_add_retention_index_to_telematic_sync_runs.php +40 -0
  238. package/server/src/Auth/Schemas/FleetOps.php +104 -5
  239. package/server/src/Console/Commands/DrainTelematicInbox.php +3 -13
  240. package/server/src/Console/Commands/ProcessOperationalAlerts.php +3 -3
  241. package/server/src/Console/Commands/PruneTelematicsData.php +318 -0
  242. package/server/src/Http/Controllers/Api/v1/OrchestrationController.php +9 -0
  243. package/server/src/Http/Controllers/FleetOpsController.php +21 -0
  244. package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +11 -0
  245. package/server/src/Http/Controllers/Internal/v1/ContactController.php +11 -0
  246. package/server/src/Http/Controllers/Internal/v1/CustomerController.php +14 -0
  247. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +13 -0
  248. package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +11 -0
  249. package/server/src/Http/Controllers/Internal/v1/DriverController.php +22 -0
  250. package/server/src/Http/Controllers/Internal/v1/FuelProviderConnectionController.php +13 -0
  251. package/server/src/Http/Controllers/Internal/v1/FuelProviderTransactionController.php +15 -0
  252. package/server/src/Http/Controllers/Internal/v1/FuelReportController.php +9 -3
  253. package/server/src/Http/Controllers/Internal/v1/InspectionFormController.php +15 -0
  254. package/server/src/Http/Controllers/Internal/v1/LiveController.php +16 -0
  255. package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +15 -0
  256. package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +15 -0
  257. package/server/src/Http/Controllers/Internal/v1/ManifestController.php +15 -0
  258. package/server/src/Http/Controllers/Internal/v1/MetricsController.php +11 -0
  259. package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +42 -1
  260. package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +12 -0
  261. package/server/src/Http/Controllers/Internal/v1/OrderController.php +56 -4
  262. package/server/src/Http/Controllers/Internal/v1/PaymentController.php +13 -0
  263. package/server/src/Http/Controllers/Internal/v1/RadarController.php +19 -0
  264. package/server/src/Http/Controllers/Internal/v1/ServiceAreaController.php +9 -3
  265. package/server/src/Http/Controllers/Internal/v1/SettingController.php +465 -14
  266. package/server/src/Http/Controllers/Internal/v1/TelematicController.php +21 -0
  267. package/server/src/Http/Controllers/Internal/v1/TrailerController.php +21 -0
  268. package/server/src/Http/Controllers/Internal/v1/VehicleController.php +21 -0
  269. package/server/src/Http/Controllers/Internal/v1/VendorController.php +17 -0
  270. package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +11 -0
  271. package/server/src/Jobs/DispatchTelematicsRetentionJobs.php +70 -0
  272. package/server/src/Jobs/PruneTelematicsDataJob.php +74 -0
  273. package/server/src/Listeners/NotifyDriverOnShiftChange.php +3 -3
  274. package/server/src/Mail/CustomerCredentialsMail.php +1 -1
  275. package/server/src/Models/Order.php +35 -3
  276. package/server/src/Models/OrderConfig.php +129 -0
  277. package/server/src/Models/TrackingNumber.php +8 -4
  278. package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +9 -1
  279. package/server/src/Providers/FleetOpsServiceProvider.php +3 -0
  280. package/server/src/Support/Analytics/LiveFleet.php +18 -2
  281. package/server/src/Support/Authorization.php +103 -0
  282. package/server/src/Support/Database/TableIndexes.php +66 -0
  283. package/server/src/Support/OrderTracker.php +2 -2
  284. package/server/src/Support/Reporting/FleetOpsReportSchema.php +476 -116
  285. package/server/src/Support/Telematics/Retention/RetentionPolicy.php +300 -0
  286. package/server/src/Support/Telematics/Retention/TelemetryActivity.php +40 -0
  287. package/server/src/Support/Telematics/TelematicService.php +12 -2
  288. package/server/src/Support/Telematics/Telemetry/Ingestor.php +4 -2
  289. package/server/src/Tracking/TrackingIntelligenceService.php +1 -1
  290. package/server/src/Tracking/TrackingOptions.php +2 -2
  291. package/server/src/Traits/AuthorizesMethods.php +37 -0
  292. package/server/src/routes.php +9 -1
  293. package/server/tests/AnalyticsRoutesTest.php +29 -2
  294. package/server/tests/Feature/Http/AfaqyRealtimeIngestionTest.php +16 -1
  295. package/server/tests/Feature/Http/Api/TelematicsRetentionIndexMigrationTest.php +115 -0
  296. package/server/tests/Feature/Http/Internal/OrderControllerActivityFlowsTest.php +72 -0
  297. package/server/tests/Feature/Http/Internal/OrderControllerCreateRecordTest.php +26 -0
  298. package/server/tests/Feature/Http/Internal/SettingControllerHelpersTest.php +71 -0
  299. package/server/tests/Feature/Http/Internal/TelematicsStorageDeadlinesTest.php +119 -0
  300. package/server/tests/InternalImportExportControllerContractsTest.php +5 -8
  301. package/server/tests/NavigatorControllerContractsTest.php +36 -4
  302. package/server/tests/NotificationAndMailContractsTest.php +31 -0
  303. package/server/tests/ObserverContractsTest.php +1 -1
  304. package/server/tests/OrchestratorConsumableApiTest.php +42 -0
  305. package/server/tests/OrderConfigLifecycleTest.php +120 -0
  306. package/server/tests/ProviderContractsTest.php +10 -0
  307. package/server/tests/ReportSchemaContractsTest.php +120 -6
  308. package/server/tests/SettingControllerContractsTest.php +429 -18
  309. package/server/tests/SmallControllerContractsTest.php +8 -5
  310. package/server/tests/Support/PruneTelematicsDataProbe.php +55 -0
  311. package/server/tests/Unit/Console/Commands/ProcessOperationalAlertsCommandTest.php +2 -2
  312. package/server/tests/Unit/Console/PruneTelematicsDataCommandTest.php +353 -0
  313. package/server/tests/Unit/Events/OrderDispatchFailedTest.php +2 -1
  314. package/server/tests/Unit/Jobs/DispatchTelematicsRetentionJobsTest.php +114 -0
  315. package/server/tests/Unit/Jobs/PruneTelematicsDataJobTest.php +60 -0
  316. package/server/tests/Unit/Orchestration/VroomEngineTransportAndSettingsTest.php +20 -0
  317. package/server/tests/Unit/Support/Analytics/LiveFleetTest.php +6 -0
  318. package/server/tests/Unit/Support/AuthorizationTest.php +142 -0
  319. package/server/tests/Unit/Support/MaintainableAndOperationalAlertsTest.php +12 -1
  320. package/server/tests/Unit/Support/MoreQuerySeamsTest.php +11 -2
  321. package/server/tests/Unit/Support/Telematics/Retention/RetentionPolicyTest.php +190 -0
  322. package/server/tests/Unit/Support/Telematics/Retention/TelemetryActivityTest.php +68 -0
  323. package/server/tests/Unit/Tracking/TrackingOptionsCompanySettingsTest.php +109 -0
  324. package/translations/en-us.yaml +108 -0
@@ -47,12 +47,20 @@ class FleetOpsReportSchema implements ReportSchema
47
47
 
48
48
  /**
49
49
  * Create the Orders table definition.
50
+ *
51
+ * Money is stored in the currency's smallest unit (e.g. cents). `meta` has no fixed shape
52
+ * (it holds whatever users, integrations and extensions put there), so no column assumes a
53
+ * key in it; read one with a computed column, e.g.
54
+ * `CAST(JSON_UNQUOTE(JSON_EXTRACT(meta, '$.total')) AS DECIMAL(15,2))`.
55
+ *
56
+ * Selecting line item columns (Payload Items) returns one row per item, so order-level
57
+ * sums over item rows repeat each order; count orders with Total Orders (a distinct count).
50
58
  */
51
59
  protected function createOrdersTable(): Table
52
60
  {
53
- return Table::make('orders')
61
+ return $this->softDeletes(Table::make('orders'))
54
62
  ->label('Orders')
55
- ->description('Delivery and service orders')
63
+ ->description('Delivery and service orders, with their payload items, tracking, assignment and payment')
56
64
  ->category('Operations')
57
65
  ->extension('fleet-ops')
58
66
  ->excludeColumns(['uuid', 'deleted_at']) // Hide foreign keys and system columns
@@ -60,7 +68,7 @@ class FleetOpsReportSchema implements ReportSchema
60
68
  ->cacheTtl(3600)
61
69
  ->columns([
62
70
  Column::make('public_id', 'string')
63
- ->label('Order ID')
71
+ ->label('ID')
64
72
  ->description('Public order identifier')
65
73
  ->searchable()
66
74
  ->filterable()
@@ -94,8 +102,21 @@ class FleetOpsReportSchema implements ReportSchema
94
102
  }),
95
103
 
96
104
  Column::make('type', 'string')
97
- ->label('Order Type')
98
- ->description('Type of order service')
105
+ ->label('Type')
106
+ ->description('Type of order service, e.g. transport or storefront')
107
+ ->filterable()
108
+ ->sortable()
109
+ ->aggregatable(),
110
+
111
+ Column::make('customer_type', 'string')
112
+ ->label('Customer Kind')
113
+ ->description('Whether the customer is a contact or a vendor')
114
+ ->filterable()
115
+ ->aggregatable(),
116
+
117
+ Column::make('facilitator_type', 'string')
118
+ ->label('Facilitator Kind')
119
+ ->description('Whether the facilitator is a vendor or an integrated vendor')
99
120
  ->filterable()
100
121
  ->aggregatable(),
101
122
 
@@ -106,6 +127,12 @@ class FleetOpsReportSchema implements ReportSchema
106
127
  ->sortable()
107
128
  ->aggregatable(),
108
129
 
130
+ Column::make('dispatched', 'boolean')
131
+ ->label('Dispatched')
132
+ ->description('Whether the order has been dispatched')
133
+ ->filterable()
134
+ ->aggregatable(),
135
+
109
136
  Column::make('dispatched_at', 'datetime')
110
137
  ->label('Dispatched At')
111
138
  ->description('When the order was dispatched')
@@ -113,6 +140,12 @@ class FleetOpsReportSchema implements ReportSchema
113
140
  ->sortable()
114
141
  ->aggregatable(),
115
142
 
143
+ Column::make('started', 'boolean')
144
+ ->label('Started')
145
+ ->description('Whether the order has been started')
146
+ ->filterable()
147
+ ->aggregatable(),
148
+
116
149
  Column::make('started_at', 'datetime')
117
150
  ->label('Started At')
118
151
  ->description('When the order was started')
@@ -120,18 +153,29 @@ class FleetOpsReportSchema implements ReportSchema
120
153
  ->sortable()
121
154
  ->aggregatable(),
122
155
 
156
+ Column::make('time_window_start', 'datetime')
157
+ ->label('Time Window Start')
158
+ ->description('Earliest time the order may be serviced')
159
+ ->filterable()
160
+ ->sortable(),
161
+
162
+ Column::make('time_window_end', 'datetime')
163
+ ->label('Time Window End')
164
+ ->description('Latest time the order may be serviced')
165
+ ->filterable()
166
+ ->sortable(),
167
+
123
168
  Column::make('distance', 'integer')
124
- ->label('Distance (km)')
125
- ->description('Total distance for the order')
169
+ ->label('Distance (m)')
170
+ ->description('Route distance for the order in meters')
171
+ ->filterable()
126
172
  ->aggregatable()
127
- ->sortable()
128
- ->transformer(function ($value) {
129
- return round($value * 0.621371, 2); // Convert km to miles
130
- }),
173
+ ->sortable(),
131
174
 
132
175
  Column::make('time', 'integer')
133
- ->label('Duration (minutes)')
134
- ->description('Estimated duration in minutes')
176
+ ->label('Duration (s)')
177
+ ->description('Estimated route duration in seconds')
178
+ ->filterable()
135
179
  ->aggregatable()
136
180
  ->sortable(),
137
181
 
@@ -144,6 +188,12 @@ class FleetOpsReportSchema implements ReportSchema
144
188
  return $value ? 'Yes' : 'No';
145
189
  }),
146
190
 
191
+ Column::make('adhoc_distance', 'integer')
192
+ ->label('Ad Hoc Distance (m)')
193
+ ->description('Radius in meters used to offer an ad hoc order to drivers')
194
+ ->filterable()
195
+ ->sortable(),
196
+
147
197
  Column::make('pod_required', 'boolean')
148
198
  ->label('POD Required')
149
199
  ->description('Whether proof of delivery is required')
@@ -153,6 +203,31 @@ class FleetOpsReportSchema implements ReportSchema
153
203
  return $value ? 'Yes' : 'No';
154
204
  }),
155
205
 
206
+ Column::make('pod_method', 'string')
207
+ ->label('POD Method')
208
+ ->description('Proof of delivery method, e.g. scan, signature or photo')
209
+ ->filterable()
210
+ ->aggregatable(),
211
+
212
+ Column::make('is_route_optimized', 'boolean')
213
+ ->label('Route Optimized')
214
+ ->description('Whether the route was optimized')
215
+ ->filterable()
216
+ ->aggregatable(),
217
+
218
+ Column::make('orchestrator_priority', 'integer')
219
+ ->label('Priority')
220
+ ->description('Dispatch priority used by the orchestrator')
221
+ ->filterable()
222
+ ->sortable()
223
+ ->aggregatable(),
224
+
225
+ Column::make('notes', 'string')
226
+ ->label('Notes')
227
+ ->description('Order notes')
228
+ ->searchable()
229
+ ->filterable(),
230
+
156
231
  Column::make('created_at', 'datetime')
157
232
  ->label('Created At')
158
233
  ->description('When the order was created')
@@ -168,76 +243,156 @@ class FleetOpsReportSchema implements ReportSchema
168
243
 
169
244
  Column::make('meta', 'json')
170
245
  ->label('Metadata')
171
- ->description('Order metadata and custom fields')
246
+ ->description('Order metadata and custom fields; its keys vary by order, so read one with a computed column, e.g. JSON_UNQUOTE(JSON_EXTRACT(meta, \'$.key\'))')
172
247
  ->searchable()
173
248
  ->filterable(),
174
249
  ])
175
250
  ->computedColumns([
176
- Column::count('total_orders', 'id')
251
+ // Distinct, so the count stays right when payload items are selected too.
252
+ Column::count('total_orders', 'DISTINCT id')
177
253
  ->label('Total Orders')
178
- ->description('Count of orders'),
254
+ ->description('Number of orders'),
255
+
256
+ Column::computed('completed_orders', "COUNT(DISTINCT CASE WHEN status = 'completed' THEN id END)", 'integer')
257
+ ->label('Completed Orders')
258
+ ->description('Number of completed orders'),
259
+
260
+ Column::computed('canceled_orders', "COUNT(DISTINCT CASE WHEN status = 'canceled' THEN id END)", 'integer')
261
+ ->label('Canceled Orders')
262
+ ->description('Number of canceled orders'),
179
263
 
180
264
  Column::sum('total_distance', 'distance')
181
- ->label('Total Distance')
265
+ ->label('Total Distance (m)')
182
266
  ->description('Sum of all order distances'),
183
267
 
184
268
  Column::avg('average_distance', 'distance')
185
- ->label('Average Distance')
269
+ ->label('Average Distance (m)')
186
270
  ->description('Average distance per order'),
187
271
 
188
272
  Column::sum('total_time', 'time')
189
- ->label('Total Time')
273
+ ->label('Total Duration (s)')
190
274
  ->description('Sum of all order durations'),
191
275
 
192
276
  Column::avg('average_time', 'time')
193
- ->label('Average Time')
277
+ ->label('Average Duration (s)')
194
278
  ->description('Average duration per order'),
195
279
 
196
- Column::sum('total_transaction_amount', 'amount')
197
- ->label('Total Transaction Amount')
198
- ->description('Sum of all transaction amounts'),
280
+ Column::sum('total_transaction_amount', 'transaction.amount')
281
+ ->label('Transaction Amount Sum (minor units)')
282
+ ->description('Sum of the orders\' transaction amounts'),
199
283
 
200
- Column::avg('average_transaction_amount', 'amount')
201
- ->label('Average Transaction Amount')
284
+ Column::avg('average_transaction_amount', 'transaction.amount')
285
+ ->label('Average Transaction Amount (minor units)')
202
286
  ->description('Average transaction amount per order'),
203
287
 
204
- Column::count('orders_with_transactions', 'transaction_uuid')
288
+ Column::count('orders_with_transactions', 'DISTINCT transaction_uuid')
205
289
  ->label('Orders with Transactions')
206
- ->description('Count of orders that have transactions'),
290
+ ->description('Number of orders that have a transaction'),
207
291
  ])
208
292
  ->relationships([
209
- // Auto-join relationships for seamless access
293
+ Relationship::hasAutoJoin('tracking_number', 'tracking_numbers')
294
+ ->label('Tracking')
295
+ ->description('The order\'s tracking number and its latest tracking status')
296
+ ->localKey('tracking_number_uuid')
297
+ ->foreignKey('uuid')
298
+ ->columns([
299
+ Column::make('tracking_number', 'string')->label('Number')->description('Tracking number'),
300
+ Column::make('public_id', 'string')->label('ID')->description('Tracking number record identifier'),
301
+ Column::make('region', 'string')->label('Region'),
302
+ ])
303
+ ->with([
304
+ Relationship::hasAutoJoin('status', 'tracking_statuses')
305
+ ->label('Tracking Status')
306
+ ->localKey('status_uuid')
307
+ ->foreignKey('uuid')
308
+ ->columns([
309
+ Column::make('status', 'string')->label('Tracking Status'),
310
+ Column::make('code', 'string')->label('Code'),
311
+ Column::make('details', 'string')->label('Details'),
312
+ Column::make('complete', 'boolean')->label('Complete'),
313
+ Column::make('city', 'string')->label('City'),
314
+ Column::make('province', 'string')->label('Province'),
315
+ Column::make('country', 'string')->label('Country'),
316
+ Column::make('created_at', 'datetime')->label('Updated At'),
317
+ ]),
318
+ ]),
319
+
320
+ Relationship::hasAutoJoin('order_config', 'order_configs')
321
+ ->label('Order Config')
322
+ ->description('The order configuration (order type) the order follows')
323
+ ->localKey('order_config_uuid')
324
+ ->foreignKey('uuid')
325
+ ->columns([
326
+ Column::make('name', 'string')->label('Name'),
327
+ Column::make('key', 'string')->label('Key'),
328
+ Column::make('namespace', 'string')->label('Namespace'),
329
+ ]),
330
+
210
331
  Relationship::hasAutoJoin('payload', 'payloads')
211
332
  ->label('Payload')
212
333
  ->localKey('payload_uuid')
213
334
  ->foreignKey('uuid')
335
+ ->columns([
336
+ Column::make('public_id', 'string')->label('ID')->description('Payload identifier'),
337
+ Column::make('type', 'string')->label('Type'),
338
+ Column::make('payment_method', 'string')->label('Payment Method'),
339
+ Column::make('cod_amount', 'integer')->label('COD Amount (minor units)')->description('Cash on delivery amount in the currency\'s smallest unit'),
340
+ Column::make('cod_currency', 'string')->label('COD Currency'),
341
+ Column::make('cod_payment_method', 'string')->label('COD Payment Method'),
342
+ Column::make('provider', 'string')->label('Provider'),
343
+ ])
214
344
  ->with([
215
345
  Relationship::hasAutoJoin('pickup', 'places')
216
346
  ->label('Pickup')
217
347
  ->localKey('pickup_uuid')
218
348
  ->foreignKey('uuid')
219
- ->columns([
220
- Column::make('name', 'string')->label('Name'),
221
- Column::make('street1', 'string')->label('Street'),
222
- Column::make('street2', 'string')->label('Street 2'),
223
- Column::make('city', 'string')->label('City'),
224
- Column::make('province', 'string')->label('Province'),
225
- Column::make('postal_code', 'string')->label('Postal Code'),
226
- Column::make('country', 'string')->label('Country'),
227
- ]),
349
+ ->columns($this->placeColumns()),
228
350
 
229
351
  Relationship::hasAutoJoin('dropoff', 'places')
230
352
  ->label('Dropoff')
231
353
  ->localKey('dropoff_uuid')
232
354
  ->foreignKey('uuid')
355
+ ->columns($this->placeColumns()),
356
+
357
+ Relationship::hasAutoJoin('return', 'places')
358
+ ->label('Return')
359
+ ->localKey('return_uuid')
360
+ ->foreignKey('uuid')
361
+ ->columns($this->placeColumns()),
362
+
363
+ // One row per item: the goods, parcels or storefront products in the order.
364
+ $this->softDeletes(Relationship::hasAutoJoin('entities', 'entities'))
365
+ ->label('Item')
366
+ ->description('Items carried by the order (storefront products, parcels, goods); one row per item')
367
+ ->localKey('uuid')
368
+ ->foreignKey('payload_uuid')
233
369
  ->columns([
234
- Column::make('name', 'string')->label('Name'),
235
- Column::make('street1', 'string')->label('Street'),
236
- Column::make('street2', 'string')->label('Street 2'),
237
- Column::make('city', 'string')->label('City'),
238
- Column::make('province', 'string')->label('Province'),
239
- Column::make('postal_code', 'string')->label('Postal Code'),
240
- Column::make('country', 'string')->label('Country'),
370
+ Column::make('public_id', 'string')->label('ID')->description('Item identifier'),
371
+ Column::make('internal_id', 'string')->label('Internal ID')->description('Internal reference; the product ID for storefront items'),
372
+ Column::make('name', 'string')->label('Name')->aggregatable(),
373
+ Column::make('type', 'string')->label('Type')->aggregatable(),
374
+ Column::make('description', 'string')->label('Description'),
375
+ Column::make('sku', 'string')->label('SKU')->aggregatable(),
376
+ Column::make('currency', 'string')->label('Currency'),
377
+ Column::make('price', 'decimal')->label('Price (minor units)')->description('Unit price in the currency\'s smallest unit'),
378
+ Column::make('sale_price', 'decimal')->label('Sale Price (minor units)')->description('Unit sale price in the currency\'s smallest unit'),
379
+ Column::make('declared_value', 'integer')->label('Declared Value (minor units)'),
380
+ Column::make('weight', 'decimal')->label('Weight'),
381
+ Column::make('weight_unit', 'string')->label('Weight Unit'),
382
+ Column::make('length', 'decimal')->label('Length'),
383
+ Column::make('width', 'decimal')->label('Width'),
384
+ Column::make('height', 'decimal')->label('Height'),
385
+ Column::make('dimensions_unit', 'string')->label('Dimensions Unit'),
386
+ Column::make('barcode', 'string')->label('Barcode'),
387
+ Column::make('meta', 'json')->label('Metadata')->description('Item metadata; read a key with a computed column, e.g. JSON_EXTRACT(payload.entities.meta, \'$.quantity\')'),
388
+ Column::make('created_at', 'datetime')->label('Created At'),
389
+ ])
390
+ ->with([
391
+ Relationship::hasAutoJoin('destination', 'places')
392
+ ->label('Destination')
393
+ ->localKey('destination_uuid')
394
+ ->foreignKey('uuid')
395
+ ->columns($this->placeColumns()),
241
396
  ]),
242
397
  ]),
243
398
 
@@ -246,6 +401,8 @@ class FleetOpsReportSchema implements ReportSchema
246
401
  ->localKey('driver_assigned_uuid')
247
402
  ->foreignKey('uuid')
248
403
  ->columns([
404
+ Column::make('public_id', 'string')->label('ID')->description('Driver identifier'),
405
+ Column::make('internal_id', 'string')->label('Internal ID'),
249
406
  Column::make('drivers_license_number', 'string')->label('License Number'),
250
407
  Column::make('country', 'string')->label('Country'),
251
408
  Column::make('city', 'string')->label('City'),
@@ -268,6 +425,9 @@ class FleetOpsReportSchema implements ReportSchema
268
425
  ->localKey('vehicle_assigned_uuid')
269
426
  ->foreignKey('uuid')
270
427
  ->columns([
428
+ Column::make('public_id', 'string')->label('ID')->description('Vehicle identifier'),
429
+ Column::make('internal_id', 'string')->label('Internal ID'),
430
+ Column::make('name', 'string')->label('Name'),
271
431
  Column::make('make', 'string')->label('Make'),
272
432
  Column::make('model', 'string')->label('Model'),
273
433
  Column::make('year', 'integer')->label('Year'),
@@ -279,9 +439,27 @@ class FleetOpsReportSchema implements ReportSchema
279
439
 
280
440
  Relationship::hasAutoJoin('customer', 'contacts')
281
441
  ->label('Customer')
442
+ ->description('The customer when it is a contact')
443
+ ->localKey('customer_uuid')
444
+ ->foreignKey('uuid')
445
+ ->columns([
446
+ Column::make('public_id', 'string')->label('ID')->description('Customer identifier'),
447
+ Column::make('internal_id', 'string')->label('Internal ID'),
448
+ Column::make('name', 'string')->label('Name'),
449
+ Column::make('title', 'string')->label('Title'),
450
+ Column::make('email', 'string')->label('Email'),
451
+ Column::make('phone', 'string')->label('Phone'),
452
+ Column::make('type', 'string')->label('Type'),
453
+ ]),
454
+
455
+ Relationship::hasAutoJoin('customer_vendor', 'vendors')
456
+ ->label('Customer Vendor')
457
+ ->description('The customer when it is a vendor')
282
458
  ->localKey('customer_uuid')
283
459
  ->foreignKey('uuid')
284
460
  ->columns([
461
+ Column::make('public_id', 'string')->label('ID')->description('Vendor identifier'),
462
+ Column::make('internal_id', 'string')->label('Internal ID'),
285
463
  Column::make('name', 'string')->label('Name'),
286
464
  Column::make('email', 'string')->label('Email'),
287
465
  Column::make('phone', 'string')->label('Phone'),
@@ -289,16 +467,48 @@ class FleetOpsReportSchema implements ReportSchema
289
467
  ]),
290
468
 
291
469
  Relationship::hasAutoJoin('facilitator', 'vendors')
292
- ->label('Faciliator')
470
+ ->label('Facilitator')
293
471
  ->localKey('facilitator_uuid')
294
472
  ->foreignKey('uuid')
295
473
  ->columns([
474
+ Column::make('public_id', 'string')->label('ID')->description('Facilitator identifier'),
475
+ Column::make('internal_id', 'string')->label('Internal ID'),
296
476
  Column::make('name', 'string')->label('Name'),
297
477
  Column::make('email', 'string')->label('Email'),
298
478
  Column::make('phone', 'string')->label('Phone'),
299
479
  Column::make('type', 'string')->label('Type'),
300
480
  ]),
301
481
 
482
+ Relationship::hasAutoJoin('created_by', 'users')
483
+ ->label('Created By')
484
+ ->localKey('created_by_uuid')
485
+ ->foreignKey('uuid')
486
+ ->columns([
487
+ Column::make('name', 'string')->label('Name'),
488
+ Column::make('email', 'string')->label('Email'),
489
+ ]),
490
+
491
+ Relationship::hasAutoJoin('purchase_rate', 'purchase_rates')
492
+ ->label('Purchase Rate')
493
+ ->description('The service quote purchased for the order')
494
+ ->localKey('purchase_rate_uuid')
495
+ ->foreignKey('uuid')
496
+ ->columns([
497
+ Column::make('public_id', 'string')->label('ID')->description('Purchase rate identifier'),
498
+ Column::make('status', 'string')->label('Status'),
499
+ ])
500
+ ->with([
501
+ Relationship::hasAutoJoin('service_quote', 'service_quotes')
502
+ ->label('Service Quote')
503
+ ->localKey('service_quote_uuid')
504
+ ->foreignKey('uuid')
505
+ ->columns([
506
+ Column::make('public_id', 'string')->label('ID')->description('Service quote identifier'),
507
+ Column::make('amount', 'integer')->label('Amount (minor units)')->description('Quoted delivery price in the currency\'s smallest unit'),
508
+ Column::make('currency', 'string')->label('Currency'),
509
+ ]),
510
+ ]),
511
+
302
512
  Relationship::hasAutoJoin('transaction', 'transactions')
303
513
  ->label('Transaction')
304
514
  ->localKey('transaction_uuid')
@@ -312,7 +522,7 @@ class FleetOpsReportSchema implements ReportSchema
312
522
  ->sortable(),
313
523
 
314
524
  Column::make('gateway_transaction_id', 'string')
315
- ->label('Gateway Transaction ID')
525
+ ->label('Gateway ID')
316
526
  ->description('Transaction ID from payment gateway')
317
527
  ->searchable()
318
528
  ->filterable()
@@ -324,15 +534,35 @@ class FleetOpsReportSchema implements ReportSchema
324
534
  ->filterable()
325
535
  ->aggregatable(),
326
536
 
537
+ Column::make('payment_method', 'string')
538
+ ->label('Payment Method')
539
+ ->description('Payment method used, e.g. card or cash')
540
+ ->filterable()
541
+ ->aggregatable(),
542
+
327
543
  Column::make('amount', 'integer')
328
- ->label('Amount')
329
- ->description('Transaction amount (in cents)')
544
+ ->label('Amount (minor units)')
545
+ ->description('Transaction amount in the currency\'s smallest unit (e.g. cents)')
330
546
  ->aggregatable()
331
- ->sortable()
332
- ->transformer(function ($value) {
333
- // Convert cents to dollars with 2 decimal places
334
- return number_format($value / 100, 2);
335
- }),
547
+ ->sortable(),
548
+
549
+ Column::make('fee_amount', 'integer')
550
+ ->label('Fee Amount (minor units)')
551
+ ->description('Gateway fee in the currency\'s smallest unit')
552
+ ->aggregatable()
553
+ ->sortable(),
554
+
555
+ Column::make('tax_amount', 'integer')
556
+ ->label('Tax Amount (minor units)')
557
+ ->description('Tax in the currency\'s smallest unit')
558
+ ->aggregatable()
559
+ ->sortable(),
560
+
561
+ Column::make('net_amount', 'integer')
562
+ ->label('Net Amount (minor units)')
563
+ ->description('Amount after fees in the currency\'s smallest unit')
564
+ ->aggregatable()
565
+ ->sortable(),
336
566
 
337
567
  Column::make('currency', 'string')
338
568
  ->label('Currency')
@@ -369,6 +599,12 @@ class FleetOpsReportSchema implements ReportSchema
369
599
  return $labels[$value] ?? ucfirst($value);
370
600
  }),
371
601
 
602
+ Column::make('settlement_status', 'string')
603
+ ->label('Settlement Status')
604
+ ->description('Whether the transaction has settled')
605
+ ->filterable()
606
+ ->aggregatable(),
607
+
372
608
  Column::make('created_at', 'datetime')
373
609
  ->label('Transaction Date')
374
610
  ->description('When the transaction was created')
@@ -378,30 +614,48 @@ class FleetOpsReportSchema implements ReportSchema
378
614
  ])
379
615
  ->with([
380
616
  // Nested relationship for transaction items
381
- Relationship::hasAutoJoin('items', 'transaction_items')
382
- ->label('Transaction Items')
617
+ $this->softDeletes(Relationship::hasAutoJoin('items', 'transaction_items'))
618
+ ->label('Transaction Item')
383
619
  ->localKey('uuid')
384
620
  ->foreignKey('transaction_uuid')
385
621
  ->columns([
386
- Column::make('amount', 'string')
387
- ->label('Item Amount')
622
+ Column::make('description', 'string')
623
+ ->label('Description')
624
+ ->description('Line item description')
625
+ ->searchable()
626
+ ->filterable(),
627
+
628
+ Column::make('quantity', 'integer')
629
+ ->label('Quantity')
630
+ ->description('Line item quantity')
631
+ ->aggregatable()
632
+ ->sortable(),
633
+
634
+ Column::make('unit_price', 'integer')
635
+ ->label('Unit Price (minor units)')
636
+ ->description('Line item unit price')
637
+ ->aggregatable()
638
+ ->sortable(),
639
+
640
+ Column::make('amount', 'integer')
641
+ ->label('Amount (minor units)')
388
642
  ->description('Line item amount')
389
643
  ->aggregatable()
390
644
  ->sortable(),
391
645
 
392
646
  Column::make('currency', 'string')
393
- ->label('Item Currency')
647
+ ->label('Currency')
394
648
  ->description('Line item currency code')
395
649
  ->filterable(),
396
650
 
397
651
  Column::make('details', 'string')
398
- ->label('Item Details')
652
+ ->label('Details')
399
653
  ->description('Detailed description of the line item')
400
654
  ->searchable()
401
655
  ->filterable(),
402
656
 
403
657
  Column::make('code', 'string')
404
- ->label('Item Code')
658
+ ->label('Code')
405
659
  ->description('Item or SKU code')
406
660
  ->searchable()
407
661
  ->filterable()
@@ -416,7 +670,7 @@ class FleetOpsReportSchema implements ReportSchema
416
670
  */
417
671
  protected function createDriversTable(): Table
418
672
  {
419
- return Table::make('drivers')
673
+ return $this->softDeletes(Table::make('drivers'))
420
674
  ->label('Drivers')
421
675
  ->description('Fleet drivers and personnel')
422
676
  ->category('Personnel')
@@ -425,30 +679,28 @@ class FleetOpsReportSchema implements ReportSchema
425
679
  ->maxRows(10000)
426
680
  ->columns([
427
681
  Column::make('public_id', 'string')
428
- ->label('Driver ID')
682
+ ->label('ID')
429
683
  ->description('Public driver identifier')
430
684
  ->searchable()
431
685
  ->filterable()
432
686
  ->sortable(),
433
687
 
434
- Column::make('name', 'string')
435
- ->label('Name')
436
- ->description('Driver full name')
688
+ Column::make('internal_id', 'string')
689
+ ->label('Internal ID')
690
+ ->description('Internal driver reference')
437
691
  ->searchable()
438
692
  ->filterable()
439
693
  ->sortable(),
440
694
 
441
- Column::make('email', 'string')
442
- ->label('Email')
443
- ->description('Driver email address')
695
+ Column::make('drivers_license_number', 'string')
696
+ ->label('License Number')
697
+ ->description('Driver license number')
444
698
  ->searchable()
445
- ->filterable()
446
- ->sortable(),
699
+ ->filterable(),
447
700
 
448
- Column::make('phone', 'string')
449
- ->label('Phone')
450
- ->description('Driver phone number')
451
- ->searchable()
701
+ Column::make('license_expiry', 'date')
702
+ ->label('License Expiry')
703
+ ->description('When the driver license expires')
452
704
  ->filterable()
453
705
  ->sortable(),
454
706
 
@@ -477,24 +729,45 @@ class FleetOpsReportSchema implements ReportSchema
477
729
  return $value ? 'Yes' : 'No';
478
730
  }),
479
731
 
732
+ Column::make('city', 'string')
733
+ ->label('City')
734
+ ->filterable()
735
+ ->aggregatable(),
736
+
737
+ Column::make('country', 'string')
738
+ ->label('Country')
739
+ ->filterable()
740
+ ->aggregatable(),
741
+
480
742
  Column::make('created_at', 'datetime')
481
743
  ->label('Hired Date')
482
- ->description('When the driver was hired')
744
+ ->description('When the driver was added')
483
745
  ->filterable()
484
746
  ->sortable()
485
747
  ->aggregatable(),
486
748
  ])
487
749
  ->computedColumns([
488
- Column::count('total_drivers', 'id')
750
+ Column::count('total_drivers', 'DISTINCT id')
489
751
  ->label('Total Drivers')
490
752
  ->description('Count of drivers'),
491
753
  ])
492
754
  ->relationships([
493
- Relationship::hasAutoJoin('current_vehicle', 'vehicles')
755
+ Relationship::hasAutoJoin('user', 'users')
756
+ ->label('Driver')
757
+ ->localKey('user_uuid')
758
+ ->foreignKey('uuid')
759
+ ->columns([
760
+ Column::make('name', 'string')->label('Name'),
761
+ Column::make('email', 'string')->label('Email'),
762
+ Column::make('phone', 'string')->label('Phone'),
763
+ ]),
764
+
765
+ Relationship::hasAutoJoin('vehicle', 'vehicles')
494
766
  ->label('Vehicle')
495
- ->localKey('current_vehicle_uuid')
767
+ ->localKey('vehicle_uuid')
496
768
  ->foreignKey('uuid')
497
769
  ->columns([
770
+ Column::make('public_id', 'string')->label('Vehicle ID'),
498
771
  Column::make('make', 'string')->label('Vehicle Make'),
499
772
  Column::make('model', 'string')->label('Vehicle Model'),
500
773
  Column::make('plate_number', 'string')->label('Plate Number'),
@@ -507,7 +780,7 @@ class FleetOpsReportSchema implements ReportSchema
507
780
  */
508
781
  protected function createVehiclesTable(): Table
509
782
  {
510
- return Table::make('vehicles')
783
+ return $this->softDeletes(Table::make('vehicles'))
511
784
  ->label('Vehicles')
512
785
  ->description('Fleet vehicles and assets')
513
786
  ->category('Fleet')
@@ -516,12 +789,26 @@ class FleetOpsReportSchema implements ReportSchema
516
789
  ->maxRows(10000)
517
790
  ->columns([
518
791
  Column::make('public_id', 'string')
519
- ->label('Vehicle ID')
792
+ ->label('ID')
520
793
  ->description('Public vehicle identifier')
521
794
  ->searchable()
522
795
  ->filterable()
523
796
  ->sortable(),
524
797
 
798
+ Column::make('internal_id', 'string')
799
+ ->label('Internal ID')
800
+ ->description('Internal vehicle reference')
801
+ ->searchable()
802
+ ->filterable()
803
+ ->sortable(),
804
+
805
+ Column::make('name', 'string')
806
+ ->label('Name')
807
+ ->description('Vehicle name')
808
+ ->searchable()
809
+ ->filterable()
810
+ ->sortable(),
811
+
525
812
  Column::make('make', 'string')
526
813
  ->label('Make')
527
814
  ->description('Vehicle manufacturer')
@@ -583,19 +870,30 @@ class FleetOpsReportSchema implements ReportSchema
583
870
  ->aggregatable(),
584
871
  ])
585
872
  ->computedColumns([
586
- Column::count('total_vehicles', 'id')
873
+ Column::count('total_vehicles', 'DISTINCT id')
587
874
  ->label('Total Vehicles')
588
875
  ->description('Count of vehicles'),
589
876
  ])
590
877
  ->relationships([
591
- Relationship::hasAutoJoin('current_driver', 'drivers')
878
+ // A driver points at the vehicle they drive (drivers.vehicle_uuid).
879
+ $this->softDeletes(Relationship::hasAutoJoin('driver', 'drivers'))
592
880
  ->label('Driver')
593
- ->localKey('current_driver_uuid')
594
- ->foreignKey('uuid')
881
+ ->localKey('uuid')
882
+ ->foreignKey('vehicle_uuid')
595
883
  ->columns([
596
- Column::make('name', 'string')->label('Driver Name'),
597
- Column::make('email', 'string')->label('Driver Email'),
598
- Column::make('phone', 'string')->label('Driver Phone'),
884
+ Column::make('public_id', 'string')->label('Driver ID'),
885
+ Column::make('status', 'string')->label('Driver Status'),
886
+ ])
887
+ ->with([
888
+ Relationship::hasAutoJoin('user', 'users')
889
+ ->label('Driver')
890
+ ->localKey('user_uuid')
891
+ ->foreignKey('uuid')
892
+ ->columns([
893
+ Column::make('name', 'string')->label('Name'),
894
+ Column::make('email', 'string')->label('Email'),
895
+ Column::make('phone', 'string')->label('Phone'),
896
+ ]),
599
897
  ]),
600
898
  ]);
601
899
  }
@@ -605,7 +903,7 @@ class FleetOpsReportSchema implements ReportSchema
605
903
  */
606
904
  protected function createAssetsTable(): Table
607
905
  {
608
- return Table::make('assets')
906
+ return $this->softDeletes(Table::make('assets'))
609
907
  ->label('Trailers and Assets')
610
908
  ->description('Independently managed fleet assets; Trailer rows use asset_class trailer')
611
909
  ->category('Fleet')
@@ -613,7 +911,7 @@ class FleetOpsReportSchema implements ReportSchema
613
911
  ->excludeColumns(['uuid', 'company_uuid', 'deleted_at', 'meta', 'attributes'])
614
912
  ->maxRows(10000)
615
913
  ->columns([
616
- Column::make('public_id', 'string')->label('Asset ID')->searchable()->filterable()->sortable(),
914
+ Column::make('public_id', 'string')->label('ID')->searchable()->filterable()->sortable(),
617
915
  Column::make('asset_class', 'string')->label('Asset Class')->filterable()->aggregatable(),
618
916
  Column::make('name', 'string')->label('Name')->searchable()->filterable()->sortable(),
619
917
  Column::make('code', 'string')->label('Code')->searchable()->filterable()->sortable(),
@@ -640,7 +938,7 @@ class FleetOpsReportSchema implements ReportSchema
640
938
  */
641
939
  protected function createPlacesTable(): Table
642
940
  {
643
- return Table::make('places')
941
+ return $this->softDeletes(Table::make('places'))
644
942
  ->label('Places')
645
943
  ->description('Locations and addresses')
646
944
  ->category('Geography')
@@ -649,7 +947,7 @@ class FleetOpsReportSchema implements ReportSchema
649
947
  ->maxRows(100000)
650
948
  ->columns([
651
949
  Column::make('public_id', 'string')
652
- ->label('Place ID')
950
+ ->label('ID')
653
951
  ->description('Public place identifier')
654
952
  ->searchable()
655
953
  ->filterable()
@@ -706,7 +1004,7 @@ class FleetOpsReportSchema implements ReportSchema
706
1004
  */
707
1005
  protected function createContactsTable(): Table
708
1006
  {
709
- return Table::make('contacts')
1007
+ return $this->softDeletes(Table::make('contacts'))
710
1008
  ->label('Contacts')
711
1009
  ->description('Customer and vendor contacts')
712
1010
  ->category('CRM')
@@ -715,7 +1013,7 @@ class FleetOpsReportSchema implements ReportSchema
715
1013
  ->maxRows(50000)
716
1014
  ->columns([
717
1015
  Column::make('public_id', 'string')
718
- ->label('Contact ID')
1016
+ ->label('ID')
719
1017
  ->description('Public contact identifier')
720
1018
  ->searchable()
721
1019
  ->filterable()
@@ -762,7 +1060,7 @@ class FleetOpsReportSchema implements ReportSchema
762
1060
  */
763
1061
  protected function createVendorsTable(): Table
764
1062
  {
765
- return Table::make('vendors')
1063
+ return $this->softDeletes(Table::make('vendors'))
766
1064
  ->label('Vendors')
767
1065
  ->description('Service providers and vendors')
768
1066
  ->category('CRM')
@@ -771,7 +1069,7 @@ class FleetOpsReportSchema implements ReportSchema
771
1069
  ->maxRows(10000)
772
1070
  ->columns([
773
1071
  Column::make('public_id', 'string')
774
- ->label('Vendor ID')
1072
+ ->label('ID')
775
1073
  ->description('Public vendor identifier')
776
1074
  ->searchable()
777
1075
  ->filterable()
@@ -818,7 +1116,7 @@ class FleetOpsReportSchema implements ReportSchema
818
1116
  */
819
1117
  protected function createFuelReportsTable(): Table
820
1118
  {
821
- return Table::make('fuel_reports')
1119
+ return $this->softDeletes(Table::make('fuel_reports'))
822
1120
  ->label('Fuel Reports')
823
1121
  ->description('Vehicle fuel consumption reports')
824
1122
  ->category('Operations')
@@ -827,24 +1125,30 @@ class FleetOpsReportSchema implements ReportSchema
827
1125
  ->maxRows(100000)
828
1126
  ->columns([
829
1127
  Column::make('public_id', 'string')
830
- ->label('Report ID')
1128
+ ->label('ID')
831
1129
  ->description('Public fuel report identifier')
832
1130
  ->searchable()
833
1131
  ->filterable()
834
1132
  ->sortable(),
835
1133
 
836
1134
  Column::make('volume', 'decimal')
837
- ->label('Volume (L)')
838
- ->description('Fuel volume in liters')
1135
+ ->label('Volume')
1136
+ ->description('Fuel volume, in the report\'s metric unit')
839
1137
  ->aggregatable()
840
1138
  ->sortable(),
841
1139
 
842
- Column::make('odometer_reading', 'integer')
1140
+ Column::make('metric_unit', 'string')
1141
+ ->label('Volume Unit')
1142
+ ->description('Unit of the fuel volume')
1143
+ ->filterable()
1144
+ ->aggregatable(),
1145
+
1146
+ Column::make('odometer', 'integer')
843
1147
  ->label('Odometer Reading')
844
1148
  ->description('Vehicle odometer reading')
845
1149
  ->sortable(),
846
1150
 
847
- Column::make('cost', 'decimal')
1151
+ Column::make('amount', 'decimal')
848
1152
  ->label('Cost')
849
1153
  ->description('Fuel cost amount')
850
1154
  ->aggregatable()
@@ -856,15 +1160,26 @@ class FleetOpsReportSchema implements ReportSchema
856
1160
  ->filterable()
857
1161
  ->aggregatable(),
858
1162
 
859
- Column::make('report_date', 'date')
1163
+ Column::make('status', 'string')
1164
+ ->label('Status')
1165
+ ->filterable()
1166
+ ->aggregatable(),
1167
+
1168
+ Column::make('report', 'string')
1169
+ ->label('Report')
1170
+ ->description('Report notes')
1171
+ ->searchable()
1172
+ ->filterable(),
1173
+
1174
+ Column::make('created_at', 'datetime')
860
1175
  ->label('Report Date')
861
- ->description('Date of fuel report')
1176
+ ->description('When the fuel report was recorded')
862
1177
  ->filterable()
863
1178
  ->sortable()
864
1179
  ->aggregatable(),
865
1180
  ])
866
1181
  ->computedColumns([
867
- Column::sum('total_fuel_cost', 'cost')
1182
+ Column::sum('total_fuel_cost', 'amount')
868
1183
  ->label('Total Fuel Cost')
869
1184
  ->description('Sum of all fuel costs'),
870
1185
 
@@ -872,7 +1187,7 @@ class FleetOpsReportSchema implements ReportSchema
872
1187
  ->label('Total Fuel Volume')
873
1188
  ->description('Sum of all fuel volumes'),
874
1189
 
875
- Column::avg('average_fuel_cost', 'cost')
1190
+ Column::avg('average_fuel_cost', 'amount')
876
1191
  ->label('Average Fuel Cost')
877
1192
  ->description('Average fuel cost per report'),
878
1193
  ])
@@ -882,6 +1197,7 @@ class FleetOpsReportSchema implements ReportSchema
882
1197
  ->localKey('vehicle_uuid')
883
1198
  ->foreignKey('uuid')
884
1199
  ->columns([
1200
+ Column::make('public_id', 'string')->label('Vehicle ID'),
885
1201
  Column::make('make', 'string')->label('Vehicle Make'),
886
1202
  Column::make('model', 'string')->label('Vehicle Model'),
887
1203
  Column::make('plate_number', 'string')->label('Plate Number'),
@@ -892,8 +1208,17 @@ class FleetOpsReportSchema implements ReportSchema
892
1208
  ->localKey('driver_uuid')
893
1209
  ->foreignKey('uuid')
894
1210
  ->columns([
895
- Column::make('name', 'string')->label('Driver Name'),
896
- Column::make('email', 'string')->label('Driver Email'),
1211
+ Column::make('public_id', 'string')->label('Driver ID'),
1212
+ ])
1213
+ ->with([
1214
+ Relationship::hasAutoJoin('user', 'users')
1215
+ ->label('Driver')
1216
+ ->localKey('user_uuid')
1217
+ ->foreignKey('uuid')
1218
+ ->columns([
1219
+ Column::make('name', 'string')->label('Name'),
1220
+ Column::make('email', 'string')->label('Email'),
1221
+ ]),
897
1222
  ]),
898
1223
  ]);
899
1224
  }
@@ -903,7 +1228,7 @@ class FleetOpsReportSchema implements ReportSchema
903
1228
  */
904
1229
  protected function createWorkOrdersTable(): Table
905
1230
  {
906
- return Table::make('work_orders')
1231
+ return $this->softDeletes(Table::make('work_orders'))
907
1232
  ->label('Work Orders')
908
1233
  ->description('Maintenance work orders, assignments, budgets, and lifecycle status')
909
1234
  ->category('Maintenance')
@@ -911,7 +1236,7 @@ class FleetOpsReportSchema implements ReportSchema
911
1236
  ->excludeColumns(['uuid', 'deleted_at', 'meta', 'checklist', 'cost_breakdown'])
912
1237
  ->maxRows(100000)
913
1238
  ->columns([
914
- Column::make('public_id', 'string')->label('Work Order ID')->searchable()->filterable()->sortable(),
1239
+ Column::make('public_id', 'string')->label('ID')->searchable()->filterable()->sortable(),
915
1240
  Column::make('code', 'string')->label('Code')->searchable()->filterable()->sortable(),
916
1241
  Column::make('subject', 'string')->label('Subject')->searchable()->filterable()->sortable(),
917
1242
  Column::make('status', 'string')->label('Status')->filterable()->sortable()->aggregatable(),
@@ -938,7 +1263,7 @@ class FleetOpsReportSchema implements ReportSchema
938
1263
  ->localKey('target_uuid')
939
1264
  ->foreignKey('uuid')
940
1265
  ->columns([
941
- Column::make('public_id', 'string')->label('Vehicle ID'),
1266
+ Column::make('public_id', 'string')->label('ID'),
942
1267
  Column::make('plate_number', 'string')->label('Plate Number'),
943
1268
  Column::make('make', 'string')->label('Make'),
944
1269
  Column::make('model', 'string')->label('Model'),
@@ -952,7 +1277,7 @@ class FleetOpsReportSchema implements ReportSchema
952
1277
  */
953
1278
  protected function createMaintenancesTable(): Table
954
1279
  {
955
- return Table::make('maintenances')
1280
+ return $this->softDeletes(Table::make('maintenances'))
956
1281
  ->label('Maintenance History')
957
1282
  ->description('Completed and scheduled maintenance records with labor, parts, tax, and total cost')
958
1283
  ->category('Maintenance')
@@ -960,7 +1285,7 @@ class FleetOpsReportSchema implements ReportSchema
960
1285
  ->excludeColumns(['uuid', 'deleted_at', 'meta', 'line_items', 'attachments'])
961
1286
  ->maxRows(100000)
962
1287
  ->columns([
963
- Column::make('public_id', 'string')->label('Maintenance ID')->searchable()->filterable()->sortable(),
1288
+ Column::make('public_id', 'string')->label('ID')->searchable()->filterable()->sortable(),
964
1289
  Column::make('type', 'string')->label('Type')->filterable()->sortable()->aggregatable(),
965
1290
  Column::make('status', 'string')->label('Status')->filterable()->sortable()->aggregatable(),
966
1291
  Column::make('priority', 'string')->label('Priority')->filterable()->sortable()->aggregatable(),
@@ -1013,7 +1338,7 @@ class FleetOpsReportSchema implements ReportSchema
1013
1338
  */
1014
1339
  protected function createInspectionSubmissionsTable(): Table
1015
1340
  {
1016
- return Table::make('inspection_submissions')
1341
+ return $this->softDeletes(Table::make('inspection_submissions'))
1017
1342
  ->label('Inspections')
1018
1343
  ->description('DVIR and inspection submissions, pass/fail status, and linked maintenance follow-up')
1019
1344
  ->category('Maintenance')
@@ -1021,7 +1346,7 @@ class FleetOpsReportSchema implements ReportSchema
1021
1346
  ->excludeColumns(['uuid', 'deleted_at', 'meta', 'location', 'signature', 'attachments'])
1022
1347
  ->maxRows(100000)
1023
1348
  ->columns([
1024
- Column::make('public_id', 'string')->label('Inspection ID')->searchable()->filterable()->sortable(),
1349
+ Column::make('public_id', 'string')->label('ID')->searchable()->filterable()->sortable(),
1025
1350
  Column::make('type', 'string')->label('Type')->filterable()->sortable()->aggregatable(),
1026
1351
  Column::make('status', 'string')->label('Status')->filterable()->sortable()->aggregatable(),
1027
1352
  Column::make('result', 'string')->label('Result')->filterable()->sortable()->aggregatable(),
@@ -1046,8 +1371,8 @@ class FleetOpsReportSchema implements ReportSchema
1046
1371
  ->localKey('inspection_form_uuid')
1047
1372
  ->foreignKey('uuid')
1048
1373
  ->columns([
1049
- Column::make('name', 'string')->label('Form Name'),
1050
- Column::make('type', 'string')->label('Form Type'),
1374
+ Column::make('name', 'string')->label('Name'),
1375
+ Column::make('type', 'string')->label('Type'),
1051
1376
  ]),
1052
1377
  Relationship::hasAutoJoin('vehicle', 'vehicles')
1053
1378
  ->label('Vehicle')
@@ -1070,4 +1395,39 @@ class FleetOpsReportSchema implements ReportSchema
1070
1395
  ]),
1071
1396
  ]);
1072
1397
  }
1398
+
1399
+ /**
1400
+ * Columns reported for a place (pickup, dropoff, return or item destination).
1401
+ */
1402
+ protected function placeColumns(): array
1403
+ {
1404
+ return [
1405
+ Column::make('public_id', 'string')->label('ID'),
1406
+ Column::make('name', 'string')->label('Name'),
1407
+ Column::make('street1', 'string')->label('Street'),
1408
+ Column::make('street2', 'string')->label('Street 2'),
1409
+ Column::make('neighborhood', 'string')->label('Neighborhood'),
1410
+ Column::make('district', 'string')->label('District'),
1411
+ Column::make('city', 'string')->label('City'),
1412
+ Column::make('province', 'string')->label('Province'),
1413
+ Column::make('postal_code', 'string')->label('Postal Code'),
1414
+ Column::make('country', 'string')->label('Country'),
1415
+ Column::make('latitude', 'decimal')->label('Latitude'),
1416
+ Column::make('longitude', 'decimal')->label('Longitude'),
1417
+ ];
1418
+ }
1419
+
1420
+ /**
1421
+ * Leave soft-deleted rows out of a table or joined relationship, on Core API releases that support it.
1422
+ *
1423
+ * @template T of Table|Relationship
1424
+ *
1425
+ * @param T $schema
1426
+ *
1427
+ * @return T
1428
+ */
1429
+ protected function softDeletes(Table|Relationship $schema): Table|Relationship
1430
+ {
1431
+ return method_exists($schema, 'softDeletes') ? $schema->softDeletes() : $schema;
1432
+ }
1073
1433
  }