@fleetbase/fleetops-engine 0.6.64 → 0.6.65

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 (284) hide show
  1. package/RELEASE.md +7 -5
  2. package/addon/components/attachment-list.hbs +65 -0
  3. package/addon/components/attachment-list.js +8 -0
  4. package/addon/components/cell/attached-vehicle.hbs +1 -1
  5. package/addon/components/cell/attached-vehicle.js +3 -3
  6. package/addon/components/cell/driver-identity.js +4 -4
  7. package/addon/components/cell/driver-name.hbs +1 -1
  8. package/addon/components/cell/translated-value.hbs +9 -0
  9. package/addon/components/cell/translated-value.js +57 -0
  10. package/addon/components/contact/card.hbs +58 -0
  11. package/addon/components/contact/card.js +19 -0
  12. package/addon/components/contact/form.hbs +1 -1
  13. package/addon/components/contact/panel-header.hbs +1 -1
  14. package/addon/components/customer/form.hbs +2 -2
  15. package/addon/components/device/manager.hbs +26 -28
  16. package/addon/components/device/manager.js +28 -2
  17. package/addon/components/device/panel-tabs/vehicle.hbs +13 -13
  18. package/addon/components/device/panel-tabs/vehicle.js +8 -0
  19. package/addon/components/driver/card.hbs +24 -13
  20. package/addon/components/driver/card.js +20 -6
  21. package/addon/components/driver/form.hbs +3 -3
  22. package/addon/components/driver/panel-header.hbs +2 -2
  23. package/addon/components/driver/pill.hbs +2 -2
  24. package/addon/components/equipment/form.js +11 -4
  25. package/addon/components/equipment/pill.hbs +20 -0
  26. package/addon/components/equipment/pill.js +3 -0
  27. package/addon/components/filter/multi-model.hbs +19 -0
  28. package/addon/components/filter/multi-model.js +90 -0
  29. package/addon/components/fleet/driver-listing.hbs +1 -1
  30. package/addon/components/fleet/vehicle-listing.hbs +1 -1
  31. package/addon/components/fleet-panel/driver-listing.hbs +1 -1
  32. package/addon/components/fleet-panel/vehicle-listing.hbs +1 -1
  33. package/addon/components/layout/fleet-ops-sidebar.js +9 -7
  34. package/addon/components/maintenance/form.js +12 -4
  35. package/addon/components/maintenance-schedule/form.js +13 -7
  36. package/addon/components/map/leaflet-live-map.hbs +52 -0
  37. package/addon/components/map/order-list-overlay/order.hbs +4 -4
  38. package/addon/components/modals/attach-equipment.hbs +22 -0
  39. package/addon/components/modals/attach-equipment.js +3 -0
  40. package/addon/components/modals/attach-telematic-device.hbs +13 -8
  41. package/addon/components/modals/attach-telematic-device.js +11 -1
  42. package/addon/components/modals/attach-trailer.hbs +30 -0
  43. package/addon/components/modals/attach-trailer.js +3 -0
  44. package/addon/components/modals/contact-form.hbs +2 -2
  45. package/addon/components/modals/convert-customer-to-vendor.hbs +1 -1
  46. package/addon/components/modals/driver-form.hbs +2 -2
  47. package/addon/components/modals/select-trailer.hbs +35 -0
  48. package/addon/components/modals/select-trailer.js +3 -0
  49. package/addon/components/modals/vehicle-form.hbs +2 -2
  50. package/addon/components/orchestrator/resource-panel.hbs +2 -2
  51. package/addon/components/order/customer-avatar-stack.hbs +2 -2
  52. package/addon/components/order/details/detail.hbs +4 -4
  53. package/addon/components/order/details/payload.hbs +2 -2
  54. package/addon/components/order/kanban-card.hbs +4 -4
  55. package/addon/components/order-list-overlay/order.hbs +4 -4
  56. package/addon/components/trailer/card.hbs +68 -0
  57. package/addon/components/trailer/card.js +22 -0
  58. package/addon/components/trailer/details/connections.hbs +57 -0
  59. package/addon/components/trailer/details/connections.js +59 -0
  60. package/addon/components/trailer/details/equipment.hbs +25 -0
  61. package/addon/components/trailer/details/equipment.js +52 -0
  62. package/addon/components/trailer/details/maintenance-history.hbs +47 -0
  63. package/addon/components/trailer/details/maintenance-history.js +40 -0
  64. package/addon/components/trailer/details/schedules.hbs +45 -0
  65. package/addon/components/trailer/details/schedules.js +40 -0
  66. package/addon/components/trailer/details/work-orders.hbs +47 -0
  67. package/addon/components/trailer/details/work-orders.js +40 -0
  68. package/addon/components/trailer/details.hbs +399 -0
  69. package/addon/components/trailer/details.js +118 -0
  70. package/addon/components/trailer/form.hbs +447 -0
  71. package/addon/components/trailer/form.js +165 -0
  72. package/addon/components/trailer/panel-header.hbs +45 -0
  73. package/addon/components/trailer/panel-header.js +3 -0
  74. package/addon/components/trailer/pill.hbs +21 -0
  75. package/addon/components/trailer/pill.js +3 -0
  76. package/addon/components/vehicle/card.hbs +42 -11
  77. package/addon/components/vehicle/card.js +31 -0
  78. package/addon/components/vehicle/details/equipment.hbs +25 -0
  79. package/addon/components/vehicle/details/equipment.js +55 -0
  80. package/addon/components/vehicle/details/trailers.hbs +35 -0
  81. package/addon/components/vehicle/details/trailers.js +55 -0
  82. package/addon/components/vehicle/form.hbs +2 -2
  83. package/addon/components/vehicle/panel-header.hbs +2 -2
  84. package/addon/components/vehicle/pill.hbs +2 -2
  85. package/addon/components/vendor/card.hbs +58 -0
  86. package/addon/components/vendor/card.js +6 -0
  87. package/addon/components/vendor/panel-header.hbs +2 -2
  88. package/addon/components/vendor/personnel-manager.hbs +2 -2
  89. package/addon/components/work-order/form.js +12 -4
  90. package/addon/controllers/connectivity/devices/index/details/vehicle.js +11 -0
  91. package/addon/controllers/connectivity/devices/index/details.js +3 -3
  92. package/addon/controllers/connectivity/devices/index.js +1 -0
  93. package/addon/controllers/connectivity/telematics/details/attachments.js +28 -47
  94. package/addon/controllers/connectivity/telematics/details/devices.js +1 -0
  95. package/addon/controllers/management/contacts/customers.js +4 -0
  96. package/addon/controllers/management/contacts/index.js +32 -0
  97. package/addon/controllers/management/trailers/index/details.js +119 -0
  98. package/addon/controllers/management/trailers/index/edit.js +67 -0
  99. package/addon/controllers/management/trailers/index/new.js +43 -0
  100. package/addon/controllers/management/trailers/index.js +599 -0
  101. package/addon/controllers/management/vehicles/index/details.js +16 -0
  102. package/addon/controllers/management/vehicles/index.js +78 -4
  103. package/addon/controllers/management/vendors/index.js +32 -0
  104. package/addon/controllers/operations/orders/index.js +3 -1
  105. package/addon/controllers/settings/custom-fields.js +8 -0
  106. package/addon/extension.js +7 -0
  107. package/addon/helpers/placeholder-image.js +6 -0
  108. package/addon/helpers/resource-image.js +10 -0
  109. package/addon/helpers/trailer-placeholder-image.js +6 -0
  110. package/addon/routes/management/trailers/index/details/connections.js +2 -0
  111. package/addon/routes/management/trailers/index/details/devices.js +2 -0
  112. package/addon/routes/management/trailers/index/details/equipment.js +2 -0
  113. package/addon/routes/management/trailers/index/details/index.js +2 -0
  114. package/addon/routes/management/trailers/index/details/maintenance-history.js +2 -0
  115. package/addon/routes/management/trailers/index/details/positions.js +2 -0
  116. package/addon/routes/management/trailers/index/details/schedules.js +2 -0
  117. package/addon/routes/management/trailers/index/details/work-orders.js +2 -0
  118. package/addon/routes/management/trailers/index/details.js +30 -0
  119. package/addon/routes/management/trailers/index/edit.js +23 -0
  120. package/addon/routes/management/trailers/index/new.js +14 -0
  121. package/addon/routes/management/trailers/index.js +42 -0
  122. package/addon/routes/management/vehicles/index/details/trailers.js +2 -0
  123. package/addon/routes/management/vehicles/index.js +7 -1
  124. package/addon/routes.js +17 -0
  125. package/addon/services/device-actions.js +26 -16
  126. package/addon/services/trailer-actions.js +394 -0
  127. package/addon/services/vehicle-actions.js +111 -0
  128. package/addon/styles/fleetops-engine.css +349 -0
  129. package/addon/templates/connectivity/devices/index/details/vehicle.hbs +19 -19
  130. package/addon/templates/connectivity/telematics/details/attachments.hbs +15 -15
  131. package/addon/templates/management/contacts/customers.hbs +48 -29
  132. package/addon/templates/management/contacts/index.hbs +52 -33
  133. package/addon/templates/management/trailers/index/details/connections.hbs +1 -0
  134. package/addon/templates/management/trailers/index/details/devices.hbs +1 -0
  135. package/addon/templates/management/trailers/index/details/equipment.hbs +1 -0
  136. package/addon/templates/management/trailers/index/details/index.hbs +1 -0
  137. package/addon/templates/management/trailers/index/details/maintenance-history.hbs +1 -0
  138. package/addon/templates/management/trailers/index/details/positions.hbs +1 -0
  139. package/addon/templates/management/trailers/index/details/schedules.hbs +1 -0
  140. package/addon/templates/management/trailers/index/details/work-orders.hbs +1 -0
  141. package/addon/templates/management/trailers/index/details.hbs +15 -0
  142. package/addon/templates/management/trailers/index/edit.hbs +12 -0
  143. package/addon/templates/management/trailers/index/new.hbs +11 -0
  144. package/addon/templates/management/trailers/index.hbs +67 -0
  145. package/addon/templates/management/vehicles/index/details/equipment.hbs +1 -1
  146. package/addon/templates/management/vehicles/index/details/trailers.hbs +1 -0
  147. package/addon/templates/management/vehicles/index/details.hbs +1 -1
  148. package/addon/templates/management/vendors/index.hbs +66 -32
  149. package/addon/utils/device-table-columns.js +10 -6
  150. package/addon/utils/live-map-card-content.js +56 -0
  151. package/addon/utils/placeholder-images.js +71 -0
  152. package/addon/utils/trailer-placeholder-image.js +11 -0
  153. package/app/components/attachment-list.js +1 -0
  154. package/app/components/cell/translated-value.js +1 -0
  155. package/app/components/contact/card.js +1 -0
  156. package/app/components/equipment/pill.js +1 -0
  157. package/app/components/filter/multi-model.js +1 -0
  158. package/app/components/modals/attach-equipment.js +1 -0
  159. package/app/components/modals/attach-trailer.js +1 -0
  160. package/app/components/modals/select-trailer.js +1 -0
  161. package/app/components/trailer/card.js +1 -0
  162. package/app/components/trailer/details/connections.js +1 -0
  163. package/app/components/trailer/details/equipment.js +1 -0
  164. package/app/components/trailer/details/maintenance-history.js +1 -0
  165. package/app/components/trailer/details/schedules.js +1 -0
  166. package/app/components/trailer/details/work-orders.js +1 -0
  167. package/app/components/trailer/details.js +1 -0
  168. package/app/components/trailer/form.js +1 -0
  169. package/app/components/trailer/panel-header.js +1 -0
  170. package/app/components/trailer/pill.js +1 -0
  171. package/app/components/vehicle/details/equipment.js +1 -0
  172. package/app/components/vehicle/details/trailers.js +1 -0
  173. package/app/components/vendor/card.js +1 -0
  174. package/app/controllers/management/trailers/index/details.js +1 -0
  175. package/app/controllers/management/trailers/index/edit.js +1 -0
  176. package/app/controllers/management/trailers/index/new.js +1 -0
  177. package/app/controllers/management/trailers/index.js +1 -0
  178. package/app/helpers/placeholder-image.js +1 -0
  179. package/app/helpers/resource-image.js +1 -0
  180. package/app/helpers/trailer-placeholder-image.js +1 -0
  181. package/app/routes/management/trailers/index/details/connections.js +1 -0
  182. package/app/routes/management/trailers/index/details/devices.js +1 -0
  183. package/app/routes/management/trailers/index/details/equipment.js +1 -0
  184. package/app/routes/management/trailers/index/details/index.js +1 -0
  185. package/app/routes/management/trailers/index/details/maintenance-history.js +1 -0
  186. package/app/routes/management/trailers/index/details/positions.js +1 -0
  187. package/app/routes/management/trailers/index/details/schedules.js +1 -0
  188. package/app/routes/management/trailers/index/details/work-orders.js +1 -0
  189. package/app/routes/management/trailers/index/details.js +1 -0
  190. package/app/routes/management/trailers/index/edit.js +1 -0
  191. package/app/routes/management/trailers/index/new.js +1 -0
  192. package/app/routes/management/trailers/index.js +1 -0
  193. package/app/routes/management/vehicles/index/details/trailers.js +1 -0
  194. package/app/services/trailer-actions.js +1 -0
  195. package/app/templates/management/trailers/index/details/connections.js +1 -0
  196. package/app/templates/management/trailers/index/details/devices.js +1 -0
  197. package/app/templates/management/trailers/index/details/equipment.js +1 -0
  198. package/app/templates/management/trailers/index/details/index.js +1 -0
  199. package/app/templates/management/trailers/index/details/maintenance-history.js +1 -0
  200. package/app/templates/management/trailers/index/details/positions.js +1 -0
  201. package/app/templates/management/trailers/index/details/schedules.js +1 -0
  202. package/app/templates/management/trailers/index/details/work-orders.js +1 -0
  203. package/app/templates/management/trailers/index/details.js +1 -0
  204. package/app/templates/management/trailers/index/edit.js +1 -0
  205. package/app/templates/management/trailers/index/new.js +1 -0
  206. package/app/templates/management/trailers/index.js +1 -0
  207. package/app/templates/management/vehicles/index/details/trailers.js +1 -0
  208. package/composer.json +1 -1
  209. package/extension.json +1 -1
  210. package/package.json +1 -1
  211. package/server/migrations/2026_09_03_000001_add_first_class_trailer_columns_to_assets_table.php +58 -0
  212. package/server/migrations/2026_09_03_000002_create_asset_connections_table.php +43 -0
  213. package/server/migrations/2026_09_03_000003_create_device_installations_table.php +33 -0
  214. package/server/src/Auth/Schemas/FleetOps.php +7 -0
  215. package/server/src/Events/TrailerLocationChanged.php +70 -0
  216. package/server/src/Exceptions/DeviceAlreadyAttachedException.php +18 -0
  217. package/server/src/Exports/TrailerExport.php +31 -0
  218. package/server/src/Http/Controllers/Api/v1/Concerns/ResolvesFleetOpsApiResources.php +8 -2
  219. package/server/src/Http/Controllers/Api/v1/DeviceController.php +22 -15
  220. package/server/src/Http/Controllers/Api/v1/EquipmentController.php +47 -0
  221. package/server/src/Http/Controllers/Api/v1/TrailerController.php +362 -0
  222. package/server/src/Http/Controllers/Api/v1/VehicleController.php +1 -0
  223. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +3 -0
  224. package/server/src/Http/Controllers/Internal/v1/LiveController.php +1 -1
  225. package/server/src/Http/Controllers/Internal/v1/SearchController.php +16 -0
  226. package/server/src/Http/Controllers/Internal/v1/TrailerController.php +360 -0
  227. package/server/src/Http/Controllers/Internal/v1/VehicleController.php +74 -0
  228. package/server/src/Http/Filter/EquipmentFilter.php +51 -0
  229. package/server/src/Http/Filter/OrderFilter.php +15 -0
  230. package/server/src/Http/Filter/TrailerFilter.php +269 -0
  231. package/server/src/Http/Filter/VehicleFilter.php +70 -3
  232. package/server/src/Http/Requests/CreateDeviceRequest.php +1 -1
  233. package/server/src/Http/Requests/CreateEquipmentRequest.php +1 -1
  234. package/server/src/Http/Requests/CreateTrailerRequest.php +54 -0
  235. package/server/src/Http/Requests/UpdateTrailerRequest.php +7 -0
  236. package/server/src/Http/Resources/v1/AssetConnection.php +90 -0
  237. package/server/src/Http/Resources/v1/Device.php +3 -1
  238. package/server/src/Http/Resources/v1/Equipment.php +3 -1
  239. package/server/src/Http/Resources/v1/Index/Vehicle.php +10 -0
  240. package/server/src/Http/Resources/v1/Trailer.php +199 -0
  241. package/server/src/Http/Resources/v1/Vehicle.php +2 -0
  242. package/server/src/Http/Resources/v1/VehicleWithoutDriver.php +3 -0
  243. package/server/src/Imports/TrailerImport.php +33 -0
  244. package/server/src/Models/Asset.php +39 -10
  245. package/server/src/Models/AssetConnection.php +43 -0
  246. package/server/src/Models/Device.php +39 -8
  247. package/server/src/Models/DeviceInstallation.php +27 -0
  248. package/server/src/Models/Equipment.php +2 -0
  249. package/server/src/Models/Trailer.php +181 -0
  250. package/server/src/Models/Vehicle.php +13 -0
  251. package/server/src/Providers/FleetOpsServiceProvider.php +4 -2
  252. package/server/src/Support/Ai/FleetOpsAiQueryResources.php +22 -0
  253. package/server/src/Support/Reporting/FleetOpsReportSchema.php +38 -0
  254. package/server/src/Support/Telematics/TelematicService.php +35 -0
  255. package/server/src/Support/TrailerSummary.php +35 -0
  256. package/server/src/routes.php +29 -0
  257. package/server/tests/CompactResourceSerializationTest.php +36 -0
  258. package/server/tests/ControllerFilterContractsTest.php +29 -0
  259. package/server/tests/Feature/Http/Api/DeviceControllerContractsTest.php +30 -13
  260. package/server/tests/Feature/Http/Api/TrailerControllerLifecycleTest.php +640 -0
  261. package/server/tests/Feature/Http/Internal/DeviceControllerContractsTest.php +20 -5
  262. package/server/tests/Feature/Http/Internal/LiveControllerEndpointsTest.php +19 -0
  263. package/server/tests/ModelAccessorContractsTest.php +10 -0
  264. package/server/tests/OrderFilterExecutionTest.php +5 -0
  265. package/server/tests/PublicApiControllerInputContractsTest.php +11 -0
  266. package/server/tests/PublicFleetOpsRestEndpointsTest.php +15 -3
  267. package/server/tests/ReportSchemaContractsTest.php +4 -0
  268. package/server/tests/TelematicsHardeningTest.php +4 -2
  269. package/server/tests/TrailerSupportCoverageTest.php +524 -0
  270. package/server/tests/Unit/Http/Resources/IndexVehicleResourceTest.php +35 -0
  271. package/server/tests/Unit/Models/EquipmentTest.php +22 -0
  272. package/server/tests/Unit/Models/ModelLookupFallbackSeamsTest.php +7 -3
  273. package/server/tests/Unit/Models/TrailerTest.php +204 -0
  274. package/server/tests/Unit/Support/Telematics/TelematicServiceTelemetryTest.php +93 -0
  275. package/server/tests/VehicleControllerHelperContractsTest.php +14 -0
  276. package/translations/ar-ae.yml +396 -0
  277. package/translations/bg-bg.yaml +424 -0
  278. package/translations/en-us.yaml +423 -0
  279. package/translations/es-pa.yaml +425 -0
  280. package/translations/fr-fr.yaml +424 -0
  281. package/translations/mn-mn.yaml +424 -0
  282. package/translations/pt-br.yaml +424 -0
  283. package/translations/ru-ru.yaml +424 -0
  284. package/translations/vi-vn.yaml +435 -0
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/trailer/form';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/trailer/panel-header';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/trailer/pill';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/vehicle/details/equipment';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/vehicle/details/trailers';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/vendor/card';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/controllers/management/trailers/index/details';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/controllers/management/trailers/index/edit';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/controllers/management/trailers/index/new';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/controllers/management/trailers/index';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/helpers/placeholder-image';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/helpers/resource-image';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/helpers/trailer-placeholder-image';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/trailers/index/details/connections';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/trailers/index/details/devices';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/trailers/index/details/equipment';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/trailers/index/details/index';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/trailers/index/details/maintenance-history';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/trailers/index/details/positions';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/trailers/index/details/schedules';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/trailers/index/details/work-orders';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/trailers/index/details';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/trailers/index/edit';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/trailers/index/new';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/trailers/index';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/management/vehicles/index/details/trailers';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/services/trailer-actions';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/trailers/index/details/connections';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/trailers/index/details/devices';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/trailers/index/details/equipment';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/trailers/index/details/index';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/trailers/index/details/maintenance-history';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/trailers/index/details/positions';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/trailers/index/details/schedules';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/trailers/index/details/work-orders';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/trailers/index/details';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/trailers/index/edit';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/trailers/index/new';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/trailers/index';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/management/vehicles/index/details/trailers';
package/composer.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbase/fleetops-api",
3
- "version": "0.6.64",
3
+ "version": "0.6.65",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "keywords": [
6
6
  "fleetbase-extension",
package/extension.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "Fleet-Ops",
3
- "version": "0.6.64",
3
+ "version": "0.6.65",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "repository": "https://github.com/fleetbase/fleetops",
6
6
  "license": "AGPL-3.0-or-later",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleetbase/fleetops-engine",
3
- "version": "0.6.64",
3
+ "version": "0.6.65",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "fleetbase": {
6
6
  "route": "fleet-ops"
@@ -0,0 +1,58 @@
1
+ <?php
2
+
3
+ use Illuminate\Database\Migrations\Migration;
4
+ use Illuminate\Database\Schema\Blueprint;
5
+ use Illuminate\Support\Facades\Schema;
6
+
7
+ return new class extends Migration {
8
+ public function up(): void
9
+ {
10
+ Schema::table('assets', function (Blueprint $table) {
11
+ // Existing Asset rows predate public identifiers. Keep this nullable so
12
+ // Trailer support does not rewrite unrelated historical Asset data.
13
+ $table->string('public_id')->nullable()->after('uuid')->unique();
14
+ $table->string('asset_class')->nullable()->after('type')->index();
15
+ $table->foreignUuid('photo_uuid')->nullable()->after('current_place_uuid')->constrained('files', 'uuid')->nullOnDelete();
16
+ $table->boolean('online')->nullable()->after('altitude')->index();
17
+ $table->timestamp('last_online_at')->nullable()->after('online')->index();
18
+ $table->json('telematics')->nullable()->after('attributes');
19
+ $table->date('purchased_at')->nullable()->after('lease_expires_at');
20
+ $table->decimal('length', 12, 3)->nullable();
21
+ $table->decimal('width', 12, 3)->nullable();
22
+ $table->decimal('height', 12, 3)->nullable();
23
+ $table->decimal('tare_weight', 12, 3)->nullable();
24
+ $table->decimal('gvwr', 12, 3)->nullable();
25
+ $table->decimal('payload_capacity', 12, 3)->nullable();
26
+ $table->decimal('cargo_volume', 12, 3)->nullable();
27
+ $table->unsignedSmallInteger('axle_count')->nullable();
28
+ $table->unsignedSmallInteger('tire_count')->nullable();
29
+ $table->unsignedSmallInteger('door_count')->nullable();
30
+ $table->string('body_type')->nullable()->index();
31
+ $table->string('coupling_type')->nullable();
32
+ $table->string('brake_type')->nullable();
33
+ $table->boolean('abs_equipped')->nullable();
34
+ $table->boolean('ebs_equipped')->nullable();
35
+ $table->boolean('refrigerated')->nullable()->index();
36
+ $table->decimal('temperature_min', 8, 3)->nullable();
37
+ $table->decimal('temperature_max', 8, 3)->nullable();
38
+ $table->decimal('reefer_engine_hours', 14, 2)->nullable();
39
+ $table->index(['company_uuid', 'asset_class', 'status'], 'assets_company_class_status_index');
40
+ });
41
+ }
42
+
43
+ public function down(): void
44
+ {
45
+ Schema::table('assets', function (Blueprint $table) {
46
+ $table->dropIndex('assets_company_class_status_index');
47
+ $table->dropForeign(['photo_uuid']);
48
+ $table->dropUnique(['public_id']);
49
+ $table->dropColumn([
50
+ 'public_id', 'asset_class', 'photo_uuid', 'online', 'last_online_at', 'telematics', 'purchased_at',
51
+ 'length', 'width', 'height', 'tare_weight', 'gvwr', 'payload_capacity', 'cargo_volume',
52
+ 'axle_count', 'tire_count', 'door_count', 'body_type', 'coupling_type', 'brake_type',
53
+ 'abs_equipped', 'ebs_equipped', 'refrigerated', 'temperature_min', 'temperature_max',
54
+ 'reefer_engine_hours',
55
+ ]);
56
+ });
57
+ }
58
+ };
@@ -0,0 +1,43 @@
1
+ <?php
2
+
3
+ use Illuminate\Database\Migrations\Migration;
4
+ use Illuminate\Database\Schema\Blueprint;
5
+ use Illuminate\Support\Facades\Schema;
6
+
7
+ return new class extends Migration {
8
+ public function up(): void
9
+ {
10
+ Schema::create('asset_connections', function (Blueprint $table) {
11
+ $table->bigIncrements('id');
12
+ $table->uuid('uuid')->unique();
13
+ $table->string('public_id')->unique();
14
+ $table->foreignUuid('company_uuid')->constrained('companies', 'uuid')->cascadeOnDelete();
15
+ $table->string('connector_type');
16
+ $table->uuid('connector_uuid');
17
+ $table->string('connected_type');
18
+ $table->uuid('connected_uuid');
19
+ $table->uuid('active_connected_uuid')->nullable()->unique();
20
+ $table->string('active_connector_position')->nullable()->unique();
21
+ $table->string('relationship_type')->default('towing');
22
+ $table->unsignedSmallInteger('position')->default(1);
23
+ $table->timestamp('connected_at');
24
+ $table->timestamp('disconnected_at')->nullable();
25
+ $table->string('source')->default('manual');
26
+ $table->string('confidence')->nullable();
27
+ $table->text('notes')->nullable();
28
+ $table->json('meta')->nullable();
29
+ $table->foreignUuid('created_by_uuid')->nullable()->constrained('users', 'uuid')->nullOnDelete();
30
+ $table->foreignUuid('updated_by_uuid')->nullable()->constrained('users', 'uuid')->nullOnDelete();
31
+ $table->timestamps();
32
+ $table->softDeletes();
33
+ $table->index(['company_uuid', 'connector_type', 'connector_uuid'], 'asset_connections_connector_index');
34
+ $table->index(['company_uuid', 'connected_type', 'connected_uuid'], 'asset_connections_connected_index');
35
+ $table->index(['company_uuid', 'disconnected_at'], 'asset_connections_active_index');
36
+ });
37
+ }
38
+
39
+ public function down(): void
40
+ {
41
+ Schema::dropIfExists('asset_connections');
42
+ }
43
+ };
@@ -0,0 +1,33 @@
1
+ <?php
2
+
3
+ use Illuminate\Database\Migrations\Migration;
4
+ use Illuminate\Database\Schema\Blueprint;
5
+ use Illuminate\Support\Facades\Schema;
6
+
7
+ return new class extends Migration {
8
+ public function up(): void
9
+ {
10
+ Schema::create('device_installations', function (Blueprint $table) {
11
+ $table->bigIncrements('id');
12
+ $table->uuid('uuid')->unique();
13
+ $table->foreignUuid('company_uuid')->constrained('companies', 'uuid')->cascadeOnDelete();
14
+ $table->foreignUuid('device_uuid')->constrained('devices', 'uuid')->cascadeOnDelete();
15
+ $table->string('attachable_type');
16
+ $table->uuid('attachable_uuid');
17
+ $table->uuid('active_device_uuid')->nullable()->unique();
18
+ $table->timestamp('installed_at');
19
+ $table->timestamp('removed_at')->nullable();
20
+ $table->string('source')->default('manual');
21
+ $table->json('metadata')->nullable();
22
+ $table->softDeletes();
23
+ $table->timestamps();
24
+ $table->index(['company_uuid', 'attachable_type', 'attachable_uuid'], 'device_installations_attachable_index');
25
+ $table->index(['device_uuid', 'installed_at'], 'device_installations_history_index');
26
+ });
27
+ }
28
+
29
+ public function down(): void
30
+ {
31
+ Schema::dropIfExists('device_installations');
32
+ }
33
+ };
@@ -61,6 +61,10 @@ class FleetOps
61
61
  'name' => 'vehicle',
62
62
  'actions' => ['assign-driver-for', 'export', 'import'],
63
63
  ],
64
+ [
65
+ 'name' => 'trailer',
66
+ 'actions' => ['export', 'import', 'attach-vehicle-for', 'detach-vehicle-for', 'attach-device-for', 'detach-device-for', 'attach-equipment-for', 'detach-equipment-for'],
67
+ ],
64
68
  [
65
69
  'name' => 'fleet',
66
70
  'actions' => ['assign-driver-for', 'assign-vehicle-for', 'remove-driver-for', 'remove-vehicle-for', 'export', 'import'],
@@ -217,6 +221,7 @@ class FleetOps
217
221
  '* fleet',
218
222
  '* driver',
219
223
  '* vehicle',
224
+ '* trailer',
220
225
  ],
221
226
  ],
