@fleetbase/fleetops-engine 0.6.16 → 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 (49) 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_11_170800_add_company_index_to_routes_table.php +21 -0
  7. package/server/migrations/2025_08_28_054920_create_warranties_table.php +56 -0
  8. package/server/migrations/2025_08_28_054921_create_telematics_table.php +60 -0
  9. package/server/migrations/2025_08_28_054922_create_assets_table.php +94 -0
  10. package/server/migrations/2025_08_28_054925_create_devices_table.php +190 -0
  11. package/server/migrations/2025_08_28_054926_create_device_events_table.php +99 -0
  12. package/server/migrations/2025_08_28_054926_create_sensors_table.php +62 -0
  13. package/server/migrations/2025_08_28_054927_create_parts_table.php +73 -0
  14. package/server/migrations/2025_08_28_054929_create_equipments_table.php +58 -0
  15. package/server/migrations/2025_08_28_054930_create_work_orders_table.php +85 -0
  16. package/server/migrations/2025_08_28_054931_create_maintenances_table.php +79 -0
  17. package/server/migrations/2025_08_28_082002_update_vehicles_table_telematics.php +60 -0
  18. package/server/src/Http/Controllers/Api/v1/OrderController.php +19 -1
  19. package/server/src/Http/Controllers/Internal/v1/OrderController.php +31 -8
  20. package/server/src/Http/Resources/v1/Order.php +111 -60
  21. package/server/src/Models/Asset.php +548 -0
  22. package/server/src/Models/Contact.php +2 -0
  23. package/server/src/Models/Device.php +435 -0
  24. package/server/src/Models/DeviceEvent.php +501 -0
  25. package/server/src/Models/Driver.php +2 -0
  26. package/server/src/Models/Entity.php +27 -50
  27. package/server/src/Models/Equipment.php +483 -0
  28. package/server/src/Models/Fleet.php +2 -0
  29. package/server/src/Models/FuelReport.php +2 -0
  30. package/server/src/Models/Issue.php +2 -0
  31. package/server/src/Models/Maintenance.php +549 -0
  32. package/server/src/Models/Order.php +32 -112
  33. package/server/src/Models/OrderConfig.php +8 -0
  34. package/server/src/Models/Part.php +502 -0
  35. package/server/src/Models/Payload.php +101 -20
  36. package/server/src/Models/Place.php +10 -4
  37. package/server/src/Models/Sensor.php +510 -0
  38. package/server/src/Models/ServiceArea.php +1 -1
  39. package/server/src/Models/Telematic.php +336 -0
  40. package/server/src/Models/Vehicle.php +45 -1
  41. package/server/src/Models/VehicleDevice.php +1 -1
  42. package/server/src/Models/Vendor.php +2 -0
  43. package/server/src/Models/Warranty.php +413 -0
  44. package/server/src/Models/Waypoint.php +2 -0
  45. package/server/src/Models/WorkOrder.php +532 -0
  46. package/server/src/Support/Utils.php +5 -0
  47. package/server/src/Traits/HasTrackingNumber.php +64 -10
  48. package/server/src/Traits/Maintainable.php +307 -0
  49. package/server/src/Traits/PayloadAccessors.php +126 -0
