@fleetbase/fleetops-engine 0.6.55 → 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 (109) hide show
  1. package/addon/components/admin/map-settings.hbs +1 -1
  2. package/addon/components/device/details.js +1 -1
  3. package/addon/components/device-event/details.hbs +192 -0
  4. package/addon/components/device-event/details.js +151 -0
  5. package/addon/components/driver/schedule.js +1 -1
  6. package/addon/components/layout/fleet-ops-sidebar.js +15 -9
  7. package/addon/components/telematic/details.hbs +1 -1
  8. package/addon/components/telematic/form.hbs +2 -2
  9. package/addon/components/telematic/settings.hbs +1 -1
  10. package/addon/controllers/connectivity/devices/index/details/events.js +1 -1
  11. package/addon/controllers/connectivity/devices/index/details/vehicle.js +2 -2
  12. package/addon/controllers/connectivity/events/details.js +68 -1
  13. package/addon/controllers/connectivity/sensors/index.js +4 -0
  14. package/addon/controllers/connectivity/telematics/details/events.js +1 -1
  15. package/addon/controllers/connectivity/telematics/details/sensors.js +4 -0
  16. package/addon/controllers/settings/map.js +15 -0
  17. package/addon/instance-initializers/register-vroom-allocation.js +1 -1
  18. package/addon/routes/connectivity/events/details.js +26 -1
  19. package/addon/routes/management/vehicles/index/details.js +3 -1
  20. package/addon/services/map-adapter/google.js +25 -0
  21. package/addon/services/map-adapter/leaflet.js +1 -1
  22. package/addon/services/map-adapter-interface.js +1 -1
  23. package/addon/services/map-manager.js +4 -1
  24. package/addon/services/map-settings.js +15 -0
  25. package/addon/styles/fleetops-engine.css +1 -1
  26. package/addon/templates/connectivity/devices/index/details/vehicle.hbs +2 -1
  27. package/addon/templates/connectivity/events/details.hbs +40 -1
  28. package/addon/templates/settings/map.hbs +38 -9
  29. package/addon/utils/leaflet-plugin-loader.js +5 -5
  30. package/addon/utils/route-colors.js +1 -1
  31. package/app/components/device-event/details.hbs +192 -0
  32. package/app/components/device-event/details.js +1 -0
  33. package/composer.json +1 -1
  34. package/extension.json +1 -1
  35. package/package.json +2 -2
  36. package/server/migrations/2026_06_23_000001_delete_bad_afaqy_telematics_sensors.php +34 -0
  37. package/server/src/Exports/ContactExport.php +12 -5
  38. package/server/src/Exports/DeviceExport.php +92 -0
  39. package/server/src/Exports/DriverExport.php +28 -3
  40. package/server/src/Exports/EquipmentExport.php +94 -0
  41. package/server/src/Exports/FleetExport.php +22 -7
  42. package/server/src/Exports/FuelReportExport.php +16 -1
  43. package/server/src/Exports/IssueExport.php +25 -3
  44. package/server/src/Exports/MaintenanceExport.php +106 -0
  45. package/server/src/Exports/MaintenanceScheduleExport.php +99 -0
  46. package/server/src/Exports/OrderExport.php +24 -5
  47. package/server/src/Exports/PartExport.php +99 -0
  48. package/server/src/Exports/PlaceExport.php +33 -7
  49. package/server/src/Exports/SensorExport.php +94 -0
  50. package/server/src/Exports/ServiceAreaExport.php +31 -7
  51. package/server/src/Exports/ServiceRateExport.php +41 -1
  52. package/server/src/Exports/TelematicExport.php +90 -0
  53. package/server/src/Exports/VehicleExport.php +274 -8
  54. package/server/src/Exports/VendorExport.php +15 -2
  55. package/server/src/Exports/WorkOrderExport.php +92 -0
  56. package/server/src/Http/Controllers/Api/v1/Concerns/ResolvesFleetOpsApiResources.php +176 -0
  57. package/server/src/Http/Controllers/Api/v1/DeviceController.php +225 -0
  58. package/server/src/Http/Controllers/Api/v1/EquipmentController.php +114 -0
  59. package/server/src/Http/Controllers/Api/v1/FuelTransactionController.php +185 -0
  60. package/server/src/Http/Controllers/Api/v1/PartController.php +120 -0
  61. package/server/src/Http/Controllers/Api/v1/SensorController.php +132 -0
  62. package/server/src/Http/Controllers/Api/v1/WorkOrderController.php +161 -0
  63. package/server/src/Http/Controllers/Internal/v1/DeviceController.php +18 -0
  64. package/server/src/Http/Controllers/Internal/v1/EquipmentController.php +17 -0
  65. package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +17 -0
  66. package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +17 -0
  67. package/server/src/Http/Controllers/Internal/v1/PartController.php +17 -0
  68. package/server/src/Http/Controllers/Internal/v1/SensorController.php +18 -0
  69. package/server/src/Http/Controllers/Internal/v1/SettingController.php +29 -5
  70. package/server/src/Http/Controllers/Internal/v1/TelematicController.php +18 -0
  71. package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +17 -0
  72. package/server/src/Http/Filter/DeviceFilter.php +33 -10
  73. package/server/src/Http/Filter/EquipmentFilter.php +23 -0
  74. package/server/src/Http/Filter/FuelProviderTransactionFilter.php +57 -2
  75. package/server/src/Http/Filter/PartFilter.php +47 -0
  76. package/server/src/Http/Filter/SensorFilter.php +34 -6
  77. package/server/src/Http/Filter/WorkOrderFilter.php +23 -0
  78. package/server/src/Http/Requests/CreateDeviceRequest.php +51 -0
  79. package/server/src/Http/Requests/CreateEquipmentRequest.php +35 -0
  80. package/server/src/Http/Requests/CreateFuelTransactionRequest.php +50 -0
  81. package/server/src/Http/Requests/CreatePartRequest.php +40 -0
  82. package/server/src/Http/Requests/CreateSensorRequest.php +47 -0
  83. package/server/src/Http/Requests/CreateWorkOrderRequest.php +42 -0
  84. package/server/src/Http/Requests/UpdateDeviceRequest.php +7 -0
  85. package/server/src/Http/Requests/UpdateEquipmentRequest.php +7 -0
  86. package/server/src/Http/Requests/UpdateFuelTransactionRequest.php +7 -0
  87. package/server/src/Http/Requests/UpdatePartRequest.php +7 -0
  88. package/server/src/Http/Requests/UpdateSensorRequest.php +7 -0
  89. package/server/src/Http/Requests/UpdateWorkOrderRequest.php +7 -0
  90. package/server/src/Http/Resources/v1/Device.php +72 -0
  91. package/server/src/Http/Resources/v1/Equipment.php +57 -0
  92. package/server/src/Http/Resources/v1/FuelTransaction.php +69 -0
  93. package/server/src/Http/Resources/v1/Part.php +64 -0
  94. package/server/src/Http/Resources/v1/Sensor.php +68 -0
  95. package/server/src/Jobs/SyncTelematicDevicesJob.php +194 -38
  96. package/server/src/Models/Order.php +2 -1
  97. package/server/src/Observers/PurchaseRateObserver.php +2 -1
  98. package/server/src/Support/Analytics/RevenueTrend.php +3 -8
  99. package/server/src/Support/Metrics/ActiveRevenueQuery.php +121 -0
  100. package/server/src/Support/Metrics/AvgOrderValueMetric.php +1 -7
  101. package/server/src/Support/Metrics/EarningsMetric.php +1 -10
  102. package/server/src/Support/Telematics/Providers/AfaqyProvider.php +104 -5
  103. package/server/src/Support/Telematics/Providers/SafeeProvider.php +550 -54
  104. package/server/src/Support/Telematics/TelematicService.php +28 -9
  105. package/server/src/routes.php +67 -14
  106. package/server/tests/ExportCoverageTest.php +79 -0
  107. package/server/tests/MetricsRegistryTest.php +45 -5
  108. package/server/tests/PublicFleetOpsRestEndpointsTest.php +191 -0
  109. package/server/tests/TelematicsHardeningTest.php +636 -1
