diff --git a/addon/models/device.js b/addon/models/device.js index a7e65e2..2c9d4c5 100644 --- a/addon/models/device.js +++ b/addon/models/device.js @@ -10,6 +10,7 @@ export default class DeviceModel extends Model { @attr('string') warranty_uuid; @attr('string') attachable_type; @attr('string') attachable_uuid; + @attr('string') photo_uuid; /** @relationships */ @belongsTo('telematic', { async: false }) telematic; @@ -19,34 +20,42 @@ export default class DeviceModel extends Model { @hasMany('custom-field-value', { async: false }) custom_field_values; /** @attributes */ - @attr('string') device_type; + @attr('string') name; + @attr('string') model; + @attr('string') location; + @attr('string') type; @attr('string') device_id; - @attr('string') device_provider; - @attr('string') device_name; - @attr('string') device_model; - @attr('string') device_location; + @attr('string') internal_id; + @attr('string') imei; + @attr('string') imsi; + @attr('string') firmware_version; + @attr('string') provider; + @attr('string') photo_url; @attr('string') manufacturer; @attr('string') serial_number; - @attr('string') installation_date; - @attr('string') last_maintenance_date; - @attr('raw') meta; - @attr('raw') data; - @attr('raw') options; + @attr('point') last_position; + @attr('object') meta; + @attr('object') data; + @attr('object') options; @attr('boolean') online; - @attr('string') status; + @attr('string', { defaultValue: 'inactive' }) status; @attr('string') data_frequency; @attr('string') notes; @attr('string') slug; - @attr('string') warranty_name; - @attr('string') telematic_name; /** @dates */ + @attr('date') last_maintenance_date; + @attr('date') installation_date; @attr('date') last_online_at; @attr('date') deleted_at; @attr('date') created_at; @attr('date') updated_at; /** @computed */ + @computed('name', 'serial_number', 'internal_id', 'imei', 'public_id') get displayName() { + return this.name || this.serial_number || this.internal_id || this.imei || this.public_id; + } + @computed('updated_at') get updatedAgo() { if (!isValidDate(this.updated_at)) { return null; diff --git a/addon/models/order.js b/addon/models/order.js index 086918d..9ef52cc 100644 --- a/addon/models/order.js +++ b/addon/models/order.js @@ -55,6 +55,7 @@ export default class OrderModel extends Model { @alias('payload.orderWaypoints') orderWaypoints; @alias('payload.entitiesByDestination') entitiesByDestination; @alias('payload.isMultiDrop') isMultiDrop; + @alias('payload.isMultiDrop') isMultiDropOrder; /** @attributes */ @attr('string') tracking; diff --git a/addon/models/payload.js b/addon/models/payload.js index a3a011d..b446990 100644 --- a/addon/models/payload.js +++ b/addon/models/payload.js @@ -73,7 +73,7 @@ export default class PayloadModel extends Model { return middleWaypoints; } - @computed('entities', 'model.payload.{entities.[],waypoints.[]}', 'waypoints') get entitiesByDestination() { + @computed('entities.@each.id', 'waypoints.@each.id') get entitiesByDestination() { const groups = []; // create groups diff --git a/addon/models/position.js b/addon/models/position.js new file mode 100644 index 0000000..48900c2 --- /dev/null +++ b/addon/models/position.js @@ -0,0 +1,86 @@ +import Model, { attr, belongsTo } from '@ember-data/model'; +import { computed } from '@ember/object'; +import { format as formatDate, isValid as isValidDate, formatDistanceToNow } from 'date-fns'; + +export default class PositionModel extends Model { + /** @ids */ + @attr('string') public_id; + @attr('string') company_uuid; + @attr('string') order_uuid; + @attr('string') destination_uuid; + @attr('string') subject_uuid; + @attr('string') subject_type; + + /** @relationships */ + @belongsTo('order', { async: false }) order; + @belongsTo('place', { async: false }) destination; + + /** @attributes */ + @attr('point') coordinates; + @attr('number') heading; + @attr('number') bearing; + @attr('number') speed; + @attr('number') altitude; + @attr('number') latitude; + @attr('number') longitude; + + /** @dates */ + @attr('date') created_at; + @attr('date') updated_at; + + /** @computed */ + @computed('coordinates') get location() { + return this.coordinates; + } + + @computed('latitude', 'longitude') get latLng() { + if (this.latitude && this.longitude) { + return [this.latitude, this.longitude]; + } + return null; + } + + @computed('created_at') get timestamp() { + if (this.created_at && isValidDate(new Date(this.created_at))) { + return formatDate(new Date(this.created_at), 'yyyy-MM-dd HH:mm:ss'); + } + return null; + } + + @computed('created_at') get createdAgo() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDistanceToNow(this.created_at); + } + + @computed('created_at') get createdAt() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'yyyy-MM-dd HH:mm'); + } + + @computed('created_at') get createdAtShort() { + if (!isValidDate(this.created_at)) { + return null; + } + return formatDate(this.created_at, 'dd, MMM'); + } + + @computed('speed') get speedKmh() { + // Convert m/s to km/h + if (this.speed !== null && this.speed !== undefined) { + return (this.speed * 3.6).toFixed(2); + } + return 0; + } + + @computed('speed') get speedMph() { + // Convert m/s to mph + if (this.speed !== null && this.speed !== undefined) { + return (this.speed * 2.23694).toFixed(2); + } + return 0; + } +} diff --git a/addon/models/sensor.js b/addon/models/sensor.js index 6f11cf8..84f2a86 100644 --- a/addon/models/sensor.js +++ b/addon/models/sensor.js @@ -6,31 +6,41 @@ export default class SensorModel extends Model { /** @ids */ @attr('string') public_id; @attr('string') company_uuid; + @attr('string') telematic_uuid; @attr('string') device_uuid; @attr('string') warranty_uuid; @attr('string') sensorable_type; @attr('string') sensorable_uuid; + @attr('string') photo_uuid; /** @relationships */ + @belongsTo('telematic', { async: false }) telematic; @belongsTo('device', { async: false }) device; @belongsTo('warranty', { async: false }) warranty; @hasMany('custom-field-value', { async: false }) custom_field_values; /** @attributes */ @attr('string') name; - @attr('string') sensor_type; + @attr('string') photo_url; + @attr('string') internal_id; + @attr('string') type; + @attr('string') serial_number; + @attr('string') imei; + @attr('string') imsi; + @attr('string') firmware_version; @attr('string') unit; + @attr('string') threshold_status; @attr('number') min_threshold; @attr('number') max_threshold; @attr('boolean') threshold_inclusive; + @attr('boolean') is_active; @attr('string') last_value; - @attr('raw') calibration; @attr('number') report_frequency_sec; - @attr('string') status; - @attr('raw') meta; + @attr('point') last_position; + @attr('object') calibration; + @attr('object') meta; @attr('string') slug; - @attr('string') device_name; - @attr('string') warranty_name; + @attr('string', { defaultValue: 'inactive' }) status; /** @dates */ @attr('date') last_reading_at; @@ -39,6 +49,10 @@ export default class SensorModel extends Model { @attr('date') updated_at; /** @computed */ + @computed('name', 'serial_number', 'internal_id', 'imei', 'public_id') get displayName() { + return this.name || this.serial_number || this.internal_id || this.imei || this.public_id; + } + @computed('updated_at') get updatedAgo() { if (!isValidDate(this.updated_at)) { return null; diff --git a/addon/models/telematic.js b/addon/models/telematic.js index c8ff289..9260eb4 100644 --- a/addon/models/telematic.js +++ b/addon/models/telematic.js @@ -17,14 +17,16 @@ export default class TelematicModel extends Model { @attr('string') model; @attr('string') serial_number; @attr('string') firmware_version; - @attr('string') status; + @attr('string', { defaultValue: 'initialized' }) status; @attr('string') imei; @attr('string') iccid; @attr('string') imsi; @attr('string') msisdn; - @attr('raw') last_metrics; - @attr('raw') config; - @attr('raw') meta; + @attr('object') last_metrics; + @attr('object') credentials; + @attr('object') config; + @attr('object') meta; + @attr('object') provider_descriptor; @attr('string') slug; @attr('string') warranty_name; diff --git a/addon/models/vehicle.js b/addon/models/vehicle.js index db74b73..b811c4c 100644 --- a/addon/models/vehicle.js +++ b/addon/models/vehicle.js @@ -190,6 +190,8 @@ export default class VehicleModel extends Model { /** @methods */ async loadDriver() { + if (!this.driver_uuid) return; + const owner = getOwner(this); const store = owner.lookup('service:store'); diff --git a/addon/serializers/device.js b/addon/serializers/device.js index 75152af..04ce467 100644 --- a/addon/serializers/device.js +++ b/addon/serializers/device.js @@ -1,4 +1,17 @@ import ApplicationSerializer from '@fleetbase/ember-core/serializers/application'; import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest'; -export default class DeviceSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) {} +export default class DeviceSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) { + /** + * Embedded relationship attributes + * + * @var {Object} + */ + get attrs() { + return { + telematic: { embedded: 'always' }, + warranty: { embedded: 'always' }, + custom_field_values: { embedded: 'always' }, + }; + } +} diff --git a/addon/serializers/sensor.js b/addon/serializers/sensor.js index dc2bfd6..3de0839 100644 --- a/addon/serializers/sensor.js +++ b/addon/serializers/sensor.js @@ -1,4 +1,18 @@ import ApplicationSerializer from '@fleetbase/ember-core/serializers/application'; import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest'; -export default class SensorSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) {} +export default class SensorSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) { + /** + * Embedded relationship attributes + * + * @var {Object} + */ + get attrs() { + return { + telematic: { embedded: 'always' }, + device: { embedded: 'always' }, + warranty: { embedded: 'always' }, + custom_field_values: { embedded: 'always' }, + }; + } +} diff --git a/app/models/position.js b/app/models/position.js new file mode 100644 index 0000000..14359a9 --- /dev/null +++ b/app/models/position.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/fleetops-data/models/position'; diff --git a/package.json b/package.json index e47d06e..eabc446 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fleetbase/fleetops-data", - "version": "0.1.20", + "version": "0.1.21", "description": "Fleetbase Fleet-Ops based models, serializers, transforms, adapters and GeoJson utility functions.", "keywords": [ "fleetbase-data", diff --git a/tests/unit/models/position-test.js b/tests/unit/models/position-test.js new file mode 100644 index 0000000..08a72e0 --- /dev/null +++ b/tests/unit/models/position-test.js @@ -0,0 +1,14 @@ +import { module, test } from 'qunit'; + +import { setupTest } from 'dummy/tests/helpers'; + +module('Unit | Model | position', function (hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function (assert) { + let store = this.owner.lookup('service:store'); + let model = store.createRecord('position', {}); + assert.ok(model); + }); +});