@fleetbase/fleetops-engine 0.6.54 → 0.6.56

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 (220) hide show
  1. package/addon/components/admin/map-settings.hbs +1 -1
  2. package/addon/components/admin/routing-settings.hbs +2 -1
  3. package/addon/components/cell/attached-vehicle.hbs +10 -0
  4. package/addon/components/cell/attached-vehicle.js +58 -0
  5. package/addon/components/cell/device-identity.hbs +24 -0
  6. package/addon/components/cell/device-identity.js +129 -0
  7. package/addon/components/cell/driver-identity.hbs +33 -0
  8. package/addon/components/cell/driver-identity.js +143 -0
  9. package/addon/components/cell/equipment-identity.hbs +5 -0
  10. package/addon/components/cell/equipment-identity.js +48 -0
  11. package/addon/components/cell/part-identity.hbs +5 -0
  12. package/addon/components/cell/part-identity.js +63 -0
  13. package/addon/components/cell/telematic-device.hbs +38 -0
  14. package/addon/components/cell/telematic-device.js +44 -0
  15. package/addon/components/cell/telematic-provider.hbs +33 -16
  16. package/addon/components/cell/telematic-provider.js +50 -8
  17. package/addon/components/cell/vehicle-identity.hbs +33 -0
  18. package/addon/components/cell/vehicle-identity.js +138 -0
  19. package/addon/components/device/details.js +1 -1
  20. package/addon/components/device/form.hbs +2 -2
  21. package/addon/components/device/form.js +7 -0
  22. package/addon/components/device/panel-header.hbs +45 -20
  23. package/addon/components/device/panel-header.js +49 -1
  24. package/addon/components/device/panel-tabs/events.hbs +30 -0
  25. package/addon/components/device/panel-tabs/events.js +128 -0
  26. package/addon/components/device/panel-tabs/sensors.hbs +30 -0
  27. package/addon/components/device/panel-tabs/sensors.js +93 -0
  28. package/addon/components/device/panel-tabs/vehicle.hbs +68 -0
  29. package/addon/components/device/panel-tabs/vehicle.js +90 -0
  30. package/addon/components/device-event/details.hbs +192 -0
  31. package/addon/components/device-event/details.js +151 -0
  32. package/addon/components/driver/schedule.js +1 -1
  33. package/addon/components/equipment/form.js +8 -1
  34. package/addon/components/layout/fleet-ops-sidebar.hbs +1 -1
  35. package/addon/components/layout/fleet-ops-sidebar.js +20 -6
  36. package/addon/components/map/drawer/device-event-listing.js +2 -0
  37. package/addon/components/map/drawer/driver-listing.js +2 -0
  38. package/addon/components/map/drawer/place-listing.js +2 -0
  39. package/addon/components/map/drawer/position-listing.hbs +11 -6
  40. package/addon/components/map/drawer/position-listing.js +17 -4
  41. package/addon/components/map/drawer/vehicle-listing.js +2 -0
  42. package/addon/components/sensor/panel-header.hbs +47 -15
  43. package/addon/components/sensor/panel-header.js +59 -1
  44. package/addon/components/table/cell/dropdown/action-item.hbs +31 -0
  45. package/addon/components/table/cell/dropdown/action-item.js +62 -0
  46. package/addon/components/table/cell/dropdown.hbs +28 -0
  47. package/addon/components/table/cell/dropdown.js +91 -0
  48. package/addon/components/telematic/details.hbs +1 -1
  49. package/addon/components/telematic/form.hbs +2 -2
  50. package/addon/components/telematic/settings.hbs +1 -1
  51. package/addon/components/vendor/panel-header.hbs +82 -0
  52. package/addon/components/vendor/panel-header.js +48 -0
  53. package/addon/controllers/connectivity/devices/index/details/events.js +1 -1
  54. package/addon/controllers/connectivity/devices/index/details/vehicle.js +50 -2
  55. package/addon/controllers/connectivity/devices/index.js +144 -129
  56. package/addon/controllers/connectivity/events/details.js +70 -0
  57. package/addon/controllers/connectivity/events/index.js +187 -11
  58. package/addon/controllers/connectivity/sensors/index.js +160 -14
  59. package/addon/controllers/connectivity/telematics/details/devices.js +126 -134
  60. package/addon/controllers/connectivity/telematics/details/events.js +1 -1
  61. package/addon/controllers/connectivity/telematics/details/sensors.js +4 -0
  62. package/addon/controllers/maintenance/equipment/index.js +1 -2
  63. package/addon/controllers/maintenance/parts/index.js +1 -2
  64. package/addon/controllers/management/drivers/index.js +82 -42
  65. package/addon/controllers/management/fuel-reports/index.js +63 -4
  66. package/addon/controllers/management/issues/index.js +63 -4
  67. package/addon/controllers/management/vehicles/index.js +33 -6
  68. package/addon/controllers/settings/map.js +15 -0
  69. package/addon/instance-initializers/register-vroom-allocation.js +1 -1
  70. package/addon/routes/connectivity/devices/index/details/vehicle.js +24 -2
  71. package/addon/routes/connectivity/devices/index.js +7 -0
  72. package/addon/routes/connectivity/events/details.js +28 -0
  73. package/addon/routes/connectivity/events/index.js +6 -2
  74. package/addon/routes/connectivity/sensors/index.js +7 -2
  75. package/addon/routes/connectivity/telematics/details/devices.js +2 -0
  76. package/addon/routes/management/vehicles/index/details.js +3 -1
  77. package/addon/services/device-actions.js +30 -0
  78. package/addon/services/device-event-actions.js +1 -1
  79. package/addon/services/equipment-actions.js +1 -0
  80. package/addon/services/map-adapter/google.js +25 -0
  81. package/addon/services/map-adapter/leaflet.js +1 -1
  82. package/addon/services/map-adapter-interface.js +1 -1
  83. package/addon/services/map-manager.js +4 -1
  84. package/addon/services/map-settings.js +15 -0
  85. package/addon/services/sensor-actions.js +3 -0
  86. package/addon/services/service-rate-actions.js +39 -1
  87. package/addon/services/vehicle-actions.js +24 -12
  88. package/addon/services/vendor-actions.js +3 -0
  89. package/addon/styles/fleetops-engine.css +9 -1
  90. package/addon/templates/connectivity/devices/index/details/vehicle.hbs +66 -2
  91. package/addon/templates/connectivity/events/details.hbs +40 -0
  92. package/addon/templates/management/vendors/index/details.hbs +2 -2
  93. package/addon/templates/settings/map.hbs +38 -9
  94. package/addon/templates/settings/notifications.hbs +2 -1
  95. package/addon/templates/settings/routing.hbs +1 -0
  96. package/addon/utils/device-table-columns.js +288 -0
  97. package/addon/utils/identity-cell-resource.js +20 -0
  98. package/addon/utils/leaflet-plugin-loader.js +5 -5
  99. package/addon/utils/map-drawer-dropdown-position.js +47 -0
  100. package/addon/utils/route-colors.js +1 -1
  101. package/addon/utils/trackable-option.js +93 -0
  102. package/app/components/cell/attached-vehicle.js +1 -0
  103. package/app/components/cell/device-identity.js +1 -0
  104. package/app/components/cell/driver-identity.js +1 -0
  105. package/app/components/cell/equipment-identity.js +1 -0
  106. package/app/components/cell/part-identity.js +1 -0
  107. package/app/components/cell/telematic-device.js +1 -0
  108. package/app/components/cell/vehicle-identity.js +1 -0
  109. package/app/components/device/panel-tabs/events.hbs +30 -0
  110. package/app/components/device/panel-tabs/events.js +128 -0
  111. package/app/components/device/panel-tabs/sensors.hbs +30 -0
  112. package/app/components/device/panel-tabs/sensors.js +93 -0
  113. package/app/components/device/panel-tabs/vehicle.hbs +68 -0
  114. package/app/components/device/panel-tabs/vehicle.js +90 -0
  115. package/app/components/device-event/details.hbs +192 -0
  116. package/app/components/device-event/details.js +1 -0
  117. package/app/components/table/cell/dropdown/action-item.js +1 -0
  118. package/app/components/table/cell/dropdown.js +1 -0
  119. package/app/components/vendor/panel-header.js +1 -0
  120. package/app/controllers/connectivity/events/{index/details.js → details.js} +1 -1
  121. package/app/routes/connectivity/events/{index/details.js → details.js} +1 -1
  122. package/app/templates/connectivity/events/{index/details.js → details.js} +1 -1
  123. package/app/utils/map-drawer-dropdown-position.js +1 -0
  124. package/app/utils/trackable-option.js +1 -0
  125. package/composer.json +1 -1
  126. package/extension.json +1 -1
  127. package/package.json +4 -4
  128. package/server/migrations/2026_06_23_000001_delete_bad_afaqy_telematics_sensors.php +34 -0
  129. package/server/src/Console/Commands/SyncTelematics.php +4 -4
  130. package/server/src/Exports/ContactExport.php +12 -5
  131. package/server/src/Exports/DeviceExport.php +92 -0
  132. package/server/src/Exports/DriverExport.php +28 -3
  133. package/server/src/Exports/EquipmentExport.php +94 -0
  134. package/server/src/Exports/FleetExport.php +22 -7
  135. package/server/src/Exports/FuelReportExport.php +16 -1
  136. package/server/src/Exports/IssueExport.php +25 -3
  137. package/server/src/Exports/MaintenanceExport.php +106 -0
  138. package/server/src/Exports/MaintenanceScheduleExport.php +99 -0
  139. package/server/src/Exports/OrderExport.php +24 -5
  140. package/server/src/Exports/PartExport.php +99 -0
  141. package/server/src/Exports/PlaceExport.php +33 -7
  142. package/server/src/Exports/SensorExport.php +94 -0
  143. package/server/src/Exports/ServiceAreaExport.php +31 -7
  144. package/server/src/Exports/ServiceRateExport.php +41 -1
  145. package/server/src/Exports/TelematicExport.php +90 -0
  146. package/server/src/Exports/VehicleExport.php +274 -8
  147. package/server/src/Exports/VendorExport.php +15 -2
  148. package/server/src/Exports/WorkOrderExport.php +92 -0
  149. package/server/src/Http/Controllers/Api/v1/Concerns/ResolvesFleetOpsApiResources.php +176 -0
  150. package/server/src/Http/Controllers/Api/v1/DeviceController.php +225 -0
  151. package/server/src/Http/Controllers/Api/v1/EquipmentController.php +114 -0
  152. package/server/src/Http/Controllers/Api/v1/FuelTransactionController.php +185 -0
  153. package/server/src/Http/Controllers/Api/v1/PartController.php +120 -0
  154. package/server/src/Http/Controllers/Api/v1/SensorController.php +132 -0
  155. package/server/src/Http/Controllers/Api/v1/WorkOrderController.php +161 -0
  156. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +36 -1
  157. package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +1 -1
  158. package/server/src/Http/Controllers/Internal/v1/EquipmentController.php +17 -0
  159. package/server/src/Http/Controllers/Internal/v1/LiveController.php +1 -1
  160. package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +17 -0
  161. package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +17 -0
  162. package/server/src/Http/Controllers/Internal/v1/PartController.php +17 -0
  163. package/server/src/Http/Controllers/Internal/v1/SensorController.php +18 -0
  164. package/server/src/Http/Controllers/Internal/v1/ServiceRateController.php +82 -13
  165. package/server/src/Http/Controllers/Internal/v1/SettingController.php +29 -5
  166. package/server/src/Http/Controllers/Internal/v1/TelematicController.php +18 -0
  167. package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +17 -0
  168. package/server/src/Http/Filter/DeviceEventFilter.php +21 -0
  169. package/server/src/Http/Filter/DeviceFilter.php +50 -4
  170. package/server/src/Http/Filter/EquipmentFilter.php +23 -0
  171. package/server/src/Http/Filter/FuelProviderTransactionFilter.php +57 -2
  172. package/server/src/Http/Filter/PartFilter.php +47 -0
  173. package/server/src/Http/Filter/SensorFilter.php +34 -6
  174. package/server/src/Http/Filter/WorkOrderFilter.php +23 -0
  175. package/server/src/Http/Requests/CreateDeviceRequest.php +51 -0
  176. package/server/src/Http/Requests/CreateEquipmentRequest.php +35 -0
  177. package/server/src/Http/Requests/CreateFuelTransactionRequest.php +50 -0
  178. package/server/src/Http/Requests/CreatePartRequest.php +40 -0
  179. package/server/src/Http/Requests/CreateSensorRequest.php +47 -0
  180. package/server/src/Http/Requests/CreateWorkOrderRequest.php +42 -0
  181. package/server/src/Http/Requests/UpdateDeviceRequest.php +7 -0
  182. package/server/src/Http/Requests/UpdateEquipmentRequest.php +7 -0
  183. package/server/src/Http/Requests/UpdateFuelTransactionRequest.php +7 -0
  184. package/server/src/Http/Requests/UpdatePartRequest.php +7 -0
  185. package/server/src/Http/Requests/UpdateSensorRequest.php +7 -0
  186. package/server/src/Http/Requests/UpdateWorkOrderRequest.php +7 -0
  187. package/server/src/Http/Resources/v1/Device.php +72 -0
  188. package/server/src/Http/Resources/v1/Equipment.php +57 -0
  189. package/server/src/Http/Resources/v1/FuelTransaction.php +69 -0
  190. package/server/src/Http/Resources/v1/Index/Vehicle.php +19 -0
  191. package/server/src/Http/Resources/v1/Part.php +64 -0
  192. package/server/src/Http/Resources/v1/Sensor.php +68 -0
  193. package/server/src/Jobs/SyncTelematicDevicesJob.php +194 -38
  194. package/server/src/Models/Device.php +2 -0
  195. package/server/src/Models/DeviceEvent.php +81 -0
  196. package/server/src/Models/Equipment.php +55 -0
  197. package/server/src/Models/Order.php +2 -1
  198. package/server/src/Observers/PurchaseRateObserver.php +2 -1
  199. package/server/src/Support/Analytics/RevenueTrend.php +3 -8
  200. package/server/src/Support/Metrics/ActiveRevenueQuery.php +121 -0
  201. package/server/src/Support/Metrics/AvgOrderValueMetric.php +1 -7
  202. package/server/src/Support/Metrics/EarningsMetric.php +1 -10
  203. package/server/src/Support/Telematics/Providers/AfaqyProvider.php +105 -5
  204. package/server/src/Support/Telematics/Providers/FlespiProvider.php +89 -15
  205. package/server/src/Support/Telematics/Providers/GeotabProvider.php +123 -35
  206. package/server/src/Support/Telematics/Providers/SafeeProvider.php +567 -47
  207. package/server/src/Support/Telematics/Providers/SamsaraProvider.php +122 -14
  208. package/server/src/Support/Telematics/TelematicService.php +28 -9
  209. package/server/src/routes.php +67 -15
  210. package/server/tests/DeviceFilterTest.php +9 -0
  211. package/server/tests/DriverVehicleStatusDefaultTest.php +19 -2
  212. package/server/tests/EquipmentAssignmentMorphTypeTest.php +35 -0
  213. package/server/tests/ExportCoverageTest.php +79 -0
  214. package/server/tests/MetricsRegistryTest.php +45 -5
  215. package/server/tests/PublicFleetOpsRestEndpointsTest.php +191 -0
  216. package/server/tests/ServiceRateRouteValidationTest.php +101 -0
  217. package/server/tests/TelematicsHardeningTest.php +873 -7
  218. package/addon/controllers/connectivity/events/index/details.js +0 -3
  219. package/addon/routes/connectivity/events/index/details.js +0 -3
  220. package/addon/templates/connectivity/events/index/details.hbs +0 -1