@@ -2,7 +2,9 @@
2
2
 
3
3
  namespace Fleetbase\FleetOps\Exports;
4
4
 
5
+ use Fleetbase\FleetOps\Models\Order;
5
6
  use Fleetbase\FleetOps\Models\Vehicle;
7
+ use Fleetbase\FleetOps\Support\Utils;
6
8
  use Maatwebsite\Excel\Concerns\FromCollection;
7
9
  use Maatwebsite\Excel\Concerns\ShouldAutoSize;
8
10
  use Maatwebsite\Excel\Concerns\WithColumnFormatting;
@@ -14,6 +16,14 @@ class VehicleExport implements FromCollection, WithHeadings, WithMapping, WithCo
14
16
  {
15
17
  protected array $selections = [];
16
18
 
19
+ protected array $dateHeadings = [
20
+ 'Purchased At',
21
+ 'Lease Expires At',
22
+ 'Loan First Payment',
23
+ 'Created At',
24
+ 'Updated At',
25
+ ];
26
+
17
27
  public function __construct(array $selections = [])
18
28
  {
19
29
  $this->selections = $selections;
@@ -21,15 +31,103 @@ class VehicleExport implements FromCollection, WithHeadings, WithMapping, WithCo
21
31
 
22
32
  public function map($vehicle): array
23
33
  {
34
+ $currency = $vehicle->currency ?: 'USD';
35
+
24
36
  return [
25
37
  $vehicle->public_id,
26
38
  $vehicle->internal_id,
27
39
  $vehicle->display_name,
28
- $vehicle->driver_name,
40
+ $vehicle->description,
41
+ $vehicle->plate_number,
42
+ $vehicle->vin,
29
43
  $vehicle->make,
30
44
  $vehicle->model,
31
45
  $vehicle->year,
46
+ $vehicle->trim,
47
+ $vehicle->color,
48
+ $vehicle->serial_number,
49
+ $vehicle->fuel_card_number,
50
+ $vehicle->class,
51
+ $vehicle->type,
52
+ $vehicle->driver_name,
53
+ $vehicle->vendor_name,
54
+ $vehicle->status,
55
+ $this->yesNo($vehicle->online),
56
+ $vehicle->call_sign,
57
+ $this->locationPart($vehicle->location, 'lat'),
58
+ $this->locationPart($vehicle->location, 'lng'),
59
+ $vehicle->heading,
60
+ $vehicle->altitude,
61
+ $vehicle->speed,
62
+ $vehicle->measurement_system,
63
+ $vehicle->fuel_volume_unit,
64
+ $vehicle->odometer,
65
+ $vehicle->odometer_unit,
66
+ $vehicle->odometer_at_purchase,
67
+ $vehicle->body_type,
68
+ $vehicle->body_sub_type,
69
+ $vehicle->usage_type,
70
+ $vehicle->ownership_type,
71
+ $vehicle->fuel_type,
72
+ $vehicle->transmission,
73
+ $vehicle->engine_number,
74
+ $vehicle->engine_make,
75
+ $vehicle->engine_model,
76
+ $vehicle->engine_family,
77
+ $vehicle->engine_configuration,
78
+ $vehicle->cylinder_arrangement,
79
+ $vehicle->number_of_cylinders,
80
+ $vehicle->engine_size,
81
+ $vehicle->engine_displacement,
82
+ $vehicle->horsepower,
83
+ $vehicle->horsepower_rpm,
84
+ $vehicle->torque,
85
+ $vehicle->torque_rpm,
86
+ $vehicle->fuel_capacity,
87
+ $vehicle->payload_capacity,
88
+ $vehicle->towing_capacity,
89
+ $vehicle->seating_capacity,
90
+ $vehicle->weight,
91
+ $vehicle->length,
92
+ $vehicle->width,
93
+ $vehicle->height,
94
+ $vehicle->cargo_volume,
95
+ $vehicle->payload_capacity_volume,
96
+ $vehicle->payload_capacity_pallets,
97
+ $vehicle->payload_capacity_parcels,
98
+ $vehicle->passenger_volume,
99
+ $vehicle->interior_volume,
100
+ $vehicle->ground_clearance,
101
+ $vehicle->bed_length,
102
+ $vehicle->emission_standard,
103
+ $this->yesNo($vehicle->dpf_equipped),
104
+ $this->yesNo($vehicle->scr_equipped),
105
+ $vehicle->gvwr,
106
+ $vehicle->gcwr,
107
+ $vehicle->currency,
108
+ $this->money($vehicle->acquisition_cost, $currency),
109
+ $this->money($vehicle->current_value, $currency),
110
+ $this->money($vehicle->insurance_value, $currency),
111
+ $vehicle->depreciation_rate,
112
+ $vehicle->estimated_service_life_distance,
113
+ $vehicle->estimated_service_life_distance_unit,
114
+ $vehicle->estimated_service_life_months,
115
+ $vehicle->purchased_at,
116
+ $vehicle->lease_expires_at,
117
+ $vehicle->financing_status,
118
+ $this->money($vehicle->loan_amount, $currency),
119
+ $vehicle->loan_number_of_payments,
120
+ $vehicle->loan_first_payment,
121
+ $this->joinSkills($vehicle->skills),
122
+ $vehicle->time_window_start,
123
+ $vehicle->time_window_end,
124
+ $vehicle->max_tasks,
125
+ $this->yesNo($vehicle->return_to_depot),
126
+ $this->assignedOrdersCount($vehicle),
127
+ $this->currentOrderReference($vehicle),
128
+ $vehicle->notes,
32
129
  $vehicle->created_at,
130
+ $vehicle->updated_at,
33
131
  ];
34
132
  }
35
133
 
@@ -39,19 +137,111 @@ class VehicleExport implements FromCollection, WithHeadings, WithMapping, WithCo
39
137
  'ID',
40
138
  'Internal ID',
41
139
  'Name',
42
- 'Driver Assigned',
140
+ 'Description',
141
+ 'Plate Number',
142
+ 'VIN',
43
143
  'Make',
44
144
  'Model',
45
145
  'Year',
46
- 'Date Created',
146
+ 'Trim',
147
+ 'Color',
148
+ 'Serial Number',
149
+ 'Fuel Card Number',
150
+ 'Class',
151
+ 'Type',
152
+ 'Driver',
153
+ 'Vendor',
154
+ 'Status',
155
+ 'Online',
156
+ 'Call Sign',
157
+ 'Latitude',
158
+ 'Longitude',
159
+ 'Heading',
160
+ 'Altitude',
161
+ 'Speed',
162
+ 'Measurement System',
163
+ 'Fuel Volume Unit',
164
+ 'Odometer',
165
+ 'Odometer Unit',
166
+ 'Odometer At Purchase',
167
+ 'Body Type',
168
+ 'Body Sub Type',
169
+ 'Usage Type',
170
+ 'Ownership Type',
171
+ 'Fuel Type',
172
+ 'Transmission',
173
+ 'Engine Number',
174
+ 'Engine Make',
175
+ 'Engine Model',
176
+ 'Engine Family',
177
+ 'Engine Configuration',
178
+ 'Cylinder Arrangement',
179
+ 'Number Of Cylinders',
180
+ 'Engine Size (L)',
181
+ 'Engine Displacement (cc)',
182
+ 'Horsepower (hp)',
183
+ 'Horsepower RPM',
184
+ 'Torque (Nm)',
185
+ 'Torque RPM',
186
+ 'Fuel Capacity (L)',
187
+ 'Payload Capacity (kg)',
188
+ 'Towing Capacity (kg)',
189
+ 'Seating Capacity',
190
+ 'Weight (kg)',
191
+ 'Length (cm)',
192
+ 'Width (cm)',
193
+ 'Height (cm)',
194
+ 'Cargo Volume (L)',
195
+ 'Payload Volume (m3)',
196
+ 'Payload Pallets',
197
+ 'Payload Parcels',
198
+ 'Passenger Volume (L)',
199
+ 'Interior Volume (L)',
200
+ 'Ground Clearance (cm)',
201
+ 'Bed Length (cm)',
202
+ 'Emission Standard',
203
+ 'DPF Equipped',
204
+ 'SCR Equipped',
205
+ 'GVWR (kg)',
206
+ 'GCWR (kg)',
207
+ 'Currency',
208
+ 'Acquisition Cost',
209
+ 'Current Value',
210
+ 'Insurance Value',
211
+ 'Depreciation Rate',
212
+ 'Estimated Service Life Distance',
213
+ 'Estimated Service Life Distance Unit',
214
+ 'Estimated Service Life Months',
215
+ 'Purchased At',
216
+ 'Lease Expires At',
217
+ 'Financing Status',
218
+ 'Loan Amount',
219
+ 'Loan Number Of Payments',
220
+ 'Loan First Payment',
221
+ 'Vehicle Skills',
222
+ 'Time Window Start',
223
+ 'Time Window End',
224
+ 'Max Tasks',
225
+ 'Return To Depot',
226
+ 'Assigned Order Count',
227
+ 'Current Order Reference',
228
+ 'Notes',
229
+ 'Created At',
230
+ 'Updated At',
47
231
  ];
48
232
  }