222
227
  [
@@ -294,6 +299,7 @@ class FleetOps
294
299
  '* work-order',
295
300
  '* equipment',
296
301
  '* part',
302
+ '* trailer',
297
303
  'see vehicle',
298
304
  'list vehicle',
299
305
  'view vehicle',
@@ -318,6 +324,7 @@ class FleetOps
318
324
  '* work-order',
319
325
  '* equipment',
320
326
  '* part',
327
+ '* trailer',
321
328
  ],
322
329
  ],
323
330
  [
@@ -0,0 +1,70 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Events;
4
+
5
+ use Fleetbase\FleetOps\Models\Trailer;
6
+ use Illuminate\Broadcasting\Channel;
7
+ use Illuminate\Broadcasting\InteractsWithSockets;
8
+ use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
9
+ use Illuminate\Foundation\Bus\Dispatchable;
10
+ use Illuminate\Queue\SerializesModels;
11
+
12
+ class TrailerLocationChanged implements ShouldBroadcast
13
+ {
14
+ use Dispatchable;
15
+ use InteractsWithSockets;
16
+ use SerializesModels;
17
+
18
+ public string $eventId;
19
+ public string $sentAt;
20
+ public string $companyUuid;
21
+ public string $trailerUuid;
22
+ public string $trailerId;
23
+ public mixed $location;
24
+ public mixed $altitude;
25
+ public mixed $heading;
26
+ public mixed $speed;
27
+ public array $additionalData;
28
+
29
+ public function __construct(Trailer $trailer, array $additionalData = [])
30
+ {
31
+ $this->eventId = uniqid('event_');
32
+ $this->sentAt = now()->toDateTimeString();
33
+ $this->companyUuid = $trailer->company_uuid;
34
+ $this->trailerUuid = $trailer->uuid;
35
+ $this->trailerId = $trailer->public_id;
36
+ $this->location = $trailer->location;
37
+ $this->altitude = $trailer->altitude;
38
+ $this->heading = $trailer->heading;
39
+ $this->speed = $trailer->speed;
40
+ $this->additionalData = $additionalData;
41
+ }
42
+
43
+ public function broadcastOn(): array
44
+ {
45
+ return [new Channel('company.' . $this->companyUuid), new Channel('trailer.' . $this->trailerId), new Channel('trailer.' . $this->trailerUuid)];
46
+ }
47
+
48
+ public function broadcastAs(): string
49
+ {
50
+ return 'trailer.location_changed';
51
+ }
52
+
53
+ public function broadcastWith(): array
54
+ {
55
+ return [
56
+ 'id' => $this->eventId,
57
+ 'api_version' => config('api.version'),
58
+ 'event' => $this->broadcastAs(),
59
+ 'created_at' => $this->sentAt,
60
+ 'data' => [
61
+ 'id' => $this->trailerId,
62
+ 'location' => $this->location,
63
+ 'altitude' => $this->altitude,
64
+ 'heading' => $this->heading,
65
+ 'speed' => $this->speed,
66
+ 'additionalData' => $this->additionalData,
67
+ ],
68
+ ];
69
+ }
70
+ }
@@ -0,0 +1,18 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Exceptions;
4
+
5
+ /**
6
+ * Thrown when a device that is already installed on one asset is attached to another
7
+ * without being detached first. Attaching silently used to re-home the device, which
8
+ * let an operator "steal" a tracker from a vehicle with no feedback.
9
+ */
10
+ class DeviceAlreadyAttachedException extends \DomainException
11
+ {
12
+ public static function for(?string $attachedToName): self
13
+ {
14
+ $target = $attachedToName ? ' to ' . $attachedToName : ' to another asset';
15
+
16
+ return new self('Device is already attached' . $target . '. Detach it before attaching it elsewhere.');
17
+ }
18
+ }
@@ -0,0 +1,31 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Exports;
4
+
5
+ use Fleetbase\FleetOps\Models\Trailer;
6
+ use Maatwebsite\Excel\Concerns\FromCollection;
7
+ use Maatwebsite\Excel\Concerns\ShouldAutoSize;
8
+ use Maatwebsite\Excel\Concerns\WithHeadings;
9
+ use Maatwebsite\Excel\Concerns\WithMapping;
10
+
11
+ class TrailerExport implements FromCollection, WithHeadings, WithMapping, ShouldAutoSize
12
+ {
13
+ public function __construct(protected array $selections = [])
14
+ {
15
+ }
16
+
17
+ public function headings(): array
18
+ {
19
+ return ['ID', 'Name', 'Code', 'Type', 'Status', 'VIN', 'Plate Number', 'Serial Number', 'Make', 'Model', 'Year', 'Length', 'Width', 'Height', 'Tare Weight', 'GVWR', 'Payload Capacity', 'Cargo Volume', 'Axle Count', 'Tire Count', 'Coupling Type', 'Brake Type', 'Refrigerated', 'Measurement System', 'Odometer', 'Odometer Unit', 'Ownership Type', 'Purchased At', 'Lease Expires At', 'Notes', 'Date Created', 'Date Updated'];
20
+ }
21
+
22
+ public function map($trailer): array
23
+ {
24
+ return [$trailer->public_id, $trailer->name, $trailer->code, $trailer->type, $trailer->status, $trailer->vin, $trailer->plate_number, $trailer->serial_number, $trailer->make, $trailer->model, $trailer->year, $trailer->length, $trailer->width, $trailer->height, $trailer->tare_weight, $trailer->gvwr, $trailer->payload_capacity, $trailer->cargo_volume, $trailer->axle_count, $trailer->tire_count, $trailer->coupling_type, $trailer->brake_type, $trailer->refrigerated ? 'Yes' : 'No', $trailer->measurement_system, $trailer->odometer, $trailer->odometer_unit, $trailer->ownership_type, $trailer->purchased_at, $trailer->lease_expires_at, $trailer->notes, $trailer->created_at, $trailer->updated_at];
25
+ }
26
+
27
+ public function collection()
28
+ {
29
+ return Trailer::where('company_uuid', session('company'))->when($this->selections, fn ($q) => $q->whereIn('uuid', $this->selections))->get();
30
+ }
31
+ }
@@ -12,10 +12,10 @@ use Fleetbase\FleetOps\Models\FuelReport;
12
12
  use Fleetbase\FleetOps\Models\Order;
13
13
  use Fleetbase\FleetOps\Models\Part;
14
14
  use Fleetbase\FleetOps\Models\Telematic;
15
+ use Fleetbase\FleetOps\Models\Trailer;
15
16
  use Fleetbase\FleetOps\Models\Vehicle;
16
17
  use Fleetbase\FleetOps\Models\Vendor;
17
18
  use Fleetbase\FleetOps\Models\Warranty;
18
- use Fleetbase\FleetOps\Support\Utils;
19
19
  use Fleetbase\Models\File;
20
20
  use Illuminate\Database\Eloquent\Model;
21
21
  use Illuminate\Database\Eloquent\ModelNotFoundException;
@@ -72,7 +72,10 @@ trait ResolvesFleetOpsApiResources
72
72
  return [null, null];
73
73
  }
