@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
|
@@ -2739,8 +2739,8 @@ test('tracking number and waypoint webhook resources serialize tracking contract
|
|
|
2739
2739
|
'scheduled_at' => '2026-07-30 09:00:00',
|
|
2740
2740
|
]);
|
|
2741
2741
|
|
|
2742
|
-
// The
|
|
2743
|
-
//
|
|
2742
|
+
// The webhook is a separate literal payload rather than a filtered toArray(), and its
|
|
2743
|
+
// shape is unchanged: the QR content is not added to it.
|
|
2744
2744
|
expect(array_key_exists('qr_code_content', (new TrackingNumberResource($trackingNumber))->toWebhookPayload()))->toBeFalse();
|
|
2745
2745
|
|
|
2746
2746
|
expect((new TrackingNumberResource($trackingNumber))->toWebhookPayload())->toMatchArray([
|
|
@@ -2790,14 +2790,15 @@ test('tracking number and waypoint webhook resources serialize tracking contract
|
|
|
2790
2790
|
]);
|
|
2791
2791
|
});
|
|
2792
2792
|
|
|
2793
|
-
test('tracking number resource publishes
|
|
2794
|
-
// qr_code is a base64 PNG
|
|
2795
|
-
//
|
|
2796
|
-
//
|
|
2793
|
+
test('tracking number resource publishes a scannable qr code content beside the image', function () {
|
|
2794
|
+
// qr_code is a base64 PNG; qr_code_content is the text current labels encode in it,
|
|
2795
|
+
// a tracking url naming the tracking number and the subject's public id. Both are in
|
|
2796
|
+
// the resource already, so it is published in every environment.
|
|
2797
2797
|
$trackingNumber = fleetopsCompactResourceFixture([
|
|
2798
|
-
'tracking_number' => 'TN-
|
|
2799
|
-
'owner_uuid' => 'owner-uuid-
|
|
2798
|
+
'tracking_number' => 'TN-SCAN',
|
|
2799
|
+
'owner_uuid' => 'owner-uuid-never-published',
|
|
2800
2800
|
'owner_type' => 'Fleetbase\\FleetOps\\Models\\Order',
|
|
2801
|
+
'owner' => (object) ['public_id' => 'order_public'],
|
|
2801
2802
|
'region' => 'sg',
|
|
2802
2803
|
'qr_code' => 'qr-data',
|
|
2803
2804
|
'barcode' => 'barcode-data',
|
|
@@ -2811,70 +2812,33 @@ test('tracking number resource publishes the qr code content only in debug mode'
|
|
|
2811
2812
|
// cover the index resource and the webhook payload.
|
|
2812
2813
|
$previousContainer = Illuminate\Container\Container::getInstance();
|
|
2813
2814
|
$container = new class extends Illuminate\Container\Container {
|
|
2814
|
-
public bool $debugMode = false;
|
|
2815
|
-
|
|
2816
2815
|
public function environment(...$environments)
|
|
2817
2816
|
{
|
|
2818
2817
|
return in_array('testing', $environments, true) || $environments === [] ? 'testing' : false;
|
|
2819
2818
|
}
|
|
2820
|
-
|
|
2821
|
-
// Stands in for the framework's Application::hasDebugModeEnabled().
|
|
2822
|
-
public function hasDebugModeEnabled()
|
|
2823
|
-
{
|
|
2824
|
-
return $this->debugMode;
|
|
2825
|
-
}
|
|
2826
2819
|
};
|
|
2827
2820
|
$container->instance('config', new Illuminate\Config\Repository([
|
|
2828
2821
|
'fleetbase' => ['console' => ['host' => 'console.fleetbase.test', 'subdomain' => null, 'secure' => true]],
|
|
2829
2822
|
]));
|
|
2830
2823
|
Illuminate\Container\Container::setInstance($container);
|
|
2831
2824
|
|
|
2832
|
-
// Drive the REAL accessor through the container rather than overriding it, so the
|
|
2833
|
-
// debug check itself is exercised and not just the resource's use of it.
|
|
2834
|
-
$container->debugMode = true;
|
|
2835
|
-
$withDebug = new TrackingNumberResource($trackingNumber);
|
|
2836
|
-
|
|
2837
2825
|
try {
|
|
2838
|
-
$
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2826
|
+
$payload = (new TrackingNumberResource($trackingNumber))->resolve($request);
|
|
2827
|
+
$withoutNumber = (new TrackingNumberResource(fleetopsCompactResourceFixture([
|
|
2828
|
+
'tracking_number' => null,
|
|
2829
|
+
'owner_type' => 'Fleetbase\\FleetOps\\Models\\Order',
|
|
2830
|
+
'owner' => null,
|
|
2831
|
+
])))->resolve($request);
|
|
2842
2832
|
} finally {
|
|
2843
2833
|
Illuminate\Container\Container::setInstance($previousContainer);
|
|
2844
2834
|
}
|
|
2845
2835
|
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
->and($
|
|
2849
|
-
|
|
2850
|
-
//
|
|
2851
|
-
->and(array_key_exists('qr_code_content', $
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
test('tracking number resource fails closed when the debug state cannot be determined', function () {
|
|
2856
|
-
// Any failure to resolve the debug state must answer false rather than defaulting to
|
|
2857
|
-
// exposure. The real accessor is exercised here with no usable application bound.
|
|
2858
|
-
$expose = new ReflectionMethod(TrackingNumberResource::class, 'exposesQrCodeContent');
|
|
2859
|
-
$expose->setAccessible(true);
|
|
2860
|
-
|
|
2861
|
-
$previous = Illuminate\Container\Container::getInstance();
|
|
2862
|
-
|
|
2863
|
-
try {
|
|
2864
|
-
// A container that is not an Application has no hasDebugModeEnabled().
|
|
2865
|
-
Illuminate\Container\Container::setInstance(new Illuminate\Container\Container());
|
|
2866
|
-
expect($expose->invoke(null))->toBeFalse();
|
|
2867
|
-
|
|
2868
|
-
// And an accessor that throws must also answer false rather than propagating —
|
|
2869
|
-
// a resource must not be able to fail serialization over a debug check.
|
|
2870
|
-
Illuminate\Container\Container::setInstance(new class extends Illuminate\Container\Container {
|
|
2871
|
-
public function hasDebugModeEnabled()
|
|
2872
|
-
{
|
|
2873
|
-
throw new RuntimeException('debug state unavailable');
|
|
2874
|
-
}
|
|
2875
|
-
});
|
|
2876
|
-
expect($expose->invoke(null))->toBeFalse();
|
|
2877
|
-
} finally {
|
|
2878
|
-
Illuminate\Container\Container::setInstance($previous);
|
|
2879
|
-
}
|
|
2836
|
+
expect($payload['qr_code_content'])->toBe('https://console.fleetbase.test/~/track-order?order=TN-SCAN&r=order_public&v=1')
|
|
2837
|
+
->and($payload['qr_code_content'])->not->toContain('owner-uuid')
|
|
2838
|
+
->and($payload['url'])->toBe('https://console.fleetbase.test/~/track/TN-SCAN')
|
|
2839
|
+
->and($payload['qr_code'])->toBe('qr-data')
|
|
2840
|
+
// Nothing to scan without a tracking number: the key is absent, not null.
|
|
2841
|
+
->and(array_key_exists('qr_code_content', $withoutNumber))->toBeFalse()
|
|
2842
|
+
// Nor is there a tracking page to link to.
|
|
2843
|
+
->and(array_key_exists('url', $withoutNumber))->toBeFalse();
|
|
2880
2844
|
});
|
|
@@ -1152,7 +1152,7 @@ test('contact filter records identity address and date filters', function () {
|
|
|
1152
1152
|
->and(collect($query->calls)->where(0, 'whereBetween')->values())->toHaveCount(1)
|
|
1153
1153
|
->and(collect($query->calls)->where(0, 'whereDate')->values())->toHaveCount(1);
|
|
1154
1154
|
|
|
1155
|
-
$address = collect($query->calls)->first(fn ($call) => $call[0] === 'whereHas' && $call[1] === '
|
|
1155
|
+
$address = collect($query->calls)->first(fn ($call) => $call[0] === 'whereHas' && $call[1] === 'place');
|
|
1156
1156
|
|
|
1157
1157
|
expect($address[2])->toBe([
|
|
1158
1158
|
['search', '1 Test Street'],
|
|
@@ -74,7 +74,7 @@ test('customer portal welcome email is opt in and does not create organization i
|
|
|
74
74
|
->not->toContain('send_invite');
|
|
75
75
|
|
|
76
76
|
expect($customerCredentials)->toContain('customer portal access is ready')
|
|
77
|
-
->and($customerCredentials)->toContain("Utils::consoleUrl(\$accessUrlSlug
|
|
77
|
+
->and($customerCredentials)->toContain("Utils::consoleUrl(\$accessUrlSlug ? 'customer-access/' . \$accessUrlSlug : 'customer-portal')")
|
|
78
78
|
->and($customerEmail)->toContain('Your customer portal access is ready')
|
|
79
79
|
->and($customerEmail)->toContain('Sign in to customer portal')
|
|
80
80
|
->and($customerEmail)->toContain('Temporary password:')
|
|
@@ -33,6 +33,8 @@ use Fleetbase\FleetOps\Models\FuelProviderTransaction;
|
|
|
33
33
|
use Fleetbase\FleetOps\Models\FuelReport;
|
|
34
34
|
use Fleetbase\FleetOps\Models\GeofenceEventLog;
|
|
35
35
|
use Fleetbase\FleetOps\Models\Order;
|
|
36
|
+
use Fleetbase\FleetOps\Models\Payload;
|
|
37
|
+
use Fleetbase\FleetOps\Models\Place;
|
|
36
38
|
use Fleetbase\FleetOps\Models\TrackingStatus;
|
|
37
39
|
use Fleetbase\FleetOps\Models\Vehicle;
|
|
38
40
|
use Fleetbase\FleetOps\Models\Waypoint;
|
|
@@ -231,6 +233,11 @@ class FleetOpsUserRemovedDriverDeleteQueryFake
|
|
|
231
233
|
{
|
|
232
234
|
public bool $deleted = false;
|
|
233
235
|
|
|
236
|
+
public function get(): Illuminate\Support\Collection
|
|
237
|
+
{
|
|
238
|
+
return collect([$this]);
|
|
239
|
+
}
|
|
240
|
+
|
|
234
241
|
public function delete(): void
|
|
235
242
|
{
|
|
236
243
|
$this->deleted = true;
|
|
@@ -832,8 +839,19 @@ test('geofence entered listener handles arrival branch outcomes', function () {
|
|
|
832
839
|
'name' => 'Event Zone',
|
|
833
840
|
], 'zone', new Point(1.3521, 103.8198));
|
|
834
841
|
|
|
835
|
-
$
|
|
836
|
-
|
|
842
|
+
$payloadTo = function (?Point $location): Payload {
|
|
843
|
+
$pickup = new Place();
|
|
844
|
+
$pickup->setRawAttributes(['uuid' => 'pickup-place-uuid', 'location' => $location], true);
|
|
845
|
+
|
|
846
|
+
$payload = new Payload();
|
|
847
|
+
$payload->setRawAttributes(['uuid' => 'arrival-payload-uuid'], true);
|
|
848
|
+
$payload->setRelation('pickup', $pickup);
|
|
849
|
+
$payload->setRelation('dropoff', null);
|
|
850
|
+
$payload->setRelation('waypoints', collect());
|
|
851
|
+
$payload->setRelation('waypointMarkers', collect());
|
|
852
|
+
|
|
853
|
+
return $payload;
|
|
854
|
+
};
|
|
837
855
|
$nearGeofence = new class {
|
|
838
856
|
public string $uuid = 'near-zone-uuid';
|
|
839
857
|
public string $public_id = 'near_zone_public';
|
|
@@ -896,66 +914,14 @@ test('geofence entered listener handles arrival branch outcomes', function () {
|
|
|
896
914
|
return $order;
|
|
897
915
|
};
|
|
898
916
|
|
|
899
|
-
$missingPlaceOrder
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
$
|
|
903
|
-
|
|
904
|
-
{
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
public function getPickupOrCurrentWaypoint(): object
|
|
908
|
-
{
|
|
909
|
-
return (object) ['place' => (object) ['location' => null]];
|
|
910
|
-
}
|
|
911
|
-
});
|
|
912
|
-
|
|
913
|
-
$farOrder = $makeOrder(new class($destination) {
|
|
914
|
-
public function __construct(private object $destination)
|
|
915
|
-
{
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
public function getPickupOrCurrentWaypoint(): object
|
|
919
|
-
{
|
|
920
|
-
return $this->destination;
|
|
921
|
-
}
|
|
922
|
-
});
|
|
923
|
-
|
|
924
|
-
$badCentroidOrder = $makeOrder(new class($destination) {
|
|
925
|
-
public function __construct(private object $destination)
|
|
926
|
-
{
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
public function getPickupOrCurrentWaypoint(): object
|
|
930
|
-
{
|
|
931
|
-
return $this->destination;
|
|
932
|
-
}
|
|
933
|
-
});
|
|
934
|
-
|
|
935
|
-
$customer = new FleetOpsGeofenceArrivalCustomerFake();
|
|
936
|
-
$successOrder = $makeOrder(new class($destination) {
|
|
937
|
-
public function __construct(private object $destination)
|
|
938
|
-
{
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
public function getPickupOrCurrentWaypoint(): object
|
|
942
|
-
{
|
|
943
|
-
return $this->destination;
|
|
944
|
-
}
|
|
945
|
-
}, $customer);
|
|
946
|
-
|
|
917
|
+
$missingPlaceOrder = $makeOrder($payloadTo(null));
|
|
918
|
+
$farOrder = $makeOrder($payloadTo(new Point(1.3521, 103.8198)));
|
|
919
|
+
$badCentroidOrder = $makeOrder($payloadTo(new Point(1.3521, 103.8198)));
|
|
920
|
+
$customer = new FleetOpsGeofenceArrivalCustomerFake();
|
|
921
|
+
$successOrder = $makeOrder($payloadTo(new Point(1.3521, 103.8198)), $customer);
|
|
947
922
|
$throwingCustomer = new FleetOpsGeofenceArrivalCustomerFake();
|
|
948
923
|
$throwingCustomer->shouldThrow = true;
|
|
949
|
-
$notificationFailureOrder = $makeOrder(new
|
|
950
|
-
public function __construct(private object $destination)
|
|
951
|
-
{
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
public function getPickupOrCurrentWaypoint(): object
|
|
955
|
-
{
|
|
956
|
-
return $this->destination;
|
|
957
|
-
}
|
|
958
|
-
}, $throwingCustomer);
|
|
924
|
+
$notificationFailureOrder = $makeOrder($payloadTo(new Point(1.3521, 103.8198)), $throwingCustomer);
|
|
959
925
|
|
|
960
926
|
$arrival->invoke($listener, $driver, $nearGeofence, $missingPlaceOrder, $event);
|
|
961
927
|
$arrival->invoke($listener, $driver, $farGeofence, $farOrder, $event);
|
|
@@ -11,7 +11,9 @@ function bindFleetOpsExpansionClosure(Closure $closure, object $target): Closure
|
|
|
11
11
|
return $closure->bindTo($target, $target::class);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
// The expansion closures declare HasOne / HasMany return types, so the fakes extend
|
|
15
|
+
// those relations; the parent constructor is skipped on purpose.
|
|
16
|
+
trait FleetOpsExpansionRecordsRelationCalls
|
|
15
17
|
{
|
|
16
18
|
public array $calls = [];
|
|
17
19
|
|
|
@@ -34,6 +36,16 @@ class FleetOpsExpansionRelationFake
|
|
|
34
36
|
}
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
class FleetOpsExpansionRelationFake extends Illuminate\Database\Eloquent\Relations\HasOne
|
|
40
|
+
{
|
|
41
|
+
use FleetOpsExpansionRecordsRelationCalls;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class FleetOpsExpansionManyRelationFake extends Illuminate\Database\Eloquent\Relations\HasMany
|
|
45
|
+
{
|
|
46
|
+
use FleetOpsExpansionRecordsRelationCalls;
|
|
47
|
+
}
|
|
48
|
+
|
|
37
49
|
class FleetOpsExpansionModelFake
|
|
38
50
|
{
|
|
39
51
|
public array $calls = [];
|
|
@@ -41,9 +53,10 @@ class FleetOpsExpansionModelFake
|
|
|
41
53
|
|
|
42
54
|
public function __construct()
|
|
43
55
|
{
|
|
44
|
-
foreach (['driver', '
|
|
56
|
+
foreach (['driver', 'customer', 'contact'] as $name) {
|
|
45
57
|
$this->relations[$name] = new FleetOpsExpansionRelationFake($name);
|
|
46
58
|
}
|
|
59
|
+
$this->relations['driverProfiles'] = new FleetOpsExpansionManyRelationFake('driverProfiles');
|
|
47
60
|
}
|
|
48
61
|
|
|
49
62
|
public function hasMany($class)
|
|
@@ -452,14 +452,16 @@ test('identity checks session context and user lookups resolve', function () {
|
|
|
452
452
|
test('verification codes files contacts and customer auth resolve', function () {
|
|
453
453
|
$connection = fleetopsCustomerHelperBoot();
|
|
454
454
|
$connection->table('verification_codes')->insert(['uuid' => 'vc-1', 'subject_uuid' => 'user-1', 'subject_type' => 'user', 'code' => '123456', 'for' => 'customer_verification']);
|
|
455
|
+
// A code is used up by the lookup that accepts it, so each check gets its own row.
|
|
456
|
+
$connection->table('verification_codes')->insert(['uuid' => 'vc-2', 'subject_uuid' => 'user-1', 'subject_type' => 'user', 'code' => '654321', 'for' => 'customer_verification']);
|
|
455
457
|
$connection->table('files')->insert(['uuid' => 'file-1', 'public_id' => 'file_custhelp1', 'company_uuid' => 'company-1', 'name' => 'photo.png']);
|
|
456
458
|
$connection->table('contacts')->insert(['uuid' => 'contact-1', 'public_id' => 'contact_custhelp1', 'company_uuid' => 'company-1', 'name' => 'Casey', 'type' => 'customer']);
|
|
457
459
|
|
|
458
460
|
$probe = new FleetOpsCustomerControllerProbe();
|
|
459
461
|
|
|
460
|
-
expect($probe->callHelper('verificationCodeExists', ['code' => '
|
|
461
|
-
->and($probe->callHelper('findVerificationCode', ['code' => '123456'])?->uuid)->toBe('vc-1')
|
|
462
|
-
->and($probe->callHelper('findVerificationCode', ['code' => '999999']))->toBeNull()
|
|
462
|
+
expect($probe->callHelper('verificationCodeExists', ['code' => '654321', 'for' => 'customer_verification']))->toBeTrue()
|
|
463
|
+
->and($probe->callHelper('findVerificationCode', ['code' => '123456', 'for' => 'customer_verification'])?->uuid)->toBe('vc-1')
|
|
464
|
+
->and($probe->callHelper('findVerificationCode', ['code' => '999999', 'for' => 'customer_verification']))->toBeNull()
|
|
463
465
|
->and($probe->callHelper('findFileByPublicId', 'file_custhelp1')?->uuid)->toBe('file-1');
|
|
464
466
|
|
|
465
467
|
expect($probe->callHelper('findCustomerContact', ['uuid' => 'contact-1'])?->name)->toBe('Casey')
|
|
@@ -829,3 +831,27 @@ test('customer place photo and quote seams resolve through their real bodies', f
|
|
|
829
831
|
expect($connection->table('contacts')->where('uuid', '88888888-8888-4888-8888-888888888820')->value('photo_uuid'))->toBe('file-b64-1');
|
|
830
832
|
app()->forgetInstance(CustomerAuth::APP_BINDING);
|
|
831
833
|
});
|
|
834
|
+
|
|
835
|
+
test('a wrong code counts against the live code, a right one uses it up, and a used code never verifies again', function () {
|
|
836
|
+
$connection = fleetopsCustomerHelperBoot();
|
|
837
|
+
$controller = new CustomerController();
|
|
838
|
+
|
|
839
|
+
$connection->table('verification_codes')->insert([
|
|
840
|
+
['uuid' => 'vc-older', 'code' => '101010', 'for' => 'fleetops_create_customer', 'meta' => json_encode(['identity' => 'spend@example.com']), 'status' => 'active', 'created_at' => '2026-10-13 09:00:00'],
|
|
841
|
+
['uuid' => 'vc-newer', 'code' => '202020', 'for' => 'fleetops_create_customer', 'meta' => json_encode(['identity' => 'spend@example.com']), 'status' => 'active', 'created_at' => '2026-10-13 09:05:00'],
|
|
842
|
+
]);
|
|
843
|
+
|
|
844
|
+
$wrong = $controller->create(CreateCustomerRequest::create('/v1/customers', 'POST', ['code' => '999999', 'identity' => 'spend@example.com', 'name' => 'Spender', 'password' => 'secret']));
|
|
845
|
+
expect($wrong->getData(true)['error'])->toContain('Invalid verification code')
|
|
846
|
+
->and(json_decode($connection->table('verification_codes')->where('uuid', 'vc-newer')->value('meta'), true)['attempts'])->toBe(1)
|
|
847
|
+
->and(json_decode($connection->table('verification_codes')->where('uuid', 'vc-older')->value('meta'), true)['attempts'])->toBe(1);
|
|
848
|
+
|
|
849
|
+
// The older code still verifies while it is live, and is used up by doing so.
|
|
850
|
+
$controller->create(CreateCustomerRequest::create('/v1/customers', 'POST', ['code' => '101010', 'identity' => 'spend@example.com', 'name' => 'Spender', 'password' => 'secret']));
|
|
851
|
+
expect($connection->table('contacts')->where('email', 'spend@example.com')->count())->toBe(1)
|
|
852
|
+
->and($connection->table('verification_codes')->where('uuid', 'vc-older')->value('status'))->toBe('used')
|
|
853
|
+
->and($connection->table('verification_codes')->where('uuid', 'vc-newer')->value('status'))->toBe('active');
|
|
854
|
+
|
|
855
|
+
$again = $controller->create(CreateCustomerRequest::create('/v1/customers', 'POST', ['code' => '101010', 'identity' => 'spend@example.com', 'name' => 'Spender', 'password' => 'secret']));
|
|
856
|
+
expect($again->getData(true)['error'])->toContain('Invalid verification code');
|
|
857
|
+
});
|
|
@@ -304,6 +304,29 @@ test('phone login reports the sms method when the transport delivers', function
|
|
|
304
304
|
->and($connection->table('verification_codes')->where('for', 'driver_login')->count())->toBe(1);
|
|
305
305
|
});
|
|
306
306
|
|
|
307
|
+
test('phone login passes an sms guard refusal through once no email can carry the code', function () {
|
|
308
|
+
$connection = fleetopsDriverAuthBoot();
|
|
309
|
+
app()->instance('twilio', new class {
|
|
310
|
+
public function message($to, $text, $mediaUrls = [], $params = [])
|
|
311
|
+
{
|
|
312
|
+
throw Fleetbase\Exceptions\SmsBlockedException::paused('platform', 300);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
Fleetbase\Twilio\Support\Laravel\Facade::clearResolvedInstances();
|
|
316
|
+
|
|
317
|
+
// With an email on file the refusal is handled like any send failure: by email.
|
|
318
|
+
app()->instance('request', Request::create('/x', 'POST', ['phone' => '6591234567']));
|
|
319
|
+
$byEmail = (new DriverController())->loginWithPhone();
|
|
320
|
+
expect($byEmail->getData(true))->toBe(['status' => 'OK', 'method' => 'email']);
|
|
321
|
+
|
|
322
|
+
// Without one, the app gets the refusal itself: 423 and how long to wait.
|
|
323
|
+
$connection->table('users')->where('uuid', 'user-1')->update(['email' => null]);
|
|
324
|
+
$refused = (new DriverController())->loginWithPhone();
|
|
325
|
+
expect($refused->getStatusCode())->toBe(423)
|
|
326
|
+
->and($refused->headers->get('Retry-After'))->toBe('300')
|
|
327
|
+
->and($refused->getData(true)['error'])->toBe('Text messages are temporarily unavailable. Try again later.');
|
|
328
|
+
});
|
|
329
|
+
|
|
307
330
|
test('code verification handles unknown users invalid codes bypass and success', function () {
|
|
308
331
|
$connection = fleetopsDriverAuthBoot();
|
|
309
332
|
$controller = new DriverController();
|
|
@@ -135,19 +135,20 @@ function fleetopsOrderNearbyBoot(): SQLiteConnection
|
|
|
135
135
|
|
|
136
136
|
$schema = $connection->getSchemaBuilder();
|
|
137
137
|
$tables = [
|
|
138
|
-
'orders'
|
|
139
|
-
'payloads'
|
|
140
|
-
'places'
|
|
141
|
-
'waypoints'
|
|
142
|
-
'entities'
|
|
143
|
-
'drivers'
|
|
144
|
-
'users'
|
|
145
|
-
'contacts'
|
|
146
|
-
'vendors'
|
|
147
|
-
'
|
|
148
|
-
'
|
|
149
|
-
'
|
|
150
|
-
'
|
|
138
|
+
'orders' => ['uuid', 'public_id', 'internal_id', 'company_uuid', 'payload_uuid', 'driver_assigned_uuid', 'customer_uuid', 'customer_type', 'facilitator_uuid', 'facilitator_type', 'tracking_number_uuid', 'status', 'pod_required', 'dispatched', 'scheduled_at', 'type'],
|
|
139
|
+
'payloads' => ['uuid', 'public_id', 'company_uuid', 'pickup_uuid', 'dropoff_uuid', 'return_uuid', 'current_waypoint_uuid', 'type'],
|
|
140
|
+
'places' => ['uuid', 'public_id', 'company_uuid', 'name', 'street1', 'city', 'country', 'location', 'meta'],
|
|
141
|
+
'waypoints' => ['uuid', 'public_id', 'company_uuid', 'payload_uuid', 'place_uuid'],
|
|
142
|
+
'entities' => ['uuid', 'public_id', 'internal_id', 'company_uuid', 'payload_uuid', 'name'],
|
|
143
|
+
'drivers' => ['uuid', 'public_id', 'company_uuid', 'user_uuid', 'location'],
|
|
144
|
+
'users' => ['uuid', 'public_id', 'company_uuid', 'type'],
|
|
145
|
+
'contacts' => ['uuid', 'public_id', 'internal_id', 'company_uuid', 'name'],
|
|
146
|
+
'vendors' => ['uuid', 'public_id', 'internal_id', 'company_uuid', 'name'],
|
|
147
|
+
'integrated_vendors' => ['uuid', 'public_id', 'company_uuid', 'provider'],
|
|
148
|
+
'companies' => ['uuid', 'public_id', 'name', 'options'],
|
|
149
|
+
'tracking_numbers' => ['uuid', 'public_id', 'company_uuid', 'tracking_number', 'owner_uuid', 'owner_type', 'status_uuid', '_key'],
|
|
150
|
+
'tracking_statuses' => ['uuid', 'public_id', 'company_uuid', 'tracking_number_uuid', 'code', 'status', 'details'],
|
|
151
|
+
'directives' => ['uuid', 'company_uuid', 'permission_uuid', 'subject_type', 'subject_uuid', 'key', 'rules'],
|
|
151
152
|
];
|
|
152
153
|
foreach ($tables as $table => $columns) {
|
|
153
154
|
$schema->create($table, function ($blueprint) use ($columns) {
|
|
@@ -276,7 +277,6 @@ test('facilitator and customer filters constrain by public and internal ids', fu
|
|
|
276
277
|
'facilitator' => 'vendor_nearby1',
|
|
277
278
|
'customer' => 'contact_nearby1',
|
|
278
279
|
]));
|
|
279
|
-
//
|
|
280
|
-
|
|
281
|
-
expect($result->count())->toBeGreaterThanOrEqual(0);
|
|
280
|
+
// Both ids resolve to the uuids the order stores, so exactly that order matches.
|
|
281
|
+
expect($result->pluck('uuid')->all())->toBe(['order-1']);
|
|
282
282
|
});
|
|
@@ -73,20 +73,21 @@ function fleetopsOrderQueryFiltersBoot(): SQLiteConnection
|
|
|
73
73
|
|
|
74
74
|
$schema = $connection->getSchemaBuilder();
|
|
75
75
|
$tables = [
|
|
76
|
-
'orders'
|
|
77
|
-
'payloads'
|
|
78
|
-
'places'
|
|
79
|
-
'waypoints'
|
|
80
|
-
'entities'
|
|
81
|
-
'tracking_numbers'
|
|
82
|
-
'tracking_statuses'
|
|
83
|
-
'drivers'
|
|
84
|
-
'users'
|
|
85
|
-
'vehicles'
|
|
86
|
-
'contacts'
|
|
87
|
-
'vendors'
|
|
88
|
-
'
|
|
89
|
-
'
|
|
76
|
+
'orders' => ['uuid', 'public_id', 'internal_id', 'company_uuid', 'payload_uuid', 'driver_assigned_uuid', 'vehicle_assigned_uuid', 'customer_uuid', 'customer_type', 'facilitator_uuid', 'facilitator_type', 'tracking_number_uuid', 'status', 'pod_required', 'dispatched', 'scheduled_at', 'type'],
|
|
77
|
+
'payloads' => ['uuid', 'public_id', 'company_uuid', 'pickup_uuid', 'dropoff_uuid', 'return_uuid', 'current_waypoint_uuid', 'type'],
|
|
78
|
+
'places' => ['uuid', 'public_id', 'company_uuid', 'name', 'location'],
|
|
79
|
+
'waypoints' => ['uuid', 'public_id', 'company_uuid', 'payload_uuid', 'place_uuid', 'location'],
|
|
80
|
+
'entities' => ['uuid', 'public_id', 'internal_id', 'company_uuid', 'payload_uuid', 'tracking_number_uuid', 'name'],
|
|
81
|
+
'tracking_numbers' => ['uuid', 'public_id', 'company_uuid', 'tracking_number', 'owner_uuid', 'status_uuid'],
|
|
82
|
+
'tracking_statuses' => ['uuid', 'public_id', 'company_uuid', 'tracking_number_uuid', 'code', 'status'],
|
|
83
|
+
'drivers' => ['uuid', 'public_id', 'company_uuid', 'user_uuid', 'location'],
|
|
84
|
+
'users' => ['uuid', 'public_id', 'company_uuid'],
|
|
85
|
+
'vehicles' => ['uuid', 'public_id', 'company_uuid'],
|
|
86
|
+
'contacts' => ['uuid', 'public_id', 'internal_id', 'company_uuid', 'name'],
|
|
87
|
+
'vendors' => ['uuid', 'public_id', 'internal_id', 'company_uuid', 'name'],
|
|
88
|
+
'integrated_vendors' => ['uuid', 'public_id', 'company_uuid', 'provider'],
|
|
89
|
+
'companies' => ['uuid', 'public_id', 'name', 'options'],
|
|
90
|
+
'directives' => ['uuid', 'company_uuid', 'permission_uuid', 'subject_type', 'subject_uuid', 'key', 'rules'],
|
|
90
91
|
];
|
|
91
92
|
foreach ($tables as $table => $columns) {
|
|
92
93
|
$schema->create($table, function ($blueprint) use ($columns) {
|
|
@@ -182,3 +183,29 @@ test('query supports entity status arrays', function () {
|
|
|
182
183
|
|
|
183
184
|
expect($result->count())->toBe(0);
|
|
184
185
|
});
|
|
186
|
+
|
|
187
|
+
test('query finds orders by facilitator and customer public ids', function () {
|
|
188
|
+
$connection = fleetopsOrderQueryFiltersBoot();
|
|
189
|
+
$connection->table('payloads')->insert(['uuid' => 'payload-1', 'public_id' => 'payload_test', 'company_uuid' => 'company-1']);
|
|
190
|
+
$connection->table('vendors')->insert(['uuid' => 'vendor-1', 'public_id' => 'vendor_facil', 'internal_id' => 'VND-1', 'company_uuid' => 'company-1']);
|
|
191
|
+
$connection->table('integrated_vendors')->insert(['uuid' => 'integrated-vendor-1', 'public_id' => 'integrated_vendor_facil', 'company_uuid' => 'company-1']);
|
|
192
|
+
$connection->table('contacts')->insert(['uuid' => 'contact-1', 'public_id' => 'contact_cust', 'company_uuid' => 'company-1']);
|
|
193
|
+
// The stored type is the class name, which is not the morph class the
|
|
194
|
+
// morph map gives these models — the mismatch that emptied every result.
|
|
195
|
+
$connection->table('orders')->insert([
|
|
196
|
+
['uuid' => 'order-1', 'public_id' => 'order_a', 'company_uuid' => 'company-1', 'payload_uuid' => 'payload-1', 'facilitator_uuid' => 'vendor-1', 'facilitator_type' => 'Fleetbase\FleetOps\Models\Vendor', 'customer_uuid' => 'contact-1', 'customer_type' => 'Fleetbase\FleetOps\Models\Contact'],
|
|
197
|
+
['uuid' => 'order-2', 'public_id' => 'order_b', 'company_uuid' => 'company-1', 'payload_uuid' => 'payload-1', 'facilitator_uuid' => 'integrated-vendor-1', 'facilitator_type' => 'Fleetbase\FleetOps\Models\IntegratedVendor', 'customer_uuid' => 'vendor-1', 'customer_type' => 'Fleetbase\FleetOps\Models\Vendor'],
|
|
198
|
+
['uuid' => 'order-3', 'public_id' => 'order_c', 'company_uuid' => 'company-1', 'payload_uuid' => 'payload-1', 'facilitator_uuid' => null, 'facilitator_type' => null, 'customer_uuid' => null, 'customer_type' => null],
|
|
199
|
+
]);
|
|
200
|
+
|
|
201
|
+
$publicIds = fn (array $input) => (new OrderController())->query(fleetopsOrderQueryFiltersRequest($input))->pluck('public_id')->sort()->values()->all();
|
|
202
|
+
|
|
203
|
+
expect($publicIds(['facilitator' => 'vendor_facil']))->toBe(['order_a'])
|
|
204
|
+
->and($publicIds(['facilitator' => 'VND-1']))->toBe(['order_a'])
|
|
205
|
+
->and($publicIds(['facilitator' => 'integrated_vendor_facil']))->toBe(['order_b'])
|
|
206
|
+
->and($publicIds(['customer' => 'contact_cust']))->toBe(['order_a'])
|
|
207
|
+
->and($publicIds(['customer' => 'vendor_facil']))->toBe(['order_b'])
|
|
208
|
+
// An unknown id matches nothing, never every order.
|
|
209
|
+
->and($publicIds(['facilitator' => 'vendor_missing']))->toBe([])
|
|
210
|
+
->and($publicIds(['customer' => 'contact_missing']))->toBe([]);
|
|
211
|
+
});
|
|
@@ -133,28 +133,63 @@ test('tracking number helpers look up owners create records and wrap resources',
|
|
|
133
133
|
->and($helper('deletedTrackingNumberResource', $found))->toBeInstanceOf(Fleetbase\FleetOps\Http\Resources\v1\DeletedResource::class)
|
|
134
134
|
->and($helper('jsonResponse', ['ok' => true], 200))->toBeInstanceOf(Illuminate\Http\JsonResponse::class);
|
|
135
135
|
|
|
136
|
-
// Qr model resolution
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
'
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
136
|
+
// Qr model resolution goes through the shared resolver and wraps the owner in its
|
|
137
|
+
// fleet-ops v1 resource.
|
|
138
|
+
$connection->table('tracking_numbers')->insert([
|
|
139
|
+
'uuid' => '44444444-4444-4444-8444-444444444404',
|
|
140
|
+
'public_id' => 'track_tnhelper2',
|
|
141
|
+
'company_uuid' => 'company-1',
|
|
142
|
+
'tracking_number' => 'FLB-HELPER-2',
|
|
143
|
+
'owner_uuid' => '44444444-4444-4444-8444-444444444402',
|
|
144
|
+
'owner_type' => Fleetbase\FleetOps\Models\Entity::class,
|
|
145
|
+
]);
|
|
146
|
+
|
|
147
|
+
$qrModel = $helper('findQrModel', 'https://console.fleetbase.test/track-order?order=FLB-HELPER-2&r=entity_tnhelper1&v=1');
|
|
148
|
+
expect($qrModel)->toBeInstanceOf(Fleetbase\FleetOps\Models\Entity::class)
|
|
149
|
+
->and($helper('qrModelResource', $qrModel))->toBeInstanceOf(Fleetbase\FleetOps\Http\Resources\v1\Entity::class)
|
|
150
|
+
->and($helper('findQrModel', '{{qr_code}}'))->toBeNull();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('tracking number owners resolve from every code format within the company', function () {
|
|
154
|
+
$connection = fleetopsTrackingNumberHelpersBoot();
|
|
155
|
+
$connection->table('orders')->insert(['uuid' => '55555555-5555-4555-8555-555555555501', 'public_id' => 'order_codes1', 'company_uuid' => 'company-1', 'status' => 'created']);
|
|
156
|
+
$connection->table('entities')->insert(['uuid' => '55555555-5555-4555-8555-555555555502', 'public_id' => 'entity_codes1', 'company_uuid' => 'company-1', 'name' => 'Parcel']);
|
|
157
|
+
$connection->table('orders')->insert(['uuid' => '55555555-5555-4555-8555-555555555503', 'public_id' => 'order_codes2', 'company_uuid' => 'company-2', 'status' => 'created']);
|
|
158
|
+
$connection->table('tracking_numbers')->insert([
|
|
159
|
+
['uuid' => 'tn-codes-1', 'public_id' => 'track_codes1', 'company_uuid' => 'company-1', 'tracking_number' => 'ACM1111111111SG', 'owner_uuid' => '55555555-5555-4555-8555-555555555501', 'owner_type' => Fleetbase\FleetOps\Models\Order::class],
|
|
160
|
+
// Entity::insertGetUuid() inserts raw, storing the owner class with a leading slash.
|
|
161
|
+
['uuid' => 'tn-codes-2', 'public_id' => 'track_codes2', 'company_uuid' => 'company-1', 'tracking_number' => 'ACM2222222222SG', 'owner_uuid' => '55555555-5555-4555-8555-555555555502', 'owner_type' => '\\' . Fleetbase\FleetOps\Models\Entity::class],
|
|
162
|
+
['uuid' => 'tn-codes-3', 'public_id' => 'track_codes3', 'company_uuid' => 'company-2', 'tracking_number' => 'OTH3333333333SG', 'owner_uuid' => '55555555-5555-4555-8555-555555555503', 'owner_type' => Fleetbase\FleetOps\Models\Order::class],
|
|
154
163
|
]);
|
|
155
164
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
165
|
+
$owner = fn (?string $code, ?string $company = 'company-1') => TrackingNumber::findOwnerByCode($code, $company)?->public_id;
|
|
166
|
+
|
|
167
|
+
// Labels in circulation carry the owner's bare uuid.
|
|
168
|
+
expect($owner('55555555-5555-4555-8555-555555555501'))->toBe('order_codes1')
|
|
169
|
+
// Current labels carry a tracking url; the host is irrelevant.
|
|
170
|
+
->and($owner('https://console.fleetbase.test/track-order?order=ACM1111111111SG&r=order_codes1&v=1'))->toBe('order_codes1')
|
|
171
|
+
->and($owner('https://old-host.example/track-order?order=ACM2222222222SG&v=1'))->toBe('entity_codes1')
|
|
172
|
+
// The Code 128 barcode, or a value typed by hand: a tracking number or public id.
|
|
173
|
+
->and($owner('ACM2222222222SG'))->toBe('entity_codes1')
|
|
174
|
+
->and($owner('entity_codes1'))->toBe('entity_codes1')
|
|
175
|
+
->and($owner('https://console.fleetbase.test/track-order?r=order_codes1'))->toBe('order_codes1');
|
|
176
|
+
|
|
177
|
+
// A url whose two identifiers disagree, or that names an unknown tracking number, is
|
|
178
|
+
// refused rather than resolved through the half that matches.
|
|
179
|
+
expect($owner('https://console.fleetbase.test/track-order?order=ACM1111111111SG&r=entity_codes1&v=1'))->toBeNull()
|
|
180
|
+
->and($owner('https://console.fleetbase.test/track-order?order=ACM9999999999SG&r=order_codes1&v=1'))->toBeNull()
|
|
181
|
+
// Unknown values, unmapped prefixes, and values that are no public id at all.
|
|
182
|
+
->and($owner('55555555-5555-4555-8555-555555555599'))->toBeNull()
|
|
183
|
+
->and($owner('ACM9999999999SG'))->toBeNull()
|
|
184
|
+
->and($owner('vehicle_codes1'))->toBeNull()
|
|
185
|
+
->and($owner('order_missing'))->toBeNull()
|
|
186
|
+
->and($owner(''))->toBeNull();
|
|
187
|
+
|
|
188
|
+
// Another company's parcel never resolves, in any format, and without a company
|
|
189
|
+
// nothing does.
|
|
190
|
+
expect($owner('55555555-5555-4555-8555-555555555503'))->toBeNull()
|
|
191
|
+
->and($owner('OTH3333333333SG'))->toBeNull()
|
|
192
|
+
->and($owner('order_codes2'))->toBeNull()
|
|
193
|
+
->and($owner('order_codes2', 'company-2'))->toBe('order_codes2')
|
|
194
|
+
->and($owner('55555555-5555-4555-8555-555555555501', null))->toBeNull();
|
|
160
195
|
});
|