49
233
 
50
234
  public function columnFormats(): array
51
235
  {
52
- return [
53
- 'H' => NumberFormat::FORMAT_DATE_DDMMYYYY,
54
- ];
236
+ return collect($this->headings())
237
+ ->mapWithKeys(function ($heading, $index) {
238
+ if (!in_array($heading, $this->dateHeadings, true)) {
239
+ return [];
240
+ }
241
+
242
+ return [$this->columnLetter($index + 1) => NumberFormat::FORMAT_DATE_DDMMYYYY];
243
+ })
244
+ ->all();
55
245
  }
56
246
 
57
247
  /**
@@ -59,10 +249,86 @@ class VehicleExport implements FromCollection, WithHeadings, WithMapping, WithCo
59
249
  */
60
250
  public function collection()
61
251
  {
252
+ $query = Vehicle::where('company_uuid', session('company'))->with(['driver.currentOrder', 'vendor']);
253
+
62
254
  if ($this->selections) {
63
- return Vehicle::where('company_uuid', session('company'))->whereIn('uuid', $this->selections)->with(['driver'])->get();
255
+ $query->whereIn('uuid', $this->selections);
256
+ }
257
+
258
+ return $query->get();
259
+ }
260
+
261
+ protected function yesNo($value): ?string
262
+ {
263
+ if ($value === null) {
264
+ return null;
265
+ }
266
+
267
+ return filter_var($value, FILTER_VALIDATE_BOOLEAN) ? 'Yes' : 'No';
268
+ }
269
+
270
+ protected function joinSkills($skills): ?string
271
+ {
272
+ if (empty($skills)) {
273
+ return null;
274
+ }
275
+
276
+ if (is_string($skills)) {
277
+ return $skills;
278
+ }
279
+
280
+ return collect($skills)->filter()->values()->join(', ');
281
+ }
282
+
283
+ protected function locationPart($location, string $part)
284
+ {
285
+ $location = Utils::castPoint($location);
286
+
287
+ if (!$location) {
288
+ return null;
289
+ }
290
+
291
+ if ($part === 'lat') {
292
+ return method_exists($location, 'getLat') ? $location->getLat() : data_get($location, 'latitude', data_get($location, 'lat'));
293
+ }
294
+
295
+ return method_exists($location, 'getLng') ? $location->getLng() : data_get($location, 'longitude', data_get($location, 'lng'));
296
+ }
297
+
298
+ protected function money($amount, ?string $currency = 'USD'): ?string
299
+ {
300
+ if ($amount === null || $amount === '') {
301
+ return null;
302
+ }
303
+
304
+ return Utils::moneyFormat($amount, $currency ?: 'USD');
305
+ }
306
+
307
+ protected function assignedOrdersCount(Vehicle $vehicle): int
308
+ {
309
+ return Order::where('vehicle_assigned_uuid', $vehicle->uuid)->count();
310
+ }
311
+
312
+ protected function currentOrderReference(Vehicle $vehicle): ?string
313
+ {
314
+ $order = data_get($vehicle, 'driver.currentOrder') ?? Order::where('vehicle_assigned_uuid', $vehicle->uuid)
315
+ ->whereNotIn('status', ['completed', 'canceled', 'cancelled'])
316
+ ->latest()
317
+ ->first();
318
+
319
+ return data_get($order, 'tracking') ?? data_get($order, 'public_id');
320
+ }
321
+
322
+ protected function columnLetter(int $index): string
323
+ {
324
+ $letter = '';
325
+
326
+ while ($index > 0) {
327
+ $index--;
328
+ $letter = chr(65 + ($index % 26)) . $letter;
329
+ $index = intdiv($index, 26);
64
330
  }
65
331
 
66
- return Vehicle::where('company_uuid', session('company'))->with(['driver'])->get();
332
+ return $letter;
67
333
  }