@@ -2,6 +2,7 @@
2
2
 
3
3
  namespace Fleetbase\FleetOps\Support\Telematics\Providers;
4
4
 
5
+ use Illuminate\Support\Carbon;
5
6
  use Illuminate\Support\Facades\Http;
6
7
 
7
8
  /**
@@ -75,19 +76,21 @@ class GeotabProvider extends AbstractProvider
75
76
  {
76
77
  $limit = $options['limit'] ?? 100;
77
78
 
78
- $response = Http::post($this->baseUrl, [
79
- 'method' => 'Get',
80
- 'params' => [
81
- 'credentials' => [
82
- 'database' => $this->credentials['database'],
83
- 'sessionId' => $this->sessionId,
84
- ],
85
- 'typeName' => 'Device',
86
- 'resultsLimit' => $limit,
87
- ],
88
- ])->json();
79
+ $response = $this->apiCall('Get', [
80
+ 'typeName' => 'Device',
81
+ 'resultsLimit' => $limit,
82
+ ]);
89
83
 
90
- $devices = $response['result'] ?? [];
84
+ $devices = $response['result'] ?? [];
85
+ $logsByDevice = $this->fetchLatestLogRecords($devices, $options);
86
+ $devices = array_map(function ($device) use ($logsByDevice) {
87
+ $deviceId = $device['id'] ?? null;
88
+ if ($deviceId && isset($logsByDevice[$deviceId])) {
89
+ $device['latest_log_record'] = $logsByDevice[$deviceId];
90
+ }
91
+
92
+ return $device;
93
+ }, $devices);
91
94
 
92
95
  return [
93
96
  'devices' => $devices,
@@ -98,43 +101,76 @@ class GeotabProvider extends AbstractProvider
98
101
 
99
102
  public function fetchDeviceDetails(string $externalId): array
100
103
  {
101
- $response = Http::post($this->baseUrl, [
102
- 'method' => 'Get',
103
- 'params' => [
104
- 'credentials' => [
105
- 'database' => $this->credentials['database'],
106
- 'sessionId' => $this->sessionId,
107
- ],
108
- 'typeName' => 'Device',
109
- 'search' => ['id' => $externalId],
110
- ],
111
- ])->json();
104
+ $response = $this->apiCall('Get', [
105
+ 'typeName' => 'Device',
106
+ 'search' => ['id' => $externalId],
107
+ ]);
112
108
 
113
109
  return $response['result'][0] ?? [];
114
110
  }
115
111
 
116
112
  public function normalizeDevice(array $payload): array
117
113
  {
114
+ $latestLog = $payload['latest_log_record'] ?? [];
115
+ $hasTelemetry = isset($latestLog['dateTime']) || isset($latestLog['latitude'], $latestLog['longitude']);
116
+
118
117
  return [
119
- 'external_id' => $payload['id'],
120
- 'device_name' => $payload['name'] ?? 'Unknown Device',
121
- 'device_provider' => 'geotab',
122
- 'device_model' => $payload['deviceType'] ?? null,
123
- 'imei' => $payload['serialNumber'] ?? null,
124
- 'vin' => $payload['vehicleIdentificationNumber'] ?? null,
125
- 'status' => 'active',
126
- 'meta' => $payload,
118
+ 'device_id' => $payload['id'] ?? null,
119
+ 'external_id' => $payload['id'] ?? null,
120
+ 'name' => $payload['name'] ?? 'Unknown Device',
121
+ 'provider' => 'geotab',
122
+ 'model' => $payload['deviceType'] ?? null,
123
+ 'imei' => $payload['serialNumber'] ?? null,
124
+ 'vin' => $payload['vehicleIdentificationNumber'] ?? null,
125
+ 'serial_number' => $payload['serialNumber'] ?? null,
126
+ 'status' => 'active',
127
+ 'online' => $hasTelemetry ? true : null,
128
+ 'last_seen_at' => $latestLog ? $this->parseTimestamp($latestLog['dateTime'] ?? null) : null,
129
+ 'location' => [
130
+ 'lat' => $latestLog['latitude'] ?? null,
131
+ 'lng' => $latestLog['longitude'] ?? null,
132
+ ],
133
+ 'speed' => $latestLog['speed'] ?? null,
134
+ 'heading' => $latestLog['bearing'] ?? $latestLog['heading'] ?? null,
135
+ 'altitude' => $latestLog['altitude'] ?? null,
136
+ 'meta' => [
137
+ 'raw' => $payload,
138
+ 'provider_status' => array_filter([
139
+ 'active_from' => $payload['activeFrom'] ?? null,
140
+ 'active_to' => $payload['activeTo'] ?? null,
141
+ 'groups' => $payload['groups'] ?? null,
142
+ 'has_log' => $hasTelemetry,
143
+ ], fn ($value) => $value !== null),
144
+ ],
127
145
  ];
128
146
  }
129
147
 
130
148
  public function normalizeEvent(array $payload): array
131
149
  {
150
+ $latestLog = $payload['latest_log_record'] ?? $payload;
151
+ $deviceId = data_get($latestLog, 'device.id') ?? $payload['deviceId'] ?? $payload['id'] ?? null;
152
+ $hasTelemetry = isset($latestLog['dateTime']) || isset($latestLog['latitude'], $latestLog['longitude']);
153
+
132
154
  return [
133
- 'external_id' => $payload['id'] ?? null,
134
- 'device_id' => $payload['device']['id'] ?? $payload['deviceId'] ?? null,
155
+ 'external_id' => $latestLog['id'] ?? $payload['id'] ?? null,
156
+ 'device_id' => $deviceId,
135
157
  'event_type' => $payload['type'] ?? 'status_data',
136
- 'occurred_at' => $payload['dateTime'] ?? now(),
137
- 'meta' => $payload,
158
+ 'occurred_at' => $this->parseTimestamp($latestLog['dateTime'] ?? null) ?? now(),
159
+ 'online' => $hasTelemetry ? true : null,
160
+ 'location' => [
161
+ 'lat' => $latestLog['latitude'] ?? null,
162
+ 'lng' => $latestLog['longitude'] ?? null,
163
+ ],
164
+ 'speed' => $latestLog['speed'] ?? null,
165
+ 'heading' => $latestLog['bearing'] ?? $latestLog['heading'] ?? null,
166
+ 'altitude' => $latestLog['altitude'] ?? null,
167
+ 'meta' => [
168
+ 'raw' => $payload,
169
+ 'provider_status' => array_filter([
170
+ 'has_log' => $hasTelemetry,
171
+ 'device' => data_get($latestLog, 'device.id'),
172
+ ], fn ($value) => $value !== null),
173
+ ],
138
174
  ];
139
175
  }
140
176
 
@@ -179,4 +215,56 @@ class GeotabProvider extends AbstractProvider
179
215
  {
180
216
  return false;
181
217
  }
218
+
219
+ protected function apiCall(string $method, array $params): array
220
+ {
221
+ $params['credentials'] = [
222
+ 'database' => $this->credentials['database'],
223
+ 'sessionId' => $this->sessionId,
224
+ ];
225
+
226
+ return Http::post($this->baseUrl, [
227
+ 'method' => $method,
228
+ 'params' => $params,
229
+ ])->json() ?? [];
230
+ }
231
+
232
+ protected function fetchLatestLogRecords(array $devices, array $options = []): array
233
+ {
234
+ $deviceIds = array_values(array_filter(array_map(fn ($device) => $device['id'] ?? null, $devices)));
235
+ if (empty($deviceIds)) {
236
+ return [];
237
+ }
238
+
239
+ $fromDate = $options['from_date'] ?? Carbon::now()->subHours(24)->toIso8601String();
240
+ $response = $this->apiCall('Get', [
241
+ 'typeName' => 'LogRecord',
242
+ 'search' => ['fromDate' => $fromDate],
243
+ 'resultsLimit' => max(count($deviceIds) * 5, 100),
244
+ ]);
245
+
246
+ $logsByDevice = [];
247
+ foreach ($response['result'] ?? [] as $record) {
248
+ $deviceId = data_get($record, 'device.id');
249
+ if (!$deviceId || !in_array($deviceId, $deviceIds, true)) {
250
+ continue;
251
+ }
252
+
253
+ $current = $logsByDevice[$deviceId] ?? null;
254
+ if (!$current || Carbon::parse($record['dateTime'] ?? now())->greaterThan(Carbon::parse($current['dateTime'] ?? now()))) {
255
+ $logsByDevice[$deviceId] = $record;
256
+ }
257
+ }
258
+
259
+ return $logsByDevice;
260
+ }
261
+
262
+ protected function parseTimestamp($value): ?string
263
+ {
264
+ if (!$value) {
265
+ return null;
266
+ }
267
+
268
+ return Carbon::parse($value)->toDateTimeString();
269
+ }
182
270
  }