74
74
 
75
- $modelClass = Utils::getMutationType($type);
75
+ $modelClass = $this->allowedMorphTypes()[$type] ?? null;
76
+ if (!$modelClass) {
77
+ throw ValidationException::withMessages(['type' => ['Unsupported resource type.']]);
78
+ }
76
79
  $model = $this->resolveModel($modelClass, $id);
77
80
 
78
81
  return [$modelClass, $model->uuid];
@@ -166,6 +169,9 @@ trait ResolvesFleetOpsApiResources
166
169
  'fleet-ops:vehicle' => Vehicle::class,
167
170
  'vehicle' => Vehicle::class,
168
171
  Vehicle::class => Vehicle::class,
172
+ 'fleet-ops:trailer' => Trailer::class,
173
+ 'trailer' => Trailer::class,
174
+ Trailer::class => Trailer::class,
169
175
  'fleet-ops:driver' => Driver::class,
170
176
  'driver' => Driver::class,
171
177
  Driver::class => Driver::class,
@@ -2,6 +2,7 @@
2
2
 
3
3
  namespace Fleetbase\FleetOps\Http\Controllers\Api\v1;
4
4
 
5
+ use Fleetbase\FleetOps\Exceptions\DeviceAlreadyAttachedException;
5
6
  use Fleetbase\FleetOps\Http\Controllers\Api\v1\Concerns\ResolvesFleetOpsApiResources;