68
334
  }
@@ -25,10 +25,16 @@ class VendorExport implements FromCollection, WithHeadings, WithMapping, WithCol
25
25
  $vendor->public_id,
26
26
  $vendor->internal_id,
27
27
  $vendor->name,
28
+ $vendor->business_id,
28
29
  $vendor->address,
29
30
  $vendor->email,
31
+ $vendor->website_url,
30
32
  $vendor->phone,
33
+ $vendor->type,
34
+ $vendor->country,
35
+ $vendor->status,
31
36
  $vendor->created_at,
37
+ $vendor->updated_at,
32
38
  ];
33
39
  }
34
40
 
@@ -38,18 +44,25 @@ class VendorExport implements FromCollection, WithHeadings, WithMapping, WithCol
38
44
  'ID',
39
45
  'Internal ID',
40
46
  'Name',
47
+ 'Business ID',
41
48
  'Address',
42
49
  'Email',
50
+ 'Website URL',
43
51
  'Phone',
52
+ 'Type',
53
+ 'Country',
54
+ 'Status',
44
55
  'Date Created',
56
+ 'Date Updated',
45
57
  ];
46
58
  }
47
59
 
48
60
  public function columnFormats(): array
49
61
  {
50
62
  return [
51
- 'F' => '+#',
52
- 'G' => NumberFormat::FORMAT_DATE_DDMMYYYY,
63
+ 'H' => '+#',
64
+ 'L' => NumberFormat::FORMAT_DATE_DDMMYYYY,
65
+ 'M' => NumberFormat::FORMAT_DATE_DDMMYYYY,
53
66
  ];
54
67
  }
