@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
|
@@ -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());
|