From 9ec4c97950f98784c9210c3220a4203d7a0a61fd Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Thu, 30 Apr 2026 13:04:08 +0800 Subject: [PATCH 1/5] minor fixes on the payload model --- addon/models/payload.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/models/payload.js b/addon/models/payload.js index b446990..fdd88ea 100644 --- a/addon/models/payload.js +++ b/addon/models/payload.js @@ -109,12 +109,12 @@ export default class PayloadModel extends Model { // eslint-disable-next-line ember/use-brace-expansion @computed('{dropoff,pickup,waypoints}', 'waypoints.[]') get places() { - return [this.pickup, ...this.waypoints.toArray(), this.pickup].filter(Boolean); + return [this.pickup, ...this.waypoints.toArray(), this.dropoff].filter(Boolean); } // eslint-disable-next-line ember/use-brace-expansion @computed('waypoints.@each.place', 'waypoints.[]') get waypointPlaces() { - return this.waypoints.toArray().map((wp) => wp.place); + return this.waypoints.toArray().map((wp) => wp.place ?? wp); } @computed('{dropoff,pickup,waypoints}', 'waypoints.[]') get payloadCoordinates() { From f442a1e6f7d5adb820f40bf030b5543dea8799ae Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Thu, 30 Apr 2026 13:16:32 +0800 Subject: [PATCH 2/5] Add explicit intermediate waypoint semantics --- addon/models/order.js | 1 + addon/models/payload.js | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/addon/models/order.js b/addon/models/order.js index 55b1d45..87e32f1 100644 --- a/addon/models/order.js +++ b/addon/models/order.js @@ -58,6 +58,7 @@ export default class OrderModel extends Model { @alias('payload.entitiesByDestination') entitiesByDestination; @alias('payload.isMultiDrop') isMultiDrop; @alias('payload.isMultiDrop') isMultiDropOrder; + @alias('payload.hasIntermediateWaypoints') hasIntermediateWaypoints; /** @attributes */ @attr('string') tracking; diff --git a/addon/models/payload.js b/addon/models/payload.js index fdd88ea..8be392c 100644 --- a/addon/models/payload.js +++ b/addon/models/payload.js @@ -35,6 +35,10 @@ export default class PayloadModel extends Model { @notEmpty('dropoff_uuid') hasDropoff; @notEmpty('return_uuid') hasReturn; + @computed('waypoints.[]') get hasIntermediateWaypoints() { + return this.waypoints.length > 0; + } + @computed('waypoints.[]', 'pickup_uuid', 'dropoff_uuid') get isMultiDrop() { return this.waypoints.length > 0 && !this.pickup_uuid && !this.dropoff_uuid; } From 67b8be9893fe444855c49958d639b83c2aef72eb Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Thu, 30 Apr 2026 18:35:11 +0800 Subject: [PATCH 3/5] Align FleetOps data models with route payload summaries --- addon/models/order.js | 23 ++++++++++++++++++++++- addon/models/payload.js | 9 ++++++++- addon/models/waypoint.js | 1 + package.json | 2 +- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/addon/models/order.js b/addon/models/order.js index 87e32f1..a33f1dd 100644 --- a/addon/models/order.js +++ b/addon/models/order.js @@ -22,6 +22,7 @@ export default class OrderModel extends Model { @attr('string') purchase_rate_uuid; @attr('string') tracking_number_uuid; @attr('string') driver_assigned_uuid; + @attr('string') vehicle_assigned_uuid; @attr('string') manifest_uuid; @attr('string') service_quote_uuid; @attr('string') order_config_uuid; @@ -77,10 +78,15 @@ export default class OrderModel extends Model { @attr('string') notes; @attr('string') type; @attr('string') status; + @attr('string') latest_status; + @attr('string') latest_status_code; @attr('number') adhoc_distance; + @attr('number') distance; + @attr('number') time; @attr('number') total_entities; @attr('number') transaction_amount; @attr('boolean') has_driver_assigned; + @attr('boolean') is_scheduled; @attr('boolean') pod_required; @attr('boolean') dispatched; @attr('boolean') started; @@ -467,10 +473,25 @@ export default class OrderModel extends Model { async loadPayload(options = {}) { const owner = getOwner(this); const store = owner.lookup('service:store'); - if (shouldNotLoadRelation(this, 'payload')) { + if (isBlank(this.payload_uuid)) { return; } + const existingPayload = this.payload; + const isLightweightIndexOrder = this.meta?._index_resource === true; + const hasLoadedWaypointCollection = typeof existingPayload?.waypoints?.toArray === 'function' || isArray(existingPayload?.waypoints); + const indexedWaypointCount = Number(existingPayload?.waypoints_count ?? 0); + const loadedWaypointCount = Number(existingPayload?.waypoints?.length ?? 0); + const needsWaypointUpgrade = indexedWaypointCount > 0 && loadedWaypointCount === 0; + + if (existingPayload && hasLoadedWaypointCollection && !needsWaypointUpgrade) { + return existingPayload; + } + + if (existingPayload && !hasLoadedWaypointCollection && !isLightweightIndexOrder) { + return existingPayload; + } + const payload = await store.queryRecord( 'payload', { diff --git a/addon/models/payload.js b/addon/models/payload.js index 8be392c..8768ecd 100644 --- a/addon/models/payload.js +++ b/addon/models/payload.js @@ -19,11 +19,14 @@ export default class PayloadModel extends Model { @hasMany('entity', { async: false }) entities; /** @attributes */ - @attr('string') meta; + @attr('raw') meta; @attr('string') cod_amount; @attr('string') cod_currency; @attr('string') cod_payment_method; + @attr('string') payment_method; @attr('string') type; + @attr('number') entities_count; + @attr('number') waypoints_count; @attr('date') deleted_at; @attr('date') created_at; @attr('date') updated_at; @@ -39,6 +42,10 @@ export default class PayloadModel extends Model { return this.waypoints.length > 0; } + @computed('waypoints_count') get waypoint_count() { + return this.waypoints_count; + } + @computed('waypoints.[]', 'pickup_uuid', 'dropoff_uuid') get isMultiDrop() { return this.waypoints.length > 0 && !this.pickup_uuid && !this.dropoff_uuid; } diff --git a/addon/models/waypoint.js b/addon/models/waypoint.js index 90d3f00..816f093 100644 --- a/addon/models/waypoint.js +++ b/addon/models/waypoint.js @@ -21,6 +21,7 @@ export default class WaypointModel extends PlaceModel { @attr('string') status_code; @attr('string') type; @attr('number') order; + @attr('boolean') complete; // Orchestrator time windows @attr('date') time_window_start; @attr('date') time_window_end; diff --git a/package.json b/package.json index 47bb20f..09eac8e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fleetbase/fleetops-data", - "version": "0.1.30", + "version": "0.1.31", "description": "Fleetbase Fleet-Ops based models, serializers, transforms, adapters and GeoJson utility functions.", "keywords": [ "fleetbase-data", From 96f12d22ba27fefc6093ba834febc81cfbeba855 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Sun, 3 May 2026 09:16:15 +0800 Subject: [PATCH 4/5] Fix recurring schedule models and polymorphic serializers --- addon/models/maintenance-schedule.js | 5 +++ addon/models/recurring-order-schedule.js | 50 +++++++++++++++++++++++ addon/serializers/entity.js | 4 -- addon/serializers/maintenance-schedule.js | 3 -- addon/serializers/maintenance.js | 3 -- addon/serializers/order.js | 3 -- addon/serializers/waypoint.js | 4 -- addon/serializers/work-order.js | 3 -- app/models/recurring-order-schedule.js | 1 + 9 files changed, 56 insertions(+), 20 deletions(-) create mode 100644 addon/models/recurring-order-schedule.js create mode 100644 app/models/recurring-order-schedule.js diff --git a/addon/models/maintenance-schedule.js b/addon/models/maintenance-schedule.js index 818abd8..a154b3b 100644 --- a/addon/models/maintenance-schedule.js +++ b/addon/models/maintenance-schedule.js @@ -7,10 +7,15 @@ export default class MaintenanceScheduleModel extends Model { @attr('string') uuid; @attr('string') public_id; @attr('string') company_uuid; + @attr('string') subject_uuid; + @attr('string') subject_type; + @attr('string') default_assignee_uuid; + @attr('string') default_assignee_type; /** @polymorphic relationships */ @belongsTo('maintenance-subject', { polymorphic: true, async: false }) subject; @belongsTo('facilitator', { polymorphic: true, async: false }) default_assignee; + /** @computed names — server-side convenience fields (read-only) */ @attr('string') subject_name; @attr('string') default_assignee_name; diff --git a/addon/models/recurring-order-schedule.js b/addon/models/recurring-order-schedule.js new file mode 100644 index 0000000..5e2e6d6 --- /dev/null +++ b/addon/models/recurring-order-schedule.js @@ -0,0 +1,50 @@ +import Model, { attr, belongsTo } from '@ember-data/model'; + +export default class RecurringOrderScheduleModel extends Model { + @attr('string') public_id; + @attr('string') uuid; + @attr('string') name; + @attr('string') description; + @attr('string') status; + @attr('string') timezone; + @attr('date') starts_at; + @attr('date') ends_at; + @attr('string') rrule; + @attr('date') last_materialized_at; + @attr('date') materialization_horizon; + @attr('string') customer_uuid; + @attr('string') customer_type; + @attr('string') facilitator_uuid; + @attr('string') facilitator_type; + @attr('string') order_config_uuid; + @attr('string') driver_assigned_uuid; + @attr('string') vehicle_assigned_uuid; + @attr('string') service_rate_uuid; + @attr() template_order_meta; + @attr() template_payload; + @attr() template_entities; + @attr() meta; + @attr() upcoming_occurrences; + @attr('date') next_occurrence_at; + @attr('date') created_at; + @attr('date') updated_at; + + @belongsTo('customer', { polymorphic: true, async: false }) customer; + @belongsTo('facilitator', { polymorphic: true, async: false }) facilitator; + @belongsTo('order-config', { async: false }) order_config; + @belongsTo('driver', { async: false }) driver_assigned; + @belongsTo('vehicle', { async: false }) vehicle_assigned; + @belongsTo('service-rate', { async: false }) service_rate; + + get isActive() { + return this.status === 'active'; + } + + get isPaused() { + return this.status === 'paused'; + } + + get isCanceled() { + return this.status === 'canceled'; + } +} diff --git a/addon/serializers/entity.js b/addon/serializers/entity.js index 1cbcc63..61aaf06 100644 --- a/addon/serializers/entity.js +++ b/addon/serializers/entity.js @@ -41,10 +41,6 @@ export default class EntitySerializer extends ApplicationSerializer.extend(Embed if (isPolymorphicTypeBlank) { key = this.keyForAttribute ? this.keyForAttribute(key, 'serialize') : key; - if (!isBlank(belongsTo.attr(`${key}_type`))) { - type = belongsTo.attr(`${key}_type`); - } - if (!belongsTo) { json[key + '_type'] = null; } else { diff --git a/addon/serializers/maintenance-schedule.js b/addon/serializers/maintenance-schedule.js index badb35b..7832ab1 100644 --- a/addon/serializers/maintenance-schedule.js +++ b/addon/serializers/maintenance-schedule.js @@ -51,9 +51,6 @@ export default class MaintenanceScheduleSerializer extends ApplicationSerializer json[key + '_type'] = null; } else { let type = belongsTo.modelName; - if (!isBlank(belongsTo.attr(`${key}_type`))) { - type = belongsTo.attr(`${key}_type`); - } // Strip abstract subtype prefixes so the server receives the bare model type // e.g. 'facilitator-vendor' -> 'vendor', 'maintenance-subject-vehicle' -> 'vehicle' if (typeof type === 'string') { diff --git a/addon/serializers/maintenance.js b/addon/serializers/maintenance.js index e3f6306..8b2155d 100644 --- a/addon/serializers/maintenance.js +++ b/addon/serializers/maintenance.js @@ -53,9 +53,6 @@ export default class MaintenanceSerializer extends ApplicationSerializer.extend( json[key + '_type'] = null; } else { let type = belongsTo.modelName; - if (!isBlank(belongsTo.attr(`${key}_type`))) { - type = belongsTo.attr(`${key}_type`); - } // Strip abstract subtype prefixes so the server receives the bare model type // e.g. 'facilitator-vendor' -> 'vendor', 'maintenance-subject-vehicle' -> 'vehicle' if (typeof type === 'string') { diff --git a/addon/serializers/order.js b/addon/serializers/order.js index d74b467..a4cd5f1 100644 --- a/addon/serializers/order.js +++ b/addon/serializers/order.js @@ -85,9 +85,6 @@ export default class OrderSerializer extends ApplicationSerializer.extend(Embedd json[key + '_type'] = null; } else { let type = belongsTo.modelName; - if (!isBlank(belongsTo.attr(`${key}_type`))) { - type = belongsTo.attr(`${key}_type`); - } // Strip abstract subtype prefixes so the server receives the bare model type // e.g. 'facilitator-vendor' -> 'vendor', 'customer-contact' -> 'contact' if (typeof type === 'string') { diff --git a/addon/serializers/waypoint.js b/addon/serializers/waypoint.js index 81b5269..cac2a6d 100644 --- a/addon/serializers/waypoint.js +++ b/addon/serializers/waypoint.js @@ -68,10 +68,6 @@ export default class WaypointSerializer extends ApplicationSerializer.extend(Emb if (isPolymorphicTypeBlank) { key = this.keyForAttribute ? this.keyForAttribute(key, 'serialize') : key; - if (!isBlank(belongsTo.attr(`${key}_type`))) { - type = belongsTo.attr(`${key}_type`); - } - // hotfix polymprohpic model types that do not exists as models like `customer-contact` `customer-vendor` should be `contact` or `vendor` if (typeof type === 'string') { if (type.startsWith('customer-')) { diff --git a/addon/serializers/work-order.js b/addon/serializers/work-order.js index dfd8bce..292124c 100644 --- a/addon/serializers/work-order.js +++ b/addon/serializers/work-order.js @@ -52,9 +52,6 @@ export default class WorkOrderSerializer extends ApplicationSerializer.extend(Em json[key + '_type'] = null; } else { let type = belongsTo.modelName; - if (!isBlank(belongsTo.attr(`${key}_type`))) { - type = belongsTo.attr(`${key}_type`); - } // Strip abstract subtype prefixes so the server receives the bare model type // e.g. 'facilitator-vendor' -> 'vendor', 'maintenance-subject-vehicle' -> 'vehicle' if (typeof type === 'string') { diff --git a/app/models/recurring-order-schedule.js b/app/models/recurring-order-schedule.js new file mode 100644 index 0000000..b65eef6 --- /dev/null +++ b/app/models/recurring-order-schedule.js @@ -0,0 +1 @@ +export { default } from '@fleetbase/fleetops-data/models/recurring-order-schedule'; From cb4cab97850e9e2a2793f438e570f265212e1515 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Sun, 3 May 2026 10:22:24 +0800 Subject: [PATCH 5/5] set proper attr transform on recurring-order-schedule model --- addon/models/recurring-order-schedule.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/addon/models/recurring-order-schedule.js b/addon/models/recurring-order-schedule.js index 5e2e6d6..fce714c 100644 --- a/addon/models/recurring-order-schedule.js +++ b/addon/models/recurring-order-schedule.js @@ -20,11 +20,11 @@ export default class RecurringOrderScheduleModel extends Model { @attr('string') driver_assigned_uuid; @attr('string') vehicle_assigned_uuid; @attr('string') service_rate_uuid; - @attr() template_order_meta; - @attr() template_payload; - @attr() template_entities; - @attr() meta; - @attr() upcoming_occurrences; + @attr('raw') template_order_meta; + @attr('raw') template_payload; + @attr('raw') template_entities; + @attr('raw') meta; + @attr('raw') upcoming_occurrences; @attr('date') next_occurrence_at; @attr('date') created_at; @attr('date') updated_at;