55
68
 
@@ -0,0 +1,92 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Exports;
4
+
5
+ use Fleetbase\FleetOps\Models\WorkOrder;
6
+ use Maatwebsite\Excel\Concerns\FromCollection;
7
+ use Maatwebsite\Excel\Concerns\ShouldAutoSize;
8
+ use Maatwebsite\Excel\Concerns\WithColumnFormatting;
9
+ use Maatwebsite\Excel\Concerns\WithHeadings;
10
+ use Maatwebsite\Excel\Concerns\WithMapping;
11
+ use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
12
+
13
+ class WorkOrderExport implements FromCollection, WithHeadings, WithMapping, WithColumnFormatting, ShouldAutoSize
14
+ {
15
+ protected array $selections = [];
16
+
17
+ public function __construct(array $selections = [])
18
+ {
19
+ $this->selections = $selections;
20
+ }
21
+
22
+ public function map($workOrder): array
23
+ {
24
+ return [
25
+ $workOrder->public_id,
26
+ $workOrder->code,
27
+ $workOrder->subject,
28
+ $workOrder->category,
29
+ $workOrder->status,
30
+ $workOrder->priority,
31
+ $workOrder->target_name,
32
+ $workOrder->assignee_name,
33
+ $workOrder->opened_at,
34
+ $workOrder->due_at,
35
+ $workOrder->closed_at,
36
+ $workOrder->completion_percentage,
37
+ $this->yesNo($workOrder->is_overdue),
38
+ $workOrder->days_until_due,
39
+ $workOrder->created_at,
40
+ $workOrder->updated_at,
41
+ ];
42
+ }
43
+
44
+ public function headings(): array
45
+ {
46
+ return [
47
+ 'ID',
48
+ 'Code',
49
+ 'Subject',
50
+ 'Category',
51
+ 'Status',
52
+ 'Priority',
53
+ 'Target',
54
+ 'Assignee',
55
+ 'Opened At',
56
+ 'Due At',
57
+ 'Closed At',
58
+ 'Completion Percentage',
59
+ 'Overdue',
60
+ 'Days Until Due',
61
+ 'Date Created',
62
+ 'Date Updated',
63
+ ];
64
+ }
65
+
66
+ public function columnFormats(): array
67
+ {
68
+ return [
69
+ 'I' => NumberFormat::FORMAT_DATE_DDMMYYYY,
70
+ 'J' => NumberFormat::FORMAT_DATE_DDMMYYYY,
71
+ 'K' => NumberFormat::FORMAT_DATE_DDMMYYYY,
72
+ 'O' => NumberFormat::FORMAT_DATE_DDMMYYYY,
73
+ 'P' => NumberFormat::FORMAT_DATE_DDMMYYYY,
74
+ ];
75
+ }
76
+
77
+ public function collection()
78
+ {
79
+ $query = WorkOrder::where('company_uuid', session('company'))->with(['target', 'assignee']);
80
+
81
+ if ($this->selections) {
82
+ $query->whereIn('uuid', $this->selections);
83
+ }
84
+
85
+ return $query->get();
86
+ }
87
+
88
+ protected function yesNo($value): string
89
+ {
90
+ return $value ? 'Yes' : 'No';
91
+ }
92
+ }
@@ -0,0 +1,176 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Http\Controllers\Api\v1\Concerns;
4
+
5
+ use Fleetbase\FleetOps\Models\Contact;
6
+ use Fleetbase\FleetOps\Models\Device;
7
+ use Fleetbase\FleetOps\Models\Driver;
8
+ use Fleetbase\FleetOps\Models\Equipment;
9
+ use Fleetbase\FleetOps\Models\FuelProviderConnection;
10
+ use Fleetbase\FleetOps\Models\FuelReport;
11
+ use Fleetbase\FleetOps\Models\Order;
12
+ use Fleetbase\FleetOps\Models\Part;
13
+ use Fleetbase\FleetOps\Models\Telematic;
14
+ use Fleetbase\FleetOps\Models\Vehicle;
15
+ use Fleetbase\FleetOps\Models\Vendor;
16
+ use Fleetbase\FleetOps\Models\Warranty;
17
+ use Fleetbase\FleetOps\Support\Utils;
18
+ use Fleetbase\Models\File;
19
+ use Illuminate\Database\Eloquent\Model;
20
+ use Illuminate\Database\Eloquent\ModelNotFoundException;
21
+ use Illuminate\Http\Request;
22
+ use Illuminate\Validation\ValidationException;
23
+
24
+ trait ResolvesFleetOpsApiResources
25
+ {
26
+ protected function resolveUuid(string $modelClass, ?string $id): ?string
27
+ {
28
+ if (empty($id)) {
29
+ return null;
30
+ }
31
+
32
+ return $this->resolveModel($modelClass, $id)->uuid;
33
+ }
34
+
35
+ protected function resolveModel(string $modelClass, string $id): Model
36
+ {
37
+ $instance = new $modelClass();
38
+ $query = $modelClass::query()->where(function ($query) use ($id, $instance) {
39
+ $query->whereRaw('0 = 1');
40
+
41
+ if (in_array('public_id', $instance->getFillable()) || method_exists($instance, 'getPublicIdType')) {
42
+ $query->orWhere('public_id', $id);
43
+ }
44
+
45
+ if (in_array('internal_id', $instance->getFillable())) {
46
+ $query->orWhere('internal_id', $id);
47
+ }
48
+ });
49
+
50
+ if (session('company') && $this->modelHasColumn($instance, 'company_uuid')) {
51
+ $query->where($instance->qualifyColumn('company_uuid'), session('company'));
52
+ }
53
+
54
+ $model = $query->first();
55
+ if ($model) {
56
+ return $model;
57
+ }
58
+
59
+ throw (new ModelNotFoundException())->setModel($modelClass, $id);
60
+ }
61
+
62
+ protected function resolveMorph(?string $type, ?string $id): array
63
+ {
64
+ if (empty($type) || empty($id)) {
65
+ return [null, null];
66
+ }
67
+
68
+ $modelClass = Utils::getMutationType($type);
69
+ $model = $this->resolveModel($modelClass, $id);
70
+
71
+ return [$modelClass, $model->uuid];
72
+ }
73
+
74
+ protected function rejectUuidIdentifiers(Request $request): void
75
+ {
76
+ $invalidKeys = array_unique(array_merge(
77
+ $this->collectUuidIdentifierKeys($request->query->all()),
78
+ $this->collectUuidIdentifierKeys($request->request->all())
79
+ ));
80
+
81
+ if (empty($invalidKeys)) {
82
+ return;
83
+ }
84
+
85
+ $messages = [];
86
+ foreach ($invalidKeys as $key) {
87
+ $messages[$key] = ['UUID identifiers are not accepted by the public API. Use public_id or internal_id values instead.'];
88
+ }
89
+
90
+ throw ValidationException::withMessages($messages);
91
+ }
92
+
93
+ protected function collectUuidIdentifierKeys(array $input, string $prefix = ''): array
94
+ {
95
+ $keys = [];
96
+
97
+ foreach ($input as $key => $value) {
98
+ $path = $prefix ? $prefix . '.' . $key : (string) $key;
99
+
100
+ if ($this->isUuidIdentifierKey((string) $key)) {
101
+ $keys[] = $path;
102
+ }
103
+
104
+ if (is_array($value)) {
105
+ $keys = array_merge($keys, $this->collectUuidIdentifierKeys($value, $path));
106
+ }
107
+ }
108
+
109
+ return $keys;
110
+ }
111
+
112
+ protected function isUuidIdentifierKey(string $key): bool
113
+ {
114
+ return preg_match('/(^uuid$|_uuid$|Uuid$|UUID$)/', $key) === 1;
115
+ }
116
+
117
+ protected function applyPublicIdRelation(array &$input, string $requestKey, string $column, string $modelClass, $request): void
118
+ {
119
+ if (!$request->exists($requestKey)) {
120
+ return;
121
+ }
122
+
123
+ $input[$column] = filled($request->input($requestKey))
124
+ ? $this->resolveUuid($modelClass, $request->input($requestKey))
125
+ : null;
126
+ }
127
+
128
+ protected function allowedMorphTypes(): array
129
+ {
130
+ return [
131
+ 'fleet-ops:vehicle' => Vehicle::class,
132
+ 'vehicle' => Vehicle::class,
133
+ Vehicle::class => Vehicle::class,
134
+ 'fleet-ops:driver' => Driver::class,
135
+ 'driver' => Driver::class,
136
+ Driver::class => Driver::class,
137
+ 'fleet-ops:equipment' => Equipment::class,
138
+ 'equipment' => Equipment::class,
139
+ Equipment::class => Equipment::class,
140
+ 'fleet-ops:part' => Part::class,
141
+ 'part' => Part::class,
142
+ Part::class => Part::class,
143
+ 'fleet-ops:vendor' => Vendor::class,
144
+ 'vendor' => Vendor::class,
145
+ Vendor::class => Vendor::class,
146
+ 'fleet-ops:contact' => Contact::class,
147
+ 'contact' => Contact::class,
148
+ Contact::class => Contact::class,
149
+ 'fleet-ops:device' => Device::class,
150
+ 'device' => Device::class,
151
+ Device::class => Device::class,
152
+ 'fleet-ops:telematic' => Telematic::class,
153
+ 'telematic' => Telematic::class,
154
+ Telematic::class => Telematic::class,
155
+ 'fleet-ops:warranty' => Warranty::class,
156
+ 'warranty' => Warranty::class,
157
+ Warranty::class => Warranty::class,
158
+ 'fleet-ops:fuel-report' => FuelReport::class,
159
+ 'fuel-report' => FuelReport::class,
160
+ FuelReport::class => FuelReport::class,
161
+ 'fleet-ops:fuel-provider-connection' => FuelProviderConnection::class,
162
+ 'fuel-provider-connection' => FuelProviderConnection::class,
163
+ FuelProviderConnection::class => FuelProviderConnection::class,
164
+ 'fleet-ops:order' => Order::class,
165
+ 'order' => Order::class,
166
+ Order::class => Order::class,
167
+ 'file' => File::class,
168
+ File::class => File::class,
169
+ ];
170
+ }
171
+
172
+ protected function modelHasColumn(Model $model, string $column): bool
173
+ {
174
+ return in_array($column, $model->getFillable()) || $column === $model->getKeyName();
175
+ }
176
+ }