@fleetbase/fleetops-engine 0.6.19 → 0.6.21
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.
- package/addon/components/custom-entity/form.hbs +14 -14
- package/addon/components/device/details.hbs +92 -43
- package/addon/components/device/form.hbs +108 -60
- package/addon/components/device/form.js +36 -8
- package/addon/components/device/panel-header.hbs +32 -0
- package/addon/components/device/panel-header.js +3 -0
- package/addon/components/driver/form.hbs +1 -1
- package/addon/components/driver/form.js +49 -47
- package/addon/components/entity/form.hbs +7 -5
- package/addon/components/layout/fleet-ops-sidebar.js +12 -12
- package/addon/components/map/drawer/device-event-listing.hbs +58 -0
- package/addon/components/map/drawer/device-event-listing.js +181 -0
- package/addon/components/map/drawer/position-listing.hbs +84 -0
- package/addon/components/map/drawer/position-listing.js +289 -0
- package/addon/components/map/drawer.js +2 -0
- package/addon/components/map/leaflet-live-map.hbs +7 -2
- package/addon/components/order/details/payload.hbs +6 -4
- package/addon/components/order/details/payload.js +2 -0
- package/addon/components/order/kanban.hbs +12 -10
- package/addon/components/order/kanban.js +27 -3
- package/addon/components/order-config-manager/custom-fields.js +1 -1
- package/addon/components/positions-replay.hbs +333 -0
- package/addon/components/positions-replay.js +372 -0
- package/addon/components/sensor/details.hbs +64 -38
- package/addon/components/sensor/form.hbs +112 -63
- package/addon/components/sensor/form.js +36 -24
- package/addon/components/sensor/panel-header.hbs +32 -0
- package/addon/components/sensor/panel-header.js +3 -0
- package/addon/components/telematic/details.hbs +40 -16
- package/addon/components/telematic/form.hbs +63 -64
- package/addon/components/telematic/form.js +73 -4
- package/addon/components/vehicle/card.hbs +1 -1
- package/addon/controllers/analytics/reports/index/edit.js +1 -1
- package/addon/controllers/connectivity/devices/index/details.js +22 -1
- package/addon/controllers/connectivity/devices/index/edit.js +66 -1
- package/addon/controllers/connectivity/devices/index.js +51 -9
- package/addon/controllers/connectivity/events/index.js +65 -16
- package/addon/controllers/connectivity/sensors/index/details.js +22 -1
- package/addon/controllers/connectivity/sensors/index/edit.js +66 -1
- package/addon/controllers/connectivity/sensors/index.js +66 -6
- package/addon/controllers/connectivity/telematics/index/details.js +22 -1
- package/addon/controllers/connectivity/telematics/index/edit.js +66 -1
- package/addon/controllers/connectivity/telematics/index.js +20 -11
- package/addon/controllers/management/fleets/index/details.js +26 -21
- package/addon/controllers/management/fleets/index/edit.js +9 -6
- package/addon/controllers/management/vehicles/index/details.js +21 -13
- package/addon/controllers/operations/orders/index/new.js +4 -2
- package/addon/controllers/operations/orders/index.js +50 -45
- package/addon/controllers/settings/custom-fields.js +6 -0
- package/addon/helpers/get-fleet-ops-option-label.js +11 -0
- package/addon/routes/connectivity/devices/index/details.js +27 -1
- package/addon/routes/connectivity/devices/index/edit.js +27 -1
- package/addon/routes/connectivity/sensors/index/details.js +27 -1
- package/addon/routes/connectivity/sensors/index/edit.js +27 -1
- package/addon/routes/connectivity/telematics/index/details.js +27 -1
- package/addon/routes/connectivity/telematics/index/edit.js +27 -1
- package/addon/routes/management/vehicles/index/details/positions.js +3 -0
- package/addon/routes/operations/orders/index.js +0 -3
- package/addon/routes.js +1 -0
- package/addon/services/movement-tracker.js +81 -30
- package/addon/services/order-creation.js +4 -8
- package/addon/services/order-validation.js +3 -3
- package/addon/styles/fleetops-engine.css +192 -0
- package/addon/templates/connectivity/devices/index/details/index.hbs +2 -2
- package/addon/templates/connectivity/devices/index/details.hbs +15 -2
- package/addon/templates/connectivity/devices/index/edit.hbs +1 -1
- package/addon/templates/connectivity/events/index.hbs +1 -1
- package/addon/templates/connectivity/sensors/index/details/index.hbs +2 -2
- package/addon/templates/connectivity/sensors/index/details.hbs +15 -2
- package/addon/templates/connectivity/sensors/index/edit.hbs +1 -1
- package/addon/templates/connectivity/telematics/index/details/index.hbs +2 -2
- package/addon/templates/connectivity/telematics/index/details.hbs +14 -2
- package/addon/templates/connectivity/telematics/index/edit.hbs +1 -1
- package/addon/templates/management/vehicles/index/details/positions.hbs +1 -0
- package/addon/templates/operations/orders/index.hbs +26 -2
- package/addon/utils/fleet-ops-options.js +95 -0
- package/addon/utils/setup-customer-portal.js +7 -0
- package/app/components/device/panel-header.js +1 -0
- package/app/components/map/drawer/device-event-listing.js +1 -0
- package/app/components/map/drawer/position-listing.js +1 -0
- package/app/components/positions-replay.js +1 -0
- package/app/components/sensor/panel-header.js +1 -0
- package/app/helpers/get-fleet-ops-option-label.js +1 -0
- package/app/routes/management/vehicles/index/details/positions.js +1 -0
- package/app/templates/management/vehicles/index/details/positions.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +4 -4
- package/server/config/telematics.php +111 -0
- package/server/migrations/2025_10_27_000001_add_telematics_integration_fields.php +70 -0
- package/server/migrations/2025_10_27_171322_fix_device_column_names.php +107 -0
- package/server/migrations/2025_10_27_203023_add_company_uuid_to_device_events_table.php +28 -0
- package/server/src/Console/Commands/ReplayVehicleLocations.php +225 -0
- package/server/src/Contracts/TelematicProviderDescriptor.php +72 -0
- package/server/src/Contracts/TelematicProviderInterface.php +119 -0
- package/server/src/Exceptions/TelematicProviderException.php +14 -0
- package/server/src/Exceptions/TelematicRateLimitExceededException.php +12 -0
- package/server/src/Http/Controllers/Api/v1/DriverController.php +24 -14
- package/server/src/Http/Controllers/Api/v1/VehicleController.php +27 -7
- package/server/src/Http/Controllers/Internal/v1/DeviceController.php +22 -0
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +50 -68
- package/server/src/Http/Controllers/Internal/v1/PositionController.php +240 -0
- package/server/src/Http/Controllers/Internal/v1/SensorController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/TelematicController.php +141 -0
- package/server/src/Http/Controllers/Internal/v1/TelematicWebhookController.php +170 -0
- package/server/src/Http/Filter/DeviceEventFilter.php +68 -0
- package/server/src/Http/Filter/PositionFilter.php +35 -0
- package/server/src/Http/Resources/v1/Position.php +44 -0
- package/server/src/Jobs/ReplayPositions.php +64 -0
- package/server/src/Jobs/SendPositionReplay.php +65 -0
- package/server/src/Jobs/SyncTelematicDevicesJob.php +106 -0
- package/server/src/Jobs/TestTelematicConnectionJob.php +102 -0
- package/server/src/Models/Device.php +72 -10
- package/server/src/Models/DeviceEvent.php +7 -0
- package/server/src/Models/Driver.php +28 -1
- package/server/src/Models/Payload.php +11 -3
- package/server/src/Models/Place.php +9 -2
- package/server/src/Models/Position.php +17 -17
- package/server/src/Models/Sensor.php +78 -13
- package/server/src/Models/Telematic.php +116 -6
- package/server/src/Models/Vehicle.php +104 -1
- package/server/src/Providers/FleetOpsServiceProvider.php +2 -0
- package/server/src/Support/Telematics/Providers/AbstractProvider.php +151 -0
- package/server/src/Support/Telematics/Providers/FlespiProvider.php +182 -0
- package/server/src/Support/Telematics/Providers/GeotabProvider.php +181 -0
- package/server/src/Support/Telematics/Providers/SamsaraProvider.php +177 -0
- package/server/src/Support/Telematics/TelematicProviderRegistry.php +147 -0
- package/server/src/Support/Telematics/TelematicService.php +223 -0
- package/server/src/Support/Utils.php +1 -1
- package/server/src/routes.php +12 -1
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Models;
|
|
4
4
|
|
|
5
5
|
use Fleetbase\Casts\Json;
|
|
6
|
+
use Fleetbase\FleetOps\Casts\Point;
|
|
7
|
+
use Fleetbase\LaravelMysqlSpatial\Eloquent\SpatialTrait;
|
|
8
|
+
use Fleetbase\LaravelMysqlSpatial\Types\Point as SpatialPoint;
|
|
9
|
+
use Fleetbase\Models\File;
|
|
6
10
|
use Fleetbase\Models\Model;
|
|
7
11
|
use Fleetbase\Models\User;
|
|
8
12
|
use Fleetbase\Traits\HasApiModelBehavior;
|
|
@@ -15,6 +19,8 @@ use Fleetbase\Traits\TracksApiCredential;
|
|
|
15
19
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
16
20
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
17
21
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
|
22
|
+
use Illuminate\Support\Arr;
|
|
23
|
+
use Illuminate\Support\Str;
|
|
18
24
|
use Spatie\Activitylog\LogOptions;
|
|
19
25
|
use Spatie\Activitylog\Traits\LogsActivity;
|
|
20
26
|
use Spatie\Sluggable\HasSlug;
|
|
@@ -37,6 +43,7 @@ class Device extends Model
|
|
|
37
43
|
use HasMetaAttributes;
|
|
38
44
|
use Searchable;
|
|
39
45
|
use HasCustomFields;
|
|
46
|
+
use SpatialTrait;
|
|
40
47
|
|
|
41
48
|
/**
|
|
42
49
|
* The database table used by the model.
|
|
@@ -57,7 +64,7 @@ class Device extends Model
|
|
|
57
64
|
*
|
|
58
65
|
* @var array
|
|
59
66
|
*/
|
|
60
|
-
protected $searchableColumns = ['name', 'model', 'serial_number', 'public_id'];
|
|
67
|
+
protected $searchableColumns = ['name', 'model', 'serial_number', 'manufacturer', 'public_id'];
|
|
61
68
|
|
|
62
69
|
/**
|
|
63
70
|
* The attributes that can be used for filtering.
|
|
@@ -75,14 +82,20 @@ class Device extends Model
|
|
|
75
82
|
'company_uuid',
|
|
76
83
|
'telematic_uuid',
|
|
77
84
|
'warranty_uuid',
|
|
78
|
-
'
|
|
85
|
+
'photo_uuid',
|
|
86
|
+
'type',
|
|
79
87
|
'device_id',
|
|
80
|
-
'
|
|
81
|
-
'
|
|
82
|
-
'
|
|
83
|
-
'
|
|
88
|
+
'internal_id',
|
|
89
|
+
'imei',
|
|
90
|
+
'imsi',
|
|
91
|
+
'firmware_version',
|
|
92
|
+
'provider',
|
|
93
|
+
'name',
|
|
94
|
+
'model',
|
|
95
|
+
'location',
|
|
84
96
|
'manufacturer',
|
|
85
97
|
'serial_number',
|
|
98
|
+
'last_position',
|
|
86
99
|
'installation_date',
|
|
87
100
|
'last_maintenance_date',
|
|
88
101
|
'meta',
|
|
@@ -110,6 +123,7 @@ class Device extends Model
|
|
|
110
123
|
'is_online',
|
|
111
124
|
'attached_to_name',
|
|
112
125
|
'connection_status',
|
|
126
|
+
'photo_url',
|
|
113
127
|
];
|
|
114
128
|
|
|
115
129
|
/**
|
|
@@ -117,7 +131,14 @@ class Device extends Model
|
|
|
117
131
|
*
|
|
118
132
|
* @var array
|
|
119
133
|
*/
|
|
120
|
-
protected $hidden = [
|
|
134
|
+
protected $hidden = [];
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* The attributes that are spatial columns.
|
|
138
|
+
*
|
|
139
|
+
* @var array
|
|
140
|
+
*/
|
|
141
|
+
protected $spatialFields = ['last_position'];
|
|
121
142
|
|
|
122
143
|
/**
|
|
123
144
|
* The attributes that should be cast to native types.
|
|
@@ -125,9 +146,10 @@ class Device extends Model
|
|
|
125
146
|
* @var array
|
|
126
147
|
*/
|
|
127
148
|
protected $casts = [
|
|
128
|
-
'last_online_at'
|
|
129
|
-
'
|
|
130
|
-
'
|
|
149
|
+
'last_online_at' => 'datetime',
|
|
150
|
+
'last_position' => Point::class,
|
|
151
|
+
'meta' => Json::class,
|
|
152
|
+
'options' => Json::class,
|
|
131
153
|
];
|
|
132
154
|
|
|
133
155
|
/**
|
|
@@ -204,6 +226,21 @@ class Device extends Model
|
|
|
204
226
|
return $this->hasMany(Sensor::class, 'device_uuid', 'uuid');
|
|
205
227
|
}
|
|
206
228
|
|
|
229
|
+
public function photo(): BelongsTo
|
|
230
|
+
{
|
|
231
|
+
return $this->belongsTo(File::class);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Get photo URL attribute.
|
|
236
|
+
*
|
|
237
|
+
* @return string
|
|
238
|
+
*/
|
|
239
|
+
public function getPhotoUrlAttribute()
|
|
240
|
+
{
|
|
241
|
+
return data_get($this, 'photo.url', 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/image-file-icon.png');
|
|
242
|
+
}
|
|
243
|
+
|
|
207
244
|
/**
|
|
208
245
|
* Get the warranty name.
|
|
209
246
|
*/
|
|
@@ -432,4 +469,29 @@ class Device extends Model
|
|
|
432
469
|
->limit($limit)
|
|
433
470
|
->get();
|
|
434
471
|
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Creates a new position for the vehicle.
|
|
475
|
+
*/
|
|
476
|
+
public function createPosition(array $attributes = [], Model|string|null $destination = null): ?Position
|
|
477
|
+
{
|
|
478
|
+
if (!isset($attributes['coordinates']) && isset($attributes['location'])) {
|
|
479
|
+
$attributes['coordinates'] = $attributes['location'];
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (!isset($attributes['coordinates']) && isset($attributes['latitude']) && isset($attributes['longitude'])) {
|
|
483
|
+
$attributes['coordinates'] = new SpatialPoint($attributes['latitude'], $attributes['longitude']);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// handle destination if set
|
|
487
|
+
$destinationUuid = Str::isUuid($destination) ? $destination : data_get($destination, 'uuid');
|
|
488
|
+
|
|
489
|
+
return Position::create([
|
|
490
|
+
...Arr::only($attributes, ['coordinates', 'heading', 'bearing', 'speed', 'altitude', 'order_uuid']),
|
|
491
|
+
'subject_uuid' => $this->uuid,
|
|
492
|
+
'subject_type' => $this->getMorphClass(),
|
|
493
|
+
'company_uuid' => $this->company_uuid,
|
|
494
|
+
'destination_uuid' => $destinationUuid,
|
|
495
|
+
]);
|
|
496
|
+
}
|
|
435
497
|
}
|
|
@@ -4,6 +4,7 @@ namespace Fleetbase\FleetOps\Models;
|
|
|
4
4
|
|
|
5
5
|
use Fleetbase\Casts\Json;
|
|
6
6
|
use Fleetbase\Models\Alert;
|
|
7
|
+
use Fleetbase\Models\Company;
|
|
7
8
|
use Fleetbase\Models\Model;
|
|
8
9
|
use Fleetbase\Models\User;
|
|
9
10
|
use Fleetbase\Traits\HasApiModelBehavior;
|
|
@@ -67,6 +68,7 @@ class DeviceEvent extends Model
|
|
|
67
68
|
* @var array
|
|
68
69
|
*/
|
|
69
70
|
protected $fillable = [
|
|
71
|
+
'company_uuid',
|
|
70
72
|
'device_uuid',
|
|
71
73
|
'payload',
|
|
72
74
|
'meta',
|
|
@@ -143,6 +145,11 @@ class DeviceEvent extends Model
|
|
|
143
145
|
return LogOptions::defaults()->logAll();
|
|
144
146
|
}
|
|
145
147
|
|
|
148
|
+
public function company(): BelongsTo
|
|
149
|
+
{
|
|
150
|
+
return $this->belongsTo(Company::class, 'company_uuid', 'uuid');
|
|
151
|
+
}
|
|
152
|
+
|
|
146
153
|
public function device(): BelongsTo
|
|
147
154
|
{
|
|
148
155
|
return $this->belongsTo(Device::class, 'device_uuid', 'uuid');
|
|
@@ -8,6 +8,7 @@ use Fleetbase\FleetOps\Scopes\DriverScope;
|
|
|
8
8
|
use Fleetbase\FleetOps\Support\Utils;
|
|
9
9
|
use Fleetbase\FleetOps\Support\Utils as FleetOpsUtils;
|
|
10
10
|
use Fleetbase\LaravelMysqlSpatial\Eloquent\SpatialTrait;
|
|
11
|
+
use Fleetbase\LaravelMysqlSpatial\Types\Point as SpatialPoint;
|
|
11
12
|
use Fleetbase\Models\File;
|
|
12
13
|
use Fleetbase\Models\Model;
|
|
13
14
|
use Fleetbase\Models\User;
|
|
@@ -24,6 +25,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
|
24
25
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
25
26
|
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
|
26
27
|
use Illuminate\Notifications\Notifiable;
|
|
28
|
+
use Illuminate\Support\Arr;
|
|
27
29
|
use Illuminate\Support\Collection;
|
|
28
30
|
use Illuminate\Support\Facades\DB;
|
|
29
31
|
use Illuminate\Support\Str;
|
|
@@ -645,7 +647,7 @@ class Driver extends Model
|
|
|
645
647
|
$positionData = [
|
|
646
648
|
'company_uuid' => session('company', $this->company_uuid),
|
|
647
649
|
'subject_uuid' => $this->uuid,
|
|
648
|
-
'subject_type' =>
|
|
650
|
+
'subject_type' => $this->getMorphClass(),
|
|
649
651
|
'coordinates' => $this->location,
|
|
650
652
|
'altitude' => $this->altitude,
|
|
651
653
|
'heading' => $this->heading,
|
|
@@ -661,6 +663,31 @@ class Driver extends Model
|
|
|
661
663
|
return ($isFirstPosition || $isPast50Meters) ? Position::create($positionData) : null;
|
|
662
664
|
}
|
|
663
665
|
|
|
666
|
+
/**
|
|
667
|
+
* Creates a new position for the vehicle.
|
|
668
|
+
*/
|
|
669
|
+
public function createPosition(array $attributes = [], Model|string|null $destination = null): ?Position
|
|
670
|
+
{
|
|
671
|
+
if (!isset($attributes['coordinates']) && isset($attributes['location'])) {
|
|
672
|
+
$attributes['coordinates'] = $attributes['location'];
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
if (!isset($attributes['coordinates']) && isset($attributes['latitude']) && isset($attributes['longitude'])) {
|
|
676
|
+
$attributes['coordinates'] = new SpatialPoint($attributes['latitude'], $attributes['longitude']);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// handle destination if set
|
|
680
|
+
$destinationUuid = Str::isUuid($destination) ? $destination : data_get($destination, 'uuid');
|
|
681
|
+
|
|
682
|
+
return Position::create([
|
|
683
|
+
...Arr::only($attributes, ['coordinates', 'heading', 'bearing', 'speed', 'altitude', 'order_uuid']),
|
|
684
|
+
'subject_uuid' => $this->uuid,
|
|
685
|
+
'subject_type' => $this->getMorphClass(),
|
|
686
|
+
'company_uuid' => $this->company_uuid,
|
|
687
|
+
'destination_uuid' => $destinationUuid,
|
|
688
|
+
]);
|
|
689
|
+
}
|
|
690
|
+
|
|
664
691
|
/**
|
|
665
692
|
* Get the user relationship from the driver.
|
|
666
693
|
*/
|
|
@@ -368,7 +368,15 @@ class Payload extends Model
|
|
|
368
368
|
) {
|
|
369
369
|
$placeUuid = $attributes['place_uuid'];
|
|
370
370
|
|
|
371
|
-
// Path 2: public_id under "
|
|
371
|
+
// Path 2: public_id under "uuid" -> resolve to uuid
|
|
372
|
+
} elseif (
|
|
373
|
+
is_array($attributes)
|
|
374
|
+
&& isset($attributes['uuid'])
|
|
375
|
+
&& ($resolvedUuid = Place::where('uuid', $attributes['uuid'])->value('uuid'))
|
|
376
|
+
) {
|
|
377
|
+
$placeUuid = $resolvedUuid;
|
|
378
|
+
|
|
379
|
+
// Path 3: public_id under "id" -> resolve to uuid
|
|
372
380
|
} elseif (
|
|
373
381
|
is_array($attributes)
|
|
374
382
|
&& isset($attributes['id'])
|
|
@@ -376,7 +384,7 @@ class Payload extends Model
|
|
|
376
384
|
) {
|
|
377
385
|
$placeUuid = $resolvedUuid;
|
|
378
386
|
|
|
379
|
-
// Path
|
|
387
|
+
// Path 4: create from mixed payload
|
|
380
388
|
} else {
|
|
381
389
|
$place = Place::createFromMixed($attributes);
|
|
382
390
|
|
|
@@ -420,7 +428,7 @@ class Payload extends Model
|
|
|
420
428
|
// -------- Upsert Waypoint --------
|
|
421
429
|
// Uniqueness: payload + place + order for deterministic row per position.
|
|
422
430
|
$unique = [
|
|
423
|
-
'payload_uuid' => $this->
|
|
431
|
+
'payload_uuid' => $this->uuid,
|
|
424
432
|
'place_uuid' => $placeUuid,
|
|
425
433
|
'order' => $index,
|
|
426
434
|
];
|
|
@@ -362,7 +362,12 @@ class Place extends Model
|
|
|
362
362
|
$results = \Geocoder\Laravel\Facades\Geocoder::geocode($address)->get();
|
|
363
363
|
|
|
364
364
|
if ($results->isEmpty() || !$results->first()) {
|
|
365
|
-
|
|
365
|
+
$place = (new static())->newInstance(['street1' => $address, 'location' => new SpatialPoint(0, 0)]);
|
|
366
|
+
if ($saveInstance) {
|
|
367
|
+
$place->save();
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return $place;
|
|
366
371
|
}
|
|
367
372
|
|
|
368
373
|
return static::createFromGoogleAddress($results->first(), $saveInstance);
|
|
@@ -550,8 +555,10 @@ class Place extends Model
|
|
|
550
555
|
}
|
|
551
556
|
|
|
552
557
|
// If has $attributes['address']
|
|
558
|
+
$address = $place['address'];
|
|
553
559
|
if (!empty($place['address'])) {
|
|
554
|
-
return static::createFromGeocodingLookup($place['address'], $saveInstance);
|
|
560
|
+
// return static::createFromGeocodingLookup($place['address'], $saveInstance);
|
|
561
|
+
return static::create(array_merge($place, static::getValuesFromGeocodingLookup($address)));
|
|
555
562
|
}
|
|
556
563
|
|
|
557
564
|
// Perform google lookup to fill address
|
|
@@ -7,6 +7,8 @@ use Fleetbase\Models\Model;
|
|
|
7
7
|
use Fleetbase\Traits\HasApiModelBehavior;
|
|
8
8
|
use Fleetbase\Traits\HasUuid;
|
|
9
9
|
use Fleetbase\Traits\TracksApiCredential;
|
|
10
|
+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
11
|
+
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
|
10
12
|
|
|
11
13
|
class Position extends Model
|
|
12
14
|
{
|
|
@@ -48,7 +50,7 @@ class Position extends Model
|
|
|
48
50
|
*
|
|
49
51
|
* @var array
|
|
50
52
|
*/
|
|
51
|
-
protected $appends = [];
|
|
53
|
+
protected $appends = ['latitude', 'longitude'];
|
|
52
54
|
|
|
53
55
|
/**
|
|
54
56
|
* Get filter parameters for this model.
|
|
@@ -85,35 +87,33 @@ class Position extends Model
|
|
|
85
87
|
*/
|
|
86
88
|
protected static $logName = 'position';
|
|
87
89
|
|
|
88
|
-
|
|
89
|
-
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
90
|
-
*/
|
|
91
|
-
public function company()
|
|
90
|
+
public function company(): BelongsTo
|
|
92
91
|
{
|
|
93
92
|
return $this->belongsTo(\Fleetbase\Models\Company::class);
|
|
94
93
|
}
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
98
|
-
*/
|
|
99
|
-
public function order()
|
|
95
|
+
public function order(): BelongsTo
|
|
100
96
|
{
|
|
101
97
|
return $this->belongsTo(Order::class);
|
|
102
98
|
}
|
|
103
99
|
|
|
104
|
-
|
|
105
|
-
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
106
|
-
*/
|
|
107
|
-
public function destination()
|
|
100
|
+
public function destination(): BelongsTo
|
|
108
101
|
{
|
|
109
102
|
return $this->belongsTo(Place::class);
|
|
110
103
|
}
|
|
111
104
|
|
|
112
|
-
|
|
113
|
-
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
|
|
114
|
-
*/
|
|
115
|
-
public function subject()
|
|
105
|
+
public function subject(): MorphTo
|
|
116
106
|
{
|
|
117
107
|
return $this->morphTo(__FUNCTION__, 'subject_type', 'subject_uuid')->withoutGlobalScopes();
|
|
118
108
|
}
|
|
109
|
+
|
|
110
|
+
public function getLongitudeAttribute(): float
|
|
111
|
+
{
|
|
112
|
+
return $this->coordinates?->getLng() ?? 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public function getLatitudeAttribute(): float
|
|
116
|
+
{
|
|
117
|
+
return $this->coordinates?->getLat() ?? 0;
|
|
118
|
+
}
|
|
119
119
|
}
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Models;
|
|
4
4
|
|
|
5
5
|
use Fleetbase\Casts\Json;
|
|
6
|
+
use Fleetbase\FleetOps\Casts\Point;
|
|
7
|
+
use Fleetbase\LaravelMysqlSpatial\Eloquent\SpatialTrait;
|
|
8
|
+
use Fleetbase\LaravelMysqlSpatial\Types\Point as SpatialPoint;
|
|
6
9
|
use Fleetbase\Models\Alert;
|
|
10
|
+
use Fleetbase\Models\File;
|
|
7
11
|
use Fleetbase\Models\Model;
|
|
8
12
|
use Fleetbase\Models\User;
|
|
9
13
|
use Fleetbase\Traits\HasApiModelBehavior;
|
|
@@ -16,6 +20,8 @@ use Fleetbase\Traits\TracksApiCredential;
|
|
|
16
20
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
17
21
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
18
22
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
|
23
|
+
use Illuminate\Support\Arr;
|
|
24
|
+
use Illuminate\Support\Str;
|
|
19
25
|
use Spatie\Activitylog\LogOptions;
|
|
20
26
|
use Spatie\Activitylog\Traits\LogsActivity;
|
|
21
27
|
use Spatie\Sluggable\HasSlug;
|
|
@@ -39,6 +45,7 @@ class Sensor extends Model
|
|
|
39
45
|
use HasMetaAttributes;
|
|
40
46
|
use Searchable;
|
|
41
47
|
use HasCustomFields;
|
|
48
|
+
use SpatialTrait;
|
|
42
49
|
|
|
43
50
|
/**
|
|
44
51
|
* The database table used by the model.
|
|
@@ -77,8 +84,16 @@ class Sensor extends Model
|
|
|
77
84
|
'company_uuid',
|
|
78
85
|
'device_uuid',
|
|
79
86
|
'warranty_uuid',
|
|
87
|
+
'telematic_uuid',
|
|
88
|
+
'photo_uuid',
|
|
80
89
|
'name',
|
|
81
|
-
'
|
|
90
|
+
'type',
|
|
91
|
+
'internal_id',
|
|
92
|
+
'imei',
|
|
93
|
+
'imsi',
|
|
94
|
+
'firmware_version',
|
|
95
|
+
'serial_number',
|
|
96
|
+
'last_position',
|
|
82
97
|
'unit',
|
|
83
98
|
'min_threshold',
|
|
84
99
|
'max_threshold',
|
|
@@ -100,12 +115,9 @@ class Sensor extends Model
|
|
|
100
115
|
* @var array
|
|
101
116
|
*/
|
|
102
117
|
protected $appends = [
|
|
103
|
-
'device_name',
|
|
104
|
-
'warranty_name',
|
|
105
|
-
'attached_to_name',
|
|
106
118
|
'is_active',
|
|
107
119
|
'threshold_status',
|
|
108
|
-
'
|
|
120
|
+
'photo_url',
|
|
109
121
|
];
|
|
110
122
|
|
|
111
123
|
/**
|
|
@@ -113,7 +125,14 @@ class Sensor extends Model
|
|
|
113
125
|
*
|
|
114
126
|
* @var array
|
|
115
127
|
*/
|
|
116
|
-
protected $hidden = [
|
|
128
|
+
protected $hidden = [];
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The attributes that are spatial columns.
|
|
132
|
+
*
|
|
133
|
+
* @var array
|
|
134
|
+
*/
|
|
135
|
+
protected $spatialFields = ['last_position'];
|
|
117
136
|
|
|
118
137
|
/**
|
|
119
138
|
* The attributes that should be cast to native types.
|
|
@@ -121,13 +140,14 @@ class Sensor extends Model
|
|
|
121
140
|
* @var array
|
|
122
141
|
*/
|
|
123
142
|
protected $casts = [
|
|
124
|
-
'min_threshold'
|
|
125
|
-
'max_threshold'
|
|
126
|
-
'threshold_inclusive'
|
|
127
|
-
'last_reading_at'
|
|
128
|
-
'report_frequency_sec'
|
|
129
|
-
'
|
|
130
|
-
'
|
|
143
|
+
'min_threshold' => 'float',
|
|
144
|
+
'max_threshold' => 'float',
|
|
145
|
+
'threshold_inclusive' => 'boolean',
|
|
146
|
+
'last_reading_at' => 'datetime',
|
|
147
|
+
'report_frequency_sec' => 'integer',
|
|
148
|
+
'last_position' => Point::class,
|
|
149
|
+
'calibration' => Json::class,
|
|
150
|
+
'meta' => Json::class,
|
|
131
151
|
];
|
|
132
152
|
|
|
133
153
|
/**
|
|
@@ -169,6 +189,11 @@ class Sensor extends Model
|
|
|
169
189
|
return LogOptions::defaults()->logAll();
|
|
170
190
|
}
|
|
171
191
|
|
|
192
|
+
public function telematic(): BelongsTo
|
|
193
|
+
{
|
|
194
|
+
return $this->belongsTo(Telematic::class, 'telematic_uuid', 'uuid');
|
|
195
|
+
}
|
|
196
|
+
|
|
172
197
|
public function device(): BelongsTo
|
|
173
198
|
{
|
|
174
199
|
return $this->belongsTo(Device::class, 'device_uuid', 'uuid');
|
|
@@ -194,12 +219,27 @@ class Sensor extends Model
|
|
|
194
219
|
return $this->morphTo();
|
|
195
220
|
}
|
|
196
221
|
|
|
222
|
+
public function photo(): BelongsTo
|
|
223
|
+
{
|
|
224
|
+
return $this->belongsTo(File::class);
|
|
225
|
+
}
|
|
226
|
+
|
|
197
227
|
public function alerts(): HasMany
|
|
198
228
|
{
|
|
199
229
|
return $this->hasMany(Alert::class, 'subject_uuid', 'uuid')
|
|
200
230
|
->where('subject_type', static::class);
|
|
201
231
|
}
|
|
202
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Get photo URL attribute.
|
|
235
|
+
*
|
|
236
|
+
* @return string
|
|
237
|
+
*/
|
|
238
|
+
public function getPhotoUrlAttribute()
|
|
239
|
+
{
|
|
240
|
+
return data_get($this, 'photo.url', 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/image-file-icon.png');
|
|
241
|
+
}
|
|
242
|
+
|
|
203
243
|
/**
|
|
204
244
|
* Get the device name.
|
|
205
245
|
*/
|
|
@@ -507,4 +547,29 @@ class Sensor extends Model
|
|
|
507
547
|
],
|
|
508
548
|
];
|
|
509
549
|
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Creates a new position for the vehicle.
|
|
553
|
+
*/
|
|
554
|
+
public function createPosition(array $attributes = [], Model|string|null $destination = null): ?Position
|
|
555
|
+
{
|
|
556
|
+
if (!isset($attributes['coordinates']) && isset($attributes['location'])) {
|
|
557
|
+
$attributes['coordinates'] = $attributes['location'];
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (!isset($attributes['coordinates']) && isset($attributes['latitude']) && isset($attributes['longitude'])) {
|
|
561
|
+
$attributes['coordinates'] = new SpatialPoint($attributes['latitude'], $attributes['longitude']);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// handle destination if set
|
|
565
|
+
$destinationUuid = Str::isUuid($destination) ? $destination : data_get($destination, 'uuid');
|
|
566
|
+
|
|
567
|
+
return Position::create([
|
|
568
|
+
...Arr::only($attributes, ['coordinates', 'heading', 'bearing', 'speed', 'altitude', 'order_uuid']),
|
|
569
|
+
'subject_uuid' => $this->uuid,
|
|
570
|
+
'subject_type' => $this->getMorphClass(),
|
|
571
|
+
'company_uuid' => $this->company_uuid,
|
|
572
|
+
'destination_uuid' => $destinationUuid,
|
|
573
|
+
]);
|
|
574
|
+
}
|
|
510
575
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Models;
|
|
4
4
|
|
|
5
5
|
use Fleetbase\Casts\Json;
|
|
6
|
+
use Fleetbase\FleetOps\Support\Telematics\TelematicProviderRegistry;
|
|
6
7
|
use Fleetbase\Models\Model;
|
|
7
8
|
use Fleetbase\Models\User;
|
|
8
9
|
use Fleetbase\Traits\HasApiModelBehavior;
|
|
@@ -85,8 +86,8 @@ class Telematic extends Model
|
|
|
85
86
|
'last_seen_at',
|
|
86
87
|
'last_metrics',
|
|
87
88
|
'config',
|
|
89
|
+
'credentials',
|
|
88
90
|
'meta',
|
|
89
|
-
'slug',
|
|
90
91
|
];
|
|
91
92
|
|
|
92
93
|
/**
|
|
@@ -94,7 +95,7 @@ class Telematic extends Model
|
|
|
94
95
|
*
|
|
95
96
|
* @var array
|
|
96
97
|
*/
|
|
97
|
-
protected $appends = ['warranty_name', 'is_online', 'signal_strength', 'last_location'];
|
|
98
|
+
protected $appends = ['warranty_name', 'is_online', 'signal_strength', 'last_location', 'provider_descriptor'];
|
|
98
99
|
|
|
99
100
|
/**
|
|
100
101
|
* The attributes excluded from the model's JSON form.
|
|
@@ -109,10 +110,97 @@ class Telematic extends Model
|
|
|
109
110
|
* @var array
|
|
110
111
|
*/
|
|
111
112
|
protected $casts = [
|
|
112
|
-
'last_seen_at'
|
|
113
|
-
'last_metrics'
|
|
114
|
-
'config'
|
|
115
|
-
'
|
|
113
|
+
'last_seen_at' => 'datetime',
|
|
114
|
+
'last_metrics' => Json::class,
|
|
115
|
+
'config' => Json::class,
|
|
116
|
+
'credentials' => Json::class,
|
|
117
|
+
'meta' => Json::class,
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Telematic statuses.
|
|
122
|
+
*
|
|
123
|
+
* @var array
|
|
124
|
+
*/
|
|
125
|
+
public static $statuses = [
|
|
126
|
+
[
|
|
127
|
+
'key' => 'initialized',
|
|
128
|
+
'label' => 'Initialized',
|
|
129
|
+
'description' => 'Provider entry has been created but not yet configured.',
|
|
130
|
+
],
|
|
131
|
+
[
|
|
132
|
+
'key' => 'configured',
|
|
133
|
+
'label' => 'Configured',
|
|
134
|
+
'description' => 'Provider credentials and settings are valid but connection not yet tested.',
|
|
135
|
+
],
|
|
136
|
+
[
|
|
137
|
+
'key' => 'connecting',
|
|
138
|
+
'label' => 'Connecting',
|
|
139
|
+
'description' => 'Attempting to establish a connection with provider API.',
|
|
140
|
+
],
|
|
141
|
+
[
|
|
142
|
+
'key' => 'connected',
|
|
143
|
+
'label' => 'Connected',
|
|
144
|
+
'description' => 'Successfully authenticated and connected to provider API.',
|
|
145
|
+
],
|
|
146
|
+
[
|
|
147
|
+
'key' => 'synchronizing',
|
|
148
|
+
'label' => 'Synchronizing',
|
|
149
|
+
'description' => 'Currently syncing data (devices, vehicles, positions, etc.) from provider.',
|
|
150
|
+
],
|
|
151
|
+
[
|
|
152
|
+
'key' => 'active',
|
|
153
|
+
'label' => 'Active',
|
|
154
|
+
'description' => 'Integration is healthy and data syncs are occurring normally.',
|
|
155
|
+
],
|
|
156
|
+
[
|
|
157
|
+
'key' => 'degraded',
|
|
158
|
+
'label' => 'Degraded',
|
|
159
|
+
'description' => 'Integration partially working; intermittent errors or missing data.',
|
|
160
|
+
],
|
|
161
|
+
[
|
|
162
|
+
'key' => 'disconnected',
|
|
163
|
+
'label' => 'Disconnected',
|
|
164
|
+
'description' => 'Connection lost or failed authentication.',
|
|
165
|
+
],
|
|
166
|
+
[
|
|
167
|
+
'key' => 'error',
|
|
168
|
+
'label' => 'Error',
|
|
169
|
+
'description' => 'Provider integration encountered a fatal issue.',
|
|
170
|
+
],
|
|
171
|
+
[
|
|
172
|
+
'key' => 'disabled',
|
|
173
|
+
'label' => 'Disabled',
|
|
174
|
+
'description' => 'Manually disabled by the user.',
|
|
175
|
+
],
|
|
176
|
+
[
|
|
177
|
+
'key' => 'archived',
|
|
178
|
+
'label' => 'Archived',
|
|
179
|
+
'description' => 'Deprecated or replaced integration, kept for record.',
|
|
180
|
+
],
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Telematic health statuses.
|
|
185
|
+
*
|
|
186
|
+
* @var array
|
|
187
|
+
*/
|
|
188
|
+
public static $healthStates = [
|
|
189
|
+
[
|
|
190
|
+
'key' => 'healthy',
|
|
191
|
+
'label' => 'Healthy',
|
|
192
|
+
'description' => 'Integration tested and stable.',
|
|
193
|
+
],
|
|
194
|
+
[
|
|
195
|
+
'key' => 'warning',
|
|
196
|
+
'label' => 'Warning',
|
|
197
|
+
'description' => 'Minor issues detected (e.g., slow response, nearing quota).',
|
|
198
|
+
],
|
|
199
|
+
[
|
|
200
|
+
'key' => 'critical',
|
|
201
|
+
'label' => 'Critical',
|
|
202
|
+
'description' => 'Persistent failure or no data received in X hours.',
|
|
203
|
+
],
|
|
116
204
|
];
|
|
117
205
|
|
|
118
206
|
/**
|
|
@@ -169,6 +257,20 @@ class Telematic extends Model
|
|
|
169
257
|
return $this->hasMany(Asset::class, 'telematic_uuid', 'uuid');
|
|
170
258
|
}
|
|
171
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Get the provider config.
|
|
262
|
+
*/
|
|
263
|
+
public function getProviderDescriptorAttribute(): array
|
|
264
|
+
{
|
|
265
|
+
$registry = app(TelematicProviderRegistry::class);
|
|
266
|
+
$provider = $registry->findByKey($this->provider);
|
|
267
|
+
if ($provider) {
|
|
268
|
+
return $provider->toArray();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return [];
|
|
272
|
+
}
|
|
273
|
+
|
|
172
274
|
/**
|
|
173
275
|
* Get the warranty name.
|
|
174
276
|
*/
|
|
@@ -333,4 +435,12 @@ class Telematic extends Model
|
|
|
333
435
|
|
|
334
436
|
return true;
|
|
335
437
|
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Sets a default status if none input.
|
|
441
|
+
*/
|
|
442
|
+
public function setStatusAttribute(?string $status = null): void
|
|
443
|
+
{
|
|
444
|
+
$this->attributes['status'] = $status ?? 'initialized';
|
|
445
|
+
}
|
|
336
446
|
}
|