@@ -0,0 +1,435 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Models;
4
+
5
+ use Fleetbase\Casts\Json;
6
+ use Fleetbase\Models\Model;
7
+ use Fleetbase\Models\User;
8
+ use Fleetbase\Traits\HasApiModelBehavior;
9
+ use Fleetbase\Traits\HasCustomFields;
10
+ use Fleetbase\Traits\HasMetaAttributes;
11
+ use Fleetbase\Traits\HasPublicId;
12
+ use Fleetbase\Traits\HasUuid;
13
+ use Fleetbase\Traits\Searchable;
14
+ use Fleetbase\Traits\TracksApiCredential;
15
+ use Illuminate\Database\Eloquent\Relations\BelongsTo;
16
+ use Illuminate\Database\Eloquent\Relations\HasMany;
17
+ use Illuminate\Database\Eloquent\Relations\MorphTo;
18
+ use Spatie\Activitylog\LogOptions;
19
+ use Spatie\Activitylog\Traits\LogsActivity;
20
+ use Spatie\Sluggable\HasSlug;
21
+ use Spatie\Sluggable\SlugOptions;
22
+
23
+ /**
24
+ * Class Device.
25
+ *
26
+ * Represents a physical device that can be mounted or carried, using a telematic
27
+ * for connectivity. Examples include dashcams, OBD devices, hardwired blackboxes, tablets.
28
+ */
29
+ class Device extends Model
30
+ {
31
+ use HasUuid;
32
+ use HasPublicId;
33
+ use TracksApiCredential;
34
+ use HasApiModelBehavior;
35
+ use HasSlug;
36
+ use LogsActivity;
37
+ use HasMetaAttributes;
38
+ use Searchable;
39
+ use HasCustomFields;
40
+
41
+ /**
42
+ * The database table used by the model.
43
+ *
44
+ * @var string
45
+ */
46
+ protected $table = 'devices';
47
+
48
+ /**
49
+ * The type of public Id to generate.
50
+ *
51
+ * @var string
52
+ */
53
+ protected $publicIdType = 'device';
54
+
55
+ /**
56
+ * The attributes that can be queried.
57
+ *
58
+ * @var array
59
+ */
60
+ protected $searchableColumns = ['name', 'model', 'serial_number', 'public_id'];
61
+
62
+ /**
63
+ * The attributes that can be used for filtering.
64
+ *
65
+ * @var array
66
+ */
67
+ protected $filterParams = ['status', 'warranty_uuid', 'attachable_type'];
68
+
69
+ /**
70
+ * The attributes that are mass assignable.
71
+ *
72
+ * @var array
73
+ */
74
+ protected $fillable = [
75
+ 'company_uuid',
76
+ 'telematic_uuid',
77
+ 'warranty_uuid',
78
+ 'device_type',
79
+ 'device_id',
80
+ 'device_provider',
81
+ 'device_name',
82
+ 'device_model',
83
+ 'device_location',
84
+ 'manufacturer',
85
+ 'serial_number',
86
+ 'installation_date',
87
+ 'last_maintenance_date',
88
+ 'meta',
89
+ 'data',
90
+ 'options',
91
+ 'online',
92
+ 'status',
93
+ 'data_frequency',
94
+ 'notes',
95
+ 'status',
96
+ 'last_online_at',
97
+ 'attachable_type',
98
+ 'attachable_uuid',
99
+ 'slug',
100
+ ];
101
+
102
+ /**
103
+ * Dynamic attributes that are appended to object.
104
+ *
105
+ * @var array
106
+ */
107
+ protected $appends = [
108
+ 'warranty_name',
109
+ 'telematic_name',
110
+ 'is_online',
111
+ 'attached_to_name',
112
+ 'connection_status',
113
+ ];
114
+
115
+ /**
116
+ * The attributes excluded from the model's JSON form.
117
+ *
118
+ * @var array
119
+ */
120
+ protected $hidden = ['warranty', 'telematic', 'attachable'];
121
+
122
+ /**
123
+ * The attributes that should be cast to native types.
124
+ *
125
+ * @var array
126
+ */
127
+ protected $casts = [
128
+ 'last_online_at' => 'datetime',
129
+ 'meta' => Json::class,
130
+ 'options' => Json::class,
131
+ ];
132
+
133
+ /**
134
+ * Properties which activity needs to be logged.
135
+ *
136
+ * @var array
137
+ */
138
+ protected static $logAttributes = '*';
139
+
140
+ /**
141
+ * Do not log empty changed.
142
+ *
143
+ * @var bool
144
+ */
145
+ protected static $submitEmptyLogs = false;
146
+
147
+ /**
148
+ * The name of the subject to log.
149
+ *
150
+ * @var string
151
+ */
152
+ protected static $logName = 'device';
153
+
154
+ /**
155
+ * Get the options for generating the slug.
156
+ */
157
+ public function getSlugOptions(): SlugOptions
158
+ {
159
+ return SlugOptions::create()
160
+ ->generateSlugsFrom(['name', 'serial_number'])
161
+ ->saveSlugsTo('slug');
162
+ }
163
+
164
+ /**
165
+ * Get the activity log options for the model.
166
+ */
167
+ public function getActivitylogOptions(): LogOptions
168
+ {
169
+ return LogOptions::defaults()->logAll();
170
+ }
171
+
172
+ public function telematic(): BelongsTo
173
+ {
174
+ return $this->belongsTo(Telematic::class, 'telematic_uuid', 'uuid');
175
+ }
176
+
177
+ public function warranty(): BelongsTo
178
+ {
179
+ return $this->belongsTo(Warranty::class, 'warranty_uuid', 'uuid');
180
+ }
181
+
182
+ public function createdBy(): BelongsTo
183
+ {
184
+ return $this->belongsTo(User::class, 'created_by_uuid', 'uuid');
185
+ }
186
+
187
+ public function updatedBy(): BelongsTo
188
+ {
189
+ return $this->belongsTo(User::class, 'updated_by_uuid', 'uuid');
190
+ }
191
+
192
+ public function attachable(): MorphTo
193
+ {
194
+ return $this->morphTo();
195
+ }
196
+
197
+ public function events(): HasMany
198
+ {
199
+ return $this->hasMany(DeviceEvent::class, 'device_uuid', 'uuid');
200
+ }
201
+
202
+ public function sensors(): HasMany
203
+ {
204
+ return $this->hasMany(Sensor::class, 'device_uuid', 'uuid');
205
+ }
206
+
207
+ /**
208
+ * Get the warranty name.
209
+ */
210
+ public function getWarrantyNameAttribute(): ?string
211
+ {
212
+ return $this->warranty?->name;
213
+ }
214
+
215
+ /**
216
+ * Get the telematic name.
217
+ */
218
+ public function getTelematicNameAttribute(): ?string
219
+ {
220
+ return $this->telematic?->name;
221
+ }
222
+
223
+ /**
224
+ * Check if the device is currently online.
225
+ */
226
+ public function getIsOnlineAttribute(): bool
227
+ {
228
+ if (!$this->last_online_at) {
229
+ return false;
230
+ }
231
+
232
+ // Consider online if last seen within 10 minutes
233
+ return $this->last_online_at->gt(now()->subMinutes(10));
234
+ }
235
+
236
+ /**
237
+ * Get the name of what the device is attached to.
238
+ */
239
+ public function getAttachedToNameAttribute(): ?string
240
+ {
241
+ if ($this->attachable) {
242
+ return $this->attachable->name ?? $this->attachable->display_name ?? null;
243
+ }
244
+
245
+ return null;
246
+ }
247
+
248
+ /**
249
+ * Get the connection status.
250
+ */
251
+ public function getConnectionStatusAttribute(): string
252
+ {
253
+ if (!$this->last_online_at) {
254
+ return 'never_connected';
255
+ }
256
+
257
+ $minutesOffline = $this->last_online_at->diffInMinutes(now());
258
+
259
+ if ($minutesOffline <= 10) {
260
+ return 'online';
261
+ } elseif ($minutesOffline <= 60) {
262
+ return 'recently_offline';
263
+ } elseif ($minutesOffline <= 1440) { // 24 hours
264
+ return 'offline';
265
+ } else {
266
+ return 'long_offline';
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Scope to get online devices.
272
+ *
273
+ * @param \Illuminate\Database\Eloquent\Builder $query
274
+ *
275
+ * @return \Illuminate\Database\Eloquent\Builder
276
+ */
277
+ public function scopeOnline($query)
278
+ {
279
+ return $query->where('last_online_at', '>=', now()->subMinutes(10));
280
+ }
281
+
282
+ /**
283
+ * Scope to get offline devices.
284
+ *
285
+ * @param \Illuminate\Database\Eloquent\Builder $query
286
+ *
287
+ * @return \Illuminate\Database\Eloquent\Builder
288
+ */
289
+ public function scopeOffline($query)
290
+ {
291
+ return $query->where(function ($q) {
292
+ $q->whereNull('last_online_at')
293
+ ->orWhere('last_online_at', '<', now()->subMinutes(10));
294
+ });
295
+ }
296
+
297
+ /**
298
+ * Scope to get devices attached to a specific type.
299
+ *
300
+ * @param \Illuminate\Database\Eloquent\Builder $query
301
+ *
302
+ * @return \Illuminate\Database\Eloquent\Builder
303
+ */
304
+ public function scopeAttachedTo($query, string $type)
305
+ {
306
+ return $query->where('attachable_type', $type);
307
+ }
308
+
309
+ /**
310
+ * Update the last online timestamp.
311
+ */
312
+ public function updateLastOnline(): bool
313
+ {
314
+ return $this->update(['last_online_at' => now()]);
315
+ }
316
+
317
+ /**
318
+ * Attach the device to an entity.
319
+ */
320
+ public function attachTo(Model $attachable): bool
321
+ {
322
+ $updated = $this->update([
323
+ 'attachable_type' => get_class($attachable),
324
+ 'attachable_uuid' => $attachable->uuid,
325
+ ]);
326
+
327
+ if ($updated) {
328
+ activity('device_attached')
329
+ ->performedOn($this)
330
+ ->withProperties([
331
+ 'attached_to_type' => get_class($attachable),
332
+ 'attached_to_uuid' => $attachable->uuid,
333
+ 'attached_to_name' => $attachable->name ?? $attachable->display_name ?? null,
334
+ ])
335
+ ->log('Device attached');
336
+ }
337
+
338
+ return $updated;
339
+ }
340
+
341
+ /**
342
+ * Detach the device from its current attachment.
343
+ */
344
+ public function detach(): bool
345
+ {
346
+ $oldAttachableType = $this->attachable_type;
347
+ $oldAttachableUuid = $this->attachable_uuid;
348
+
349
+ $updated = $this->update([
350
+ 'attachable_type' => null,
351
+ 'attachable_uuid' => null,
352
+ ]);
353
+
354
+ if ($updated) {
355
+ activity('device_detached')
356
+ ->performedOn($this)
357
+ ->withProperties([
358
+ 'previous_attached_to_type' => $oldAttachableType,
359
+ 'previous_attached_to_uuid' => $oldAttachableUuid,
360
+ ])
361
+ ->log('Device detached');
362
+ }
363
+
364
+ return $updated;
365
+ }
366
+
367
+ /**
368
+ * Check if the device supports a specific feature.
369
+ */
370
+ public function supportsFeature(string $feature): bool
371
+ {
372
+ $options = $this->options ?? [];
373
+ $features = $options['supported_features'] ?? [];
374
+
375
+ return in_array($feature, $features);
376
+ }
377
+
378
+ /**
379
+ * Get the device configuration.
380
+ */
381
+ public function getConfiguration(): array
382
+ {
383
+ return $this->options ?? [];
384
+ }
385
+
386
+ /**
387
+ * Update the device configuration.
388
+ */
389
+ public function updateConfiguration(array $config): bool
390
+ {
391
+ $currentOptions = $this->options ?? [];
392
+ $newOptions = array_merge($currentOptions, $config);
393
+
394
+ return $this->update(['options' => $newOptions]);
395
+ }
396
+
397
+ /**
398
+ * Send a command to the device via its telematic.
399
+ */
400
+ public function sendCommand(string $command, array $parameters = []): bool
401
+ {
402
+ if (!$this->telematic) {
403
+ return false;
404
+ }
405
+
406
+ // Log the command for the device
407
+ activity('device_command')
408
+ ->performedOn($this)
409
+ ->withProperties([
410
+ 'command' => $command,
411
+ 'parameters' => $parameters,
412
+ 'via_telematic' => $this->telematic->uuid,
413
+ 'timestamp' => now(),
414
+ ])
415
+ ->log("Command '{$command}' sent to device");
416
+
417
+ // Delegate to telematic
418
+ return $this->telematic->sendCommand($command, array_merge($parameters, [
419
+ 'target_device' => $this->uuid,
420
+ ]));
421
+ }
422
+
423
+ /**
424
+ * Get recent events for the device.
425
+ *
426
+ * @return \Illuminate\Database\Eloquent\Collection
427
+ */
428
+ public function getRecentEvents(int $limit = 10)
429
+ {
430
+ return $this->events()
431
+ ->orderBy('created_at', 'desc')
432
+ ->limit($limit)
433
+ ->get();
434
+ }
435
+ }