6
7
  use Fleetbase\FleetOps\Http\Requests\CreateDeviceRequest;
7
8
  use Fleetbase\FleetOps\Http\Requests\UpdateDeviceRequest;
@@ -9,7 +10,6 @@ use Fleetbase\FleetOps\Http\Resources\v1\DeletedResource;
9
10
  use Fleetbase\FleetOps\Http\Resources\v1\Device as DeviceResource;
10
11
  use Fleetbase\FleetOps\Models\Device;
11
12
  use Fleetbase\FleetOps\Models\Telematic;
12
- use Fleetbase\FleetOps\Models\Vehicle;
13
13
  use Fleetbase\FleetOps\Models\Warranty;
14
14
  use Fleetbase\FleetOps\Support\Utils;
15
15
  use Fleetbase\Http\Controllers\Controller;
@@ -90,28 +90,34 @@ class DeviceController extends Controller
90
90
  $this->rejectUuidIdentifiers($request);
91
91
 
92
92
  $request->validate([
93
- 'vehicle' => 'required_without:attachable|string|nullable',
93
+ 'vehicle' => 'required_without:attachable|string|nullable',
94
+ 'attachable' => 'required_without:vehicle|string|nullable',
95
+ 'attachable_type' => 'nullable|in:fleet-ops:vehicle,fleet-ops:trailer,vehicle,trailer',
94
96
  ]);
