@fleetbase/fleetops-engine 0.6.70 → 0.6.72
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/RELEASE.md +18 -47
- package/addon/components/admin/tracking-page-settings.hbs +56 -0
- package/addon/components/admin/tracking-page-settings.js +67 -0
- package/addon/components/device/form.hbs +2 -2
- package/addon/components/driver/details.hbs +1 -1
- package/addon/components/driver/form.hbs +1 -1
- package/addon/components/equipment/form.hbs +1 -1
- package/addon/components/layout/fleet-ops-sidebar.js +11 -3
- package/addon/components/maintenance/form.hbs +3 -3
- package/addon/components/map/google-live-map.js +2 -2
- package/addon/components/map/leaflet-live-map.js +45 -32
- package/addon/components/orchestrator/phase-builder.js +2 -1
- package/addon/components/orchestrator-workbench.hbs +7 -1
- package/addon/components/orchestrator-workbench.js +16 -2
- package/addon/components/order/details/activity.hbs +8 -6
- package/addon/components/order/details/activity.js +9 -0
- package/addon/components/order/details.hbs +29 -0
- package/addon/components/order/details.js +26 -0
- package/addon/components/order/form/details.hbs +30 -4
- package/addon/components/order/form/details.js +46 -0
- package/addon/components/order/form/route.hbs +5 -3
- package/addon/components/order/form/route.js +24 -1
- package/addon/components/order/form.hbs +12 -0
- package/addon/components/order/form.js +21 -1
- package/addon/components/order/kanban.js +72 -0
- package/addon/components/order-config-manager/activity-flow.js +45 -10
- package/addon/components/order-config-manager/lifecycle.hbs +250 -0
- package/addon/components/order-config-manager/lifecycle.js +358 -0
- package/addon/components/order-config-manager.js +5 -1
- package/addon/components/service-rate/details.hbs +1 -1
- package/addon/components/service-rate/form.hbs +1 -1
- package/addon/components/tracking-page/full-view.hbs +276 -0
- package/addon/components/tracking-page/full-view.js +474 -0
- package/addon/components/tracking-page/locale-selector.js +30 -0
- package/addon/components/tracking-page/map.hbs +44 -0
- package/addon/components/tracking-page/map.js +328 -0
- package/addon/components/tracking-page/order-list.hbs +35 -0
- package/addon/components/tracking-page/public-view.hbs +60 -0
- package/addon/components/tracking-page/settings-preview.hbs +21 -0
- package/addon/components/tracking-page/settings-preview.js +23 -0
- package/addon/components/tracking-page/verify-panel.hbs +109 -0
- package/addon/components/tracking-page.hbs +142 -0
- package/addon/components/tracking-page.js +564 -0
- package/addon/components/trailer/form.hbs +2 -2
- package/addon/components/vehicle/form.hbs +3 -3
- package/addon/components/warranty/form.hbs +2 -2
- package/addon/components/widget/live-fleet.js +54 -6
- package/addon/components/widget/proof-of-delivery.hbs +49 -0
- package/addon/components/widget/proof-of-delivery.js +62 -0
- package/addon/components/work-order/form.hbs +3 -3
- package/addon/controllers/analytics/reports/index.js +10 -1
- package/addon/controllers/connectivity/devices/index/details.js +1 -0
- package/addon/controllers/connectivity/devices/index.js +8 -2
- package/addon/controllers/connectivity/events/index.js +31 -1
- package/addon/controllers/connectivity/sensors/index/details.js +1 -1
- package/addon/controllers/connectivity/sensors/index.js +37 -1
- package/addon/controllers/maintenance/equipment/index/details.js +2 -2
- package/addon/controllers/maintenance/equipment/index.js +28 -9
- package/addon/controllers/maintenance/inspection-forms/index.js +32 -12
- package/addon/controllers/maintenance/inspection-submissions/index/details.js +2 -1
- package/addon/controllers/maintenance/inspection-submissions/index.js +49 -9
- package/addon/controllers/maintenance/maintenances/index/details.js +2 -0
- package/addon/controllers/maintenance/maintenances/index.js +20 -1
- package/addon/controllers/maintenance/parts/index/details.js +2 -2
- package/addon/controllers/maintenance/parts/index.js +28 -8
- package/addon/controllers/maintenance/schedules/index.js +33 -4
- package/addon/controllers/maintenance/work-orders/index/details.js +3 -3
- package/addon/controllers/maintenance/work-orders/index.js +39 -8
- package/addon/controllers/management/contacts/customers.js +13 -0
- package/addon/controllers/management/contacts/index.js +43 -1
- package/addon/controllers/management/drivers/index/details.js +1 -0
- package/addon/controllers/management/drivers/index.js +32 -2
- package/addon/controllers/management/fleets/index/details.js +1 -0
- package/addon/controllers/management/fleets/index.js +39 -1
- package/addon/controllers/management/fuel-reports/index.js +22 -2
- package/addon/controllers/management/fuel-transactions/index.js +43 -7
- package/addon/controllers/management/issues/index/details.js +1 -0
- package/addon/controllers/management/issues/index.js +22 -2
- package/addon/controllers/management/places/index.js +36 -1
- package/addon/controllers/management/trailers/index/details.js +1 -0
- package/addon/controllers/management/trailers/index.js +50 -2
- package/addon/controllers/management/vehicles/index/details.js +1 -0
- package/addon/controllers/management/vehicles/index.js +33 -2
- package/addon/controllers/management/vendors/index.js +26 -2
- package/addon/controllers/operations/orders/index/details.js +50 -7
- package/addon/controllers/operations/orders/index.js +59 -4
- package/addon/controllers/operations/scheduler/index.js +45 -14
- package/addon/controllers/operations/service-rates/index.js +15 -1
- package/addon/controllers/settings/index.js +6 -0
- package/addon/controllers/settings/map.js +75 -0
- package/addon/controllers/settings/orchestrator.js +8 -6
- package/addon/controllers/settings/tracking-page.js +212 -0
- package/addon/extension.js +97 -1
- package/addon/helpers/parcel-box-image.js +16 -0
- package/addon/routes/operations/orders/index/details.js +1 -0
- package/addon/routes/operations/orders/index/new.js +5 -4
- package/addon/routes/operations/scheduler/index.js +1 -1
- package/addon/routes/settings/tracking-page.js +31 -0
- package/addon/routes.js +1 -0
- package/addon/services/contact-actions.js +1 -0
- package/addon/services/customer-actions.js +2 -1
- package/addon/services/device-actions.js +1 -0
- package/addon/services/device-event-actions.js +1 -0
- package/addon/services/driver-actions.js +4 -13
- package/addon/services/equipment-actions.js +1 -0
- package/addon/services/fleet-actions.js +1 -0
- package/addon/services/fuel-report-actions.js +1 -0
- package/addon/services/inspection-form-actions.js +1 -0
- package/addon/services/inspection-submission-actions.js +1 -0
- package/addon/services/integrated-vendor-actions.js +1 -0
- package/addon/services/issue-actions.js +1 -0
- package/addon/services/location.js +69 -21
- package/addon/services/maintenance-actions.js +1 -0
- package/addon/services/maintenance-schedule-actions.js +2 -1
- package/addon/services/map-settings.js +28 -0
- package/addon/services/order-actions.js +7 -0
- package/addon/services/order-allocation.js +1 -1
- package/addon/services/order-presentation.js +129 -0
- package/addon/services/part-actions.js +1 -0
- package/addon/services/place-actions.js +1 -0
- package/addon/services/sensor-actions.js +1 -0
- package/addon/services/service-area-actions.js +1 -0
- package/addon/services/service-rate-actions.js +1 -0
- package/addon/services/telematic-actions.js +1 -0
- package/addon/services/trailer-actions.js +4 -14
- package/addon/services/vehicle-actions.js +4 -13
- package/addon/services/vendor-actions.js +1 -0
- package/addon/services/work-order-actions.js +1 -0
- package/addon/services/zone-actions.js +1 -0
- package/addon/styles/fleetops-engine.css +1391 -0
- package/addon/templates/analytics/reports/index/details.hbs +1 -0
- package/addon/templates/analytics/reports/index.hbs +1 -0
- package/addon/templates/connectivity/devices/index/details.hbs +1 -0
- package/addon/templates/connectivity/devices/index.hbs +1 -0
- package/addon/templates/connectivity/events/index.hbs +1 -0
- package/addon/templates/connectivity/sensors/index/details.hbs +1 -0
- package/addon/templates/connectivity/sensors/index.hbs +1 -0
- package/addon/templates/maintenance/equipment/index/details.hbs +1 -0
- package/addon/templates/maintenance/equipment/index.hbs +2 -0
- package/addon/templates/maintenance/inspection-forms/index/details.hbs +1 -0
- package/addon/templates/maintenance/inspection-forms/index.hbs +1 -0
- package/addon/templates/maintenance/inspection-submissions/index/details.hbs +1 -0
- package/addon/templates/maintenance/inspection-submissions/index.hbs +1 -0
- package/addon/templates/maintenance/maintenances/index/details.hbs +1 -0
- package/addon/templates/maintenance/maintenances/index.hbs +1 -0
- package/addon/templates/maintenance/parts/index/details.hbs +1 -0
- package/addon/templates/maintenance/parts/index.hbs +2 -0
- package/addon/templates/maintenance/schedules/index/details.hbs +1 -0
- package/addon/templates/maintenance/schedules/index.hbs +2 -0
- package/addon/templates/maintenance/work-orders/index/details.hbs +1 -0
- package/addon/templates/maintenance/work-orders/index.hbs +1 -0
- package/addon/templates/management/contacts/customers/details.hbs +1 -0
- package/addon/templates/management/contacts/customers.hbs +1 -0
- package/addon/templates/management/contacts/index/details.hbs +1 -0
- package/addon/templates/management/contacts/index.hbs +1 -0
- package/addon/templates/management/contacts.hbs +1 -0
- package/addon/templates/management/drivers/index/details.hbs +1 -0
- package/addon/templates/management/drivers/index.hbs +2 -0
- package/addon/templates/management/fleets/index/details.hbs +1 -0
- package/addon/templates/management/fleets/index.hbs +1 -0
- package/addon/templates/management/fuel-reports/index/details.hbs +1 -0
- package/addon/templates/management/fuel-reports/index.hbs +1 -0
- package/addon/templates/management/fuel-transactions/index.hbs +1 -0
- package/addon/templates/management/issues/index/details.hbs +1 -0
- package/addon/templates/management/issues/index.hbs +1 -0
- package/addon/templates/management/places/index/details.hbs +1 -0
- package/addon/templates/management/places/index.hbs +1 -0
- package/addon/templates/management/trailers/index/details.hbs +1 -0
- package/addon/templates/management/trailers/index.hbs +2 -0
- package/addon/templates/management/vehicles/index/details.hbs +1 -0
- package/addon/templates/management/vehicles/index.hbs +2 -0
- package/addon/templates/management/vendors/index/details.hbs +1 -0
- package/addon/templates/management/vendors/index.hbs +2 -0
- package/addon/templates/management/vendors/integrated.hbs +1 -0
- package/addon/templates/operations/orders/index/details.hbs +1 -0
- package/addon/templates/operations/orders/index.hbs +1 -0
- package/addon/templates/operations/service-rates/index/details.hbs +1 -0
- package/addon/templates/operations/service-rates/index.hbs +1 -0
- package/addon/templates/settings/map.hbs +46 -0
- package/addon/templates/settings/tracking-page.hbs +318 -0
- package/addon/utils/identity-cell-resource.js +2 -56
- package/addon/utils/map-default-view.js +132 -0
- package/addon/utils/normalize-order-config-flow.js +6 -1
- package/addon/utils/placeholder-images.js +4 -69
- package/addon/utils/resource-descriptors/assets.js +2 -57
- package/addon/utils/resource-descriptors/helpers.js +23 -122
- package/addon/utils/resource-descriptors/operations.js +2 -61
- package/addon/utils/resource-descriptors/people.js +3 -142
- package/addon/utils/resource-descriptors/shared.js +18 -0
- package/addon/utils/tracking-live-source.js +123 -0
- package/addon/utils/tracking-page-theme.js +123 -0
- package/app/components/admin/tracking-page-settings.js +1 -0
- package/app/components/tracking-page/full-view.js +1 -0
- package/app/components/tracking-page/locale-selector.js +1 -0
- package/app/components/tracking-page/map.js +1 -0
- package/app/components/tracking-page/order-list.js +1 -0
- package/app/components/tracking-page/public-view.js +1 -0
- package/app/components/tracking-page/settings-preview.js +1 -0
- package/app/components/tracking-page/verify-panel.js +1 -0
- package/app/components/tracking-page.js +1 -0
- package/app/components/widget/proof-of-delivery.js +1 -0
- package/app/controllers/settings/tracking-page.js +1 -0
- package/app/helpers/parcel-box-image.js +1 -0
- package/app/routes/settings/tracking-page.js +1 -0
- package/app/services/order-presentation.js +1 -0
- package/app/templates/settings/tracking-page.js +1 -0
- package/app/utils/map-default-view.js +1 -0
- package/app/utils/tracking-live-source.js +1 -0
- package/app/utils/tracking-page-theme.js +1 -0
- package/composer.json +2 -2
- package/extension.json +1 -1
- package/package.json +4 -4
- package/scripts/pest-bootstrap.php +4 -0
- package/server/config/fleetops.php +4 -0
- package/server/migrations/2026_10_08_000001_create_tracking_sessions_tables.php +51 -0
- package/server/migrations/2026_10_10_000001_add_trashed_index_to_device_events.php +40 -0
- package/server/migrations/2026_10_10_000002_add_trashed_index_to_positions.php +40 -0
- package/server/migrations/2026_10_12_000001_add_deleted_at_to_tracking_sessions_tables.php +32 -0
- package/server/resources/views/labels/default.php +2 -2
- package/server/resources/views/labels/entity-label.php +2 -2
- package/server/resources/views/labels/waypoint-label.php +2 -2
- package/server/src/Auth/Schemas/FleetOps.php +5 -0
- package/server/src/Console/Commands/ProcessOperationalAlerts.php +1 -0
- package/server/src/Console/Commands/PruneTelematicsData.php +101 -26
- package/server/src/Events/OrderChanged.php +257 -0
- package/server/src/Events/OrderDriverUnassigned.php +68 -0
- package/server/src/Exceptions/OrderEditLockedException.php +32 -0
- package/server/src/Expansions/CompanyExpansion.php +3 -2
- package/server/src/Expansions/UserExpansion.php +12 -10
- package/server/src/Http/Controllers/Api/v1/CustomerController.php +108 -18
- package/server/src/Http/Controllers/Api/v1/DriverController.php +95 -10
- package/server/src/Http/Controllers/Api/v1/EntityController.php +66 -0
- package/server/src/Http/Controllers/Api/v1/FleetController.php +10 -4
- package/server/src/Http/Controllers/Api/v1/OrderController.php +139 -36
- package/server/src/Http/Controllers/Api/v1/PayloadController.php +76 -8
- package/server/src/Http/Controllers/Api/v1/PlaceController.php +3 -3
- package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +6 -32
- package/server/src/Http/Controllers/Api/v1/VehicleController.php +5 -0
- package/server/src/Http/Controllers/Internal/v1/ContactController.php +3 -0
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +10 -0
- package/server/src/Http/Controllers/Internal/v1/FleetController.php +16 -2
- package/server/src/Http/Controllers/Internal/v1/InspectionSubmissionController.php +13 -8
- package/server/src/Http/Controllers/Internal/v1/IssueController.php +2 -0
- package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +4 -2
- package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +93 -11
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +118 -28
- package/server/src/Http/Controllers/Internal/v1/PositionController.php +22 -0
- package/server/src/Http/Controllers/Internal/v1/ProofController.php +55 -4
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +303 -10
- package/server/src/Http/Controllers/Internal/v1/TrailerController.php +1 -0
- package/server/src/Http/Controllers/Internal/v1/VehicleController.php +1 -0
- package/server/src/Http/Controllers/Public/TrackingController.php +518 -0
- package/server/src/Http/Filter/ContactFilter.php +1 -1
- package/server/src/Http/Filter/InspectionFormFilter.php +23 -0
- package/server/src/Http/Filter/InspectionSubmissionFilter.php +23 -0
- package/server/src/Http/Filter/MaintenanceFilter.php +23 -0
- package/server/src/Http/Filter/OrderFilter.php +39 -4
- package/server/src/Http/Filter/ProofFilter.php +18 -0
- package/server/src/Http/Filter/RouteFilter.php +18 -0
- package/server/src/Http/Filter/TelematicFilter.php +23 -0
- package/server/src/Http/Filter/WarrantyFilter.php +23 -0
- package/server/src/Http/Requests/CancelOrderRequest.php +2 -1
- package/server/src/Http/Resources/v1/Concerns/ResolvesPublicRelationFields.php +14 -1
- package/server/src/Http/Resources/v1/Index/Customer.php +18 -0
- package/server/src/Http/Resources/v1/Index/Order.php +11 -2
- package/server/src/Http/Resources/v1/PublicOrderTracking.php +153 -0
- package/server/src/Http/Resources/v1/TrackingNumber.php +8 -34
- package/server/src/Http/Resources/v1/Zone.php +31 -23
- package/server/src/Jobs/FinalizeApiOrderCreation.php +3 -1
- package/server/src/Jobs/ProcessAllocationJob.php +16 -6
- package/server/src/Jobs/PublishTrackingUpdate.php +50 -0
- package/server/src/Listeners/HandleGeofenceEntered.php +31 -15
- package/server/src/Listeners/HandleOrderCanceled.php +9 -1
- package/server/src/Listeners/HandleUserRemovedFromCompany.php +2 -1
- package/server/src/Listeners/PublishTrackingUpdates.php +27 -0
- package/server/src/Mail/CustomerCredentialsMail.php +4 -2
- package/server/src/Models/AssetConnection.php +3 -0
- package/server/src/Models/Contact.php +3 -0
- package/server/src/Models/Device.php +28 -0
- package/server/src/Models/DeviceEvent.php +7 -0
- package/server/src/Models/Driver.php +20 -7
- package/server/src/Models/Entity.php +12 -4
- package/server/src/Models/Fleet.php +11 -32
- package/server/src/Models/FleetDriver.php +3 -0
- package/server/src/Models/FleetVehicle.php +3 -0
- package/server/src/Models/FuelReport.php +5 -13
- package/server/src/Models/Issue.php +4 -16
- package/server/src/Models/Order.php +234 -11
- package/server/src/Models/OrderConfig.php +129 -0
- package/server/src/Models/Payload.php +227 -35
- package/server/src/Models/Place.php +7 -1
- package/server/src/Models/ServiceArea.php +7 -0
- package/server/src/Models/ServiceRate.php +7 -17
- package/server/src/Models/TrackingNumber.php +109 -6
- package/server/src/Models/TrackingSession.php +33 -0
- package/server/src/Models/TrackingSessionGrant.php +22 -0
- package/server/src/Models/TrackingStatus.php +6 -0
- package/server/src/Models/Vehicle.php +21 -2
- package/server/src/Models/Vendor.php +7 -0
- package/server/src/Models/Waypoint.php +13 -4
- package/server/src/Notifications/OrderAssigned.php +2 -1
- package/server/src/Notifications/OrderCanceled.php +7 -1
- package/server/src/Notifications/OrderChanged.php +87 -0
- package/server/src/Notifications/OrderCompleted.php +2 -1
- package/server/src/Notifications/OrderDispatchFailed.php +2 -1
- package/server/src/Notifications/OrderDispatched.php +2 -1
- package/server/src/Notifications/OrderFailed.php +2 -1
- package/server/src/Notifications/OrderUnassigned.php +66 -0
- package/server/src/Notifications/WaypointCompleted.php +2 -1
- package/server/src/Observers/CompanyUserObserver.php +8 -7
- package/server/src/Observers/DriverObserver.php +6 -1
- package/server/src/Observers/OrderObserver.php +141 -1
- package/server/src/Observers/TrackingNumberObserver.php +18 -6
- package/server/src/Observers/UserObserver.php +2 -1
- package/server/src/Observers/VehicleObserver.php +8 -3
- package/server/src/Orchestration/Engines/RouteSequencingEngine.php +21 -3
- package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +38 -8
- package/server/src/Orchestration/OrchestrationEngineRegistry.php +61 -1
- package/server/src/Orchestration/Support/OrchestratorSettings.php +61 -0
- package/server/src/Orchestration/Support/RouteMetrics.php +165 -0
- package/server/src/Providers/EventServiceProvider.php +11 -0
- package/server/src/Providers/FleetOpsServiceProvider.php +13 -0
- package/server/src/Support/ApiCacheThrottle.php +76 -0
- package/server/src/Support/LiveOrderQuery.php +3 -1
- package/server/src/Support/OrderEdit.php +365 -0
- package/server/src/Support/OrderEditPolicy.php +292 -0
- package/server/src/Support/ProfileAccountManager.php +54 -1
- package/server/src/Support/ResolvesOrderServiceStops.php +5 -0
- package/server/src/Support/SocketChannels.php +346 -0
- package/server/src/Support/Telematics/TelematicService.php +7 -2
- package/server/src/Support/Telematics/Telemetry/Inbox.php +8 -1
- package/server/src/Support/TrackingChannel.php +55 -0
- package/server/src/Support/TrackingCode.php +242 -0
- package/server/src/Support/TrackingPage/TrackingAccess.php +356 -0
- package/server/src/Support/TrackingPage/TrackingPageConfig.php +264 -0
- package/server/src/Support/TrackingPage/TrackingRecipient.php +111 -0
- package/server/src/Support/TrackingPage/TrackingResolver.php +201 -0
- package/server/src/Support/TrackingPage/TrackingTarget.php +40 -0
- package/server/src/Support/TrackingPage/TrackingView.php +543 -0
- package/server/src/Support/TrackingPublisher.php +261 -0
- package/server/src/Support/TrackingScope.php +182 -0
- package/server/src/Support/TrackingUpdate.php +402 -0
- package/server/src/Support/Utils.php +15 -3
- package/server/src/Traits/HasTrackingNumber.php +2 -0
- package/server/src/routes.php +39 -7
- package/server/tests/ApiCustomerControllerContractsTest.php +54 -7
- package/server/tests/ApiDriverPasswordContractsTest.php +25 -21
- package/server/tests/ApiEntityControllerContractsTest.php +84 -0
- package/server/tests/ApiOrderControllerContractsTest.php +245 -0
- package/server/tests/ApiPayloadControllerContractsTest.php +121 -0
- package/server/tests/ApiPlaceControllerContractsTest.php +1 -1
- package/server/tests/ApiTrackingNumberControllerContractsTest.php +6 -9
- package/server/tests/CompactResourceSerializationTest.php +23 -59
- package/server/tests/ControllerFilterContractsTest.php +1 -1
- package/server/tests/CustomerContactIdentitySafetyTest.php +1 -1
- package/server/tests/EventContractsTest.php +26 -60
- package/server/tests/ExpansionContractsTest.php +15 -2
- package/server/tests/Feature/Http/Api/CustomerControllerHelperSeamsTest.php +29 -3
- package/server/tests/Feature/Http/Api/DriverControllerAuthFlowsTest.php +23 -0
- package/server/tests/Feature/Http/Api/OrderControllerNearbyFiltersTest.php +16 -16
- package/server/tests/Feature/Http/Api/OrderControllerQueryFiltersTest.php +41 -14
- package/server/tests/Feature/Http/Api/TrackingNumberControllerHelpersTest.php +57 -22
- package/server/tests/Feature/Http/Internal/DriverControllerCreateRecordTest.php +23 -9
- package/server/tests/Feature/Http/Internal/OrchestrationControllerContractsTest.php +171 -1
- package/server/tests/Feature/Http/Internal/OrderControllerActivityFlowsTest.php +72 -0
- package/server/tests/Feature/Http/Internal/OrderControllerContractsTest.php +110 -14
- package/server/tests/Feature/Http/Internal/OrderControllerCreateRecordTest.php +26 -0
- package/server/tests/Feature/Http/Internal/OrderControllerHelpersTest.php +7 -5
- package/server/tests/Feature/Http/Internal/PositionControllerReplayChannelTest.php +135 -0
- package/server/tests/Feature/Http/Internal/ProofControllerContractsTest.php +3 -3
- package/server/tests/Feature/Http/Internal/ProofControllerRecentTest.php +170 -0
- package/server/tests/Feature/Http/Public/TrackingControllerTest.php +495 -0
- package/server/tests/IndexCustomerPhotoTest.php +151 -0
- package/server/tests/ModelAccessorContractsTest.php +4 -3
- package/server/tests/NotificationAndMailContractsTest.php +5 -8
- package/server/tests/ObserverContractsTest.php +72 -10
- package/server/tests/OrderActivityFlowRegressionTest.php +3 -2
- package/server/tests/OrderConfigLifecycleTest.php +120 -0
- package/server/tests/OrderFilterExecutionTest.php +167 -2
- package/server/tests/ProcessAllocationJobContractsTest.php +20 -0
- package/server/tests/PublicOrderTrackingResourceTest.php +221 -0
- package/server/tests/QueueJobContractsTest.php +2 -1
- package/server/tests/RequestContractsTest.php +1 -1
- package/server/tests/RouteRegistrationExecutionTest.php +26 -0
- package/server/tests/RouteSequencingEngineTest.php +17 -0
- package/server/tests/SettingControllerContractsTest.php +110 -0
- package/server/tests/Support/TrackingPageDatabase.php +200 -0
- package/server/tests/TenantScopingTest.php +206 -0
- package/server/tests/TrackingPageSettingsTest.php +343 -0
- package/server/tests/Unit/Console/PruneTelematicsDataCommandTest.php +51 -0
- package/server/tests/Unit/Events/OrderDispatchFailedTest.php +2 -1
- package/server/tests/Unit/Http/Filter/ContactFilterAddressTest.php +61 -0
- package/server/tests/Unit/Http/Resources/IndexOrderResourceTest.php +30 -0
- package/server/tests/Unit/Jobs/FinalizeApiOrderCreationDispatchGuardTest.php +266 -0
- package/server/tests/Unit/Listeners/HandleGeofenceEnteredTest.php +182 -22
- package/server/tests/Unit/Listeners/HandleUserRemovedFromCompanyTest.php +5 -0
- package/server/tests/Unit/Models/DriverAssignVehicleTest.php +81 -0
- package/server/tests/Unit/Models/FleetTest.php +4 -3
- package/server/tests/Unit/Models/OrderCancelReasonTest.php +143 -0
- package/server/tests/Unit/Models/OrderPayloadConfigAndDistanceTest.php +60 -0
- package/server/tests/Unit/Models/OrderPayloadRouteTest.php +4 -2
- package/server/tests/Unit/Models/PayloadTest.php +18 -4
- package/server/tests/Unit/Models/ServiceRatePersistenceAndServicabilityTest.php +2 -2
- package/server/tests/Unit/Models/TrackingNumberTest.php +67 -6
- package/server/tests/Unit/Models/VehicleTest.php +16 -2
- package/server/tests/Unit/Models/WaypointTest.php +4 -3
- package/server/tests/Unit/Notifications/OrderChangeNotificationsTest.php +59 -0
- package/server/tests/Unit/Notifications/TerminalOrderNotificationsTest.php +3 -3
- package/server/tests/Unit/Observers/DriverDeletionCleanupTest.php +158 -0
- package/server/tests/Unit/Observers/FleetOpsCompanyUserAndServiceAreaObserversTest.php +20 -0
- package/server/tests/Unit/Observers/ObserverListenerSeamsTest.php +3 -3
- package/server/tests/Unit/Observers/OrderAssignmentObserverTest.php +100 -0
- package/server/tests/Unit/Observers/OrderDeleteCascadeTest.php +213 -0
- package/server/tests/Unit/Observers/VehicleObserverDeleteTest.php +67 -0
- package/server/tests/Unit/Orchestration/EngineSelectionAndRouteMetricsTest.php +336 -0
- package/server/tests/Unit/Orchestration/Engines/VroomOrchestrationEngineLifecycleTest.php +8 -1
- package/server/tests/Unit/Support/ApiCacheDependenciesTest.php +347 -0
- package/server/tests/Unit/Support/OrderEditPolicyTest.php +156 -0
- package/server/tests/Unit/Support/OrderOperationsTest.php +514 -0
- package/server/tests/Unit/Support/OsrmProofAndIssueFilterTest.php +4 -3
- package/server/tests/Unit/Support/ProfileAccountManagerTest.php +141 -0
- package/server/tests/Unit/Support/QuerySeamsTest.php +5 -1
- package/server/tests/Unit/Support/SocketChannelsTest.php +396 -0
- package/server/tests/Unit/Support/TrackingChannelTest.php +232 -0
- package/server/tests/Unit/Support/TrackingCodeTest.php +186 -0
- package/server/tests/Unit/Support/TrackingPage/TrackingAccessTest.php +200 -0
- package/server/tests/Unit/Support/TrackingPage/TrackingRecipientTest.php +51 -0
- package/server/tests/Unit/Support/TrackingPage/TrackingResolverTest.php +181 -0
- package/server/tests/Unit/Support/TrackingPage/TrackingViewTest.php +479 -0
- package/server/tests/Unit/Support/TrackingPublisherTest.php +425 -0
- package/server/tests/Unit/Support/TrackingUpdateTest.php +363 -0
- package/server/tests/Unit/Support/UtilsAdditionalTest.php +9 -0
- package/server/tests/Unit/Support/UtilsGeoMatrixAndVendorTest.php +25 -0
- package/server/tests/VehicleResourceContractsTest.php +46 -0
- package/server/tests/VroomOrchestrationEngineTest.php +34 -1
- package/server/tests/ZoneGeofenceSettingsResourceTest.php +121 -0
- package/translations/ar-ae.yml +274 -0
- package/translations/bg-bg.yaml +274 -0
- package/translations/en-us.yaml +347 -0
- package/translations/es-pa.yaml +274 -0
- package/translations/fr-fr.yaml +274 -0
- package/translations/mn-mn.yaml +274 -0
- package/translations/pt-br.yaml +274 -0
- package/translations/ru-ru.yaml +276 -2
- package/translations/uk-ua.yaml +275 -1
- package/translations/vi-vn.yaml +274 -0
- package/addon/components/cell/contact-identity.hbs +0 -1
- package/addon/components/cell/customer-identity.hbs +0 -1
- package/addon/components/cell/driver-identity.hbs +0 -1
- package/addon/components/cell/fleet-identity.hbs +0 -1
- package/addon/components/cell/order-identity.hbs +0 -1
- package/addon/components/cell/place-identity.hbs +0 -1
- package/addon/components/cell/vehicle-identity.hbs +0 -1
- package/addon/components/cell/vendor-identity.hbs +0 -1
- package/addon/components/contact/pill.hbs +0 -24
- package/addon/components/contact/summary.hbs +0 -1
- package/addon/components/customer/pill.hbs +0 -24
- package/addon/components/customer/summary.hbs +0 -1
- package/addon/components/driver/pill.hbs +0 -24
- package/addon/components/driver/summary.hbs +0 -1
- package/addon/components/fleet/pill.hbs +0 -24
- package/addon/components/fleet/summary.hbs +0 -1
- package/addon/components/order/pill.hbs +0 -24
- package/addon/components/order/summary.hbs +0 -1
- package/addon/components/place/pill.hbs +0 -24
- package/addon/components/place/summary.hbs +0 -1
- package/addon/components/select-option/contact.hbs +0 -12
- package/addon/components/select-option/customer.hbs +0 -12
- package/addon/components/select-option/driver.hbs +0 -12
- package/addon/components/select-option/fleet.hbs +0 -12
- package/addon/components/select-option/order.hbs +0 -12
- package/addon/components/select-option/place.hbs +0 -12
- package/addon/components/select-option/vehicle.hbs +0 -12
- package/addon/components/select-option/vendor.hbs +0 -12
- package/addon/components/vehicle/pill.hbs +0 -24
- package/addon/components/vehicle/summary.hbs +0 -1
- package/addon/components/vendor/pill.hbs +0 -24
- package/addon/components/vendor/summary.hbs +0 -1
- package/app/components/cell/contact-identity.js +0 -1
- package/app/components/cell/customer-identity.js +0 -1
- package/app/components/cell/driver-identity.js +0 -1
- package/app/components/cell/fleet-identity.js +0 -1
- package/app/components/cell/order-identity.js +0 -1
- package/app/components/cell/place-identity.js +0 -1
- package/app/components/cell/vehicle-identity.js +0 -1
- package/app/components/cell/vendor-identity.js +0 -1
- package/app/components/contact/pill.js +0 -1
- package/app/components/contact/summary.js +0 -1
- package/app/components/customer/pill.js +0 -1
- package/app/components/customer/summary.js +0 -1
- package/app/components/driver/pill.js +0 -1
- package/app/components/driver/summary.js +0 -1
- package/app/components/fleet/pill.js +0 -1
- package/app/components/fleet/summary.js +0 -1
- package/app/components/order/pill.js +0 -1
- package/app/components/order/summary.js +0 -1
- package/app/components/place/pill.js +0 -1
- package/app/components/place/summary.js +0 -1
- package/app/components/select-option/contact.js +0 -1
- package/app/components/select-option/customer.js +0 -1
- package/app/components/select-option/driver.js +0 -1
- package/app/components/select-option/fleet.js +0 -1
- package/app/components/select-option/order.js +0 -1
- package/app/components/select-option/place.js +0 -1
- package/app/components/select-option/vehicle.js +0 -1
- package/app/components/select-option/vendor.js +0 -1
- package/app/components/vehicle/pill.js +0 -1
- package/app/components/vehicle/summary.js +0 -1
- package/app/components/vendor/pill.js +0 -1
- package/app/components/vendor/summary.js +0 -1
|
@@ -1,14 +1,40 @@
|
|
|
1
1
|
import Component from '@glimmer/component';
|
|
2
2
|
import { action } from '@ember/object';
|
|
3
3
|
import { tracked } from '@glimmer/tracking';
|
|
4
|
+
import { inject as service } from '@ember/service';
|
|
4
5
|
|
|
5
6
|
export default class OrderDetailsComponent extends Component {
|
|
7
|
+
@service orderPresentation;
|
|
6
8
|
@tracked proofReloadToken = 0;
|
|
7
9
|
|
|
8
10
|
get effectiveProofReloadToken() {
|
|
9
11
|
return `${this.args.proofReloadToken ?? 0}:${this.proofReloadToken}`;
|
|
10
12
|
}
|
|
11
13
|
|
|
14
|
+
/** The extension presentation profile applying to this order's config, if any. */
|
|
15
|
+
get profile() {
|
|
16
|
+
return this.orderPresentation.profileFor(this.args.resource);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Profile sections with the change handler each native section expects. */
|
|
20
|
+
get profileSections() {
|
|
21
|
+
const handlers = {
|
|
22
|
+
activity: this.handleActivityChanged,
|
|
23
|
+
detail: this.args.onDetailsChanged,
|
|
24
|
+
'custom-fields': this.args.onCustomFieldsChanged,
|
|
25
|
+
notes: this.args.onNotesChanged,
|
|
26
|
+
route: this.args.onRouteChanged,
|
|
27
|
+
payload: this.args.onPayloadChanged,
|
|
28
|
+
documents: this.args.onDocumentsChanged,
|
|
29
|
+
comments: this.args.onCommentsChanged,
|
|
30
|
+
metadata: this.args.onMetadataChanged,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return this.orderPresentation.renderableSectionsFor(this.profile, 'details').map((section) => {
|
|
34
|
+
return section.native ? { ...section, onChange: handlers[section.name] } : section;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
12
38
|
@action handleActivityChanged(optionsOrActivity) {
|
|
13
39
|
if (typeof this.args.onActivityChanged === 'function') {
|
|
14
40
|
this.args.onActivityChanged(optionsOrActivity?.activityCreated ?? optionsOrActivity);
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
@onChange={{perform this.selectOrderConfig}}
|
|
10
10
|
@placeholder={{t "order.fields.order-type-placeholder"}}
|
|
11
11
|
@triggerClass="form-select form-input"
|
|
12
|
-
@disabled={{cannot-write @resource}}
|
|
12
|
+
@disabled={{or (cannot-write @resource) this.orderTypeLocked}}
|
|
13
13
|
as |orderConfig|
|
|
14
14
|
>
|
|
15
15
|
<SelectOption::OrderConfig @option={{orderConfig}} />
|
|
@@ -17,8 +17,19 @@
|
|
|
17
17
|
</div>
|
|
18
18
|
</InputGroup>
|
|
19
19
|
|
|
20
|
+
{{#if this.profileDetailFields}}
|
|
21
|
+
<div class="contents">
|
|
22
|
+
<LazyEngineComponent @component={{this.profileDetailFields}} as |ProfileDetailFields|>
|
|
23
|
+
<ProfileDetailFields @resource={{@resource}} @order={{@resource}} @profile={{this.profile}} />
|
|
24
|
+
</LazyEngineComponent>
|
|
25
|
+
</div>
|
|
26
|
+
{{/if}}
|
|
27
|
+
|
|
28
|
+
{{#if this.show.internalId}}
|
|
20
29
|
<InputGroup @name={{t "order.fields.internal-id"}} @value={{@resource.internal_id}} @helpText={{t "order.fields.internal-id-help-text"}} @disabled={{cannot-write @resource}} />
|
|
30
|
+
{{/if}}
|
|
21
31
|
|
|
32
|
+
{{#if this.show.schedule}}
|
|
22
33
|
<InputGroup>
|
|
23
34
|
<InputLabel @labelText={{t "order.fields.schedule"}} @helpText={{t "order.fields.schedule-help-text"}} />
|
|
24
35
|
<DateTimeInput
|
|
@@ -30,7 +41,9 @@
|
|
|
30
41
|
@disabled={{or @resource.dispatched (cannot-write @resource)}}
|
|
31
42
|
/>
|
|
32
43
|
</InputGroup>
|
|
44
|
+
{{/if}}
|
|
33
45
|
|
|
46
|
+
{{#if this.show.customer}}
|
|
34
47
|
<InputGroup @name={{t "order.fields.customer"}} @helpText={{t "order.fields.customer-help-text"}}>
|
|
35
48
|
<ModelSelect
|
|
36
49
|
@modelName="customer"
|
|
@@ -48,7 +61,9 @@
|
|
|
48
61
|
<SelectOption::Customer @option={{model}} />
|
|
49
62
|
</ModelSelect>
|
|
50
63
|
</InputGroup>
|
|
64
|
+
{{/if}}
|
|
51
65
|
|
|
66
|
+
{{#if this.show.facilitator}}
|
|
52
67
|
<InputGroup @name={{t "order.fields.facilitator"}} @helpText={{t "order.fields.facilitator-help-text"}}>
|
|
53
68
|
<ModelSelect
|
|
54
69
|
@modelName="facilitator"
|
|
@@ -66,8 +81,9 @@
|
|
|
66
81
|
<SelectOption::Facilitator @option={{model}} />
|
|
67
82
|
</ModelSelect>
|
|
68
83
|
</InputGroup>
|
|
84
|
+
{{/if}}
|
|
69
85
|
|
|
70
|
-
{{#if (and @resource.facilitator.isIntegratedVendor @resource.facilitator.service_types.length)}}
|
|
86
|
+
{{#if (and this.show.serviceType @resource.facilitator.isIntegratedVendor @resource.facilitator.service_types.length)}}
|
|
71
87
|
<InputGroup @name={{t "order.fields.service-type"}} @helpText={{concat (t "order.fields.service-type-help-text") @resource.facilitator.name "."}}>
|
|
72
88
|
<Select
|
|
73
89
|
class="w-full"
|
|
@@ -82,6 +98,7 @@
|
|
|
82
98
|
</InputGroup>
|
|
83
99
|
{{/if}}
|
|
84
100
|
|
|
101
|
+
{{#if this.show.driver}}
|
|
85
102
|
<InputGroup @name={{t "order.fields.assign-driver"}} @helpText={{t "order.fields.assign-driver-help-text"}}>
|
|
86
103
|
<ModelSelect
|
|
87
104
|
@modelName="driver"
|
|
@@ -101,7 +118,9 @@
|
|
|
101
118
|
<SelectOption::Driver @option={{model}} />
|
|
102
119
|
</ModelSelect>
|
|
103
120
|
</InputGroup>
|
|
121
|
+
{{/if}}
|
|
104
122
|
|
|
123
|
+
{{#if this.show.vehicle}}
|
|
105
124
|
<InputGroup @name={{t "order.fields.assign-vehicle"}} @helpText={{t "order.fields.assign-vehicle-help-text"}}>
|
|
106
125
|
<ModelSelect
|
|
107
126
|
@modelName="vehicle"
|
|
@@ -120,8 +139,9 @@
|
|
|
120
139
|
<SelectOption::Vehicle @option={{model}} />
|
|
121
140
|
</ModelSelect>
|
|
122
141
|
</InputGroup>
|
|
142
|
+
{{/if}}
|
|
123
143
|
|
|
124
|
-
{{#if (and @resource.pod_required (not @resource.facilitator.isIntegratedVendor))}}
|
|
144
|
+
{{#if (and this.show.pod @resource.pod_required (not @resource.facilitator.isIntegratedVendor))}}
|
|
125
145
|
<InputGroup @name={{t "order.fields.proof-delivery"}} @helpText={{t "order.fields.proof-delivery-help-text"}} @required={{true}}>
|
|
126
146
|
<div class="fleetbase-model-select fleetbase-power-select ember-model-select">
|
|
127
147
|
<PowerSelect
|
|
@@ -142,7 +162,7 @@
|
|
|
142
162
|
</InputGroup>
|
|
143
163
|
{{/if}}
|
|
144
164
|
|
|
145
|
-
{{#if @resource.adhoc}}
|
|
165
|
+
{{#if (and this.show.adhoc @resource.adhoc)}}
|
|
146
166
|
<div>
|
|
147
167
|
<InputGroup
|
|
148
168
|
@name={{t "order.fields.adhoc-ping"}}
|
|
@@ -158,6 +178,7 @@
|
|
|
158
178
|
</div>
|
|
159
179
|
{{/if}}
|
|
160
180
|
|
|
181
|
+
{{#if this.show.adhoc}}
|
|
161
182
|
<div class="lg:col-span-2">
|
|
162
183
|
<InputGroup @wrapperClass="pt-2">
|
|
163
184
|
<Toggle
|
|
@@ -170,7 +191,9 @@
|
|
|
170
191
|
/>
|
|
171
192
|
</InputGroup>
|
|
172
193
|
</div>
|
|
194
|
+
{{/if}}
|
|
173
195
|
|
|
196
|
+
{{#if this.show.dispatch}}
|
|
174
197
|
<div class="lg:col-span-2">
|
|
175
198
|
<InputGroup @wrapperClass="pt-1">
|
|
176
199
|
<Toggle
|
|
@@ -183,7 +206,9 @@
|
|
|
183
206
|
/>
|
|
184
207
|
</InputGroup>
|
|
185
208
|
</div>
|
|
209
|
+
{{/if}}
|
|
186
210
|
|
|
211
|
+
{{#if this.show.pod}}
|
|
187
212
|
<div class="lg:col-span-2">
|
|
188
213
|
<InputGroup @wrapperClass="pt-1">
|
|
189
214
|
<Toggle
|
|
@@ -196,6 +221,7 @@
|
|
|
196
221
|
/>
|
|
197
222
|
</InputGroup>
|
|
198
223
|
</div>
|
|
224
|
+
{{/if}}
|
|
199
225
|
|
|
200
226
|
<RegistryYield @registry="fleet-ops:component:order:form:details" as |RegistryComponent|>
|
|
201
227
|
<RegistryComponent @order={{@resource}} @resource={{@resource}} />
|
|
@@ -13,6 +13,7 @@ export default class OrderFormDetailsComponent extends Component {
|
|
|
13
13
|
@service leafletMapManager;
|
|
14
14
|
@service leafletLayerVisibilityManager;
|
|
15
15
|
@service currentUser;
|
|
16
|
+
@service orderPresentation;
|
|
16
17
|
@tracked customFields;
|
|
17
18
|
|
|
18
19
|
constructor() {
|
|
@@ -20,6 +21,40 @@ export default class OrderFormDetailsComponent extends Component {
|
|
|
20
21
|
this.orderConfigActions.loadAll.perform();
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
/** The presentation profile applying to the order's current config, if any. */
|
|
25
|
+
get profile() {
|
|
26
|
+
return this.orderPresentation.profileFor(this.args.resource);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Extension fields rendered inside the details grid when a profile applies. */
|
|
30
|
+
get profileDetailFields() {
|
|
31
|
+
return this.profile?.form?.detailFields ?? null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** A persisted order keeps its profiled order type; reclassification is not supported. */
|
|
35
|
+
get orderTypeLocked() {
|
|
36
|
+
return Boolean(this.profile) && this.args.resource?.isNew === false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Field visibility; everything is visible unless a presentation profile hides it. */
|
|
40
|
+
get show() {
|
|
41
|
+
const hidden = this.args.hiddenFields ?? this.orderPresentation.hiddenFieldsFor(this.args.resource);
|
|
42
|
+
const visible = (key) => !hidden.includes(key);
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
internalId: visible('internal-id'),
|
|
46
|
+
schedule: visible('schedule'),
|
|
47
|
+
customer: visible('customer'),
|
|
48
|
+
facilitator: visible('facilitator'),
|
|
49
|
+
serviceType: visible('service-type'),
|
|
50
|
+
driver: visible('driver'),
|
|
51
|
+
vehicle: visible('vehicle'),
|
|
52
|
+
pod: visible('pod'),
|
|
53
|
+
adhoc: visible('adhoc'),
|
|
54
|
+
dispatch: visible('dispatch'),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
23
58
|
get integratedVendorServiceType() {
|
|
24
59
|
return this.args.resource?.type;
|
|
25
60
|
}
|
|
@@ -38,12 +73,23 @@ export default class OrderFormDetailsComponent extends Component {
|
|
|
38
73
|
|
|
39
74
|
@task *selectOrderConfig(orderConfig) {
|
|
40
75
|
if (!orderConfig) return;
|
|
76
|
+
const previousProfile = this.orderPresentation.profileFor(this.args.resource);
|
|
41
77
|
this.args.resource.setProperties({
|
|
42
78
|
order_config_uuid: orderConfig.id,
|
|
43
79
|
order_config: orderConfig,
|
|
44
80
|
type: orderConfig.key,
|
|
45
81
|
});
|
|
46
82
|
this.args.resource.payload.set('type', orderConfig.key);
|
|
83
|
+
|
|
84
|
+
// Let presentation profiles clean up or prepare the draft when the order type changes.
|
|
85
|
+
const nextProfile = this.orderPresentation.profileFor(this.args.resource);
|
|
86
|
+
if (previousProfile && previousProfile !== nextProfile && typeof previousProfile.release === 'function') {
|
|
87
|
+
previousProfile.release(this.args.resource);
|
|
88
|
+
}
|
|
89
|
+
if (nextProfile && nextProfile !== previousProfile) {
|
|
90
|
+
this.orderPresentation.prepare(this.args.resource);
|
|
91
|
+
}
|
|
92
|
+
|
|
47
93
|
this.requestServiceQuoteRefresh('details.order_config.changed');
|
|
48
94
|
|
|
49
95
|
try {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
<ContentPanel @title={{t "order.fields.route"}} @open={{true}} @wrapperClass="bordered-top">
|
|
1
|
+
<ContentPanel @title={{or this.profileTitle (t "order.fields.route")}} @open={{true}} @wrapperClass="bordered-top">
|
|
2
2
|
<div class="flex flex-row items-center justify-between mb-4">
|
|
3
3
|
<div class="flex">
|
|
4
|
-
|
|
4
|
+
{{#if this.allowsMultipleWaypoints}}
|
|
5
|
+
<Toggle @isToggled={{this.multipleWaypoints}} @onToggle={{this.toggleWaypoints}} @label={{t "order.fields.route-label"}} />
|
|
6
|
+
{{/if}}
|
|
5
7
|
</div>
|
|
6
8
|
<div class="flex flex-1 justify-end space-x-2">
|
|
7
9
|
{{#if this.multipleWaypoints}}
|
|
@@ -149,7 +151,7 @@
|
|
|
149
151
|
<div class="flex items-center justify-end">
|
|
150
152
|
<div class="flex-row space-x-1 pr-0.5">
|
|
151
153
|
{{#if @resource.payload.pickup}}
|
|
152
|
-
<a href="javascript:;" {{on "click" (fn this.editPlace @resource.payload.pickup)}}>
|
|
154
|
+
<a href="javascript:;" data-test-edit-place="pickup" {{on "click" (fn this.editPlace @resource.payload.pickup)}}>
|
|
153
155
|
<FaIcon @icon="edit" />
|
|
154
156
|
</a>
|
|
155
157
|
<a href="javascript:;" {{on "click" (fn this.setPayloadPlace "pickup" null)}}>
|
|
@@ -22,6 +22,7 @@ export default class OrderFormRouteComponent extends Component {
|
|
|
22
22
|
@service notifications;
|
|
23
23
|
@service placeActions;
|
|
24
24
|
@service orderCreation;
|
|
25
|
+
@service orderPresentation;
|
|
25
26
|
@tracked multipleWaypoints = false;
|
|
26
27
|
@tracked routingControl;
|
|
27
28
|
@tracked route;
|
|
@@ -35,6 +36,16 @@ export default class OrderFormRouteComponent extends Component {
|
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
/** A presentation profile may hide multi-drop routing and rename the route panel. */
|
|
40
|
+
get allowsMultipleWaypoints() {
|
|
41
|
+
const hidden = this.args.hiddenFields ?? this.orderPresentation.hiddenFieldsFor(this.args.resource);
|
|
42
|
+
return !hidden.includes('multiple-waypoints');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get profileTitle() {
|
|
46
|
+
return this.orderPresentation.profileFor(this.args.resource)?.form?.titles?.route ?? null;
|
|
47
|
+
}
|
|
48
|
+
|
|
38
49
|
get coordinates() {
|
|
39
50
|
return this.routePoints.map(({ place }) => [place.latitude, place.longitude]);
|
|
40
51
|
}
|
|
@@ -195,7 +206,19 @@ export default class OrderFormRouteComponent extends Component {
|
|
|
195
206
|
}
|
|
196
207
|
|
|
197
208
|
@action editPlace(place) {
|
|
198
|
-
|
|
209
|
+
// The place is edited in place, so the form already shows the change; there is no list
|
|
210
|
+
// to refresh, only the route preview and quote that depend on its location.
|
|
211
|
+
this.placeActions.modal.edit(
|
|
212
|
+
place,
|
|
213
|
+
{},
|
|
214
|
+
{
|
|
215
|
+
refresh: false,
|
|
216
|
+
callback: () => {
|
|
217
|
+
this.previewRoute();
|
|
218
|
+
this.requestServiceQuoteRefresh('route.place.updated');
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
);
|
|
199
222
|
}
|
|
200
223
|
|
|
201
224
|
@action async previewRoute() {
|
|
@@ -16,6 +16,18 @@
|
|
|
16
16
|
RegistryYieldEnd=(component "registry-yield" registry="fleet-ops:component:order:form:end" order=@resource)
|
|
17
17
|
)
|
|
18
18
|
}}
|
|
19
|
+
{{else if this.profile}}
|
|
20
|
+
{{#each this.profileSections key="key" as |section|}}
|
|
21
|
+
{{#if section.native}}
|
|
22
|
+
{{#let (component section.componentName resource=@resource hiddenFields=this.hiddenFields) as |NativeSection|}}
|
|
23
|
+
<NativeSection />
|
|
24
|
+
{{/let}}
|
|
25
|
+
{{else}}
|
|
26
|
+
<LazyEngineComponent @component={{section.component}} as |ProfileSection|>
|
|
27
|
+
<ProfileSection @resource={{@resource}} @order={{@resource}} @controller={{@controller}} @profile={{this.profile}} @hiddenFields={{this.hiddenFields}} />
|
|
28
|
+
</LazyEngineComponent>
|
|
29
|
+
{{/if}}
|
|
30
|
+
{{/each}}
|
|
19
31
|
{{else}}
|
|
20
32
|
<RegistryYield @registry="fleet-ops:component:order:form:start" as |RegistryComponent|>
|
|
21
33
|
<RegistryComponent @order={{@resource}} @resource={{@resource}} />
|
|
@@ -11,6 +11,7 @@ export default class OrderFormComponent extends Component {
|
|
|
11
11
|
@service customFieldsRegistry;
|
|
12
12
|
@service mapManager;
|
|
13
13
|
@service currentUser;
|
|
14
|
+
@service orderPresentation;
|
|
14
15
|
@tracked customFields;
|
|
15
16
|
|
|
16
17
|
constructor() {
|
|
@@ -18,6 +19,19 @@ export default class OrderFormComponent extends Component {
|
|
|
18
19
|
this.orderConfigActions.loadAll.perform();
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
/** The extension presentation profile applying to this order's config, if any. */
|
|
23
|
+
get profile() {
|
|
24
|
+
return this.orderPresentation.profileFor(this.args.resource);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get profileSections() {
|
|
28
|
+
return this.orderPresentation.renderableSectionsFor(this.profile, 'form');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get hiddenFields() {
|
|
32
|
+
return this.orderPresentation.hiddenFieldsFor(this.args.resource);
|
|
33
|
+
}
|
|
34
|
+
|
|
21
35
|
@action selectFacilitator(model) {
|
|
22
36
|
this.args.resource.set('facilitator', model);
|
|
23
37
|
this.args.resource.set('driver', null);
|
|
@@ -32,7 +46,13 @@ export default class OrderFormComponent extends Component {
|
|
|
32
46
|
});
|
|
33
47
|
this.args.resource.payload.set('type', orderConfig.key);
|
|
34
48
|
|
|
35
|
-
|
|
49
|
+
// loadSubjectCustomFields rejects when the custom fields cannot be loaded (ember-core 0.3.25).
|
|
50
|
+
try {
|
|
51
|
+
this.customFields = yield this.customFieldsRegistry.loadSubjectCustomFields.perform(orderConfig);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
this.customFields = undefined;
|
|
54
|
+
debug('Unable to load order custom fields: ' + err.message);
|
|
55
|
+
}
|
|
36
56
|
}
|
|
37
57
|
|
|
38
58
|
@task *selectDriver(driver) {
|
|
@@ -13,7 +13,9 @@ export default class OrderKanbanComponent extends Component {
|
|
|
13
13
|
@service fetch;
|
|
14
14
|
@service notifications;
|
|
15
15
|
@service intl;
|
|
16
|
+
@service store;
|
|
16
17
|
@tracked statuses = [];
|
|
18
|
+
@tracked orderConfigRecord = null;
|
|
17
19
|
@tracked orders = this.args.orders ?? [];
|
|
18
20
|
@tracked orderConfig = this.args.orderConfig ?? null;
|
|
19
21
|
|
|
@@ -23,6 +25,11 @@ export default class OrderKanbanComponent extends Component {
|
|
|
23
25
|
};
|
|
24
26
|
|
|
25
27
|
get columns() {
|
|
28
|
+
const lifecycleColumns = this.#lifecycleColumns();
|
|
29
|
+
if (lifecycleColumns) {
|
|
30
|
+
return lifecycleColumns;
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
const start = this.#defaultStatuses.start ?? [];
|
|
27
34
|
const end = this.#defaultStatuses.end ?? [];
|
|
28
35
|
const loaded = isArray(this.statuses) ? this.statuses : [];
|
|
@@ -112,6 +119,64 @@ export default class OrderKanbanComponent extends Component {
|
|
|
112
119
|
this.loadStatuses.perform();
|
|
113
120
|
}
|
|
114
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Columns for an order config with a configured lifecycle (`meta.lifecycle`): the flow's own
|
|
124
|
+
* activities in graph order from the initial activity, titled with their status labels.
|
|
125
|
+
* No default dispatch columns are injected. Returns null for configs without a lifecycle.
|
|
126
|
+
*/
|
|
127
|
+
#lifecycleColumns() {
|
|
128
|
+
const config = this.orderConfigRecord;
|
|
129
|
+
const lifecycle = config?.meta?.lifecycle;
|
|
130
|
+
const flow = config?.flow;
|
|
131
|
+
if (!lifecycle || !flow || typeof flow !== 'object') {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const activities = Object.values(flow).filter((activity) => activity && activity.code);
|
|
136
|
+
const byKeyOrCode = new Map();
|
|
137
|
+
for (const activity of activities) {
|
|
138
|
+
byKeyOrCode.set(activity.key ?? activity.code, activity);
|
|
139
|
+
byKeyOrCode.set(activity.code, activity);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Breadth-first walk from the initial activity, then any activities not reachable from it.
|
|
143
|
+
const ordered = [];
|
|
144
|
+
const seen = new Set();
|
|
145
|
+
const queue = [byKeyOrCode.get(lifecycle.initial)].filter(Boolean);
|
|
146
|
+
while (queue.length) {
|
|
147
|
+
const activity = queue.shift();
|
|
148
|
+
if (seen.has(activity.code)) continue;
|
|
149
|
+
seen.add(activity.code);
|
|
150
|
+
ordered.push(activity);
|
|
151
|
+
for (const child of activity.activities ?? []) {
|
|
152
|
+
const next = byKeyOrCode.get(typeof child === 'string' ? child : (child?.key ?? child?.code));
|
|
153
|
+
if (next && !seen.has(next.code)) queue.push(next);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
for (const activity of activities.sort((a, b) => (a.sequence ?? 0) - (b.sequence ?? 0))) {
|
|
157
|
+
if (!seen.has(activity.code)) {
|
|
158
|
+
seen.add(activity.code);
|
|
159
|
+
ordered.push(activity);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Keep orders whose status is not part of the flow visible rather than silently dropping them.
|
|
164
|
+
const columns = ordered.map((activity) => ({ id: activity.code, title: this.#activityTitle(activity) }));
|
|
165
|
+
for (const status of isArray(this.statuses) ? this.statuses : []) {
|
|
166
|
+
if (status && !seen.has(status)) {
|
|
167
|
+
seen.add(status);
|
|
168
|
+
columns.push({ id: status, title: titleize(smartHumanize(status)) });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return columns.map((column, index) => ({ ...column, position: index, cards: this.#getOrdersByStatus(column.id, this.orders) }));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
#activityTitle(activity) {
|
|
176
|
+
const label = typeof activity.status === 'string' ? activity.status.trim() : '';
|
|
177
|
+
return label && !label.includes('{') ? label : titleize(smartHumanize(activity.code));
|
|
178
|
+
}
|
|
179
|
+
|
|
115
180
|
#getOrdersByStatus(status, orders = []) {
|
|
116
181
|
let filteredOrders = orders.filter((order) => order.status === status);
|
|
117
182
|
if (this.orderConfig) {
|
|
@@ -125,6 +190,13 @@ export default class OrderKanbanComponent extends Component {
|
|
|
125
190
|
const params = {};
|
|
126
191
|
if (this.orderConfig) params.order_config_uuid = this.orderConfig;
|
|
127
192
|
|
|
193
|
+
try {
|
|
194
|
+
this.orderConfigRecord = this.orderConfig ? yield this.store.findRecord('order-config', this.orderConfig) : null;
|
|
195
|
+
} catch (err) {
|
|
196
|
+
this.orderConfigRecord = null;
|
|
197
|
+
debug('Unable to load order config for board: ' + err.message);
|
|
198
|
+
}
|
|
199
|
+
|
|
128
200
|
try {
|
|
129
201
|
const statuses = yield this.fetch.get('orders/statuses', params);
|
|
130
202
|
this.statuses = isArray(statuses) ? statuses : [];
|
|
@@ -34,7 +34,17 @@ export default class OrderConfigManagerActivityFlowComponent extends Component {
|
|
|
34
34
|
* An array of activity codes that should not be modified.
|
|
35
35
|
* @type {Array.<string>}
|
|
36
36
|
*/
|
|
37
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Activities that cannot be edited or removed. Configs with their own lifecycle
|
|
39
|
+
* (`meta.lifecycle`) are not bound to the default dispatch activities.
|
|
40
|
+
*/
|
|
41
|
+
get immutableActivities() {
|
|
42
|
+
return this.lifecycle ? [] : ['created', 'dispatched', 'started'];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get lifecycle() {
|
|
46
|
+
return this.config?.meta?.lifecycle ?? null;
|
|
47
|
+
}
|
|
38
48
|
|
|
39
49
|
/**
|
|
40
50
|
* The configuration data for the activity flow.
|
|
@@ -180,6 +190,12 @@ export default class OrderConfigManagerActivityFlowComponent extends Component {
|
|
|
180
190
|
this.clearGraph({
|
|
181
191
|
onAfter: () => {
|
|
182
192
|
this.flow = {};
|
|
193
|
+
// A configured lifecycle resets to its saved flow, never to the default dispatch flow.
|
|
194
|
+
if (this.lifecycle && this.config?.flow && Object.keys(this.config.flow).length) {
|
|
195
|
+
this.deserializeFlow(this.config.flow);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
183
199
|
const defaultActivities = this.getDefaultActivities();
|
|
184
200
|
this.addActivityToGraph(defaultActivities);
|
|
185
201
|
},
|
|
@@ -361,7 +377,7 @@ export default class OrderConfigManagerActivityFlowComponent extends Component {
|
|
|
361
377
|
}
|
|
362
378
|
});
|
|
363
379
|
|
|
364
|
-
const rootCode = getOrderConfigFlowRootCode(deserializedFlow);
|
|
380
|
+
const rootCode = getOrderConfigFlowRootCode(deserializedFlow, this.lifecycle?.initial);
|
|
365
381
|
if (rootCode && deserializedFlow[rootCode]) {
|
|
366
382
|
this.addDeserializedActivityToGraph(deserializedFlow[rootCode]);
|
|
367
383
|
}
|
|
@@ -439,6 +455,10 @@ export default class OrderConfigManagerActivityFlowComponent extends Component {
|
|
|
439
455
|
* and creates links from the parent to each child. It then calls itself to add any children of the current child activities.
|
|
440
456
|
* Finally, it repositions all child activities to maintain visual consistency.
|
|
441
457
|
*
|
|
458
|
+
* A flow is a graph, not a tree: an activity may be reachable from several parents, and a
|
|
459
|
+
* configured lifecycle can loop back (e.g. active -> extended -> active). An activity that is
|
|
460
|
+
* already on the graph only gets a link from this parent; it is never placed or walked twice.
|
|
461
|
+
*
|
|
442
462
|
* @param {Object} parentActivity - The parent activity to which child activities will be added.
|
|
443
463
|
* @param {Array} [childActivities=[]] - An array of child activity objects to be added. Defaults to an empty array.
|
|
444
464
|
*/
|
|
@@ -447,6 +467,11 @@ export default class OrderConfigManagerActivityFlowComponent extends Component {
|
|
|
447
467
|
return;
|
|
448
468
|
}
|
|
449
469
|
childActivities.forEach((childActivityObject) => {
|
|
470
|
+
if (childActivityObject.get('node')) {
|
|
471
|
+
this.addLinkToGraph(parentActivity, childActivityObject);
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
|
|
450
475
|
const childPositionals = this.getActivityPositioning(childActivityObject, parentActivity);
|
|
451
476
|
const childActivity = this.createActivityNode(childActivityObject, childPositionals);
|
|
452
477
|
childActivity.set('parentId', parentActivity.get('id'));
|
|
@@ -823,16 +848,26 @@ export default class OrderConfigManagerActivityFlowComponent extends Component {
|
|
|
823
848
|
const addButton = this.createAddActivityButton(activity, { x: width });
|
|
824
849
|
let tools = [];
|
|
825
850
|
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
}
|
|
851
|
+
const code = activity.get('code');
|
|
852
|
+
const canUpdate = this.abilities.can('fleet-ops update order-config');
|
|
829
853
|
|
|
830
|
-
if (
|
|
831
|
-
|
|
832
|
-
|
|
854
|
+
if (this.lifecycle) {
|
|
855
|
+
// The configured initial activity is the root: it can gain children but not be removed.
|
|
856
|
+
if (canUpdate) {
|
|
857
|
+
tools = code === this.lifecycle.initial ? [addButton] : [removeButton, addButton];
|
|
858
|
+
}
|
|
859
|
+
} else {
|
|
860
|
+
if (code === 'created' || code === 'dispatched') {
|
|
861
|
+
tools = [];
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
if (code === 'started' && canUpdate) {
|
|
865
|
+
tools = [addButton];
|
|
866
|
+
}
|
|
833
867
|
|
|
834
|
-
|
|
835
|
-
|
|
868
|
+
if (!this.immutableActivities.includes(code) && canUpdate) {
|
|
869
|
+
tools = [removeButton, addButton];
|
|
870
|
+
}
|
|
836
871
|
}
|
|
837
872
|
|
|
838
873
|
const activityNodeView = activityNode.findView(this.paper);
|