@fleetbase/fleetops-engine 0.6.71 → 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 +15 -18
- 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/form/route.hbs +1 -1
- package/addon/components/order/form/route.js +13 -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/operations/orders/index/details.js +19 -3
- package/addon/controllers/operations/scheduler/index.js +45 -14
- 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 +65 -1
- package/addon/helpers/parcel-box-image.js +16 -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/location.js +69 -21
- package/addon/services/map-settings.js +28 -0
- package/addon/services/order-allocation.js +1 -1
- package/addon/styles/fleetops-engine.css +1391 -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/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/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 +84 -24
- 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 +200 -9
- 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 +101 -2
- 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/OrderControllerContractsTest.php +110 -14
- 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/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/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 +287 -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
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
|
|
4
4
|
|
|
5
5
|
use Fleetbase\FleetOps\Jobs\DispatchTelematicsRetentionJobs;
|
|
6
|
+
use Fleetbase\FleetOps\Orchestration\Support\OrchestratorSettings;
|
|
6
7
|
use Fleetbase\FleetOps\Support\Telematics\Retention\RetentionPolicy;
|
|
7
8
|
use Fleetbase\FleetOps\Support\Telematics\Telemetry\Queue;
|
|
9
|
+
use Fleetbase\FleetOps\Support\TrackingPage\TrackingPageConfig;
|
|
10
|
+
use Fleetbase\FleetOps\Support\Utils;
|
|
8
11
|
use Fleetbase\FleetOps\Tracking\TrackingProviderRegistry;
|
|
9
12
|
use Fleetbase\FleetOps\Traits\AuthorizesMethods;
|
|
10
13
|
use Fleetbase\Http\Controllers\Controller;
|
|
11
14
|
use Fleetbase\Models\Setting;
|
|
15
|
+
use Fleetbase\Services\SmsService;
|
|
12
16
|
use Fleetbase\Support\Auth;
|
|
13
17
|
use Fleetbase\Support\NotificationRegistry;
|
|
14
18
|
use Illuminate\Database\MySqlConnection;
|
|
@@ -47,6 +51,11 @@ class SettingController extends Controller
|
|
|
47
51
|
'saveTelematicsSettings' => 'update telematics-settings',
|
|
48
52
|
'getTelematicsStorageUsage' => 'admin',
|
|
49
53
|
'runTelematicsRetention' => 'admin',
|
|
54
|
+
'getTrackingPageSettings' => 'view tracking-page-settings',
|
|
55
|
+
'saveTrackingPageSettings' => 'update tracking-page-settings',
|
|
56
|
+
'validateTrackingPageSlug' => 'update tracking-page-settings',
|
|
57
|
+
'getAdminTrackingPageSettings' => 'admin',
|
|
58
|
+
'saveAdminTrackingPageSettings' => 'admin',
|
|
50
59
|
]);
|
|
51
60
|
}
|
|
52
61
|
|
|
@@ -387,6 +396,10 @@ class SettingController extends Controller
|
|
|
387
396
|
'googleMapsMapType' => 'roadmap',
|
|
388
397
|
'showGoogleMapsTrafficLayer' => false,
|
|
389
398
|
'showGoogleMapsTransitLayer' => false,
|
|
399
|
+
'defaultMapLatitude' => null,
|
|
400
|
+
'defaultMapLongitude' => null,
|
|
401
|
+
'defaultMapZoom' => null,
|
|
402
|
+
'fitMapToVehicles' => false,
|
|
390
403
|
];
|
|
391
404
|
|
|
392
405
|
$systemMapSettings = $this->lookupSetting('fleet-ops.map-settings', []);
|
|
@@ -400,6 +413,12 @@ class SettingController extends Controller
|
|
|
400
413
|
$mapSettings['googleMapsApiKey'] = $this->googleMapsApiKey();
|
|
401
414
|
$mapSettings['googleMapsMapId'] = data_get($systemMapSettings, 'googleMapsMapId', '');
|
|
402
415
|
|
|
416
|
+
// Last-resort starting point for the live map when the company has no
|
|
417
|
+
// configured default view and the browser cannot locate the user: the
|
|
418
|
+
// centre of the company's country, so a fresh account opens in the
|
|
419
|
+
// right part of the world instead of a hardcoded city.
|
|
420
|
+
$mapSettings['companyMapCenter'] = $this->companyMapCenter();
|
|
421
|
+
|
|
403
422
|
return response()->json($mapSettings);
|
|
404
423
|
}
|
|
405
424
|
|
|
@@ -421,6 +440,9 @@ class SettingController extends Controller
|
|
|
421
440
|
// from the payload in case a client accidentally sends it.
|
|
422
441
|
unset($settings['googleMapsApiKey']);
|
|
423
442
|
|
|
443
|
+
// Derived server-side on every read, never persisted.
|
|
444
|
+
unset($settings['companyMapCenter']);
|
|
445
|
+
|
|
424
446
|
// Validate provider value
|
|
425
447
|
$settings = $this->normalizeCompanyMapSettings($settings);
|
|
426
448
|
|
|
@@ -479,9 +501,99 @@ class SettingController extends Controller
|
|
|
479
501
|
'googleMapsMapType' => $googleMapsMapType,
|
|
480
502
|
'showGoogleMapsTrafficLayer' => filter_var(data_get($settings, 'showGoogleMapsTrafficLayer', false), FILTER_VALIDATE_BOOLEAN),
|
|
481
503
|
'showGoogleMapsTransitLayer' => filter_var(data_get($settings, 'showGoogleMapsTransitLayer', false), FILTER_VALIDATE_BOOLEAN),
|
|
504
|
+
...$this->normalizeDefaultMapView($settings),
|
|
505
|
+
];
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Normalize the company's default live map view. A centre is only kept as
|
|
510
|
+
* a valid latitude/longitude pair — half a coordinate would send the map
|
|
511
|
+
* to the equator or the meridian — and the zoom is clamped to the range
|
|
512
|
+
* both map providers support.
|
|
513
|
+
*/
|
|
514
|
+
protected function normalizeDefaultMapView(array $settings): array
|
|
515
|
+
{
|
|
516
|
+
$latitude = $this->normalizeCoordinate(data_get($settings, 'defaultMapLatitude'), 90);
|
|
517
|
+
$longitude = $this->normalizeCoordinate(data_get($settings, 'defaultMapLongitude'), 180);
|
|
518
|
+
$hasCenter = $latitude !== null && $longitude !== null;
|
|
519
|
+
$zoom = filter_var(data_get($settings, 'defaultMapZoom'), FILTER_VALIDATE_INT);
|
|
520
|
+
|
|
521
|
+
return [
|
|
522
|
+
'defaultMapLatitude' => $hasCenter ? $latitude : null,
|
|
523
|
+
'defaultMapLongitude' => $hasCenter ? $longitude : null,
|
|
524
|
+
'defaultMapZoom' => $zoom === false ? null : max(1, min(20, $zoom)),
|
|
525
|
+
'fitMapToVehicles' => filter_var(data_get($settings, 'fitMapToVehicles', false), FILTER_VALIDATE_BOOLEAN),
|
|
482
526
|
];
|
|
483
527
|
}
|
|
484
528
|
|
|
529
|
+
protected function normalizeCoordinate($value, float $limit): ?float
|
|
530
|
+
{
|
|
531
|
+
if ($value === null || $value === '' || !is_numeric($value)) {
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
$value = (float) $value;
|
|
536
|
+
|
|
537
|
+
return abs($value) <= $limit ? $value : null;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Resolve the centre of the current company's country, from its country
|
|
542
|
+
* code or, when none was recorded, the country of its timezone.
|
|
543
|
+
*/
|
|
544
|
+
protected function companyMapCenter(): ?array
|
|
545
|
+
{
|
|
546
|
+
$company = $this->currentCompany();
|
|
547
|
+
$country = $this->normalizeCountryCode(data_get($company, 'country')) ?? $this->countryFromTimezone(data_get($company, 'timezone'));
|
|
548
|
+
if ($country === null) {
|
|
549
|
+
return null;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
$coordinates = data_get($this->countryData($country), 'coordinates', []);
|
|
553
|
+
$latitude = $this->normalizeCoordinate(data_get($coordinates, 'latitude'), 90);
|
|
554
|
+
$longitude = $this->normalizeCoordinate(data_get($coordinates, 'longitude'), 180);
|
|
555
|
+
if ($latitude === null || $longitude === null || ($latitude == 0 && $longitude == 0)) {
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return [
|
|
560
|
+
'country' => $country,
|
|
561
|
+
'latitude' => $latitude,
|
|
562
|
+
'longitude' => $longitude,
|
|
563
|
+
];
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
protected function normalizeCountryCode($country): ?string
|
|
567
|
+
{
|
|
568
|
+
return is_string($country) && preg_match('/^[A-Za-z]{2}$/', $country) ? strtoupper($country) : null;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
protected function countryFromTimezone($timezone): ?string
|
|
572
|
+
{
|
|
573
|
+
if (!is_string($timezone) || $timezone === '') {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
try {
|
|
578
|
+
$location = (new \DateTimeZone($timezone))->getLocation();
|
|
579
|
+
} catch (\Throwable $e) {
|
|
580
|
+
return null;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// UTC and other non-geographic zones report the country code "??".
|
|
584
|
+
return $this->normalizeCountryCode(data_get($location, 'country_code'));
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
protected function countryData(string $country): ?array
|
|
588
|
+
{
|
|
589
|
+
try {
|
|
590
|
+
return Utils::getCountryData($country);
|
|
591
|
+
} catch (\Throwable $e) {
|
|
592
|
+
// The countries package throws for codes it does not know.
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
485
597
|
/**
|
|
486
598
|
* Sanitize a Leaflet XYZ tile URL template — only http(s) URLs are accepted,
|
|
487
599
|
* anything else is discarded so the frontend falls back to the default tiles.
|
|
@@ -547,14 +659,7 @@ class SettingController extends Controller
|
|
|
547
659
|
*/
|
|
548
660
|
public function getOrchestratorSettings()
|
|
549
661
|
{
|
|
550
|
-
$
|
|
551
|
-
'allocation_engine' => 'vroom',
|
|
552
|
-
'auto_allocate_on_create' => false,
|
|
553
|
-
'auto_reallocate_on_complete' => false,
|
|
554
|
-
'max_travel_time_seconds' => 3600,
|
|
555
|
-
'balance_workload' => false,
|
|
556
|
-
];
|
|
557
|
-
$settings = $this->lookupFromCompanySetting('fleet-ops.allocation-settings', $defaults);
|
|
662
|
+
$settings = $this->lookupFromCompanySetting(OrchestratorSettings::KEY, OrchestratorSettings::defaults());
|
|
558
663
|
|
|
559
664
|
return response()->json($settings);
|
|
560
665
|
}
|
|
@@ -567,13 +672,13 @@ class SettingController extends Controller
|
|
|
567
672
|
public function saveOrchestratorSettings(Request $request)
|
|
568
673
|
{
|
|
569
674
|
$settings = [
|
|
570
|
-
'allocation_engine' => $request->input('allocation_engine',
|
|
675
|
+
'allocation_engine' => $request->input('allocation_engine', OrchestratorSettings::DEFAULT_ENGINE),
|
|
571
676
|
'auto_allocate_on_create' => (bool) $request->input('auto_allocate_on_create', false),
|
|
572
677
|
'auto_reallocate_on_complete' => (bool) $request->input('auto_reallocate_on_complete', false),
|
|
573
678
|
'max_travel_time_seconds' => (int) $request->input('max_travel_time_seconds', 3600),
|
|
574
679
|
'balance_workload' => (bool) $request->input('balance_workload', false),
|
|
575
680
|
];
|
|
576
|
-
$this->configureCompanySetting(
|
|
681
|
+
$this->configureCompanySetting(OrchestratorSettings::KEY, $settings);
|
|
577
682
|
|
|
578
683
|
return response()->json($settings);
|
|
579
684
|
}
|
|
@@ -1074,6 +1179,194 @@ class SettingController extends Controller
|
|
|
1074
1179
|
return $statistics;
|
|
1075
1180
|
}
|
|
1076
1181
|
|
|
1182
|
+
/**
|
|
1183
|
+
* The company's customer tracking page settings, with what the settings screen needs to
|
|
1184
|
+
* explain them: whether the slug is usable, whether SMS can be sent, and whether the
|
|
1185
|
+
* customer portal is there for sign-in.
|
|
1186
|
+
*
|
|
1187
|
+
* @return \Illuminate\Http\JsonResponse
|
|
1188
|
+
*/
|
|
1189
|
+
public function getTrackingPageSettings()
|
|
1190
|
+
{
|
|
1191
|
+
return response()->json($this->trackingPageView($this->trackingPageConfig()));
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
/**
|
|
1195
|
+
* Save the company's tracking page settings.
|
|
1196
|
+
*
|
|
1197
|
+
* The slug is indexed so the public page can find the company in one read. A slug that
|
|
1198
|
+
* is invalid, reserved or taken can't be saved while the organization page is on; while
|
|
1199
|
+
* it is off, the slug is kept but not indexed.
|
|
1200
|
+
*
|
|
1201
|
+
* @return \Illuminate\Http\JsonResponse
|
|
1202
|
+
*/
|
|
1203
|
+
public function saveTrackingPageSettings(Request $request)
|
|
1204
|
+
{
|
|
1205
|
+
$previous = $this->trackingPageConfig();
|
|
1206
|
+
$config = TrackingPageConfig::sanitize((array) $request->input('trackingPage', []), $this->trackingPageAdminConfig(), $this->trackingPageCompanyName());
|
|
1207
|
+
$slug = $config['org_page']['slug'];
|
|
1208
|
+
$validation = $this->trackingPageSlugValidation($slug);
|
|
1209
|
+
|
|
1210
|
+
if ($config['org_page']['enabled'] && !$validation['valid']) {
|
|
1211
|
+
return response()->error($validation['message'], 422);
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
if ($validation['valid']) {
|
|
1215
|
+
$previousSlug = $previous['org_page']['slug'];
|
|
1216
|
+
if ($previousSlug !== $slug && $this->trackingPageSlugOwner($previousSlug) === $this->trackingPageCompanyUuid()) {
|
|
1217
|
+
$this->configureSetting(TrackingPageConfig::SLUG_INDEX_PREFIX . $previousSlug, null);
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
$this->configureSetting(TrackingPageConfig::SLUG_INDEX_PREFIX . $slug, $this->trackingPageCompanyUuid());
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
$this->configureCompanySetting(TrackingPageConfig::SETTING_KEY, $config);
|
|
1224
|
+
|
|
1225
|
+
return response()->json($this->trackingPageView($config));
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
/**
|
|
1229
|
+
* Check a slug while it is typed.
|
|
1230
|
+
*
|
|
1231
|
+
* @return \Illuminate\Http\JsonResponse
|
|
1232
|
+
*/
|
|
1233
|
+
public function validateTrackingPageSlug(Request $request)
|
|
1234
|
+
{
|
|
1235
|
+
$slug = strtolower(trim((string) $request->input('slug', '')));
|
|
1236
|
+
|
|
1237
|
+
return response()->json(array_merge(['slug' => $slug], $this->trackingPageSlugValidation($slug)));
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
/**
|
|
1241
|
+
* Instance-wide defaults for the generic tracking page.
|
|
1242
|
+
*
|
|
1243
|
+
* @return \Illuminate\Http\JsonResponse
|
|
1244
|
+
*/
|
|
1245
|
+
public function getAdminTrackingPageSettings()
|
|
1246
|
+
{
|
|
1247
|
+
return response()->json($this->trackingPageAdminConfig());
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
/**
|
|
1251
|
+
* Save the instance-wide defaults for the generic tracking page.
|
|
1252
|
+
*
|
|
1253
|
+
* @return \Illuminate\Http\JsonResponse
|
|
1254
|
+
*/
|
|
1255
|
+
public function saveAdminTrackingPageSettings(Request $request)
|
|
1256
|
+
{
|
|
1257
|
+
$config = TrackingPageConfig::sanitizeAdmin((array) $request->input('trackingPage', []));
|
|
1258
|
+
$this->configureSetting(TrackingPageConfig::ADMIN_SETTING_KEY, $config);
|
|
1259
|
+
|
|
1260
|
+
return response()->json($config);
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
protected function trackingPageConfig(): array
|
|
1264
|
+
{
|
|
1265
|
+
return TrackingPageConfig::sanitize(
|
|
1266
|
+
(array) $this->lookupCompanySetting(TrackingPageConfig::SETTING_KEY, []),
|
|
1267
|
+
$this->trackingPageAdminConfig(),
|
|
1268
|
+
$this->trackingPageCompanyName()
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
protected function trackingPageAdminConfig(): array
|
|
1273
|
+
{
|
|
1274
|
+
return TrackingPageConfig::sanitizeAdmin((array) $this->lookupSetting(TrackingPageConfig::ADMIN_SETTING_KEY, []));
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
/**
|
|
1278
|
+
* The saved config plus the read-only facts the settings screen shows beside it.
|
|
1279
|
+
*/
|
|
1280
|
+
protected function trackingPageView(array $config): array
|
|
1281
|
+
{
|
|
1282
|
+
$accent = $config['branding']['accent'];
|
|
1283
|
+
|
|
1284
|
+
return array_merge($config, [
|
|
1285
|
+
'slug_validation' => $this->trackingPageSlugValidation($config['org_page']['slug']),
|
|
1286
|
+
'accent_ink' => TrackingPageConfig::inkFor($accent),
|
|
1287
|
+
'accent_contrast' => TrackingPageConfig::contrastRatio($accent, TrackingPageConfig::inkFor($accent)),
|
|
1288
|
+
'sms_available' => $this->smsProviderConfigured(),
|
|
1289
|
+
'customer_portal_installed' => $this->customerPortalInstalled(),
|
|
1290
|
+
'admin' => $this->trackingPageAdminConfig(),
|
|
1291
|
+
]);
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
/**
|
|
1295
|
+
* @return array{valid: bool, code: string, message: string}
|
|
1296
|
+
*/
|
|
1297
|
+
protected function trackingPageSlugValidation(string $slug): array
|
|
1298
|
+
{
|
|
1299
|
+
$error = TrackingPageConfig::slugError($slug);
|
|
1300
|
+
if ($error === 'invalid') {
|
|
1301
|
+
return ['valid' => false, 'code' => 'invalid', 'message' => 'Use 3 to 40 lowercase letters, numbers and single hyphens, starting and ending with a letter or number.'];
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
if ($error === 'reserved') {
|
|
1305
|
+
return ['valid' => false, 'code' => 'reserved', 'message' => 'This address is reserved. Please choose another.'];
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
$owner = $this->trackingPageSlugOwner($slug);
|
|
1309
|
+
if ($owner !== null && $owner !== $this->trackingPageCompanyUuid()) {
|
|
1310
|
+
return ['valid' => false, 'code' => 'taken', 'message' => 'Another organization already uses this address.'];
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
return ['valid' => true, 'code' => 'available', 'message' => 'This address is available.'];
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
protected function trackingPageSlugOwner(string $slug): ?string
|
|
1317
|
+
{
|
|
1318
|
+
$owner = $this->lookupSetting(TrackingPageConfig::SLUG_INDEX_PREFIX . $slug);
|
|
1319
|
+
|
|
1320
|
+
return is_string($owner) && $owner !== '' ? $owner : null;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
protected function trackingPageCompanyUuid(): ?string
|
|
1324
|
+
{
|
|
1325
|
+
return data_get($this->currentCompany(), 'uuid');
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
protected function trackingPageCompanyName(): ?string
|
|
1329
|
+
{
|
|
1330
|
+
return data_get($this->currentCompany(), 'name');
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
/**
|
|
1334
|
+
* Whether the instance can send SMS. Twilio is listed as always available, so it counts
|
|
1335
|
+
* only with credentials; other providers report their own configuration.
|
|
1336
|
+
*/
|
|
1337
|
+
protected function smsProviderConfigured(): bool
|
|
1338
|
+
{
|
|
1339
|
+
if (filled(config('services.twilio.sid')) && filled(config('services.twilio.token'))) {
|
|
1340
|
+
return true;
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
return collect($this->smsProviders())
|
|
1344
|
+
->except(SmsService::PROVIDER_TWILIO)
|
|
1345
|
+
->contains(fn ($provider) => (bool) data_get($provider, 'available'));
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
protected function smsProviders(): array
|
|
1349
|
+
{
|
|
1350
|
+
// @codeCoverageIgnoreStart
|
|
1351
|
+
// Reads the live SMS provider configuration; tests replace this seam.
|
|
1352
|
+
return (new SmsService())->getAvailableProviders();
|
|
1353
|
+
// @codeCoverageIgnoreEnd
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
protected function customerPortalInstalled(): bool
|
|
1357
|
+
{
|
|
1358
|
+
return collect($this->installedFleetbaseExtensions())
|
|
1359
|
+
->contains(fn ($package) => data_get($package, 'name') === 'fleetbase/customer-portal-api');
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
protected function installedFleetbaseExtensions(): array
|
|
1363
|
+
{
|
|
1364
|
+
// @codeCoverageIgnoreStart
|
|
1365
|
+
// Reads the installed composer packages; tests replace this seam.
|
|
1366
|
+
return Utils::getInstalledFleetbaseExtensions();
|
|
1367
|
+
// @codeCoverageIgnoreEnd
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1077
1370
|
protected function dispatchTelematicsPrune(): void
|
|
1078
1371
|
{
|
|
1079
1372
|
Queue::dispatch(new DispatchTelematicsRetentionJobs());
|