95
97
 
96
- $deviceId = $id;
97
- $vehicleId = $request->input('vehicle') ?? $request->input('attachable');
98
+ $deviceId = $id;
99
+ $attachableId = $request->input('vehicle') ?? $request->input('attachable');
100
+ $attachableType = $request->filled('vehicle') ? 'fleet-ops:vehicle' : $request->input('attachable_type', 'fleet-ops:vehicle');
98
101
 
99
102
  try {
100
- $device = $this->resolveModel(Device::class, $deviceId);
101
- $vehicle = $this->resolveModel(Vehicle::class, $vehicleId);
103
+ $device = $this->resolveModel(Device::class, $deviceId);
104
+ [$modelClass] = $this->resolveMorph($attachableType, $attachableId);
105
+ $attachable = $this->resolveModel($modelClass, $attachableId);
102
106
  } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $exception) {
103
- $this->logDeviceAttachmentLookupFailure('attach', $deviceId, $vehicleId);
107
+ $this->logDeviceAttachmentLookupFailure('attach', $deviceId, $attachableId);
104
108
 
105
- return response()->json(['error' => 'Device or vehicle resource not found.'], 404);
109
+ return response()->json(['error' => 'Device or attachable resource not found.'], 404);
106
110
  }
107
111
 
108
112
  try {
109
- $device->attachTo($vehicle);
113
+ $device->attachTo($attachable);
110
114
  $this->loadDeviceRelations($device);
115
+ } catch (DeviceAlreadyAttachedException $e) {
116
+ return response()->json(['error' => $e->getMessage()], 409);
111
117
  } catch (\Throwable $e) {
112
- $this->logDeviceAttachmentFailure('attach', $device, $vehicle, $e);
118
+ $this->logDeviceAttachmentFailure('attach', $device, $attachable, $e);
113
119
 
114
- return response()->json(['error' => 'Unable to attach device to vehicle.'], 500);
120
+ return response()->json(['error' => 'Unable to attach device to resource.'], 500);
115
121
  }
