Skip to content

feat: add schedule, schedule-item and availability relationships to Driver model#45

Open
roncodes wants to merge 14 commits intomainfrom
feat/driver-scheduling-relationships
Open

feat: add schedule, schedule-item and availability relationships to Driver model#45
roncodes wants to merge 14 commits intomainfrom
feat/driver-scheduling-relationships

Conversation

@roncodes
Copy link
Copy Markdown
Member

Summary

Connects the Driver Ember Data model to the fleetbase/core-api scheduling system by adding three hasMany relationships.

Changes

addon/models/driver.js

Added the following relationships under a new @scheduling-relationships section:

Relationship Type Target Model Purpose
schedules hasMany (async) schedule Polymorphic Schedule records where the driver is the subject
schedule_items hasMany (async) schedule-item Individual shift records (ScheduleItem) where assignee_type='driver'
availabilities hasMany (async) schedule-availability Time-off and preferred working hour records

Why

The core-api already contains a complete scheduling system (Schedule, ScheduleItem, ScheduleAvailability, ScheduleConstraint, ScheduleTemplate) with all routes registered. These Ember Data relationships are the missing link that allows the FleetOps frontend to:

  1. Driver Schedule Panel — A new driver/schedule component (in the companion fleetbase/fleetops PR) renders a per-driver FullCalendar shift management view using these relationships.
  2. Intelligent Order Allocation Engine — The AllocationPayloadBuilder queries schedule_items to retrieve a driver's active shift start_at/end_at and injects them as time_window hard constraints into the VROOM optimization payload, ensuring no driver is assigned a route that exceeds their scheduled shift.

Related

Ronald A Richardson and others added 14 commits March 30, 2026 04:45
…river model

Connects the Driver Ember Data model to the core-api scheduling system by
adding three hasMany relationships:

- schedules: polymorphic Schedule records where the driver is the subject
- schedule_items: individual shift records (ScheduleItem) where the driver
  is the assignee (assignee_type='driver', assignee_uuid=driver.id)
- availabilities: ScheduleAvailability records for time-off and preferred
  working hours

These relationships are required by:
1. The new driver/schedule panel component which renders a per-driver
   FullCalendar shift management view
2. The Intelligent Order Allocation Engine AllocationPayloadBuilder which
   queries active schedule_items to inject shift time_window constraints
   into the VROOM optimization payload

Refs: fleetbase/fleetops#214
…rializer

The backend stores STI discriminator values (e.g. `fliit_contact`) in the
contacts.type column and passes them straight through in the Contact HTTP
Resource.  Ember Data's VendorModel declares `@hasMany('contact') personnels`
and tries to resolve each embedded record by its `type` field as a model
registry name — finding `fliit_contact` instead of `contact` and throwing:

  Assertion Failed: Encountered a relationship identifier with type
  'fliit_contact' for the hasMany relationship 'personnels' on <vendor:…>,
  Expected an identifier with type 'contact'.

Fix:
- Add `personnels: { embedded: 'always' }` to VendorSerializer attrs so the
  inline objects are processed through the normalize pipeline.
- Override `normalize()` in VendorSerializer to strip known package prefixes
  (fliit_, fleet_ops_, fleetops_) from each personnel's `type` field,
  converting it to the bare Ember model name (e.g. `contact`).
- Preserve the original discriminator value under `subtype` so application
  code that depends on it (role checks, routing, conditional rendering) is
  completely unaffected.
- Add `@attr('string') subtype` to ContactModel to expose the preserved value.

No backend changes required.
The VendorModel declares `@hasMany('contact') personnels` but the
VendorSerializer did not declare personnels as embedded.  Without the
embedded declaration, Ember Data attempts to resolve each inline personnel
object by reading its `type` field as a model registry name.  The backend
stores an STI discriminator in that field (e.g. `fliit_contact`) which does
not exist in the Ember Data registry, causing:

  Assertion Failed: Encountered a relationship identifier with type
  'fliit_contact' for the hasMany relationship 'personnels' on <vendor:…>

Fix: add `personnels: { embedded: 'always' }` to VendorSerializer attrs.
The EmbeddedRecordsMixin then resolves each record using the declared
relationship model type (`contact`) and the `type` attribute on each
payload object is treated as a plain domain attribute — untouched.

Also reverts the unnecessary `subtype` attr added to ContactModel in the
previous commit.
Adds the maintenance-schedule model to the fleetops-data package so the
Ember Data store can resolve 'maintenance-schedule' queries from the
maintenance module.

Files added:
- addon/models/maintenance-schedule.js: full model with all interval
  fields (time/distance/engine-hours), next-due thresholds, default
  assignee attrs, status, subject polymorphic fields, and computed
  date helpers (updatedAt, createdAt, nextDueAt, isActive, isPaused)
- app/models/maintenance-schedule.js: re-export shim following the
  same pattern as all other models in this package
…e module

