@fleetbase/fleetops-engine 0.6.17 → 0.6.18

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 (44) hide show
  1. package/addon/components/layout/fleet-ops-sidebar.hbs +25 -0
  2. package/addon/templates/virtual.hbs +3 -3
  3. package/composer.json +3 -2
  4. package/extension.json +1 -1
  5. package/package.json +1 -1
  6. package/server/migrations/2025_08_28_054920_create_warranties_table.php +56 -0
  7. package/server/migrations/2025_08_28_054921_create_telematics_table.php +60 -0
  8. package/server/migrations/2025_08_28_054922_create_assets_table.php +94 -0
  9. package/server/migrations/2025_08_28_054925_create_devices_table.php +190 -0
  10. package/server/migrations/2025_08_28_054926_create_device_events_table.php +99 -0
  11. package/server/migrations/2025_08_28_054926_create_sensors_table.php +62 -0
  12. package/server/migrations/2025_08_28_054927_create_parts_table.php +73 -0
  13. package/server/migrations/2025_08_28_054929_create_equipments_table.php +58 -0
  14. package/server/migrations/2025_08_28_054930_create_work_orders_table.php +85 -0
  15. package/server/migrations/2025_08_28_054931_create_maintenances_table.php +79 -0
  16. package/server/migrations/2025_08_28_082002_update_vehicles_table_telematics.php +60 -0
  17. package/server/src/Http/Controllers/Api/v1/OrderController.php +6 -1
  18. package/server/src/Http/Resources/v1/Order.php +111 -60
  19. package/server/src/Models/Asset.php +548 -0
  20. package/server/src/Models/Contact.php +2 -0
  21. package/server/src/Models/Device.php +435 -0
  22. package/server/src/Models/DeviceEvent.php +501 -0
  23. package/server/src/Models/Driver.php +2 -0
  24. package/server/src/Models/Entity.php +2 -0
  25. package/server/src/Models/Equipment.php +483 -0
  26. package/server/src/Models/Fleet.php +2 -0
  27. package/server/src/Models/FuelReport.php +2 -0
  28. package/server/src/Models/Issue.php +2 -0
  29. package/server/src/Models/Maintenance.php +549 -0
  30. package/server/src/Models/Order.php +32 -112
  31. package/server/src/Models/OrderConfig.php +8 -0
  32. package/server/src/Models/Part.php +502 -0
  33. package/server/src/Models/Payload.php +101 -20
  34. package/server/src/Models/Place.php +10 -4
  35. package/server/src/Models/Sensor.php +510 -0
  36. package/server/src/Models/ServiceArea.php +1 -1
  37. package/server/src/Models/Telematic.php +336 -0
  38. package/server/src/Models/Vehicle.php +45 -1
  39. package/server/src/Models/VehicleDevice.php +1 -1
  40. package/server/src/Models/Vendor.php +2 -0
  41. package/server/src/Models/Warranty.php +413 -0
  42. package/server/src/Models/WorkOrder.php +532 -0
  43. package/server/src/Support/Utils.php +5 -0
  44. package/server/src/Traits/Maintainable.php +307 -0
@@ -0,0 +1,307 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Traits;
4
+
5
+ use Fleetbase\FleetOps\Models\Maintenance;
6
+ use Illuminate\Database\Eloquent\Relations\MorphMany;
7
+
8
+ /**
9
+ * Trait Maintainable.
10
+ *
11
+ * Provides maintenance-related functionality for models that can be maintained.
12
+ * This trait can be used by Asset, Equipment, and other maintainable entities.
13
+ */
14
+ trait Maintainable
15
+ {
16
+ /**
17
+ * Get all maintenances for this maintainable entity.
18
+ */
19
+ public function maintenances(): MorphMany
20
+ {
21
+ return $this->morphMany(Maintenance::class, 'maintainable');
22
+ }
23
+
24
+ /**
25
+ * Get scheduled maintenances.
26
+ */
27
+ public function scheduledMaintenances(): MorphMany
28
+ {
29
+ return $this->maintenances()->where('status', 'scheduled');
30
+ }
31
+
32
+ /**
33
+ * Get completed maintenances.
34
+ */
35
+ public function completedMaintenances(): MorphMany
36
+ {
37
+ return $this->maintenances()->where('status', 'completed');
38
+ }
39
+
40
+ /**
41
+ * Get overdue maintenances.
42
+ */
43
+ public function overdueMaintenances(): MorphMany
44
+ {
45
+ return $this->maintenances()
46
+ ->where('status', 'scheduled')
47
+ ->where('scheduled_at', '<', now());
48
+ }
49
+
50
+ /**
51
+ * Get the last completed maintenance.
52
+ */
53
+ public function getLastMaintenanceAttribute(): ?Maintenance
54
+ {
55
+ return $this->completedMaintenances()
56
+ ->orderBy('completed_at', 'desc')
57
+ ->first();
58
+ }
59
+
60
+ /**
61
+ * Get the next scheduled maintenance.
62
+ */
63
+ public function getNextMaintenanceAttribute(): ?Maintenance
64
+ {
65
+ return $this->scheduledMaintenances()
66
+ ->orderBy('scheduled_at', 'asc')
67
+ ->first();
68
+ }
69
+
70
+ /**
71
+ * Check if the entity needs maintenance.
72
+ */
73
+ public function needsMaintenance(): bool
74
+ {
75
+ // Check if there's overdue maintenance
76
+ if ($this->overdueMaintenances()->exists()) {
77
+ return true;
78
+ }
79
+
80
+ // Check maintenance intervals based on usage metrics
81
+ return $this->checkMaintenanceIntervals();
82
+ }
83
+
84
+ /**
85
+ * Check maintenance intervals based on usage metrics.
86
+ */
87
+ protected function checkMaintenanceIntervals(): bool
88
+ {
89
+ $lastMaintenance = $this->last_maintenance;
90
+
91
+ if (!$lastMaintenance) {
92
+ // If no maintenance history, check against purchase/creation date
93
+ $baseDate = $this->purchased_at ?? $this->created_at;
94
+
95
+ return $this->checkIntervalsSinceDate($baseDate);
96
+ }
97
+
98
+ // Check intervals since last maintenance
99
+ return $this->checkIntervalsSinceDate($lastMaintenance->completed_at);
100
+ }
101
+
102
+ /**
103
+ * Check maintenance intervals since a specific date.
104
+ *
105
+ * @param \Carbon\Carbon $date
106
+ */
107
+ protected function checkIntervalsSinceDate($date): bool
108
+ {
109
+ $specs = $this->specs ?? [];
110
+ $meta = $this->meta ?? [];
111
+
112
+ // Check time-based intervals
113
+ $maintenanceIntervalDays = $specs['maintenance_interval_days'] ?? $meta['maintenance_interval_days'] ?? null;
114
+ if ($maintenanceIntervalDays && $date->diffInDays(now()) >= $maintenanceIntervalDays) {
115
+ return true;
116
+ }
117
+
118
+ // Check odometer-based intervals (for assets with odometer)
119
+ if (isset($this->odometer) && isset($specs['maintenance_interval_miles'])) {
120
+ $lastOdometer = $this->last_maintenance?->odometer ?? 0;
121
+ $milesSinceLastMaintenance = $this->odometer - $lastOdometer;
122
+ if ($milesSinceLastMaintenance >= $specs['maintenance_interval_miles']) {
123
+ return true;
124
+ }
125
+ }
126
+
127
+ // Check engine hours-based intervals (for assets with engine hours)
128
+ if (isset($this->engine_hours) && isset($specs['maintenance_interval_hours'])) {
129
+ $lastEngineHours = $this->last_maintenance?->engine_hours ?? 0;
130
+ $hoursSinceLastMaintenance = $this->engine_hours - $lastEngineHours;
131
+ if ($hoursSinceLastMaintenance >= $specs['maintenance_interval_hours']) {
132
+ return true;
133
+ }
134
+ }
135
+
136
+ return false;
137
+ }
138
+
139
+ /**
140
+ * Schedule maintenance for the entity.
141
+ */
142
+ public function scheduleMaintenance(string $type, \DateTime $scheduledAt, array $details = []): Maintenance
143
+ {
144
+ return Maintenance::create([
145
+ 'company_uuid' => $this->company_uuid,
146
+ 'maintainable_type' => static::class,
147
+ 'maintainable_uuid' => $this->uuid,
148
+ 'type' => $type,
149
+ 'status' => 'scheduled',
150
+ 'scheduled_at' => $scheduledAt,
151
+ 'odometer' => $this->odometer ?? null,
152
+ 'engine_hours' => $this->engine_hours ?? null,
153
+ 'summary' => $details['summary'] ?? null,
154
+ 'notes' => $details['notes'] ?? null,
155
+ 'priority' => $details['priority'] ?? 'medium',
156
+ 'created_by_uuid' => auth()->id(),
157
+ ]);
158
+ }
159
+
160
+ /**
161
+ * Get maintenance cost for a specific period.
162
+ */
163
+ public function getMaintenanceCost(int $days = 365): float
164
+ {
165
+ $startDate = now()->subDays($days);
166
+
167
+ return $this->completedMaintenances()
168
+ ->where('completed_at', '>=', $startDate)
169
+ ->sum('total_cost') ?? 0;
170
+ }
171
+
172
+ /**
173
+ * Get maintenance frequency (maintenances per year).
174
+ */
175
+ public function getMaintenanceFrequency(int $days = 365): float
176
+ {
177
+ $startDate = now()->subDays($days);
178
+ $maintenanceCount = $this->completedMaintenances()
179
+ ->where('completed_at', '>=', $startDate)
180
+ ->count();
181
+
182
+ return ($maintenanceCount / $days) * 365;
183
+ }
184
+
185
+ /**
186
+ * Get average maintenance duration in hours.
187
+ */
188
+ public function getAverageMaintenanceDuration(int $days = 365): ?float
189
+ {
190
+ $startDate = now()->subDays($days);
191
+ $maintenances = $this->completedMaintenances()
192
+ ->where('completed_at', '>=', $startDate)
193
+ ->whereNotNull('started_at')
194
+ ->whereNotNull('completed_at')
195
+ ->get();
196
+
197
+ if ($maintenances->isEmpty()) {
198
+ return null;
199
+ }
200
+
201
+ $totalHours = $maintenances->sum(function ($maintenance) {
202
+ return $maintenance->started_at->diffInHours($maintenance->completed_at);
203
+ });
204
+
205
+ return $totalHours / $maintenances->count();
206
+ }
207
+
208
+ /**
209
+ * Get maintenance efficiency rating.
210
+ */
211
+ public function getMaintenanceEfficiency(int $days = 365): ?float
212
+ {
213
+ $startDate = now()->subDays($days);
214
+ $maintenances = $this->completedMaintenances()
215
+ ->where('completed_at', '>=', $startDate)
216
+ ->get();
217
+
218
+ if ($maintenances->isEmpty()) {
219
+ return null;
220
+ }
221
+
222
+ $onTimeCount = $maintenances->filter(function ($maintenance) {
223
+ return $maintenance->wasCompletedOnTime();
224
+ })->count();
225
+
226
+ return ($onTimeCount / $maintenances->count()) * 100;
227
+ }
228
+
229
+ /**
230
+ * Get upcoming maintenance due dates.
231
+ *
232
+ * @return \Illuminate\Database\Eloquent\Collection
233
+ */
234
+ public function getUpcomingMaintenance(int $days = 30)
235
+ {
236
+ $endDate = now()->addDays($days);
237
+
238
+ return $this->scheduledMaintenances()
239
+ ->where('scheduled_at', '<=', $endDate)
240
+ ->orderBy('scheduled_at', 'asc')
241
+ ->get();
242
+ }
243
+
244
+ /**
245
+ * Create preventive maintenance schedule.
246
+ */
247
+ public function createPreventiveMaintenanceSchedule(array $intervals = []): array
248
+ {
249
+ $schedule = [];
250
+ $specs = $this->specs ?? [];
251
+ $defaultIntervals = $specs['maintenance_intervals'] ?? [];
252
+
253
+ $intervals = array_merge($defaultIntervals, $intervals);
254
+
255
+ foreach ($intervals as $type => $interval) {
256
+ $lastMaintenance = $this->completedMaintenances()
257
+ ->where('type', $type)
258
+ ->orderBy('completed_at', 'desc')
259
+ ->first();
260
+
261
+ $baseDate = $lastMaintenance?->completed_at ?? $this->created_at;
262
+ $nextDue = $baseDate->copy()->addDays($interval['days'] ?? 365);
263
+
264
+ if ($nextDue->isFuture()) {
265
+ $schedule[] = [
266
+ 'type' => $type,
267
+ 'due_date' => $nextDue,
268
+ 'interval_days' => $interval['days'] ?? 365,
269
+ 'priority' => $interval['priority'] ?? 'medium',
270
+ 'description' => $interval['description'] ?? "Scheduled {$type} maintenance",
271
+ ];
272
+ }
273
+ }
274
+
275
+ return $schedule;
276
+ }
277
+
278
+ /**
279
+ * Get maintenance history summary.
280
+ */
281
+ public function getMaintenanceHistorySummary(int $days = 365): array
282
+ {
283
+ $startDate = now()->subDays($days);
284
+ $maintenances = $this->maintenances()
285
+ ->where('created_at', '>=', $startDate)
286
+ ->get();
287
+
288
+ $completed = $maintenances->where('status', 'completed');
289
+ $scheduled = $maintenances->where('status', 'scheduled');
290
+ $overdue = $scheduled->filter(function ($maintenance) {
291
+ return $maintenance->scheduled_at->isPast();
292
+ });
293
+
294
+ return [
295
+ 'total_maintenances' => $maintenances->count(),
296
+ 'completed_count' => $completed->count(),
297
+ 'scheduled_count' => $scheduled->count(),
298
+ 'overdue_count' => $overdue->count(),
299
+ 'total_cost' => $completed->sum('total_cost'),
300
+ 'average_cost' => $completed->avg('total_cost'),
301
+ 'total_downtime_hours' => $completed->sum('duration_hours'),
302
+ 'average_duration_hours' => $completed->avg('duration_hours'),
303
+ 'on_time_percentage' => $this->getMaintenanceEfficiency($days),
304
+ 'most_common_type' => $completed->groupBy('type')->sortByDesc->count()->keys()->first(),
305
+ ];
306
+ }
307
+ }