116
122
 
117
123
  return response()->json([
@@ -136,7 +142,7 @@ class DeviceController extends Controller
136
142
  } catch (\Throwable $e) {
137
143
  $this->logDeviceAttachmentFailure('detach', $device, null, $e);
138
144
 
139
- return response()->json(['error' => 'Unable to detach device from vehicle.'], 500);
145
+ return response()->json(['error' => 'Unable to detach device from resource.'], 500);
140
146
  }
141
147
 
142
148
  return response()->json([
@@ -242,14 +248,15 @@ class DeviceController extends Controller
242
248
  ]);
243
249
  }
244
250
 
245
- protected function logDeviceAttachmentFailure(string $action, Device $device, ?Vehicle $vehicle, \Throwable $exception): void
251
+ protected function logDeviceAttachmentFailure(string $action, Device $device, ?\Illuminate\Database\Eloquent\Model $attachable, \Throwable $exception): void
246
252
  {
247
253
  Log::error('Public API device attachment failed', [
248
254
  'action' => $action,
249
255
  'device_uuid' => $device->uuid,
250
256
  'device_id' => $device->public_id,
251
- 'vehicle_uuid' => $vehicle?->uuid,
252
- 'vehicle_id' => $vehicle?->public_id,
257
+ 'attachable_type' => $attachable ? get_class($attachable) : null,
258
+ 'attachable_uuid' => $attachable?->uuid,
259
+ 'attachable_id' => $attachable?->public_id,
253
260
  'company_uuid' => session('company'),
254
261
  'request_id' => request()->headers->get('X-Request-ID') ?? request()->headers->get('X-Correlation-ID'),
255
262
  'exception_class' => get_class($exception),