- Add abstract MaintenanceSubject base model with common attributes (name, status, photo_url, dates)
- Add MaintenanceSubjectVehicle concrete model extending base (vehicle-specific attrs: make, model, year, plate_number, vin, odometer, engine_hours)
- Add MaintenanceSubjectEquipment concrete model extending base (equipment-specific attrs: serial_number, manufacturer, purchase_price)
- Add app re-export shims for all three maintenance-subject models
- Update MaintenanceSchedule model: replace subject_type/subject_uuid attrs with @belongsTo('maintenance-subject', {polymorphic: true}) and @belongsTo('facilitator', {polymorphic: true}) for default_assignee
- Update WorkOrder model: replace target_type/target_uuid with @belongsTo('maintenance-subject', {polymorphic: true}) and assignee_type/assignee_uuid with @belongsTo('facilitator', {polymorphic: true})
- Update Maintenance model: replace maintainable_type/maintainable_uuid with @belongsTo('maintenance-subject', {polymorphic: true}) and performed_by_type/performed_by_uuid with @belongsTo('facilitator', {polymorphic: true})
- Add MaintenanceScheduleSerializer with normalizePolymorphicType/serializePolymorphicType for subject and default_assignee
- Update WorkOrderSerializer with type mapping: fleet-ops:vehicle -> maintenance-subject-vehicle, fleet-ops:equipment -> maintenance-subject-equipment
- Update MaintenanceSerializer with type mapping for maintainable and performed_by relationships
- All serializers use EmbeddedRecordsMixin with embedded: always for polymorphic relationships

Follows the existing facilitator pattern (abstract base + concrete subtypes) used throughout the fleetops-data package.
… transformers exist

- maintenance-schedule: subject + default_assignee now embedded: always
- work-order: target + assignee + custom_field_values now embedded: always
- maintenance: maintainable + performed_by now embedded: always (work_order and
  custom_field_values were already embedded)

The backend PHP resource transformers (MaintenanceSchedule, WorkOrder, Maintenance)
eager-load these relationships via $with and embed them in every response, so the
frontend serializers can safely declare them as embedded: always.
…hicType

The previous commit incorrectly changed the normalizePolymorphicType maps from
PHP class names to shorthand strings. This would break any model that does not
go through the new resource transformers. The maps must stay as PHP class names
since that is what the backend returns for *_type fields on the parent record.

The backend resource transformers already handle the Ember Data type resolution
problem correctly by injecting a 'type' field into the embedded object — the
serializer maps do not need to change.
…e models

MoneyInput component emits cents as integers, and the backend Money cast
stores/retrieves integer cent values. Using @attr('number') caused JS number
coercion issues with large cent values. Using @attr('string') passes the raw
integer string through Ember Data without any transformation, which is correct
for MoneyInput's @value binding.

Affected models and attributes:
- equipment: purchase_price
- part: unit_cost, msrp
- maintenance: labor_cost, parts_cost, tax, total_cost
- work-order: estimated_cost, approved_budget, actual_cost
… Data models

Audited every maintenance-related server-side resource (fillable + appends)
against the corresponding fleetops-data Ember Data model and added all fields
that were present in the API response but absent from the model definition.

Equipment:
  + uuid
  + equipped_to_name  (server appended)
  + is_equipped       (server appended)
  + age_in_days       (server appended — computed from purchased_at)
  + depreciated_value (server appended — straight-line depreciation)

Part:
  + uuid
  + total_value   (server appended — quantity_on_hand × unit_cost)
  + is_in_stock   (server appended)
  + is_low_stock  (server appended)
  + asset_name    (server appended)

WorkOrder:
  + is_overdue           (server appended)
  + days_until_due       (server appended)
  + completion_percentage (server appended)
  + estimated_duration   (server appended)
  (estimated_cost, approved_budget, actual_cost, currency, cost_breakdown,
   cost_center, budget_code were already present from a prior commit)

Maintenance:
  + work_order_subject (server convenience field)
  + duration_hours     (server appended — diff of started_at/completed_at)
  + is_overdue         (server appended)
  + days_until_due     (server appended)
  + cost_breakdown     (server appended)

Asset:
  + uuid
  + current_location      (server appended)
  + is_online             (server appended)
  + last_maintenance      (server appended)
  + next_maintenance_due  (server appended)

Warranty:
  + uuid
  + subject_name    (server appended)
  + is_active       (server appended)
  + is_expired      (server appended)
  + days_remaining  (server appended)
  + coverage_summary (server appended)
  + status          (server appended)

Device:
  + uuid
  + warranty_name     (server appended)
  + telematic_name    (server appended)
  + is_online         (server appended)
  + attached_to_name  (server appended)
  + connection_status (server appended)

Sensor:
  + uuid
  Reorganised: moved photo_url, is_active, threshold_status under a clear
  "server-computed" section (they were already declared but mixed into attributes)

MaintenanceSchedule: no changes needed — subject_name and default_assignee_name
were already present.
…acilitator_type

All three maintenance serializers (work-order, maintenance, maintenance-schedule)
previously only mapped full PHP class names in MAINTENANCE_SUBJECT_TYPE_MAP and
FACILITATOR_TYPE_MAP. The fixed backend resources now inject bare slug strings
(e.g. 'facilitator-vendor', 'maintenance-subject-vehicle') via subject_type and
facilitator_type fields on the embedded object, so the old maps never matched.

Changes:
- Expand all type maps to cover: bare slug, fleet-ops: short-form, bare model
  name, and full PHP class name - so any variant the backend ever sends is handled.
- normalizePolymorphicType now reads the injected subject_type / facilitator_type
  field first (set by the fixed PHP resource), falling back to the raw _type field.
- serializePolymorphicType EMBER_TO_SHORTHAND maps extended to cover raw model
  names (vehicle, equipment, vendor, contact, driver) so saving works even when
  the record was set directly from a non-subtyped model (e.g. target=@vehicle).

Affected serializers: work-order, maintenance, maintenance-schedule.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant