@fleetbase/fleetops-data
Version:
Fleetbase Fleet-Ops based models, serializers, transforms, adapters and GeoJson utility functions.
587 lines (471 loc) • 17.6 kB
JavaScript
import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
import { tracked } from '@glimmer/tracking';
import { computed, setProperties, set } from '@ember/object';
import { notEmpty, not, bool, alias, equal } from '@ember/object/computed';
import { isArray } from '@ember/array';
import { isBlank } from '@ember/utils';
import { getOwner } from '@ember/application';
import { format as formatDate, formatDistanceToNow, isValid as isValidDate } from 'date-fns';
import isNotModel from '@fleetbase/ember-core/utils/is-not-model';
import shouldNotLoadRelation from '../utils/should-not-load-relation';
export default class OrderModel extends Model {
/** @ids */
public_id;
internal_id;
company_uuid;
transaction_uuid;
customer_uuid;
facilitator_uuid;
payload_uuid;
route_uuid;
purchase_rate_uuid;
tracking_number_uuid;
driver_assigned_uuid;
service_quote_uuid;
order_config_uuid;
payload_id;
purchase_rate_id;
driver_id;
/** @relationships */
company;
order_config;
customer;
facilitator;
transaction;
payload;
driver_assigned;
vehicle_assigned;
route;
purchase_rate;
tracking_number;
tracking_statuses;
comments;
files;
custom_field_values;
/** @aliases */
driver;
vehicle;
/** @attributes */
tracking;
qr_code;
barcode;
pickup_name;
dropoff_name;
driver_name;
customer_name;
customer_type;
facilitator_name;
facilitator_type;
created_by_name;
updated_by_name;
pod_method;
notes;
type;
status;
adhoc_distance;
total_entities;
transaction_amount;
has_driver_assigned;
pod_required;
dispatched;
started;
adhoc;
is_route_optimized;
customer_is_contact;
customer_is_vendor;
facilitator_is_contact;
facilitator_is_vendor;
meta;
options;
tracker_data;
eta;
/** @dates */
scheduled_at;
dispatched_at;
deleted_at;
created_at;
updated_at;
/** @tracked */
selected = false;
/** @computed */
has_facilitator;
has_customer;
isIntegratedVendorOrder;
has_tracking_number;
has_purchase_rate;
has_tracking_statuses;
has_payload;
missing_tracking_number;
missing_purchase_rate;
missing_tracking_statuses;
missing_payload;
isDispatched;
isNotDispatched;
get pickupName() {
const { payload, meta } = this;
if (payload?.pickup) {
return payload.pickup.name ?? payload.pickup.street1;
}
if (payload?.currentWaypoint) {
return payload.currentWaypoint.name ?? payload.currentWaypoint.street1;
}
if (payload?.waypoints.firstObject) {
return payload.waypoints.firstObject.name ?? payload.waypoints.firstObject.street1;
}
if (meta.pickup_is_driver_location === true) {
return 'Dynamic';
}
return 'None';
}
get dropoffName() {
const { payload, meta } = this;
if (payload?.dropoff) {
return payload.dropoff.name ?? payload.dropoff.street1;
}
if (payload?.waypoints.lastObject) {
return payload.waypoints.lastObject.name ?? payload.waypoints.lastObject.street1;
}
if (meta.pickup_is_driver_location === true) {
return 'Dynamic';
}
return 'None';
}
get eventTitle() {
return `${this.scheduledAtTime} - ${this.public_id}`;
}
get updatedAgo() {
if (!isValidDate(this.updated_at)) {
return null;
}
return formatDistanceToNow(this.updated_at);
}
get updatedAt() {
if (!isValidDate(this.updated_at)) {
return null;
}
return formatDate(this.updated_at, 'PP HH:mm');
}
get updatedAtShort() {
if (!isValidDate(this.updated_at)) {
return null;
}
return formatDate(this.updated_at, 'dd, MMM');
}
get createdAgo() {
if (!isValidDate(this.created_at)) {
return null;
}
return formatDistanceToNow(this.created_at);
}
get createdAt() {
if (!isValidDate(this.created_at)) {
return null;
}
return formatDate(this.created_at, 'PP HH:mm');
}
get createdAtShort() {
if (!isValidDate(this.created_at)) {
return null;
}
return formatDate(this.created_at, 'dd, MMM');
}
get createdAtWithTime() {
if (!isValidDate(this.created_at)) {
return null;
}
return formatDate(this.created_at, 'PP HH:mm');
}
get createdAtDetailed() {
if (!isValidDate(this.created_at)) {
return null;
}
return formatDate(this.created_at, 'PP HH:mm');
}
get dispatchedAgo() {
if (!isValidDate(this.dispatched_at)) {
return null;
}
return formatDistanceToNow(this.dispatched_at);
}
get dispatchedAt() {
if (!isValidDate(this.dispatched_at)) {
return null;
}
return formatDate(this.dispatched_at, 'PP HH:mm');
}
get dispatchedAtShort() {
if (!isValidDate(this.dispatched_at)) {
return null;
}
return formatDate(this.dispatched_at, 'dd, MMM');
}
get startedAgo() {
if (!isValidDate(this.started_at)) {
return null;
}
return formatDistanceToNow(this.started_at);
}
get startedAt() {
if (!isValidDate(this.started_at)) {
return null;
}
return formatDate(this.started_at, 'PP HH:mm');
}
get startedAtShort() {
if (!isValidDate(this.started_at)) {
return null;
}
return formatDate(this.started_at, 'dd, MMM');
}
get scheduledAt() {
if (!isValidDate(this.scheduled_at)) {
return null;
}
return formatDate(this.scheduled_at, 'PP HH:mm');
}
get scheduledAtTime() {
if (!isValidDate(this.scheduled_at)) {
return null;
}
return formatDate(this.scheduled_at, 'HH:mm');
}
// eslint-disable-next-line ember/use-brace-expansion
get isMultipleDropoffOrder() {
return this.payload?.isMultiDrop;
}
get hasActiveStatus() {
return this.status !== 'canceled' && this.status !== 'completed';
}
get canLoadDriver() {
return this.has_driver_assigned && !this.driver_assigned;
}
get shouldDisplayDispatchLabel() {
return this.dispatched === true && this.status !== 'canceled' && this.status !== 'completed' && this.status !== 'dispatched';
}
get canBeDispatched() {
return !this.isIntegratedVendorOrder && this.isNotDispatched && this.status !== 'canceled' && this.status !== 'completed' && this.status !== 'dispatched';
}
isFresh;
isPreparing;
isCompleted;
isCanceled;
isReady;
get isPickupReady() {
return this.status === 'ready' && this?.meta?.is_pickup === true;
}
get activityHasEnded() {
return this.isCanceled || this.isCompleted;
}
/** @methods */
setPayload(payload = null) {
if (isNotModel(payload)) {
return this;
}
if (!payload.type) {
payload.type = this.type;
}
setProperties(this, { payload });
return this;
}
setRoute(route = null) {
if (isNotModel(route)) {
return this;
}
setProperties(this, { route });
return this;
}
serializeMetaFromFields(metaFields = []) {
if (!isArray(metaFields)) {
return this;
}
const meta = {};
for (let i = 0; i < metaFields.length; i++) {
const metaField = metaFields[i];
if (!metaField || !metaField.key) {
continue;
}
meta[metaField.key] = metaField.value;
}
setProperties(this, { meta });
return this;
}
serializeMetaFromGroupedFields(metaFields = []) {
if (!isArray(metaFields)) {
return this;
}
const meta = this.meta || {};
for (let i = 0; i < metaFields.length; i++) {
const metaGroup = metaFields.objectAt(i);
if (!metaGroup || !isArray(metaGroup.items)) {
continue;
}
for (let groupIndex = 0; groupIndex < metaGroup.items.length; groupIndex++) {
const metaField = metaGroup.items.objectAt(groupIndex);
if (!metaField || !metaField.key) {
continue;
}
meta[metaField.key] = metaField.value || null;
}
}
setProperties(this, { meta });
return this;
}
serializeMeta() {
const { meta } = this;
if (!isArray(meta)) {
return this;
}
const serializedMeta = {};
for (let i = 0; i < meta.length; i++) {
const metaField = meta.objectAt(i);
const { key, value } = metaField;
if (!key) {
continue;
}
set(serializedMeta, key, value);
}
setProperties(this, { meta: serializedMeta });
return this;
}
async persistProperty(key, value, options = {}) {
return this.persistProperties({ [key]: value }, options);
}
async persistProperties(properties = {}, options = {}) {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
this.setProperties(properties);
if (typeof options.onBefore === 'function') {
options.onBefore(this);
}
const order = await fetch.put(`orders/${this.id}`, properties, { normalizeToEmberData: true, normalizeModelType: 'order' });
if (typeof options.onAfter === 'function') {
options.onAfter(order);
}
}
async loadPayload(options = {}) {
const owner = getOwner(this);
const store = owner.lookup('service:store');
if (shouldNotLoadRelation(this, 'payload')) {
return;
}
const payload = await store.queryRecord(
'payload',
{
uuid: this.payload_uuid,
single: true,
with: ['pickup', 'dropoff', 'return', 'waypoints', 'entities'],
},
options
);
this.set('payload', payload);
return payload;
}
async loadCustomer(options = {}) {
const owner = getOwner(this);
const store = owner.lookup('service:store');
if (shouldNotLoadRelation(this, 'customer')) {
return;
}
if (!this.customer_uuid || !isBlank(this.customer)) {
return;
}
const customer = await store.findRecord(`customer-${this.customer_type}`, this.customer_uuid, options);
this.set('customer', customer);
return customer;
}
async loadPurchaseRate(options = {}) {
const owner = getOwner(this);
const store = owner.lookup('service:store');
if (shouldNotLoadRelation(this, 'purchase_rate')) {
return;
}
const purchaseRate = await store.findRecord('purchase-rate', this.purchase_rate_uuid, options);
this.set('purchase_rate', purchaseRate);
return purchaseRate;
}
async loadOrderConfig(options = {}) {
const owner = getOwner(this);
const store = owner.lookup('service:store');
if (shouldNotLoadRelation(this, 'order_config')) {
return;
}
const orderConfig = await store.findRecord('order-config', this.order_config_uuid, options);
this.set('order_config', orderConfig);
return orderConfig;
}
async loadDriver(options = {}) {
const owner = getOwner(this);
const store = owner.lookup('service:store');
if (shouldNotLoadRelation(this, 'driver_assigned')) {
return;
}
const driverAssigned = await store.findRecord('driver', this.driver_assigned_uuid, options);
this.set('driver_assigned', driverAssigned);
return driverAssigned;
}
async loadTrackingNumber(options = {}) {
const owner = getOwner(this);
const store = owner.lookup('service:store');
if (shouldNotLoadRelation(this, 'tracking_number')) {
return;
}
const trackingNumber = await store.findRecord('tracking-number', this.tracking_number_uuid, options);
this.set('tracking_number', trackingNumber);
return trackingNumber;
}
async loadTrackingActivity(options = {}) {
const owner = getOwner(this);
const store = owner.lookup('service:store');
if (!this.tracking_number_uuid) {
return;
}
const activity = await store.query(
'tracking-status',
{
tracking_number_uuid: this.tracking_number_uuid,
},
options
);
this.set('tracking_statuses', activity.toArray());
return activity;
}
async loadComments(options = {}) {
const owner = getOwner(this);
const store = owner.lookup('service:store');
const comments = await store.query(
'comment',
{
subject_uuid: this.id,
withoutParent: 1,
sort: '-created_at',
},
options
);
this.set('comments', comments);
return comments;
}
async loadFiles(options = {}) {
const owner = getOwner(this);
const store = owner.lookup('service:store');
const files = await store.query('file', { subject_uuid: this.id, sort: '-created_at' }, options);
this.set('files', files);
return files;
}
async loadTrackerData(params = {}, options = {}) {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
const trackerData = await fetch.get(`orders/${this.id}/tracker`, params, options);
this.set('tracker_data', trackerData);
return trackerData;
}
async loadETA(params = {}, options = {}) {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
const eta = await fetch.get(`orders/${this.id}/eta`, params, options);
this.set('eta', eta);
return eta;
}
}