@fleetbase/fleetops-engine 0.6.58 → 0.6.59
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/README.md +3 -0
- package/addon/components/customer/form.hbs +0 -49
- package/addon/components/entity/card.hbs +1 -0
- package/addon/components/modals/order-label.hbs +1 -1
- package/addon/components/place/form.hbs +1 -1
- package/addon/services/entity-actions.js +32 -0
- package/addon/styles/fleetops-engine.css +0 -1
- package/composer.json +8 -3
- package/extension.json +1 -1
- package/index.js +7 -1
- package/package.json +2 -1
- package/scripts/coverage-file-runner.php +240 -0
- package/scripts/coverage-runner.php +2 -1
- package/scripts/coverage-summary.php +41 -2
- package/scripts/pest-bootstrap.php +237 -3
- package/scripts/pest-file-runner.php +13 -1
- package/scripts/pest-runner.php +57 -2
- package/server/resources/views/labels/entity-label.php +4 -4
- package/server/src/Casts/MultiPolygon.php +8 -3
- package/server/src/Casts/OrderConfigEntities.php +10 -3
- package/server/src/Casts/Point.php +10 -6
- package/server/src/Casts/Polygon.php +5 -2
- package/server/src/Console/Commands/AssignCustomerRoles.php +28 -6
- package/server/src/Console/Commands/AssignDriverRoles.php +36 -6
- package/server/src/Console/Commands/AuditCustomerUserConflicts.php +6 -1
- package/server/src/Console/Commands/DispatchAdhocOrders.php +12 -2
- package/server/src/Console/Commands/FixCustomerCompanies.php +46 -11
- package/server/src/Console/Commands/FixDriverCompanies.php +18 -3
- package/server/src/Console/Commands/FixLegacyOrderConfigs.php +31 -6
- package/server/src/Console/Commands/ProcessMaintenanceTriggers.php +94 -42
- package/server/src/Console/Commands/PurgeUnpurchasedServiceQuotes.php +42 -12
- package/server/src/Console/Commands/ReplayVehicleLocations.php +120 -55
- package/server/src/Console/Commands/SendDriverNotification.php +25 -4
- package/server/src/Console/Commands/SendMaintenanceReminders.php +43 -23
- package/server/src/Console/Commands/SimulateOrderRouteNavigation.php +36 -6
- package/server/src/Console/Commands/TrackOrderDistanceAndTime.php +6 -1
- package/server/src/Events/DriverLocationChanged.php +1 -1
- package/server/src/Events/DriverSimulatedLocationChanged.php +1 -1
- package/server/src/Events/EntityActivityChanged.php +1 -1
- package/server/src/Events/EntityCompleted.php +1 -1
- package/server/src/Events/EntityDriverAssigned.php +1 -1
- package/server/src/Events/FuelProviderTransactionImported.php +1 -1
- package/server/src/Events/FuelProviderTransactionMatched.php +1 -1
- package/server/src/Events/FuelProviderTransactionUnmatched.php +1 -1
- package/server/src/Events/FuelReportCreatedFromProvider.php +1 -1
- package/server/src/Events/GeofenceDwelled.php +1 -1
- package/server/src/Events/GeofenceEntered.php +1 -1
- package/server/src/Events/GeofenceExited.php +1 -1
- package/server/src/Events/VehicleLocationChanged.php +1 -1
- package/server/src/Events/WaypointActivityChanged.php +1 -1
- package/server/src/Events/WaypointCompleted.php +1 -1
- package/server/src/Exceptions/IntegratedVendorException.php +2 -2
- package/server/src/Exceptions/TelematicRateLimitExceededException.php +1 -1
- package/server/src/Http/Controllers/Api/v1/ContactController.php +89 -22
- package/server/src/Http/Controllers/Api/v1/CustomerController.php +296 -97
- package/server/src/Http/Controllers/Api/v1/DeviceController.php +48 -14
- package/server/src/Http/Controllers/Api/v1/DriverController.php +168 -63
- package/server/src/Http/Controllers/Api/v1/EntityController.php +112 -66
- package/server/src/Http/Controllers/Api/v1/EquipmentController.php +40 -10
- package/server/src/Http/Controllers/Api/v1/FleetController.php +54 -14
- package/server/src/Http/Controllers/Api/v1/FuelReportController.php +54 -14
- package/server/src/Http/Controllers/Api/v1/FuelTransactionController.php +36 -11
- package/server/src/Http/Controllers/Api/v1/GeofenceController.php +39 -21
- package/server/src/Http/Controllers/Api/v1/IssueController.php +54 -14
- package/server/src/Http/Controllers/Api/v1/LabelController.php +61 -22
- package/server/src/Http/Controllers/Api/v1/NavigatorController.php +21 -5
- package/server/src/Http/Controllers/Api/v1/OrderConfigController.php +35 -5
- package/server/src/Http/Controllers/Api/v1/OrderController.php +388 -203
- package/server/src/Http/Controllers/Api/v1/PartController.php +40 -10
- package/server/src/Http/Controllers/Api/v1/PayloadController.php +90 -30
- package/server/src/Http/Controllers/Api/v1/PlaceController.php +188 -91
- package/server/src/Http/Controllers/Api/v1/PurchaseRateController.php +100 -36
- package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +96 -26
- package/server/src/Http/Controllers/Api/v1/ServiceQuoteController.php +169 -81
- package/server/src/Http/Controllers/Api/v1/ServiceRateController.php +104 -75
- package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +83 -14
- package/server/src/Http/Controllers/Api/v1/TrackingStatusController.php +66 -16
- package/server/src/Http/Controllers/Api/v1/VehicleController.php +121 -67
- package/server/src/Http/Controllers/Api/v1/VendorController.php +54 -14
- package/server/src/Http/Controllers/Api/v1/WorkOrderController.php +47 -12
- package/server/src/Http/Controllers/Api/v1/ZoneController.php +84 -24
- package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +15 -5
- package/server/src/Http/Controllers/Internal/v1/ContactController.php +113 -28
- package/server/src/Http/Controllers/Internal/v1/CustomerController.php +36 -11
- package/server/src/Http/Controllers/Internal/v1/DeviceController.php +9 -4
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +167 -69
- package/server/src/Http/Controllers/Internal/v1/EquipmentController.php +18 -3
- package/server/src/Http/Controllers/Internal/v1/FleetController.php +137 -60
- package/server/src/Http/Controllers/Internal/v1/FleetOpsLookupController.php +24 -9
- package/server/src/Http/Controllers/Internal/v1/FuelReportController.php +18 -3
- package/server/src/Http/Controllers/Internal/v1/GeocoderController.php +26 -8
- package/server/src/Http/Controllers/Internal/v1/GettingStartedController.php +12 -2
- package/server/src/Http/Controllers/Internal/v1/IntegratedVendorController.php +27 -6
- package/server/src/Http/Controllers/Internal/v1/IssueController.php +82 -29
- package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +34 -26
- package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +141 -97
- package/server/src/Http/Controllers/Internal/v1/ManifestController.php +28 -8
- package/server/src/Http/Controllers/Internal/v1/MetricsController.php +21 -12
- package/server/src/Http/Controllers/Internal/v1/MorphController.php +90 -18
- package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +88 -35
- package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +149 -39
- package/server/src/Http/Controllers/Internal/v1/OrderConfigController.php +54 -18
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +298 -86
- package/server/src/Http/Controllers/Internal/v1/PartController.php +18 -3
- package/server/src/Http/Controllers/Internal/v1/PaymentController.php +46 -14
- package/server/src/Http/Controllers/Internal/v1/PlaceController.php +31 -5
- package/server/src/Http/Controllers/Internal/v1/ProofController.php +88 -48
- package/server/src/Http/Controllers/Internal/v1/SearchController.php +1 -1
- package/server/src/Http/Controllers/Internal/v1/SensorController.php +6 -1
- package/server/src/Http/Controllers/Internal/v1/ServiceAreaController.php +6 -1
- package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +255 -105
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +88 -35
- package/server/src/Http/Controllers/Internal/v1/TelematicController.php +1 -4
- package/server/src/Http/Controllers/Internal/v1/Traits/DriverSchedulingTrait.php +42 -14
- package/server/src/Http/Controllers/Internal/v1/VendorController.php +103 -33
- package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +42 -12
- package/server/src/Http/Filter/DriverFilter.php +2 -2
- package/server/src/Http/Filter/OrderFilter.php +1 -1
- package/server/src/Http/Filter/VehicleFilter.php +21 -7
- package/server/src/Http/Middleware/AuthenticateCustomerToken.php +12 -2
- package/server/src/Http/Requests/BulkDispatchRequest.php +3 -9
- package/server/src/Http/Requests/CancelOrderRequest.php +2 -6
- package/server/src/Http/Requests/CreateContactRequest.php +2 -6
- package/server/src/Http/Requests/CreateDeviceRequest.php +2 -2
- package/server/src/Http/Requests/CreateDriverRequest.php +3 -9
- package/server/src/Http/Requests/CreateEntityRequest.php +2 -6
- package/server/src/Http/Requests/CreateEquipmentRequest.php +2 -2
- package/server/src/Http/Requests/CreateFleetRequest.php +2 -6
- package/server/src/Http/Requests/CreateFuelReportRequest.php +2 -6
- package/server/src/Http/Requests/CreateFuelTransactionRequest.php +2 -2
- package/server/src/Http/Requests/CreateIssueRequest.php +2 -6
- package/server/src/Http/Requests/CreateOrderRequest.php +7 -8
- package/server/src/Http/Requests/CreatePartRequest.php +2 -2
- package/server/src/Http/Requests/CreatePayloadRequest.php +7 -9
- package/server/src/Http/Requests/CreatePlaceRequest.php +2 -6
- package/server/src/Http/Requests/CreatePurchaseRateRequest.php +2 -6
- package/server/src/Http/Requests/CreateSensorRequest.php +2 -2
- package/server/src/Http/Requests/CreateServiceAreaRequest.php +2 -6
- package/server/src/Http/Requests/CreateServiceQuoteRequest.php +2 -6
- package/server/src/Http/Requests/CreateServiceRateRequest.php +2 -6
- package/server/src/Http/Requests/CreateTrackingNumberRequest.php +2 -6
- package/server/src/Http/Requests/CreateTrackingStatusRequest.php +2 -6
- package/server/src/Http/Requests/CreateVehicleRequest.php +2 -6
- package/server/src/Http/Requests/CreateVendorRequest.php +2 -6
- package/server/src/Http/Requests/CreateWorkOrderRequest.php +2 -2
- package/server/src/Http/Requests/CreateZoneRequest.php +2 -6
- package/server/src/Http/Requests/DecodeTrackingNumberQR.php +2 -6
- package/server/src/Http/Requests/DriverSimulationRequest.php +2 -6
- package/server/src/Http/Requests/Internal/AssignOrderRequest.php +3 -7
- package/server/src/Http/Requests/Internal/CreateDriverRequest.php +4 -12
- package/server/src/Http/Requests/Internal/CreateOrderConfigRequest.php +2 -6
- package/server/src/Http/Requests/Internal/CreateOrderRequest.php +7 -8
- package/server/src/Http/Requests/Internal/FleetActionRequest.php +18 -12
- package/server/src/Http/Requests/Internal/UpdateDriverRequest.php +6 -3
- package/server/src/Http/Requests/QueryServiceQuotesRequest.php +2 -6
- package/server/src/Http/Requests/ScheduleOrderRequest.php +2 -6
- package/server/src/Http/Requests/UpdateIssueRequest.php +1 -3
- package/server/src/Http/Resources/v1/Customer.php +2 -2
- package/server/src/Http/Resources/v1/Maintenance.php +3 -4
- package/server/src/Http/Resources/v1/MaintenanceSchedule.php +3 -4
- package/server/src/Http/Resources/v1/Order.php +3 -7
- package/server/src/Http/Resources/v1/PurchaseRate.php +4 -6
- package/server/src/Http/Resources/v1/TrackingStatus.php +4 -6
- package/server/src/Http/Resources/v1/WorkOrder.php +3 -4
- package/server/src/Imports/ContactImport.php +10 -1
- package/server/src/Imports/DriverImport.php +10 -1
- package/server/src/Imports/EquipmentImport.php +6 -1
- package/server/src/Imports/FleetImport.php +10 -1
- package/server/src/Imports/FuelReportImport.php +10 -1
- package/server/src/Imports/IssueImport.php +10 -1
- package/server/src/Imports/MaintenanceImport.php +6 -1
- package/server/src/Imports/MaintenanceScheduleImport.php +6 -1
- package/server/src/Imports/PartImport.php +6 -1
- package/server/src/Imports/PlaceImport.php +10 -1
- package/server/src/Imports/VehicleImport.php +10 -1
- package/server/src/Imports/VendorImport.php +10 -1
- package/server/src/Imports/WorkOrderImport.php +6 -1
- package/server/src/Integrations/Lalamove/Lalamove.php +3 -7
- package/server/src/Integrations/Lalamove/LalamoveServiceType.php +5 -8
- package/server/src/Jobs/CheckGeofenceDwell.php +41 -16
- package/server/src/Jobs/FinalizeApiOrderCreation.php +17 -2
- package/server/src/Jobs/FinalizeInternalOrderCreation.php +11 -1
- package/server/src/Jobs/NotifyBulkAssignedDriver.php +29 -16
- package/server/src/Jobs/ProcessAllocationJob.php +59 -25
- package/server/src/Jobs/ReplayPositions.php +17 -10
- package/server/src/Jobs/SendPositionReplay.php +18 -7
- package/server/src/Jobs/SimulateDrivingRoute.php +14 -3
- package/server/src/Jobs/SyncFuelProviderTransactionsJob.php +12 -2
- package/server/src/Listeners/HandleDeliveryCompletion.php +11 -1
- package/server/src/Listeners/HandleGeofenceDwelled.php +6 -1
- package/server/src/Listeners/HandleGeofenceEntered.php +4 -2
- package/server/src/Listeners/HandleGeofenceExited.php +6 -1
- package/server/src/Listeners/HandleOrderCanceled.php +18 -3
- package/server/src/Listeners/HandleOrderDispatchFailed.php +12 -2
- package/server/src/Listeners/HandleOrderDispatched.php +61 -26
- package/server/src/Listeners/HandleOrderDriverAssigned.php +12 -2
- package/server/src/Listeners/HandleUserRemovedFromCompany.php +19 -6
- package/server/src/Listeners/NotifyDriverOnShiftChange.php +24 -4
- package/server/src/Listeners/NotifyOrderEvent.php +11 -6
- package/server/src/Models/Contact.php +6 -7
- package/server/src/Models/Device.php +26 -3
- package/server/src/Models/Driver.php +0 -6
- package/server/src/Models/Entity.php +4 -4
- package/server/src/Models/Equipment.php +1 -1
- package/server/src/Models/FuelReport.php +5 -1
- package/server/src/Models/IntegratedVendor.php +2 -2
- package/server/src/Models/Issue.php +5 -1
- package/server/src/Models/MaintenanceSchedule.php +25 -10
- package/server/src/Models/Order.php +18 -15
- package/server/src/Models/OrderConfig.php +1 -1
- package/server/src/Models/Payload.php +9 -16
- package/server/src/Models/Place.php +20 -13
- package/server/src/Models/ServiceArea.php +3 -6
- package/server/src/Models/ServiceQuote.php +5 -0
- package/server/src/Models/ServiceRate.php +13 -6
- package/server/src/Models/Telematic.php +2 -2
- package/server/src/Models/TrackingNumber.php +55 -10
- package/server/src/Models/TrackingStatus.php +24 -4
- package/server/src/Models/Waypoint.php +44 -10
- package/server/src/Models/Zone.php +3 -6
- package/server/src/Notifications/DriverArrivedAtGeofence.php +1 -1
- package/server/src/Notifications/OrderDispatched.php +3 -9
- package/server/src/Notifications/OrderPing.php +3 -9
- package/server/src/Observers/CategoryObserver.php +6 -1
- package/server/src/Observers/CompanyObserver.php +5 -0
- package/server/src/Observers/CompanyUserObserver.php +12 -2
- package/server/src/Observers/DriverObserver.php +19 -4
- package/server/src/Observers/FleetObserver.php +6 -1
- package/server/src/Observers/PurchaseRateObserver.php +66 -11
- package/server/src/Observers/ServiceAreaObserver.php +12 -2
- package/server/src/Observers/ServiceRateObserver.php +21 -6
- package/server/src/Observers/TrackingNumberObserver.php +19 -4
- package/server/src/Observers/UserObserver.php +6 -1
- package/server/src/Observers/VehicleObserver.php +27 -7
- package/server/src/Observers/WorkOrderObserver.php +27 -7
- package/server/src/Orchestration/Engines/DriverAssignmentEngine.php +8 -3
- package/server/src/Orchestration/Support/OrchestrationPayloadBuilder.php +2 -2
- package/server/src/Providers/FleetOpsServiceProvider.php +12 -0
- package/server/src/Providers/NotificationServiceProvider.php +6 -0
- package/server/src/Support/Ai/Capabilities/AssetStatusCapability.php +36 -26
- package/server/src/Support/Ai/Capabilities/CreateOrderPreviewCapability.php +18 -5
- package/server/src/Support/Ai/Capabilities/OrderInsightsCapability.php +6 -1
- package/server/src/Support/Ai/Capabilities/SearchResourcesCapability.php +26 -6
- package/server/src/Support/Analytics/FuelEfficiency.php +9 -3
- package/server/src/Support/Analytics/FuelProviderSummary.php +14 -5
- package/server/src/Support/Analytics/GeofenceViolations.php +40 -20
- package/server/src/Support/Analytics/IssuesInsights.php +38 -18
- package/server/src/Support/Analytics/MaintenanceOverview.php +51 -21
- package/server/src/Support/Analytics/OnTimeDelivery.php +3 -2
- package/server/src/Support/Analytics/OperationsPulse.php +59 -35
- package/server/src/Support/Analytics/OrdersByStatus.php +12 -7
- package/server/src/Support/Analytics/RevenueTrend.php +16 -6
- package/server/src/Support/Analytics/TopDrivers.php +3 -2
- package/server/src/Support/FleetOps.php +109 -104
- package/server/src/Support/Geocoding.php +52 -14
- package/server/src/Support/GeofenceIntersectionService.php +47 -27
- package/server/src/Support/LiveOrderQuery.php +6 -1
- package/server/src/Support/Metrics/ActiveRevenueQuery.php +3 -2
- package/server/src/Support/Metrics/FuelCostsMetric.php +6 -1
- package/server/src/Support/ResolvesOrderServiceStops.php +10 -0
- package/server/src/Support/Telematics/Providers/GeotabProvider.php +9 -4
- package/server/src/Support/Utils.php +122 -16
- package/server/src/Tracking/Providers/GoogleRoutesTrackingProvider.php +6 -1
- package/server/src/Tracking/Providers/OsrmTrackingProvider.php +11 -6
- package/server/src/Tracking/TrackingProviderManager.php +2 -3
- package/server/src/Tracking/TrackingProviderRegistry.php +8 -4
- package/server/src/Traits/PayloadAccessors.php +6 -1
- package/server/src/routes.php +23 -16
- package/server/tests/AiOperationalQueryCapabilityTest.php +457 -1
- package/server/tests/AiPreviewCapabilityContractsTest.php +180 -0
- package/server/tests/AnalyticsRoutesTest.php +380 -1
- package/server/tests/AnalyticsWidgetContractsTest.php +740 -0
- package/server/tests/ApiContactControllerContractsTest.php +284 -0
- package/server/tests/ApiCustomerControllerContractsTest.php +962 -0
- package/server/tests/ApiDriverControllerContractsTest.php +571 -0
- package/server/tests/ApiEntityControllerContractsTest.php +329 -0
- package/server/tests/ApiEquipmentControllerContractsTest.php +239 -0
- package/server/tests/ApiFleetControllerContractsTest.php +176 -0
- package/server/tests/ApiFuelReportControllerContractsTest.php +217 -0
- package/server/tests/ApiIssueControllerContractsTest.php +217 -0
- package/server/tests/ApiOrderControllerContractsTest.php +1030 -0
- package/server/tests/ApiPartControllerContractsTest.php +251 -0
- package/server/tests/ApiPayloadControllerContractsTest.php +314 -0
- package/server/tests/ApiPlaceControllerContractsTest.php +541 -0
- package/server/tests/ApiPurchaseRateControllerContractsTest.php +283 -0
- package/server/tests/ApiServiceAreaZoneControllerContractsTest.php +442 -0
- package/server/tests/ApiServiceQuoteControllerContractsTest.php +322 -0
- package/server/tests/ApiTrackingNumberControllerContractsTest.php +225 -0
- package/server/tests/ApiTrackingStatusControllerContractsTest.php +254 -0
- package/server/tests/ApiVehicleControllerContractsTest.php +368 -0
- package/server/tests/ApiVendorControllerContractsTest.php +199 -0
- package/server/tests/AssetAndPlaceSearchContractsTest.php +220 -0
- package/server/tests/BackendSmallModelContractsTest.php +354 -0
- package/server/tests/CapacityAllocationEngineTest.php +56 -0
- package/server/tests/CommandContractsTest.php +2695 -0
- package/server/tests/CompactResourceSerializationTest.php +2745 -0
- package/server/tests/ControllerFilterContractsTest.php +1273 -0
- package/server/tests/ControllerHelperContractsTest.php +1740 -0
- package/server/tests/ControllerSerializationContractsTest.php +141 -0
- package/server/tests/CoverageSummaryScriptTest.php +93 -0
- package/server/tests/CustomerContactIdentitySafetyTest.php +1 -6
- package/server/tests/CustomerEndpointTest.php +165 -1
- package/server/tests/DriverFilterExecutionTest.php +263 -0
- package/server/tests/DriverGeofenceProcessingTest.php +153 -0
- package/server/tests/DriverResourceSerializationTest.php +245 -0
- package/server/tests/DriverSchedulingTraitContractsTest.php +259 -0
- package/server/tests/EventContractsTest.php +1259 -0
- package/server/tests/ExceptionContractsTest.php +81 -0
- package/server/tests/ExpansionContractsTest.php +242 -0
- package/server/tests/ExportCoverageTest.php +116 -0
- package/server/tests/Feature/Http/Api/ContactControllerPhotoAndDeleteTest.php +199 -0
- package/server/tests/Feature/Http/Api/CustomerControllerHelperSeamsTest.php +831 -0
- package/server/tests/Feature/Http/Api/DeviceControllerContractsTest.php +347 -0
- package/server/tests/Feature/Http/Api/DeviceControllerCrudTest.php +176 -0
- package/server/tests/Feature/Http/Api/DriverControllerAuthFlowsTest.php +451 -0
- package/server/tests/Feature/Http/Api/DriverControllerHelpersTest.php +240 -0
- package/server/tests/Feature/Http/Api/DriverControllerLookupTest.php +186 -0
- package/server/tests/Feature/Http/Api/DriverControllerOrganizationsTest.php +112 -0
- package/server/tests/Feature/Http/Api/DriverControllerSessionHelpersTest.php +207 -0
- package/server/tests/Feature/Http/Api/DriverControllerSwitchOrgAndGeofenceTest.php +329 -0
- package/server/tests/Feature/Http/Api/DriverControllerTrackTest.php +383 -0
- package/server/tests/Feature/Http/Api/EntityControllerHelpersTest.php +150 -0
- package/server/tests/Feature/Http/Api/FuelTransactionControllerContractsTest.php +352 -0
- package/server/tests/Feature/Http/Api/GeofenceControllerContractsTest.php +364 -0
- package/server/tests/Feature/Http/Api/LabelControllerSubjectsTest.php +148 -0
- package/server/tests/Feature/Http/Api/OrderConfigControllerTest.php +112 -0
- package/server/tests/Feature/Http/Api/OrderControllerCreateTest.php +279 -0
- package/server/tests/Feature/Http/Api/OrderControllerIntegratedVendorTest.php +295 -0
- package/server/tests/Feature/Http/Api/OrderControllerLifecycleActionsTest.php +279 -0
- package/server/tests/Feature/Http/Api/OrderControllerLookupHelpersTest.php +207 -0
- package/server/tests/Feature/Http/Api/OrderControllerNearbyFiltersTest.php +282 -0
- package/server/tests/Feature/Http/Api/OrderControllerPersistenceHelpersTest.php +216 -0
- package/server/tests/Feature/Http/Api/OrderControllerQueryFiltersTest.php +184 -0
- package/server/tests/Feature/Http/Api/OrderControllerStartActivityTest.php +663 -0
- package/server/tests/Feature/Http/Api/PayloadControllerHelpersTest.php +134 -0
- package/server/tests/Feature/Http/Api/PlaceAndServiceQuoteSeamsTest.php +479 -0
- package/server/tests/Feature/Http/Api/PurchaseRateControllerHelpersTest.php +176 -0
- package/server/tests/Feature/Http/Api/PurchaseRateControllerOrderCreationTest.php +268 -0
- package/server/tests/Feature/Http/Api/SensorControllerCrudTest.php +239 -0
- package/server/tests/Feature/Http/Api/ServiceAreaControllerBorderAndSeamsTest.php +187 -0
- package/server/tests/Feature/Http/Api/ServiceQuoteControllerQueryTest.php +405 -0
- package/server/tests/Feature/Http/Api/ServiceQuoteControllerVendorBridgeTest.php +212 -0
- package/server/tests/Feature/Http/Api/ServiceRateControllerContractsTest.php +263 -0
- package/server/tests/Feature/Http/Api/SmallApiControllerHelpersTest.php +272 -0
- package/server/tests/Feature/Http/Api/TrackingNumberControllerHelpersTest.php +154 -0
- package/server/tests/Feature/Http/Api/TrackingStatusControllerHelpersTest.php +165 -0
- package/server/tests/Feature/Http/Api/VehicleControllerTrackingTest.php +483 -0
- package/server/tests/Feature/Http/Api/WorkOrderControllerContractsTest.php +326 -0
- package/server/tests/Feature/Http/Api/WorkOrderControllerHelpersTest.php +130 -0
- package/server/tests/Feature/Http/Api/ZoneControllerBordersAndSeamsTest.php +294 -0
- package/server/tests/Feature/Http/FleetOpsRouteRegistrationTest.php +189 -0
- package/server/tests/Feature/Http/Internal/AnalyticsControllerSeamsTest.php +53 -0
- package/server/tests/Feature/Http/Internal/ContactControllerContractsTest.php +240 -0
- package/server/tests/Feature/Http/Internal/ContactControllerCustomerGuardsTest.php +128 -0
- package/server/tests/Feature/Http/Internal/ContactControllerEndpointsTest.php +294 -0
- package/server/tests/Feature/Http/Internal/CustomerControllerCredentialsTest.php +196 -0
- package/server/tests/Feature/Http/Internal/DeviceControllerContractsTest.php +370 -0
- package/server/tests/Feature/Http/Internal/DeviceControllerExportAndFiltersTest.php +151 -0
- package/server/tests/Feature/Http/Internal/DriverControllerContractsTest.php +1109 -0
- package/server/tests/Feature/Http/Internal/DriverControllerCreateRecordTest.php +233 -0
- package/server/tests/Feature/Http/Internal/DriverControllerExistingUserAdoptionTest.php +710 -0
- package/server/tests/Feature/Http/Internal/DriverControllerHelpersTest.php +218 -0
- package/server/tests/Feature/Http/Internal/FleetAssignmentsAndTriggersTest.php +198 -0
- package/server/tests/Feature/Http/Internal/FleetOpsLookupControllerDbTest.php +90 -0
- package/server/tests/Feature/Http/Internal/HubControllerTest.php +206 -0
- package/server/tests/Feature/Http/Internal/IssueControllerContractsTest.php +404 -0
- package/server/tests/Feature/Http/Internal/IssueControllerExportImportTest.php +118 -0
- package/server/tests/Feature/Http/Internal/LiveControllerEndpointsTest.php +246 -0
- package/server/tests/Feature/Http/Internal/LiveControllerTest.php +778 -0
- package/server/tests/Feature/Http/Internal/MaintenanceScheduleControllerContractsTest.php +263 -0
- package/server/tests/Feature/Http/Internal/MaintenanceScheduleControllerSurfacesTest.php +214 -0
- package/server/tests/Feature/Http/Internal/MetricsControllerContractsTest.php +249 -0
- package/server/tests/Feature/Http/Internal/MetricsControllerHelpersTest.php +66 -0
- package/server/tests/Feature/Http/Internal/MorphControllerHelpersTest.php +125 -0
- package/server/tests/Feature/Http/Internal/NavigatorControllerHelpersTest.php +201 -0
- package/server/tests/Feature/Http/Internal/OrchestrationControllerContractsTest.php +928 -0
- package/server/tests/Feature/Http/Internal/OrchestrationControllerHelpersTest.php +214 -0
- package/server/tests/Feature/Http/Internal/OrchestrationControllerImportOrdersTest.php +340 -0
- package/server/tests/Feature/Http/Internal/OrderConfigControllerContractsTest.php +314 -0
- package/server/tests/Feature/Http/Internal/OrderControllerActivityFlowsTest.php +663 -0
- package/server/tests/Feature/Http/Internal/OrderControllerCapturePhotoTest.php +507 -0
- package/server/tests/Feature/Http/Internal/OrderControllerContractsTest.php +1742 -0
- package/server/tests/Feature/Http/Internal/OrderControllerCreateRecordTest.php +488 -0
- package/server/tests/Feature/Http/Internal/OrderControllerHelperSeamsTest.php +298 -0
- package/server/tests/Feature/Http/Internal/OrderControllerHelpersTest.php +267 -0
- package/server/tests/Feature/Http/Internal/OrderControllerImportFromFilesTest.php +179 -0
- package/server/tests/Feature/Http/Internal/OrderControllerUpstreamNotFoundTest.php +80 -0
- package/server/tests/Feature/Http/Internal/PaymentControllerPaymentsTest.php +154 -0
- package/server/tests/Feature/Http/Internal/PlaceControllerTest.php +252 -0
- package/server/tests/Feature/Http/Internal/PositionControllerReplayMetricsTest.php +163 -0
- package/server/tests/Feature/Http/Internal/ProofControllerContractsTest.php +219 -0
- package/server/tests/Feature/Http/Internal/SearchControllerEndpointTest.php +151 -0
- package/server/tests/Feature/Http/Internal/ServiceQuoteControllerHelpersTest.php +208 -0
- package/server/tests/Feature/Http/Internal/ServiceQuoteControllerQueryRecordTest.php +217 -0
- package/server/tests/Feature/Http/Internal/ServiceQuoteControllerVendorBridgeTest.php +239 -0
- package/server/tests/Feature/Http/Internal/ServiceQuotePreliminaryQueryTest.php +271 -0
- package/server/tests/Feature/Http/Internal/SettingControllerHelpersTest.php +133 -0
- package/server/tests/Feature/Http/Internal/SmallInternalControllersTest.php +180 -0
- package/server/tests/Feature/Http/Internal/TelematicControllerEndpointsTest.php +417 -0
- package/server/tests/Feature/Http/Internal/VehicleControllerEndpointsTest.php +361 -0
- package/server/tests/Feature/Http/Internal/VendorControllerEndpointsTest.php +203 -0
- package/server/tests/Feature/Http/Internal/WorkOrderAndConfigSurfacesTest.php +289 -0
- package/server/tests/Feature/Http/Internal/WorkOrderControllerContractsTest.php +199 -0
- package/server/tests/Feature/Http/TelematicWebhookIngestTest.php +343 -0
- package/server/tests/Feature/Http/Telematics/TelematicWebhookControllerProcessingTest.php +254 -0
- package/server/tests/FleetOpsSupportContractsTest.php +187 -0
- package/server/tests/FlespiProviderContractsTest.php +244 -0
- package/server/tests/FlowResourceTest.php +295 -0
- package/server/tests/FuelProviderConnectionControllerContractsTest.php +303 -0
- package/server/tests/FuelProviderImplementationTest.php +753 -0
- package/server/tests/FuelProviderResourceContractsTest.php +171 -0
- package/server/tests/FuelProviderTransactionControllerContractsTest.php +181 -0
- package/server/tests/GeofenceIntersectionServiceContractsTest.php +164 -0
- package/server/tests/HOSConstraintContractsTest.php +128 -0
- package/server/tests/HubAndGettingStartedContractsTest.php +158 -0
- package/server/tests/ImportContractsTest.php +191 -0
- package/server/tests/InternalCustomerControllerContractsTest.php +238 -0
- package/server/tests/InternalFleetControllerContractsTest.php +389 -0
- package/server/tests/InternalImportExportControllerContractsTest.php +289 -0
- package/server/tests/InternalMetricsControllerContractsTest.php +69 -0
- package/server/tests/InternalPlaceWorkOrderControllerContractsTest.php +207 -0
- package/server/tests/InternalServiceQuoteCheckoutControllerContractsTest.php +470 -0
- package/server/tests/InternalVendorControllerContractsTest.php +331 -0
- package/server/tests/InventoryTelemetryModelContractsTest.php +516 -0
- package/server/tests/IssueTimelineContractsTest.php +191 -0
- package/server/tests/LabelPdfRenderingTest.php +57 -0
- package/server/tests/LalamoveIntegrationContractsTest.php +167 -0
- package/server/tests/LiveOrderQueryTest.php +145 -18
- package/server/tests/LookupAndGeocoderControllerContractsTest.php +357 -0
- package/server/tests/MaintainableTraitContractsTest.php +245 -0
- package/server/tests/MaintenanceScheduleControllerContractsTest.php +101 -0
- package/server/tests/MaintenanceWarrantyContractsTest.php +237 -0
- package/server/tests/ManifestControllerContractsTest.php +310 -0
- package/server/tests/MetricsRegistryTest.php +596 -10
- package/server/tests/MiddlewareContractsTest.php +150 -0
- package/server/tests/ModelAccessorContractsTest.php +3201 -0
- package/server/tests/MorphControllerContractsTest.php +410 -0
- package/server/tests/NavigatorControllerContractsTest.php +206 -0
- package/server/tests/NotificationAndMailContractsTest.php +677 -0
- package/server/tests/ObserverContractsTest.php +1414 -0
- package/server/tests/OperationalAlgorithmContractsTest.php +852 -0
- package/server/tests/OperationsMonitorEndpointTest.php +2 -1
- package/server/tests/OrchestrationPayloadBuilderTest.php +87 -0
- package/server/tests/OrderActivityFlowRegressionTest.php +354 -7
- package/server/tests/OrderDispatchListenerContractsTest.php +577 -0
- package/server/tests/OrderFilterExecutionTest.php +244 -0
- package/server/tests/OrderQueuedClosureRegressionTest.php +2 -1
- package/server/tests/PaymentControllerContractsTest.php +199 -0
- package/server/tests/PointResolutionTest.php +54 -0
- package/server/tests/ProcessAllocationJobContractsTest.php +224 -0
- package/server/tests/ProofAndSensorControllerContractsTest.php +44 -0
- package/server/tests/ProviderContractsTest.php +409 -0
- package/server/tests/PublicApiControllerInputContractsTest.php +294 -0
- package/server/tests/QueueJobContractsTest.php +764 -0
- package/server/tests/ReportSchemaContractsTest.php +271 -0
- package/server/tests/RequestContractsTest.php +966 -0
- package/server/tests/RouteRegistrationExecutionTest.php +178 -0
- package/server/tests/RouteSequencingEngineTest.php +179 -0
- package/server/tests/RulesAndCastsTest.php +246 -0
- package/server/tests/SamsaraProviderContractsTest.php +272 -0
- package/server/tests/SearchControllerContractsTest.php +311 -0
- package/server/tests/ServiceRateRouteValidationTest.php +76 -0
- package/server/tests/SettingControllerContractsTest.php +410 -0
- package/server/tests/SmallControllerContractsTest.php +456 -0
- package/server/tests/SupportAnalyticsCustomerAuthContractsTest.php +221 -0
- package/server/tests/SupportJobAndAiCoverageTest.php +812 -0
- package/server/tests/SupportServiceContractsTest.php +287 -0
- package/server/tests/SupportValueObjectsTest.php +155 -0
- package/server/tests/TelematicControllerContractsTest.php +185 -0
- package/server/tests/TelematicProviderRegistryTest.php +167 -0
- package/server/tests/TelematicServiceHelperContractsTest.php +315 -0
- package/server/tests/TelematicWebhookControllerContractsTest.php +253 -0
- package/server/tests/TelematicsHardeningTest.php +642 -86
- package/server/tests/TrackingIntelligenceTest.php +644 -1
- package/server/tests/TrackingNumberTraitContractsTest.php +106 -0
- package/server/tests/Unit/Casts/SpatialCastBranchesTest.php +75 -0
- package/server/tests/Unit/Console/AssignCustomerRolesCommandTest.php +102 -0
- package/server/tests/Unit/Console/AssignDriverRolesCommandTest.php +113 -0
- package/server/tests/Unit/Console/Commands/FixLegacyOrderConfigsHelpersTest.php +108 -0
- package/server/tests/Unit/Console/Commands/ProcessOperationalAlertsCommandTest.php +265 -0
- package/server/tests/Unit/Console/Commands/ReplayVehicleLocationsCommandTest.php +320 -0
- package/server/tests/Unit/Console/Commands/SimulateGeofenceEventsCommandTest.php +207 -0
- package/server/tests/Unit/Console/FixCommandsAndMaintenanceControllerTest.php +256 -0
- package/server/tests/Unit/Console/FleetOpsCommandsTest.php +198 -0
- package/server/tests/Unit/Console/ReplayVehicleLocationsCommandTest.php +252 -0
- package/server/tests/Unit/Console/SendMaintenanceRemindersTest.php +212 -0
- package/server/tests/Unit/Console/SimulateGeofenceEventsCommandTest.php +232 -0
- package/server/tests/Unit/Console/SyncTelematicsCommandTest.php +136 -0
- package/server/tests/Unit/Constraints/HOSConstraintTest.php +158 -0
- package/server/tests/Unit/Events/EventModelRecordTest.php +93 -0
- package/server/tests/Unit/Events/OrderDispatchFailedTest.php +34 -0
- package/server/tests/Unit/Exports/ExportCollectionsTest.php +142 -0
- package/server/tests/Unit/Exports/OperationalExportMappingTest.php +651 -0
- package/server/tests/Unit/Exports/VehicleExportTest.php +284 -0
- package/server/tests/Unit/Flow/EventFiringTest.php +95 -0
- package/server/tests/Unit/Http/Api/QueryWithRequestSeamsTest.php +198 -0
- package/server/tests/Unit/Http/Api/SensorInputTest.php +95 -0
- package/server/tests/Unit/Http/Filter/DeviceFilterTest.php +199 -0
- package/server/tests/Unit/Http/Filter/EmptyValueGuardsTest.php +66 -0
- package/server/tests/Unit/Http/Filter/FilterDateRangesTest.php +72 -0
- package/server/tests/Unit/Http/Filter/FuelProviderTransactionFilterTest.php +172 -0
- package/server/tests/Unit/Http/Filter/InternalRelationUuidLookupTest.php +135 -0
- package/server/tests/Unit/Http/Filter/IssueFilterTest.php +129 -0
- package/server/tests/Unit/Http/Filter/PartFilterTest.php +173 -0
- package/server/tests/Unit/Http/Internal/ControllerDelegationSeamsTest.php +136 -0
- package/server/tests/Unit/Http/Internal/ControllerExcelSeamsTest.php +89 -0
- package/server/tests/Unit/Http/Middleware/SetupDriverSessionTest.php +32 -0
- package/server/tests/Unit/Http/Requests/CreateFuelReportRequestTest.php +47 -0
- package/server/tests/Unit/Http/Requests/FleetActionRequestTest.php +80 -0
- package/server/tests/Unit/Http/Requests/RequestAuthorizationTest.php +50 -0
- package/server/tests/Unit/Http/Resources/CustomerResourceTest.php +108 -0
- package/server/tests/Unit/Http/Resources/EntityCustomerTypeTest.php +35 -0
- package/server/tests/Unit/Http/Resources/FleetResourceTest.php +102 -0
- package/server/tests/Unit/Http/Resources/IndexOrderResourceTest.php +210 -0
- package/server/tests/Unit/Http/Resources/IndexVehicleResourceTest.php +194 -0
- package/server/tests/Unit/Http/Resources/MaintenanceResourcesTest.php +182 -0
- package/server/tests/Unit/Http/Resources/OrderAndDriverResourceTest.php +121 -0
- package/server/tests/Unit/Http/Resources/OrderConfigResourceTest.php +47 -0
- package/server/tests/Unit/Http/Resources/PayloadResourceTest.php +111 -0
- package/server/tests/Unit/Http/Resources/RelationResourceFallbacksTest.php +32 -0
- package/server/tests/Unit/Http/Resources/ResourceRelationResolutionTest.php +55 -0
- package/server/tests/Unit/Http/Resources/TrackingNumberResourceTest.php +174 -0
- package/server/tests/Unit/Http/Resources/WaypointResourceTest.php +295 -0
- package/server/tests/Unit/Http/Resources/WorkOrderResourceTest.php +164 -0
- package/server/tests/Unit/Imports/ImportDelegationTest.php +151 -0
- package/server/tests/Unit/Integrations/Lalamove/LalamoveDeliveryStopTest.php +79 -0
- package/server/tests/Unit/Integrations/Lalamove/LalamoveLifecycleTest.php +211 -0
- package/server/tests/Unit/Integrations/Lalamove/LalamoveQuoteAndServiceOrderTest.php +381 -0
- package/server/tests/Unit/Integrations/Lalamove/LalamoveServiceTypeTest.php +51 -0
- package/server/tests/Unit/Integrations/LalamoveQuotationTest.php +194 -0
- package/server/tests/Unit/Integrations/LalamoveResponseHandlingTest.php +58 -0
- package/server/tests/Unit/Jobs/GeofenceDwellAndBulkNotifyTest.php +183 -0
- package/server/tests/Unit/Jobs/ReplayPositionsTest.php +57 -0
- package/server/tests/Unit/Jobs/SimulateWaypointReachedTest.php +92 -0
- package/server/tests/Unit/Listeners/HandleGeofenceEnteredTest.php +256 -0
- package/server/tests/Unit/Listeners/HandleOrderDispatchFailedListenerTest.php +101 -0
- package/server/tests/Unit/Listeners/HandleOrderDispatchedConcreteTest.php +203 -0
- package/server/tests/Unit/Listeners/HandleOrderDispatchedHelpersTest.php +186 -0
- package/server/tests/Unit/Listeners/HandleUserRemovedFromCompanyTest.php +65 -0
- package/server/tests/Unit/Listeners/ListenerDelegationSeamsTest.php +83 -0
- package/server/tests/Unit/Models/AssetTest.php +469 -0
- package/server/tests/Unit/Models/ContactCustomerUserTest.php +370 -0
- package/server/tests/Unit/Models/ContactTest.php +577 -0
- package/server/tests/Unit/Models/DeviceEventTest.php +481 -0
- package/server/tests/Unit/Models/DeviceLastPositionDefaultTest.php +128 -0
- package/server/tests/Unit/Models/DriverModelHelpersTest.php +268 -0
- package/server/tests/Unit/Models/DriverTest.php +401 -0
- package/server/tests/Unit/Models/EntityTest.php +171 -0
- package/server/tests/Unit/Models/EquipmentTest.php +434 -0
- package/server/tests/Unit/Models/FleetTest.php +153 -0
- package/server/tests/Unit/Models/FuelProviderTransactionTest.php +82 -0
- package/server/tests/Unit/Models/FuelReportImportAndLabelsTest.php +193 -0
- package/server/tests/Unit/Models/ImportRowFallbackSeamsTest.php +100 -0
- package/server/tests/Unit/Models/IntegratedVendorLifecycleTest.php +203 -0
- package/server/tests/Unit/Models/IntegratedVendorTest.php +135 -0
- package/server/tests/Unit/Models/IssueTest.php +160 -0
- package/server/tests/Unit/Models/MaintenanceScheduleTest.php +319 -0
- package/server/tests/Unit/Models/MaintenanceTest.php +277 -0
- package/server/tests/Unit/Models/MaintenanceWorkOrderImportTest.php +161 -0
- package/server/tests/Unit/Models/ManifestStopTest.php +121 -0
- package/server/tests/Unit/Models/ManifestTest.php +163 -0
- package/server/tests/Unit/Models/ModelLookupFallbackSeamsTest.php +149 -0
- package/server/tests/Unit/Models/OrderConfigTest.php +341 -0
- package/server/tests/Unit/Models/OrderDynamicContractsTest.php +190 -0
- package/server/tests/Unit/Models/OrderPayloadConfigAndDistanceTest.php +426 -0
- package/server/tests/Unit/Models/OrderPayloadRouteTest.php +227 -0
- package/server/tests/Unit/Models/OrderPurchaseAndDriversTest.php +188 -0
- package/server/tests/Unit/Models/OrderTest.php +917 -0
- package/server/tests/Unit/Models/PartTest.php +399 -0
- package/server/tests/Unit/Models/PayloadTest.php +710 -0
- package/server/tests/Unit/Models/PayloadWaypointsAndEntitiesTest.php +317 -0
- package/server/tests/Unit/Models/PlaceCreationAndImportTest.php +384 -0
- package/server/tests/Unit/Models/PlaceGeocodingResultsTest.php +253 -0
- package/server/tests/Unit/Models/PlaceSharedAndGeocodingTest.php +271 -0
- package/server/tests/Unit/Models/PlaceTest.php +589 -0
- package/server/tests/Unit/Models/PositionTest.php +49 -0
- package/server/tests/Unit/Models/RouteTest.php +55 -0
- package/server/tests/Unit/Models/SensorReadingsTest.php +168 -0
- package/server/tests/Unit/Models/SensorTest.php +284 -0
- package/server/tests/Unit/Models/ServiceAreaGeometryTest.php +129 -0
- package/server/tests/Unit/Models/ServiceAreaTest.php +125 -0
- package/server/tests/Unit/Models/ServiceQuoteTest.php +617 -0
- package/server/tests/Unit/Models/ServiceRateFeeTest.php +73 -0
- package/server/tests/Unit/Models/ServiceRatePersistenceAndServicabilityTest.php +428 -0
- package/server/tests/Unit/Models/ServiceRateTest.php +533 -0
- package/server/tests/Unit/Models/SmallModelSurfacesTest.php +294 -0
- package/server/tests/Unit/Models/TrackingNumberTest.php +199 -0
- package/server/tests/Unit/Models/TrackingStatusTest.php +131 -0
- package/server/tests/Unit/Models/VehicleDeviceTest.php +115 -0
- package/server/tests/Unit/Models/VehiclePositionsAndImportTest.php +220 -0
- package/server/tests/Unit/Models/VehicleTest.php +266 -0
- package/server/tests/Unit/Models/VendorRelationsAndImportTest.php +107 -0
- package/server/tests/Unit/Models/WarrantyTest.php +187 -0
- package/server/tests/Unit/Models/WaypointTest.php +366 -0
- package/server/tests/Unit/Models/WorkOrderTest.php +272 -0
- package/server/tests/Unit/Models/ZoneTest.php +83 -0
- package/server/tests/Unit/Notifications/MonitoringNotificationsTest.php +136 -0
- package/server/tests/Unit/Notifications/OrderAssignedChannelsTest.php +53 -0
- package/server/tests/Unit/Notifications/OrderDispatchedChannelsTest.php +81 -0
- package/server/tests/Unit/Notifications/OrderFailedChannelsTest.php +73 -0
- package/server/tests/Unit/Notifications/OrderPingChannelsTest.php +69 -0
- package/server/tests/Unit/Notifications/TerminalOrderNotificationsTest.php +185 -0
- package/server/tests/Unit/Observers/FleetOpsCompanyUserAndServiceAreaObserversTest.php +133 -0
- package/server/tests/Unit/Observers/ObserverHelperExecutionTest.php +135 -0
- package/server/tests/Unit/Observers/ObserverListenerSeamsTest.php +267 -0
- package/server/tests/Unit/Observers/PurchaseRateObserverAndOrderJobsTest.php +169 -0
- package/server/tests/Unit/Orchestration/Engines/DriverAssignmentEngineTest.php +393 -0
- package/server/tests/Unit/Orchestration/Engines/VroomOrchestrationEngineLifecycleTest.php +397 -0
- package/server/tests/Unit/Orchestration/OrchestrationEngineRegistryTest.php +45 -0
- package/server/tests/Unit/Orchestration/VroomEngineTransportAndSettingsTest.php +253 -0
- package/server/tests/Unit/Providers/FleetOpsAiRegistrationTest.php +59 -0
- package/server/tests/Unit/Rules/ResolvableVehicleTest.php +85 -0
- package/server/tests/Unit/Support/Ai/AssetStatusCapabilityQueriesTest.php +120 -0
- package/server/tests/Unit/Support/Ai/Capabilities/CreateOrderPreviewCapabilityTest.php +385 -0
- package/server/tests/Unit/Support/Ai/Capabilities/OrderInsightsCapabilityTest.php +226 -0
- package/server/tests/Unit/Support/Ai/Capabilities/SearchResourcesCapabilityTest.php +237 -0
- package/server/tests/Unit/Support/AiCapabilityPermissionsTest.php +124 -0
- package/server/tests/Unit/Support/AlgoEdgeBranchesTest.php +24 -0
- package/server/tests/Unit/Support/Analytics/GeofenceViolationsTest.php +109 -0
- package/server/tests/Unit/Support/Analytics/LiveFleetTest.php +205 -0
- package/server/tests/Unit/Support/Analytics/MaintenanceOverviewTest.php +236 -0
- package/server/tests/Unit/Support/Analytics/OnTimeDeliveryAndTopDriversTest.php +250 -0
- package/server/tests/Unit/Support/CreateOrderPreviewDraftingTest.php +235 -0
- package/server/tests/Unit/Support/CustomerAuthTest.php +132 -0
- package/server/tests/Unit/Support/FuelEfficiencyAndCanceledHandlersTest.php +164 -0
- package/server/tests/Unit/Support/FuelProviderRegistryResolutionTest.php +51 -0
- package/server/tests/Unit/Support/FuelProviderServiceMatchingTest.php +280 -0
- package/server/tests/Unit/Support/GeocodingInjectedClientTest.php +268 -0
- package/server/tests/Unit/Support/GeocodingLocateTest.php +32 -0
- package/server/tests/Unit/Support/GeofenceIntersectionServiceTest.php +188 -0
- package/server/tests/Unit/Support/GettingStartedTest.php +164 -0
- package/server/tests/Unit/Support/GuardReturnSeamsTest.php +172 -0
- package/server/tests/Unit/Support/IntegratedVendorsResolverTest.php +250 -0
- package/server/tests/Unit/Support/IssuesInsightsAndAllocationJobTest.php +156 -0
- package/server/tests/Unit/Support/MagicAccessorSeamsTest.php +54 -0
- package/server/tests/Unit/Support/MaintainableAndOperationalAlertsTest.php +215 -0
- package/server/tests/Unit/Support/Metrics/AvgOrderValueMetricTest.php +308 -0
- package/server/tests/Unit/Support/Metrics/CountMetricsTest.php +280 -0
- package/server/tests/Unit/Support/Metrics/FuelCostsMetricTest.php +102 -0
- package/server/tests/Unit/Support/Metrics/MetricQuerySeamsTest.php +129 -0
- package/server/tests/Unit/Support/Metrics/OrdersScheduledMetricTest.php +146 -0
- package/server/tests/Unit/Support/MoreQuerySeamsTest.php +410 -0
- package/server/tests/Unit/Support/OperationalQueryDistributionTest.php +152 -0
- package/server/tests/Unit/Support/OperationsPulseTest.php +130 -0
- package/server/tests/Unit/Support/OptimizeOrderRouteCapabilityTest.php +147 -0
- package/server/tests/Unit/Support/OrchestrationPayloadBuilderTest.php +135 -0
- package/server/tests/Unit/Support/OrchestrationRouteAndVehicleTasksTest.php +254 -0
- package/server/tests/Unit/Support/OsrmProofAndIssueFilterTest.php +247 -0
- package/server/tests/Unit/Support/PetroAppFuelProviderTest.php +165 -0
- package/server/tests/Unit/Support/PlaceSearchRankingTest.php +191 -0
- package/server/tests/Unit/Support/QuerySeamsTest.php +309 -0
- package/server/tests/Unit/Support/ResolvesOrderServiceStopsDbTest.php +303 -0
- package/server/tests/Unit/Support/ResolvesOrderServiceStopsTest.php +382 -0
- package/server/tests/Unit/Support/SkipAndFallbackGuardsTest.php +70 -0
- package/server/tests/Unit/Support/TelematicCredentialResolutionTest.php +31 -0
- package/server/tests/Unit/Support/TelematicServiceTest.php +256 -0
- package/server/tests/Unit/Support/Telematics/Providers/AbstractProviderTest.php +154 -0
- package/server/tests/Unit/Support/Telematics/Providers/AfaqyProviderTest.php +191 -0
- package/server/tests/Unit/Support/Telematics/Providers/AfaqyProviderTransportTest.php +138 -0
- package/server/tests/Unit/Support/Telematics/Providers/GeotabProviderTest.php +329 -0
- package/server/tests/Unit/Support/Telematics/Providers/ProviderTransportSeamsTest.php +133 -0
- package/server/tests/Unit/Support/Telematics/Providers/SafeeProviderTest.php +487 -0
- package/server/tests/Unit/Support/Telematics/TelematicProviderRegistryTest.php +39 -0
- package/server/tests/Unit/Support/Telematics/TelematicServiceLifecycleTest.php +711 -0
- package/server/tests/Unit/Support/Telematics/TelematicServiceTelemetryTest.php +364 -0
- package/server/tests/Unit/Support/UtilsAdditionalTest.php +256 -0
- package/server/tests/Unit/Support/UtilsGeoMatrixAndVendorTest.php +382 -0
- package/server/tests/Unit/Tracking/TrackingContextTest.php +114 -0
- package/server/tests/Unit/Tracking/TrackingIntelligenceAndContextTest.php +477 -0
- package/server/tests/Unit/Tracking/TrackingProviderManagerFallbacksTest.php +208 -0
- package/server/tests/Unit/Traits/HasTrackingNumberTest.php +303 -0
- package/server/tests/Unit/Traits/PayloadAccessorsTest.php +150 -0
- package/server/tests/UtilsContractsTest.php +244 -0
- package/server/tests/VehicleControllerHelperContractsTest.php +488 -0
- package/server/tests/VehicleDataParsingTest.php +45 -0
- package/server/tests/VehicleResourceContractsTest.php +313 -0
- package/translations/bg-bg.yaml +2 -0
- package/translations/en-us.yaml +2 -0
- package/translations/es-pa.yaml +2 -0
- package/translations/fr-fr.yaml +2 -0
- package/translations/mn-mn.yaml +2 -0
- package/translations/pt-br.yaml +2 -0
- package/translations/ru-ru.yaml +2 -0
- package/server/tests/DeviceFilterTest.php +0 -44
- package/server/tests/LiveControllerViewportTest.php +0 -52
|
@@ -0,0 +1,1414 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
use Carbon\Carbon;
|
|
4
|
+
use Fleetbase\FleetOps\Listeners\NotifyDriverOnShiftChange;
|
|
5
|
+
use Fleetbase\FleetOps\Models\Contact;
|
|
6
|
+
use Fleetbase\FleetOps\Models\Driver;
|
|
7
|
+
use Fleetbase\FleetOps\Models\Fleet;
|
|
8
|
+
use Fleetbase\FleetOps\Models\Maintenance;
|
|
9
|
+
use Fleetbase\FleetOps\Models\MaintenanceSchedule;
|
|
10
|
+
use Fleetbase\FleetOps\Models\Order;
|
|
11
|
+
use Fleetbase\FleetOps\Models\Payload;
|
|
12
|
+
use Fleetbase\FleetOps\Models\Place;
|
|
13
|
+
use Fleetbase\FleetOps\Models\PurchaseRate;
|
|
14
|
+
use Fleetbase\FleetOps\Models\ServiceArea;
|
|
15
|
+
use Fleetbase\FleetOps\Models\ServiceRate;
|
|
16
|
+
use Fleetbase\FleetOps\Models\TrackingNumber;
|
|
17
|
+
use Fleetbase\FleetOps\Models\TrackingStatus;
|
|
18
|
+
use Fleetbase\FleetOps\Models\Vehicle;
|
|
19
|
+
use Fleetbase\FleetOps\Models\WorkOrder;
|
|
20
|
+
use Fleetbase\FleetOps\Models\Zone;
|
|
21
|
+
use Fleetbase\FleetOps\Notifications\DriverShiftChanged;
|
|
22
|
+
use Fleetbase\FleetOps\Observers\CategoryObserver;
|
|
23
|
+
use Fleetbase\FleetOps\Observers\CompanyObserver;
|
|
24
|
+
use Fleetbase\FleetOps\Observers\CompanyUserObserver;
|
|
25
|
+
use Fleetbase\FleetOps\Observers\ContactObserver;
|
|
26
|
+
use Fleetbase\FleetOps\Observers\DriverObserver;
|
|
27
|
+
use Fleetbase\FleetOps\Observers\FleetObserver;
|
|
28
|
+
use Fleetbase\FleetOps\Observers\OrderObserver;
|
|
29
|
+
use Fleetbase\FleetOps\Observers\PayloadObserver;
|
|
30
|
+
use Fleetbase\FleetOps\Observers\PlaceObserver;
|
|
31
|
+
use Fleetbase\FleetOps\Observers\PurchaseRateObserver;
|
|
32
|
+
use Fleetbase\FleetOps\Observers\ServiceAreaObserver;
|
|
33
|
+
use Fleetbase\FleetOps\Observers\ServiceRateObserver;
|
|
34
|
+
use Fleetbase\FleetOps\Observers\TrackingNumberObserver;
|
|
35
|
+
use Fleetbase\FleetOps\Observers\UserObserver;
|
|
36
|
+
use Fleetbase\FleetOps\Observers\VehicleObserver;
|
|
37
|
+
use Fleetbase\FleetOps\Observers\WorkOrderObserver;
|
|
38
|
+
use Fleetbase\FleetOps\Observers\ZoneObserver;
|
|
39
|
+
use Fleetbase\Models\Category;
|
|
40
|
+
use Fleetbase\Models\Company;
|
|
41
|
+
use Fleetbase\Models\CompanyUser;
|
|
42
|
+
use Fleetbase\Models\Schedule;
|
|
43
|
+
use Fleetbase\Models\ScheduleItem;
|
|
44
|
+
use Fleetbase\Models\Transaction;
|
|
45
|
+
use Fleetbase\Models\TransactionItem;
|
|
46
|
+
use Fleetbase\Models\User;
|
|
47
|
+
use Illuminate\Cache\ArrayStore;
|
|
48
|
+
use Illuminate\Cache\Repository;
|
|
49
|
+
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
|
50
|
+
use Illuminate\Support\Facades\Cache;
|
|
51
|
+
|
|
52
|
+
if (!class_exists('Illuminate\Foundation\Auth\User')) {
|
|
53
|
+
class_alias(Illuminate\Database\Eloquent\Model::class, 'Illuminate\Foundation\Auth\User');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
class FleetOpsWorkOrderObserverProbe extends WorkOrderObserver
|
|
57
|
+
{
|
|
58
|
+
public bool $maintenanceExists = false;
|
|
59
|
+
public ?MaintenanceSchedule $schedule = null;
|
|
60
|
+
public array $createdMaintenance = [];
|
|
61
|
+
public array $completedEvents = [];
|
|
62
|
+
|
|
63
|
+
protected function hasMaintenanceRecord(WorkOrder $workOrder): bool
|
|
64
|
+
{
|
|
65
|
+
return $this->maintenanceExists;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
protected function createMaintenance(array $attributes): Maintenance
|
|
69
|
+
{
|
|
70
|
+
$this->createdMaintenance[] = $attributes;
|
|
71
|
+
|
|
72
|
+
return new Maintenance();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
protected function findSchedule(string $uuid): ?MaintenanceSchedule
|
|
76
|
+
{
|
|
77
|
+
return $this->schedule && $this->schedule->uuid === $uuid ? $this->schedule : null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
protected function dispatchCompletedEvent(WorkOrder $workOrder): void
|
|
81
|
+
{
|
|
82
|
+
$this->completedEvents[] = $workOrder;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
class FleetOpsWorkOrderObserverWorkOrderFake extends WorkOrder
|
|
87
|
+
{
|
|
88
|
+
public bool $statusWasChanged = true;
|
|
89
|
+
|
|
90
|
+
public function wasChanged($attributes = null): bool
|
|
91
|
+
{
|
|
92
|
+
return $attributes === 'status' ? $this->statusWasChanged : false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
class FleetOpsWorkOrderObserverScheduleFake extends MaintenanceSchedule
|
|
97
|
+
{
|
|
98
|
+
public array $resets = [];
|
|
99
|
+
|
|
100
|
+
public function resetAfterCompletion(?int $completedOdometer = null, ?int $completedEngineHours = null, ?Carbon $completedAt = null): bool
|
|
101
|
+
{
|
|
102
|
+
$this->resets[] = [$completedOdometer, $completedEngineHours, $completedAt];
|
|
103
|
+
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
class FleetOpsOrderObserverOrderFake extends Order
|
|
109
|
+
{
|
|
110
|
+
public ?string $uuid = null;
|
|
111
|
+
public ?string $status = null;
|
|
112
|
+
public bool $started = false;
|
|
113
|
+
public ?Carbon $started_at = null;
|
|
114
|
+
public bool $statusDirty = false;
|
|
115
|
+
public bool $driverWasChanged = false;
|
|
116
|
+
public bool $integratedVendor = false;
|
|
117
|
+
public array $originalData = [];
|
|
118
|
+
public array $events = [];
|
|
119
|
+
|
|
120
|
+
public function isDirty($attributes = null): bool
|
|
121
|
+
{
|
|
122
|
+
return $attributes === 'status' ? $this->statusDirty : false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public function getOriginal($key = null, $default = null): mixed
|
|
126
|
+
{
|
|
127
|
+
return $key === null ? $this->originalData : ($this->originalData[$key] ?? $default);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public function wasChanged($attributes = null): bool
|
|
131
|
+
{
|
|
132
|
+
return $attributes === 'driver_assigned_uuid' ? $this->driverWasChanged : false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public function setDriverLocationAsPickup($force = false)
|
|
136
|
+
{
|
|
137
|
+
$this->events[] = 'setDriverLocationAsPickup';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
public function notifyDriverAssigned(): void
|
|
141
|
+
{
|
|
142
|
+
$this->events[] = 'notifyDriverAssigned';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public function isIntegratedVendorOrder(): bool
|
|
146
|
+
{
|
|
147
|
+
return $this->integratedVendor;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
class FleetOpsContactObserverContactFake extends Contact
|
|
152
|
+
{
|
|
153
|
+
public bool $hasUser = false;
|
|
154
|
+
public bool $customer = false;
|
|
155
|
+
public bool $typeDirty = false;
|
|
156
|
+
public bool $emailChanged = false;
|
|
157
|
+
public bool $phoneChanged = false;
|
|
158
|
+
public array $events = [];
|
|
159
|
+
public array $originalData = [];
|
|
160
|
+
|
|
161
|
+
public function doesntHaveUser(): bool
|
|
162
|
+
{
|
|
163
|
+
$this->events[] = 'doesntHaveUser';
|
|
164
|
+
|
|
165
|
+
return !$this->hasUser;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public function createUser(bool $sendInvite = false): User
|
|
169
|
+
{
|
|
170
|
+
$this->events[] = 'createUser';
|
|
171
|
+
$this->hasUser = true;
|
|
172
|
+
|
|
173
|
+
return new User();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public function assertCustomerIdentityIsAvailable(): void
|
|
177
|
+
{
|
|
178
|
+
$this->events[] = 'assertCustomerIdentityIsAvailable';
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public function isCustomer(): bool
|
|
182
|
+
{
|
|
183
|
+
$this->events[] = 'isCustomer';
|
|
184
|
+
|
|
185
|
+
return $this->customer;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
public function normalizeCustomerUser(?User $user = null, bool $quiet = false): ?User
|
|
189
|
+
{
|
|
190
|
+
$this->events[] = 'normalizeCustomerUser';
|
|
191
|
+
|
|
192
|
+
return $user ?? new User();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
public function syncWithUser(): bool
|
|
196
|
+
{
|
|
197
|
+
$this->events[] = 'syncWithUser';
|
|
198
|
+
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
public function deleteUser(): ?bool
|
|
203
|
+
{
|
|
204
|
+
$this->events[] = 'deleteUser';
|
|
205
|
+
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
public function getOriginal($key = null, $default = null): mixed
|
|
210
|
+
{
|
|
211
|
+
return $key === null ? $this->originalData : ($this->originalData[$key] ?? $default);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public function isDirty($attributes = null): bool
|
|
215
|
+
{
|
|
216
|
+
return $attributes === 'type' ? $this->typeDirty : false;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public function wasChanged($attributes = null): bool
|
|
220
|
+
{
|
|
221
|
+
return match ($attributes) {
|
|
222
|
+
'email' => $this->emailChanged,
|
|
223
|
+
'phone' => $this->phoneChanged,
|
|
224
|
+
default => false,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
class FleetOpsDriverObserverProbe extends DriverObserver
|
|
230
|
+
{
|
|
231
|
+
public array $invalidations = [];
|
|
232
|
+
public array $unassigned = [];
|
|
233
|
+
public ?User $user = null;
|
|
234
|
+
|
|
235
|
+
protected function invalidateLiveCache(): void
|
|
236
|
+
{
|
|
237
|
+
$this->invalidations[] = ['drivers', 'operations-monitor'];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
protected function unassignOrders(Driver $driver): int
|
|
241
|
+
{
|
|
242
|
+
$this->unassigned[] = $driver->uuid;
|
|
243
|
+
|
|
244
|
+
return 1;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
protected function findDriverUser(Driver $driver): ?User
|
|
248
|
+
{
|
|
249
|
+
return $this->user;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
class FleetOpsDriverObserverUserFake extends User
|
|
254
|
+
{
|
|
255
|
+
public bool $driverRole = true;
|
|
256
|
+
public bool $deleted = false;
|
|
257
|
+
|
|
258
|
+
public function hasRole($roles, ?string $guard = null): bool
|
|
259
|
+
{
|
|
260
|
+
return $roles === 'Driver' && $this->driverRole;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
public function delete()
|
|
264
|
+
{
|
|
265
|
+
$this->deleted = true;
|
|
266
|
+
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
class FleetOpsVehicleObserverProbe extends VehicleObserver
|
|
272
|
+
{
|
|
273
|
+
public ?string $identifier = null;
|
|
274
|
+
public ?Driver $driver = null;
|
|
275
|
+
public array $deleted = [];
|
|
276
|
+
public array $invalidated = [];
|
|
277
|
+
|
|
278
|
+
protected function getDriverIdentifier(): ?string
|
|
279
|
+
{
|
|
280
|
+
return $this->identifier;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
protected function findDriver(string $identifier): ?Driver
|
|
284
|
+
{
|
|
285
|
+
return $this->driver && $identifier === $this->identifier ? $this->driver : null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
protected function deleteDriversAssignedTo(Vehicle $vehicle): mixed
|
|
289
|
+
{
|
|
290
|
+
$this->deleted[] = $vehicle->uuid;
|
|
291
|
+
|
|
292
|
+
return 1;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
protected function invalidateLiveCache(): void
|
|
296
|
+
{
|
|
297
|
+
$this->invalidated[] = ['vehicles', 'operations-monitor'];
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
class FleetOpsVehicleObserverDriverFake extends Driver
|
|
302
|
+
{
|
|
303
|
+
public array $assignments = [];
|
|
304
|
+
|
|
305
|
+
public function assignVehicle(Vehicle $vehicle): self
|
|
306
|
+
{
|
|
307
|
+
$this->assignments[] = $vehicle;
|
|
308
|
+
|
|
309
|
+
return $this;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
class FleetOpsServiceRateObserverProbe extends ServiceRateObserver
|
|
314
|
+
{
|
|
315
|
+
public mixed $rateFeesInput = null;
|
|
316
|
+
public mixed $parcelFeesInput = null;
|
|
317
|
+
public array $deletedModelBatches = [];
|
|
318
|
+
|
|
319
|
+
protected function rateFeesInput(): mixed
|
|
320
|
+
{
|
|
321
|
+
return $this->rateFeesInput;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
protected function parcelFeesInput(): mixed
|
|
325
|
+
{
|
|
326
|
+
return $this->parcelFeesInput;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
protected function deleteModels(mixed $models): void
|
|
330
|
+
{
|
|
331
|
+
$this->deletedModelBatches[] = $models;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
class FleetOpsServiceRateObserverServiceRateFake extends ServiceRate
|
|
336
|
+
{
|
|
337
|
+
public bool $fixedMeter = false;
|
|
338
|
+
public bool $perDrop = false;
|
|
339
|
+
public bool $multiZone = false;
|
|
340
|
+
public bool $parcelService = false;
|
|
341
|
+
public array $rateFeeCalls = [];
|
|
342
|
+
public array $parcelFeeCalls = [];
|
|
343
|
+
public bool $relationsLoaded = false;
|
|
344
|
+
|
|
345
|
+
public function isFixedMeter(): bool
|
|
346
|
+
{
|
|
347
|
+
return $this->fixedMeter;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
public function isPerDrop(): bool
|
|
351
|
+
{
|
|
352
|
+
return $this->perDrop;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
public function isMultiZoneDistance(): bool
|
|
356
|
+
{
|
|
357
|
+
return $this->multiZone;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
public function isParcelService(): bool
|
|
361
|
+
{
|
|
362
|
+
return $this->parcelService;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
public function setServiceRateFees(?array $serviceRateFees = [])
|
|
366
|
+
{
|
|
367
|
+
$this->rateFeeCalls[] = $serviceRateFees;
|
|
368
|
+
|
|
369
|
+
return $this;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
public function setServiceRateParcelFees(?array $serviceRateParcelFees = [])
|
|
373
|
+
{
|
|
374
|
+
$this->parcelFeeCalls[] = $serviceRateParcelFees;
|
|
375
|
+
|
|
376
|
+
return $this;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
public function load($relations)
|
|
380
|
+
{
|
|
381
|
+
$this->relationsLoaded = $relations === ['parcelFees', 'rateFees'];
|
|
382
|
+
$this->setRelation('parcelFees', new EloquentCollection(['parcel-fee']));
|
|
383
|
+
$this->setRelation('rateFees', new EloquentCollection(['rate-fee']));
|
|
384
|
+
|
|
385
|
+
return $this;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
class FleetOpsTrackingNumberObserverProbe extends TrackingNumberObserver
|
|
390
|
+
{
|
|
391
|
+
public array $barcodes = [];
|
|
392
|
+
public array $statuses = [];
|
|
393
|
+
|
|
394
|
+
protected function generateTrackingNumber(TrackingNumber $trackingNumber): string
|
|
395
|
+
{
|
|
396
|
+
return 'TN-' . $trackingNumber->region;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
protected function generateBarcode(string $ownerUuid, string $type): string
|
|
400
|
+
{
|
|
401
|
+
$this->barcodes[] = [$ownerUuid, $type];
|
|
402
|
+
|
|
403
|
+
return $type . '-png';
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
protected function createTrackingStatus(array $attributes): TrackingStatus
|
|
407
|
+
{
|
|
408
|
+
$this->statuses[] = $attributes;
|
|
409
|
+
|
|
410
|
+
$status = new TrackingStatus();
|
|
411
|
+
$status->setRawAttributes(array_merge(['uuid' => 'status-uuid'], $attributes), true);
|
|
412
|
+
|
|
413
|
+
return $status;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
class FleetOpsTrackingNumberObserverTrackingNumberFake extends TrackingNumber
|
|
418
|
+
{
|
|
419
|
+
public array $ownerStatuses = [];
|
|
420
|
+
|
|
421
|
+
public function updateOwnerStatus(?TrackingStatus $trackingStatus = null)
|
|
422
|
+
{
|
|
423
|
+
$this->ownerStatuses[] = $trackingStatus;
|
|
424
|
+
|
|
425
|
+
return $this;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
class FleetOpsZoneObserverProbe extends ZoneObserver
|
|
430
|
+
{
|
|
431
|
+
public array $invalidations = [];
|
|
432
|
+
|
|
433
|
+
protected function invalidateServiceAreaCache(Zone $zone, ?string $serviceAreaUuid = null): void
|
|
434
|
+
{
|
|
435
|
+
$serviceAreaUuid ??= $zone->service_area_uuid;
|
|
436
|
+
if (!$serviceAreaUuid) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
$this->invalidations[] = [$zone->company_uuid, $serviceAreaUuid];
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
class FleetOpsNotifyDriverOnShiftChangeProbe extends NotifyDriverOnShiftChange
|
|
445
|
+
{
|
|
446
|
+
public ?Schedule $schedule = null;
|
|
447
|
+
public array $settings = [];
|
|
448
|
+
public bool $createdEvent = false;
|
|
449
|
+
public array $sent = [];
|
|
450
|
+
|
|
451
|
+
protected function getSchedule(ScheduleItem $scheduleItem): ?Schedule
|
|
452
|
+
{
|
|
453
|
+
return $this->schedule;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
protected function getSchedulingSettings(): array
|
|
457
|
+
{
|
|
458
|
+
return $this->settings;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
protected function isCreatedEvent(object $event): bool
|
|
462
|
+
{
|
|
463
|
+
return $this->createdEvent;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
protected function notifyDriver(Driver $driver, DriverShiftChanged $notification): void
|
|
467
|
+
{
|
|
468
|
+
$this->sent[] = [$driver, $notification];
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
class FleetOpsFleetObserverProbe extends FleetObserver
|
|
473
|
+
{
|
|
474
|
+
public array $cleared = [];
|
|
475
|
+
|
|
476
|
+
protected function clearParentFleet(string $fleetUuid): void
|
|
477
|
+
{
|
|
478
|
+
$this->cleared[] = $fleetUuid;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
class FleetOpsServiceAreaObserverProbe extends ServiceAreaObserver
|
|
483
|
+
{
|
|
484
|
+
public array $countries = [];
|
|
485
|
+
public array $deleted = [];
|
|
486
|
+
|
|
487
|
+
protected function createPolygonFromCountry(string $country): mixed
|
|
488
|
+
{
|
|
489
|
+
$this->countries[] = $country;
|
|
490
|
+
|
|
491
|
+
return 'polygon-' . $country;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
protected function deleteModels(mixed $models): void
|
|
495
|
+
{
|
|
496
|
+
$this->deleted[] = $models;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
class FleetOpsServiceAreaObserverServiceAreaFake extends ServiceArea
|
|
501
|
+
{
|
|
502
|
+
public function getAttribute($key)
|
|
503
|
+
{
|
|
504
|
+
if ($key === 'border') {
|
|
505
|
+
return $this->attributes['border'] ?? null;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return parent::getAttribute($key);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
public function setAttribute($key, $value)
|
|
512
|
+
{
|
|
513
|
+
if ($key === 'border') {
|
|
514
|
+
$this->attributes['border'] = $value;
|
|
515
|
+
|
|
516
|
+
return $this;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
return parent::setAttribute($key, $value);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
public function load($relations)
|
|
523
|
+
{
|
|
524
|
+
return $this;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
class FleetOpsCompanyUserObserverProbe extends CompanyUserObserver
|
|
529
|
+
{
|
|
530
|
+
public array $deleted = [];
|
|
531
|
+
public ?Driver $driver = null;
|
|
532
|
+
|
|
533
|
+
protected function deleteDrivers(string $userUuid): void
|
|
534
|
+
{
|
|
535
|
+
$this->deleted[] = $userUuid;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
protected function findDriver(string $userUuid): ?Driver
|
|
539
|
+
{
|
|
540
|
+
return $this->driver;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
class FleetOpsCompanyUserFake extends CompanyUser
|
|
545
|
+
{
|
|
546
|
+
public bool $statusChanged = true;
|
|
547
|
+
|
|
548
|
+
public function wasChanged($attributes = null): bool
|
|
549
|
+
{
|
|
550
|
+
return $attributes === 'status' ? $this->statusChanged : false;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
class FleetOpsObserverDriverFake extends Driver
|
|
555
|
+
{
|
|
556
|
+
public array $updates = [];
|
|
557
|
+
|
|
558
|
+
public function update(array $attributes = [], array $options = []): bool
|
|
559
|
+
{
|
|
560
|
+
$this->updates[] = $attributes;
|
|
561
|
+
|
|
562
|
+
return true;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
class FleetOpsCategoryObserverProbe extends CategoryObserver
|
|
567
|
+
{
|
|
568
|
+
public array $deleted = [];
|
|
569
|
+
|
|
570
|
+
protected function deleteCustomFields(string $categoryUuid): void
|
|
571
|
+
{
|
|
572
|
+
$this->deleted[] = $categoryUuid;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
class FleetOpsCompanyObserverProbe extends CompanyObserver
|
|
577
|
+
{
|
|
578
|
+
public array $configs = [];
|
|
579
|
+
|
|
580
|
+
protected function createTransportConfig(Company $company): void
|
|
581
|
+
{
|
|
582
|
+
$this->configs[] = $company->uuid;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
class FleetOpsUserObserverProbe extends UserObserver
|
|
587
|
+
{
|
|
588
|
+
public array $deleted = [];
|
|
589
|
+
|
|
590
|
+
protected function deleteDrivers(string $userUuid): void
|
|
591
|
+
{
|
|
592
|
+
$this->deleted[] = $userUuid;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
class FleetOpsPayloadObserverPayloadFake extends Payload
|
|
597
|
+
{
|
|
598
|
+
public int $updates = 0;
|
|
599
|
+
|
|
600
|
+
public function updateOrderDistanceAndTime(): ?Order
|
|
601
|
+
{
|
|
602
|
+
$this->updates++;
|
|
603
|
+
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
class FleetOpsPurchaseRateObserverProbe extends PurchaseRateObserver
|
|
609
|
+
{
|
|
610
|
+
public bool $loaded = false;
|
|
611
|
+
public ?Company $company = null;
|
|
612
|
+
public ?Order $order = null;
|
|
613
|
+
public array $currencyInputs = [];
|
|
614
|
+
public array $transactions = [];
|
|
615
|
+
public array $items = [];
|
|
616
|
+
public bool $hasQuote = true;
|
|
617
|
+
public ?string $quoteCurrency = null;
|
|
618
|
+
public int|float $quoteAmount = 0;
|
|
619
|
+
public Illuminate\Support\Collection $quoteItems;
|
|
620
|
+
public string $transactionId = 'generated-transaction-id';
|
|
621
|
+
|
|
622
|
+
public function __construct()
|
|
623
|
+
{
|
|
624
|
+
$this->quoteItems = collect();
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
protected function generateUuid(): string
|
|
628
|
+
{
|
|
629
|
+
return 'purchase-rate-uuid';
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
protected function loadRelations(PurchaseRate $purchaseRate): void
|
|
633
|
+
{
|
|
634
|
+
$this->loaded = true;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
protected function findCompany(?string $uuid): ?Company
|
|
638
|
+
{
|
|
639
|
+
$this->currencyInputs[] = ['findCompany', $uuid];
|
|
640
|
+
|
|
641
|
+
return $this->company;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
protected function getCompanyTransactionCurrency(mixed $company): string
|
|
645
|
+
{
|
|
646
|
+
$this->currencyInputs[] = ['currency', $company instanceof Company ? $company->uuid : $company];
|
|
647
|
+
|
|
648
|
+
return 'USD';
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
protected function getServiceQuoteCurrency(PurchaseRate $purchaseRate): ?string
|
|
652
|
+
{
|
|
653
|
+
return $this->quoteCurrency;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
protected function getServiceQuoteAmount(PurchaseRate $purchaseRate): int|float
|
|
657
|
+
{
|
|
658
|
+
return $this->quoteAmount;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
protected function getTransactionId(PurchaseRate $purchaseRate): string
|
|
662
|
+
{
|
|
663
|
+
return $this->transactionId;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
protected function hasServiceQuote(PurchaseRate $purchaseRate): bool
|
|
667
|
+
{
|
|
668
|
+
return $this->hasQuote;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
protected function getServiceQuoteItems(PurchaseRate $purchaseRate): Illuminate\Support\Collection
|
|
672
|
+
{
|
|
673
|
+
return $this->quoteItems;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
protected function createTransaction(array $attributes): Transaction
|
|
677
|
+
{
|
|
678
|
+
$this->transactions[] = $attributes;
|
|
679
|
+
|
|
680
|
+
$transaction = new Transaction();
|
|
681
|
+
$transaction->setRawAttributes(['uuid' => 'transaction-uuid'], true);
|
|
682
|
+
|
|
683
|
+
return $transaction;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
protected function createTransactionItem(array $attributes): TransactionItem
|
|
687
|
+
{
|
|
688
|
+
$this->items[] = $attributes;
|
|
689
|
+
|
|
690
|
+
return new TransactionItem();
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
protected function resolveOrder(PurchaseRate $purchaseRate): ?Order
|
|
694
|
+
{
|
|
695
|
+
return $this->order;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
test('work order observer creates maintenance resets schedule and dispatches completed event on close', function () {
|
|
700
|
+
Carbon::setTestNow(Carbon::parse('2026-04-01 12:00:00'));
|
|
701
|
+
|
|
702
|
+
$schedule = new FleetOpsWorkOrderObserverScheduleFake();
|
|
703
|
+
$schedule->setRawAttributes(['uuid' => 'schedule-uuid']);
|
|
704
|
+
|
|
705
|
+
$workOrder = new FleetOpsWorkOrderObserverWorkOrderFake();
|
|
706
|
+
$workOrder->setRawAttributes([
|
|
707
|
+
'uuid' => 'work-order-uuid',
|
|
708
|
+
'company_uuid' => 'company-uuid',
|
|
709
|
+
'status' => 'closed',
|
|
710
|
+
'target_type' => 'fleet-ops:vehicle',
|
|
711
|
+
'target_uuid' => 'vehicle-uuid',
|
|
712
|
+
'priority' => 'high',
|
|
713
|
+
'opened_at' => Carbon::parse('2026-03-01 09:00:00'),
|
|
714
|
+
'closed_at' => Carbon::parse('2026-03-05 10:30:00'),
|
|
715
|
+
'assignee_type' => 'fleet-ops:contact',
|
|
716
|
+
'assignee_uuid' => 'assignee-uuid',
|
|
717
|
+
'subject' => 'Replace brakes',
|
|
718
|
+
'created_by_uuid' => 'creator-uuid',
|
|
719
|
+
'schedule_uuid' => 'schedule-uuid',
|
|
720
|
+
'meta' => [
|
|
721
|
+
'completion_data' => [
|
|
722
|
+
'notes' => 'Completed cleanly',
|
|
723
|
+
'odometer' => '12000',
|
|
724
|
+
'engine_hours' => '550',
|
|
725
|
+
'labor_cost' => 1000,
|
|
726
|
+
'parts_cost' => 2500,
|
|
727
|
+
'tax' => 300,
|
|
728
|
+
'total_cost' => 3800,
|
|
729
|
+
'currency' => 'USD',
|
|
730
|
+
'line_items' => [['label' => 'Brake pads']],
|
|
731
|
+
],
|
|
732
|
+
],
|
|
733
|
+
]);
|
|
734
|
+
|
|
735
|
+
$observer = new FleetOpsWorkOrderObserverProbe();
|
|
736
|
+
$observer->schedule = $schedule;
|
|
737
|
+
|
|
738
|
+
$observer->updated($workOrder);
|
|
739
|
+
|
|
740
|
+
expect($observer->createdMaintenance)->toHaveCount(1)
|
|
741
|
+
->and($observer->createdMaintenance[0])->toMatchArray([
|
|
742
|
+
'company_uuid' => 'company-uuid',
|
|
743
|
+
'work_order_uuid' => 'work-order-uuid',
|
|
744
|
+
'maintainable_type' => 'fleet-ops:vehicle',
|
|
745
|
+
'maintainable_uuid' => 'vehicle-uuid',
|
|
746
|
+
'type' => 'scheduled',
|
|
747
|
+
'status' => 'done',
|
|
748
|
+
'priority' => 'high',
|
|
749
|
+
'performed_by_type' => 'fleet-ops:contact',
|
|
750
|
+
'performed_by_uuid' => 'assignee-uuid',
|
|
751
|
+
'summary' => 'Replace brakes',
|
|
752
|
+
'notes' => 'Completed cleanly',
|
|
753
|
+
'odometer' => '12000',
|
|
754
|
+
'engine_hours' => '550',
|
|
755
|
+
'total_cost' => 3800,
|
|
756
|
+
'created_by_uuid' => 'creator-uuid',
|
|
757
|
+
])
|
|
758
|
+
->and($observer->createdMaintenance[0]['completed_at']->toDateTimeString())->toBe('2026-03-05 10:30:00')
|
|
759
|
+
->and($schedule->resets)->toHaveCount(1)
|
|
760
|
+
->and($schedule->resets[0][0])->toBe(12000)
|
|
761
|
+
->and($schedule->resets[0][1])->toBe(550)
|
|
762
|
+
->and($schedule->resets[0][2]->toDateTimeString())->toBe('2026-03-05 10:30:00')
|
|
763
|
+
->and($observer->completedEvents)->toBe([$workOrder]);
|
|
764
|
+
|
|
765
|
+
Carbon::setTestNow();
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
test('purchase rate observer creates transaction items and defaults generated attributes', function () {
|
|
769
|
+
session(['company' => 'session-company-uuid']);
|
|
770
|
+
|
|
771
|
+
$order = new Order();
|
|
772
|
+
$order->setRawAttributes(['uuid' => 'order-uuid'], true);
|
|
773
|
+
|
|
774
|
+
$purchaseRate = new PurchaseRate();
|
|
775
|
+
$purchaseRate->setRawAttributes([
|
|
776
|
+
'company_uuid' => 'purchase-company-uuid',
|
|
777
|
+
'customer_uuid' => 'customer-uuid',
|
|
778
|
+
'customer_type' => 'fleet-ops:contact',
|
|
779
|
+
'payload_uuid' => 'payload-uuid',
|
|
780
|
+
'meta' => ['transaction_id' => 'gateway-id'],
|
|
781
|
+
'status' => null,
|
|
782
|
+
], true);
|
|
783
|
+
|
|
784
|
+
$company = new Company();
|
|
785
|
+
$company->setRawAttributes(['uuid' => 'session-company-uuid'], true);
|
|
786
|
+
|
|
787
|
+
$observer = new FleetOpsPurchaseRateObserverProbe();
|
|
788
|
+
$observer->order = $order;
|
|
789
|
+
$observer->company = $company;
|
|
790
|
+
$observer->quoteAmount = 4550;
|
|
791
|
+
$observer->transactionId = 'gateway-id';
|
|
792
|
+
$observer->quoteItems = collect([
|
|
793
|
+
(object) ['amount' => 1200, 'details' => 'Base rate', 'code' => 'base'],
|
|
794
|
+
(object) ['amount' => null],
|
|
795
|
+
]);
|
|
796
|
+
|
|
797
|
+
$observer->creating($purchaseRate);
|
|
798
|
+
|
|
799
|
+
expect($observer->loaded)->toBeTrue()
|
|
800
|
+
->and($purchaseRate->uuid)->toBe('purchase-rate-uuid')
|
|
801
|
+
->and($purchaseRate->transaction_uuid)->toBe('transaction-uuid')
|
|
802
|
+
->and($purchaseRate->status)->toBe(Transaction::STATUS_SUCCESS)
|
|
803
|
+
->and($observer->currencyInputs)->toBe([
|
|
804
|
+
['findCompany', 'session-company-uuid'],
|
|
805
|
+
['currency', 'session-company-uuid'],
|
|
806
|
+
])
|
|
807
|
+
->and($observer->transactions[0])->toMatchArray([
|
|
808
|
+
'company_uuid' => 'session-company-uuid',
|
|
809
|
+
'customer_uuid' => 'customer-uuid',
|
|
810
|
+
'customer_type' => 'fleet-ops:contact',
|
|
811
|
+
'subject_uuid' => 'order-uuid',
|
|
812
|
+
'subject_type' => Order::class,
|
|
813
|
+
'context_uuid' => 'purchase-rate-uuid',
|
|
814
|
+
'context_type' => PurchaseRate::class,
|
|
815
|
+
'gateway_transaction_id' => 'gateway-id',
|
|
816
|
+
'gateway' => 'internal',
|
|
817
|
+
'amount' => 4550,
|
|
818
|
+
'currency' => 'USD',
|
|
819
|
+
'type' => 'dispatch',
|
|
820
|
+
'direction' => Transaction::DIRECTION_CREDIT,
|
|
821
|
+
'status' => Transaction::STATUS_SUCCESS,
|
|
822
|
+
'settlement_status' => Transaction::SETTLEMENT_STATUS_UNPAID,
|
|
823
|
+
])
|
|
824
|
+
->and($observer->items)->toBe([
|
|
825
|
+
[
|
|
826
|
+
'transaction_uuid' => 'transaction-uuid',
|
|
827
|
+
'amount' => 1200,
|
|
828
|
+
'currency' => 'USD',
|
|
829
|
+
'details' => 'Base rate',
|
|
830
|
+
'code' => 'base',
|
|
831
|
+
],
|
|
832
|
+
[
|
|
833
|
+
'transaction_uuid' => 'transaction-uuid',
|
|
834
|
+
'amount' => 0,
|
|
835
|
+
'currency' => 'USD',
|
|
836
|
+
'details' => 'Internal dispatch',
|
|
837
|
+
'code' => 'internal',
|
|
838
|
+
],
|
|
839
|
+
]);
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
test('purchase rate observer uses service quote currency and handles missing order or quote items', function () {
|
|
843
|
+
session(['company' => null]);
|
|
844
|
+
|
|
845
|
+
$purchaseRate = new PurchaseRate();
|
|
846
|
+
$purchaseRate->setRawAttributes([
|
|
847
|
+
'uuid' => 'existing-purchase-rate',
|
|
848
|
+
'company_uuid' => 'purchase-company-uuid',
|
|
849
|
+
'payload_uuid' => null,
|
|
850
|
+
'status' => 'pending',
|
|
851
|
+
], true);
|
|
852
|
+
|
|
853
|
+
$observer = new FleetOpsPurchaseRateObserverProbe();
|
|
854
|
+
$observer->quoteAmount = 250;
|
|
855
|
+
$observer->quoteCurrency = 'SGD';
|
|
856
|
+
$observer->quoteItems = collect();
|
|
857
|
+
|
|
858
|
+
$observer->creating($purchaseRate);
|
|
859
|
+
|
|
860
|
+
expect($purchaseRate->uuid)->toBe('existing-purchase-rate')
|
|
861
|
+
->and($purchaseRate->status)->toBe('pending')
|
|
862
|
+
->and($observer->currencyInputs)->toBe([['findCompany', 'purchase-company-uuid']])
|
|
863
|
+
->and($observer->transactions[0])->toMatchArray([
|
|
864
|
+
'company_uuid' => 'purchase-company-uuid',
|
|
865
|
+
'subject_uuid' => null,
|
|
866
|
+
'subject_type' => null,
|
|
867
|
+
'context_uuid' => 'existing-purchase-rate',
|
|
868
|
+
'amount' => 250,
|
|
869
|
+
'currency' => 'SGD',
|
|
870
|
+
])
|
|
871
|
+
->and($observer->items)->toBe([]);
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
test('place observer uppercases address fields and invalidates live places cache', function () {
|
|
875
|
+
Cache::swap(new Repository(new ArrayStore()));
|
|
876
|
+
session(['company' => 'company-uuid']);
|
|
877
|
+
|
|
878
|
+
$place = new Place();
|
|
879
|
+
$place->name = 'central depot';
|
|
880
|
+
$place->street1 = 'main road';
|
|
881
|
+
$place->city = 'singapore';
|
|
882
|
+
$place->country = 'sg';
|
|
883
|
+
$place->postal_code = 12345;
|
|
884
|
+
$place->neighborhood = null;
|
|
885
|
+
|
|
886
|
+
$observer = new PlaceObserver();
|
|
887
|
+
$observer->creating($place);
|
|
888
|
+
$observer->created($place);
|
|
889
|
+
$observer->updated($place);
|
|
890
|
+
$observer->deleted($place);
|
|
891
|
+
|
|
892
|
+
expect($place->name)->toBe('CENTRAL DEPOT')
|
|
893
|
+
->and($place->street1)->toBe('MAIN ROAD')
|
|
894
|
+
->and($place->city)->toBe('SINGAPORE')
|
|
895
|
+
->and($place->country)->toBe('SG')
|
|
896
|
+
->and($place->postal_code)->toBe(12345)
|
|
897
|
+
->and(Cache::get('live:company-uuid:places:version'))->toBe(3);
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
test('fleet service area company category user and payload observers delegate lifecycle side effects', function () {
|
|
901
|
+
Cache::swap(new Repository(new ArrayStore()));
|
|
902
|
+
session(['company' => 'company-uuid']);
|
|
903
|
+
|
|
904
|
+
$fleet = new Fleet();
|
|
905
|
+
$fleet->setRawAttributes(['uuid' => 'fleet-uuid'], true);
|
|
906
|
+
|
|
907
|
+
$fleetObserver = new FleetOpsFleetObserverProbe();
|
|
908
|
+
$fleetObserver->created($fleet);
|
|
909
|
+
$fleetObserver->updated($fleet);
|
|
910
|
+
$fleetObserver->deleted($fleet);
|
|
911
|
+
|
|
912
|
+
expect($fleetObserver->cleared)->toBe(['fleet-uuid'])
|
|
913
|
+
->and(Cache::get('live:company-uuid:operations-monitor:version'))->toBe(3);
|
|
914
|
+
|
|
915
|
+
$serviceArea = new FleetOpsServiceAreaObserverServiceAreaFake();
|
|
916
|
+
$serviceArea->country = 'SG';
|
|
917
|
+
$serviceArea->setRelation('zones', collect(['zone-a', 'zone-b']));
|
|
918
|
+
|
|
919
|
+
$serviceAreaObserver = new FleetOpsServiceAreaObserverProbe();
|
|
920
|
+
$serviceAreaObserver->creating($serviceArea);
|
|
921
|
+
$serviceAreaObserver->deleted($serviceArea);
|
|
922
|
+
|
|
923
|
+
expect($serviceArea->border)->toBe('polygon-SG')
|
|
924
|
+
->and($serviceAreaObserver->countries)->toBe(['SG'])
|
|
925
|
+
->and($serviceAreaObserver->deleted)->toHaveCount(1);
|
|
926
|
+
|
|
927
|
+
$withBorder = new FleetOpsServiceAreaObserverServiceAreaFake();
|
|
928
|
+
$withBorder->border = 'existing-border';
|
|
929
|
+
$withBorder->country = 'MY';
|
|
930
|
+
$serviceAreaObserver->creating($withBorder);
|
|
931
|
+
|
|
932
|
+
expect($withBorder->border)->toBe('existing-border')
|
|
933
|
+
->and($serviceAreaObserver->countries)->toBe(['SG']);
|
|
934
|
+
|
|
935
|
+
$companyUser = new FleetOpsCompanyUserFake();
|
|
936
|
+
$companyUser->setRawAttributes([
|
|
937
|
+
'user_uuid' => 'user-uuid',
|
|
938
|
+
'status' => 'inactive',
|
|
939
|
+
], true);
|
|
940
|
+
|
|
941
|
+
$driver = new FleetOpsObserverDriverFake();
|
|
942
|
+
$companyUserObserver = new FleetOpsCompanyUserObserverProbe();
|
|
943
|
+
$companyUserObserver->driver = $driver;
|
|
944
|
+
$companyUserObserver->deleted($companyUser);
|
|
945
|
+
$companyUserObserver->updated($companyUser);
|
|
946
|
+
|
|
947
|
+
expect($companyUserObserver->deleted)->toBe(['user-uuid'])
|
|
948
|
+
->and($driver->updates)->toBe([['status' => 'inactive']]);
|
|
949
|
+
|
|
950
|
+
$companyUser->statusChanged = false;
|
|
951
|
+
$companyUserObserver->updated($companyUser);
|
|
952
|
+
|
|
953
|
+
expect($driver->updates)->toHaveCount(1);
|
|
954
|
+
|
|
955
|
+
$category = new Category();
|
|
956
|
+
$category->setRawAttributes(['uuid' => 'category-uuid'], true);
|
|
957
|
+
$categoryObserver = new FleetOpsCategoryObserverProbe();
|
|
958
|
+
$categoryObserver->deleted($category);
|
|
959
|
+
|
|
960
|
+
$company = new Company();
|
|
961
|
+
$company->setRawAttributes(['uuid' => 'company-uuid'], true);
|
|
962
|
+
$companyObserver = new FleetOpsCompanyObserverProbe();
|
|
963
|
+
$companyObserver->created($company);
|
|
964
|
+
|
|
965
|
+
$user = new User();
|
|
966
|
+
$user->setRawAttributes(['uuid' => 'user-uuid'], true);
|
|
967
|
+
$userObserver = new FleetOpsUserObserverProbe();
|
|
968
|
+
$userObserver->deleted($user);
|
|
969
|
+
|
|
970
|
+
$payload = new FleetOpsPayloadObserverPayloadFake();
|
|
971
|
+
(new PayloadObserver())->created($payload);
|
|
972
|
+
|
|
973
|
+
expect($categoryObserver->deleted)->toBe(['category-uuid'])
|
|
974
|
+
->and($companyObserver->configs)->toBe(['company-uuid'])
|
|
975
|
+
->and($userObserver->deleted)->toBe(['user-uuid'])
|
|
976
|
+
->and($payload->updates)->toBe(1);
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
test('work order observer skips non closing duplicate and missing schedule branches', function () {
|
|
980
|
+
$observer = new FleetOpsWorkOrderObserverProbe();
|
|
981
|
+
|
|
982
|
+
$unchanged = new FleetOpsWorkOrderObserverWorkOrderFake();
|
|
983
|
+
$unchanged->setRawAttributes(['status' => 'closed']);
|
|
984
|
+
$unchanged->statusWasChanged = false;
|
|
985
|
+
$observer->updated($unchanged);
|
|
986
|
+
|
|
987
|
+
$open = new FleetOpsWorkOrderObserverWorkOrderFake();
|
|
988
|
+
$open->setRawAttributes(['status' => 'open']);
|
|
989
|
+
$observer->updated($open);
|
|
990
|
+
|
|
991
|
+
expect($observer->createdMaintenance)->toBe([])
|
|
992
|
+
->and($observer->completedEvents)->toBe([]);
|
|
993
|
+
|
|
994
|
+
$duplicate = new FleetOpsWorkOrderObserverWorkOrderFake();
|
|
995
|
+
$duplicate->setRawAttributes([
|
|
996
|
+
'uuid' => 'duplicate-work-order',
|
|
997
|
+
'status' => 'closed',
|
|
998
|
+
'schedule_uuid' => 'missing-schedule',
|
|
999
|
+
]);
|
|
1000
|
+
$observer->maintenanceExists = true;
|
|
1001
|
+
$observer->updated($duplicate);
|
|
1002
|
+
|
|
1003
|
+
expect($observer->createdMaintenance)->toBe([])
|
|
1004
|
+
->and($observer->completedEvents)->toBe([$duplicate]);
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
test('order observer starts dispatched orders and invalidates live cache entries', function () {
|
|
1008
|
+
Cache::swap(new Repository(new ArrayStore()));
|
|
1009
|
+
session(['company' => 'company-uuid']);
|
|
1010
|
+
Carbon::setTestNow(Carbon::parse('2026-04-02 08:15:00'));
|
|
1011
|
+
|
|
1012
|
+
$order = new FleetOpsOrderObserverOrderFake();
|
|
1013
|
+
$order->uuid = 'order-uuid';
|
|
1014
|
+
$order->status = 'started';
|
|
1015
|
+
$order->started = false;
|
|
1016
|
+
$order->started_at = null;
|
|
1017
|
+
$order->originalData = ['status' => 'dispatched'];
|
|
1018
|
+
$order->statusDirty = true;
|
|
1019
|
+
|
|
1020
|
+
$observer = new OrderObserver();
|
|
1021
|
+
|
|
1022
|
+
$observer->updating($order);
|
|
1023
|
+
$observer->created($order);
|
|
1024
|
+
|
|
1025
|
+
expect($order->started)->toBeTrue()
|
|
1026
|
+
->and($order->started_at->toDateTimeString())->toBe('2026-04-02 08:15:00')
|
|
1027
|
+
->and(Cache::get('live:company-uuid:orders:version'))->toBe(1)
|
|
1028
|
+
->and(Cache::get('live:company-uuid:routes:version'))->toBe(1)
|
|
1029
|
+
->and(Cache::get('live:company-uuid:coordinates:version'))->toBe(1);
|
|
1030
|
+
|
|
1031
|
+
Carbon::setTestNow();
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
test('order observer preserves explicit start fields and notifies assigned driver on update', function () {
|
|
1035
|
+
Cache::swap(new Repository(new ArrayStore()));
|
|
1036
|
+
session(['company' => 'company-uuid']);
|
|
1037
|
+
|
|
1038
|
+
$explicitStart = Carbon::parse('2026-04-01 10:00:00');
|
|
1039
|
+
$order = new FleetOpsOrderObserverOrderFake();
|
|
1040
|
+
$order->uuid = 'order-update-uuid';
|
|
1041
|
+
$order->status = 'started';
|
|
1042
|
+
$order->started = true;
|
|
1043
|
+
$order->started_at = $explicitStart;
|
|
1044
|
+
$order->originalData = ['status' => 'dispatched'];
|
|
1045
|
+
$order->statusDirty = true;
|
|
1046
|
+
$order->driverWasChanged = true;
|
|
1047
|
+
|
|
1048
|
+
$observer = new OrderObserver();
|
|
1049
|
+
|
|
1050
|
+
$observer->updating($order);
|
|
1051
|
+
$observer->updated($order);
|
|
1052
|
+
|
|
1053
|
+
expect($order->started)->toBeTrue()
|
|
1054
|
+
->and($order->started_at)->toBe($explicitStart)
|
|
1055
|
+
->and($order->events)->toBe([
|
|
1056
|
+
'setDriverLocationAsPickup',
|
|
1057
|
+
'notifyDriverAssigned',
|
|
1058
|
+
])
|
|
1059
|
+
->and(Cache::get('live:company-uuid:orders:version'))->toBe(1);
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
test('order observer ignores non dispatched start transitions', function () {
|
|
1063
|
+
$order = new FleetOpsOrderObserverOrderFake();
|
|
1064
|
+
$order->status = 'started';
|
|
1065
|
+
$order->started = false;
|
|
1066
|
+
$order->started_at = null;
|
|
1067
|
+
$order->originalData = ['status' => 'created'];
|
|
1068
|
+
$order->statusDirty = true;
|
|
1069
|
+
|
|
1070
|
+
(new OrderObserver())->updating($order);
|
|
1071
|
+
|
|
1072
|
+
expect($order->started)->toBeFalse()
|
|
1073
|
+
->and($order->started_at)->toBeNull();
|
|
1074
|
+
});
|
|
1075
|
+
|
|
1076
|
+
test('order observer invalidates cache on delete and forwards to integrated vendors', function () {
|
|
1077
|
+
Cache::swap(new Repository(new ArrayStore()));
|
|
1078
|
+
session(['company' => 'company-uuid']);
|
|
1079
|
+
|
|
1080
|
+
$order = new FleetOpsOrderObserverOrderFake();
|
|
1081
|
+
$order->uuid = 'order-deleted-uuid';
|
|
1082
|
+
|
|
1083
|
+
(new OrderObserver())->deleted($order);
|
|
1084
|
+
|
|
1085
|
+
expect(Cache::get('live:company-uuid:orders:version'))->toBe(1)
|
|
1086
|
+
->and(Cache::get('live:company-uuid:routes:version'))->toBe(1)
|
|
1087
|
+
->and(Cache::get('live:company-uuid:coordinates:version'))->toBe(1);
|
|
1088
|
+
|
|
1089
|
+
// Integrated vendor orders additionally notify the upstream provider. The
|
|
1090
|
+
// provider is unreachable in the harness, so the assertion is that the
|
|
1091
|
+
// forwarding is attempted rather than skipped.
|
|
1092
|
+
$integrated = new FleetOpsOrderObserverOrderFake();
|
|
1093
|
+
$integrated->uuid = 'order-deleted-integrated';
|
|
1094
|
+
$integrated->integratedVendor = true;
|
|
1095
|
+
|
|
1096
|
+
expect(fn () => (new OrderObserver())->deleted($integrated))->toThrow(Error::class);
|
|
1097
|
+
});
|
|
1098
|
+
|
|
1099
|
+
test('contact observer creates syncs normalizes and deletes associated users', function () {
|
|
1100
|
+
$observer = new ContactObserver();
|
|
1101
|
+
$contact = new FleetOpsContactObserverContactFake();
|
|
1102
|
+
$contact->setRawAttributes(['type' => 'customer']);
|
|
1103
|
+
$contact->customer = true;
|
|
1104
|
+
|
|
1105
|
+
$observer->creating($contact);
|
|
1106
|
+
$observer->saving($contact);
|
|
1107
|
+
$observer->deleted($contact);
|
|
1108
|
+
|
|
1109
|
+
expect($contact->events)->toBe([
|
|
1110
|
+
'doesntHaveUser',
|
|
1111
|
+
'createUser',
|
|
1112
|
+
'assertCustomerIdentityIsAvailable',
|
|
1113
|
+
'doesntHaveUser',
|
|
1114
|
+
'isCustomer',
|
|
1115
|
+
'normalizeCustomerUser',
|
|
1116
|
+
'syncWithUser',
|
|
1117
|
+
'deleteUser',
|
|
1118
|
+
]);
|
|
1119
|
+
});
|
|
1120
|
+
|
|
1121
|
+
test('contact observer creates the user account on save when none exists yet', function () {
|
|
1122
|
+
$observer = new ContactObserver();
|
|
1123
|
+
$contact = new FleetOpsContactObserverContactFake();
|
|
1124
|
+
$contact->setRawAttributes(['type' => 'contact']);
|
|
1125
|
+
|
|
1126
|
+
// Saving without a prior creating() leaves the contact userless, which is
|
|
1127
|
+
// the arm that provisions the account rather than reusing it.
|
|
1128
|
+
$observer->saving($contact);
|
|
1129
|
+
|
|
1130
|
+
expect($contact->events)->toBe([
|
|
1131
|
+
'assertCustomerIdentityIsAvailable',
|
|
1132
|
+
'doesntHaveUser',
|
|
1133
|
+
'createUser',
|
|
1134
|
+
'isCustomer',
|
|
1135
|
+
'syncWithUser',
|
|
1136
|
+
]);
|
|
1137
|
+
});
|
|
1138
|
+
|
|
1139
|
+
test('contact observer prevents changing existing customer contact type', function () {
|
|
1140
|
+
$observer = new ContactObserver();
|
|
1141
|
+
$contact = new FleetOpsContactObserverContactFake();
|
|
1142
|
+
$contact->exists = true;
|
|
1143
|
+
$contact->typeDirty = true;
|
|
1144
|
+
$contact->originalData = ['type' => 'customer'];
|
|
1145
|
+
$contact->setRawAttributes(['type' => 'driver']);
|
|
1146
|
+
|
|
1147
|
+
expect(fn () => $observer->saving($contact))
|
|
1148
|
+
->toThrow(Exception::class, 'Customer contact type cannot be changed.');
|
|
1149
|
+
});
|
|
1150
|
+
|
|
1151
|
+
test('driver observer defaults location unassigns related records and deletes driver users', function () {
|
|
1152
|
+
$driver = new Driver();
|
|
1153
|
+
$driver->setRawAttributes([
|
|
1154
|
+
'uuid' => 'driver-uuid',
|
|
1155
|
+
'user_uuid' => 'user-uuid',
|
|
1156
|
+
], true);
|
|
1157
|
+
|
|
1158
|
+
$observer = new FleetOpsDriverObserverProbe();
|
|
1159
|
+
$user = new FleetOpsDriverObserverUserFake();
|
|
1160
|
+
|
|
1161
|
+
$observer->user = $user;
|
|
1162
|
+
$observer->creating($driver);
|
|
1163
|
+
$observer->created($driver);
|
|
1164
|
+
$observer->updated($driver);
|
|
1165
|
+
$observer->deleting($driver);
|
|
1166
|
+
$observer->deleted($driver);
|
|
1167
|
+
|
|
1168
|
+
expect($driver->location)->toBeInstanceOf(Fleetbase\LaravelMysqlSpatial\Types\Point::class)
|
|
1169
|
+
->and($driver->vehicle_uuid)->toBeNull()
|
|
1170
|
+
->and($observer->invalidations)->toBe([
|
|
1171
|
+
['drivers', 'operations-monitor'],
|
|
1172
|
+
['drivers', 'operations-monitor'],
|
|
1173
|
+
['drivers', 'operations-monitor'],
|
|
1174
|
+
])
|
|
1175
|
+
->and($observer->unassigned)->toBe(['driver-uuid'])
|
|
1176
|
+
->and($user->deleted)->toBeTrue();
|
|
1177
|
+
|
|
1178
|
+
$driverWithLocation = new Driver();
|
|
1179
|
+
$location = new Fleetbase\LaravelMysqlSpatial\Types\Point(1.3, 103.8);
|
|
1180
|
+
$driverWithLocation->location = $location;
|
|
1181
|
+
$observer->creating($driverWithLocation);
|
|
1182
|
+
|
|
1183
|
+
expect($driverWithLocation->location)->toBe($location);
|
|
1184
|
+
});
|
|
1185
|
+
|
|
1186
|
+
test('vehicle observer assigns requested driver and invalidates caches', function () {
|
|
1187
|
+
$observer = new FleetOpsVehicleObserverProbe();
|
|
1188
|
+
$observer->identifier = 'driver-uuid';
|
|
1189
|
+
$observer->driver = new FleetOpsVehicleObserverDriverFake();
|
|
1190
|
+
|
|
1191
|
+
$vehicle = new Vehicle();
|
|
1192
|
+
$vehicle->setRawAttributes(['uuid' => 'vehicle-uuid'], true);
|
|
1193
|
+
|
|
1194
|
+
$observer->created($vehicle);
|
|
1195
|
+
$observer->updating($vehicle);
|
|
1196
|
+
$observer->deleted($vehicle);
|
|
1197
|
+
|
|
1198
|
+
expect($observer->driver->assignments)->toBe([$vehicle, $vehicle])
|
|
1199
|
+
->and($vehicle->getRelation('driver'))->toBe($observer->driver)
|
|
1200
|
+
->and($observer->deleted)->toBe(['vehicle-uuid'])
|
|
1201
|
+
->and($observer->invalidated)->toBe([
|
|
1202
|
+
['vehicles', 'operations-monitor'],
|
|
1203
|
+
['vehicles', 'operations-monitor'],
|
|
1204
|
+
['vehicles', 'operations-monitor'],
|
|
1205
|
+
]);
|
|
1206
|
+
|
|
1207
|
+
$withoutDriver = new FleetOpsVehicleObserverProbe();
|
|
1208
|
+
$withoutDriver->created(new Vehicle());
|
|
1209
|
+
|
|
1210
|
+
expect($withoutDriver->invalidated)->toBe([['vehicles', 'operations-monitor']]);
|
|
1211
|
+
});
|
|
1212
|
+
|
|
1213
|
+
test('service rate observer syncs rate and parcel fee inputs and deletes loaded fees', function () {
|
|
1214
|
+
$observer = new FleetOpsServiceRateObserverProbe();
|
|
1215
|
+
$observer->rateFeesInput = [['fee' => 10]];
|
|
1216
|
+
$observer->parcelFeesInput = [['parcel_fee' => 20]];
|
|
1217
|
+
|
|
1218
|
+
$serviceRate = new FleetOpsServiceRateObserverServiceRateFake();
|
|
1219
|
+
$serviceRate->fixedMeter = true;
|
|
1220
|
+
$serviceRate->parcelService = true;
|
|
1221
|
+
|
|
1222
|
+
$observer->created($serviceRate);
|
|
1223
|
+
|
|
1224
|
+
expect($serviceRate->rateFeeCalls)->toBe([[['fee' => 10]]])
|
|
1225
|
+
->and($serviceRate->parcelFeeCalls)->toBe([[['parcel_fee' => 20]]]);
|
|
1226
|
+
|
|
1227
|
+
$serviceRate->fixedMeter = false;
|
|
1228
|
+
$serviceRate->perDrop = true;
|
|
1229
|
+
$serviceRate->multiZone = false;
|
|
1230
|
+
$serviceRate->parcelService = false;
|
|
1231
|
+
$serviceRate->rateFeeCalls = [];
|
|
1232
|
+
$serviceRate->parcelFeeCalls = [];
|
|
1233
|
+
$observer->updated($serviceRate);
|
|
1234
|
+
|
|
1235
|
+
expect($serviceRate->rateFeeCalls)->toBe([[['fee' => 10]]])
|
|
1236
|
+
->and($serviceRate->parcelFeeCalls)->toBe([]);
|
|
1237
|
+
|
|
1238
|
+
// Parcel services sync their parcel fees on update too, not only on create
|
|
1239
|
+
$serviceRate->perDrop = false;
|
|
1240
|
+
$serviceRate->parcelService = true;
|
|
1241
|
+
$serviceRate->rateFeeCalls = [];
|
|
1242
|
+
$serviceRate->parcelFeeCalls = [];
|
|
1243
|
+
$observer->updated($serviceRate);
|
|
1244
|
+
|
|
1245
|
+
expect($serviceRate->rateFeeCalls)->toBe([])
|
|
1246
|
+
->and($serviceRate->parcelFeeCalls)->toBe([[['parcel_fee' => 20]]]);
|
|
1247
|
+
|
|
1248
|
+
$observer->deleted($serviceRate);
|
|
1249
|
+
|
|
1250
|
+
expect($serviceRate->relationsLoaded)->toBeTrue()
|
|
1251
|
+
->and($observer->deletedModelBatches)->toHaveCount(2);
|
|
1252
|
+
});
|
|
1253
|
+
|
|
1254
|
+
test('tracking number observer generates codes and creates initial tracking status', function () {
|
|
1255
|
+
session(['company' => 'company-uuid']);
|
|
1256
|
+
|
|
1257
|
+
$trackingNumber = new FleetOpsTrackingNumberObserverTrackingNumberFake();
|
|
1258
|
+
$trackingNumber->setRawAttributes([
|
|
1259
|
+
'uuid' => 'tracking-uuid',
|
|
1260
|
+
'region' => 'sg',
|
|
1261
|
+
'owner_uuid' => 'owner-uuid',
|
|
1262
|
+
'owner_type' => Order::class,
|
|
1263
|
+
], true);
|
|
1264
|
+
|
|
1265
|
+
$observer = new FleetOpsTrackingNumberObserverProbe();
|
|
1266
|
+
$observer->creating($trackingNumber);
|
|
1267
|
+
$observer->created($trackingNumber);
|
|
1268
|
+
|
|
1269
|
+
expect($trackingNumber->tracking_number)->toBe('TN-sg')
|
|
1270
|
+
->and($trackingNumber->qr_code)->toBe('QRCODE-png')
|
|
1271
|
+
->and($trackingNumber->barcode)->toBe('PDF417-png')
|
|
1272
|
+
->and($observer->barcodes)->toBe([
|
|
1273
|
+
['owner-uuid', 'QRCODE'],
|
|
1274
|
+
['owner-uuid', 'PDF417'],
|
|
1275
|
+
])
|
|
1276
|
+
->and($observer->statuses[0])->toMatchArray([
|
|
1277
|
+
'company_uuid' => 'company-uuid',
|
|
1278
|
+
'tracking_number_uuid' => 'tracking-uuid',
|
|
1279
|
+
'status' => 'Order Created',
|
|
1280
|
+
'details' => 'New order created.',
|
|
1281
|
+
'code' => 'CREATED',
|
|
1282
|
+
])
|
|
1283
|
+
->and($observer->statuses[0]['location'])->toBeInstanceOf(Fleetbase\LaravelMysqlSpatial\Types\Point::class)
|
|
1284
|
+
->and($trackingNumber->ownerStatuses)->toHaveCount(1);
|
|
1285
|
+
});
|
|
1286
|
+
|
|
1287
|
+
test('zone observer invalidates service area cache for lifecycle events and original service area', function () {
|
|
1288
|
+
$zone = new Zone();
|
|
1289
|
+
$zone->setRawAttributes([
|
|
1290
|
+
'uuid' => 'zone-uuid',
|
|
1291
|
+
'company_uuid' => 'company-uuid',
|
|
1292
|
+
'service_area_uuid' => 'service-area-old',
|
|
1293
|
+
], true);
|
|
1294
|
+
$zone->service_area_uuid = 'service-area-new';
|
|
1295
|
+
|
|
1296
|
+
$observer = new FleetOpsZoneObserverProbe();
|
|
1297
|
+
$observer->created($zone);
|
|
1298
|
+
$observer->updated($zone);
|
|
1299
|
+
$observer->deleted($zone);
|
|
1300
|
+
$observer->restored($zone);
|
|
1301
|
+
$observer->created(new Zone());
|
|
1302
|
+
|
|
1303
|
+
expect($observer->invalidations)->toBe([
|
|
1304
|
+
['company-uuid', 'service-area-new'],
|
|
1305
|
+
['company-uuid', 'service-area-old'],
|
|
1306
|
+
['company-uuid', 'service-area-new'],
|
|
1307
|
+
['company-uuid', 'service-area-new'],
|
|
1308
|
+
['company-uuid', 'service-area-new'],
|
|
1309
|
+
]);
|
|
1310
|
+
});
|
|
1311
|
+
|
|
1312
|
+
test('notify driver on shift change exits early and sends enabled driver notifications', function () {
|
|
1313
|
+
$listener = new FleetOpsNotifyDriverOnShiftChangeProbe();
|
|
1314
|
+
|
|
1315
|
+
$listener->handle((object) []);
|
|
1316
|
+
expect($listener->sent)->toBe([]);
|
|
1317
|
+
|
|
1318
|
+
$scheduleItem = new ScheduleItem();
|
|
1319
|
+
$listener->handle((object) ['scheduleItem' => $scheduleItem]);
|
|
1320
|
+
expect($listener->sent)->toBe([]);
|
|
1321
|
+
|
|
1322
|
+
$schedule = new Schedule();
|
|
1323
|
+
$schedule->setRelation('subject', new User());
|
|
1324
|
+
$listener->schedule = $schedule;
|
|
1325
|
+
$listener->handle((object) ['scheduleItem' => $scheduleItem]);
|
|
1326
|
+
expect($listener->sent)->toBe([]);
|
|
1327
|
+
|
|
1328
|
+
$driver = new Driver();
|
|
1329
|
+
$schedule->setRelation('subject', $driver);
|
|
1330
|
+
$listener->handle((object) ['scheduleItem' => $scheduleItem]);
|
|
1331
|
+
expect($listener->sent)->toBe([]);
|
|
1332
|
+
|
|
1333
|
+
$listener->settings = ['notify_drivers_on_shift_change' => true];
|
|
1334
|
+
$listener->createdEvent = true;
|
|
1335
|
+
$listener->handle((object) ['scheduleItem' => $scheduleItem]);
|
|
1336
|
+
|
|
1337
|
+
expect($listener->sent)->toHaveCount(1)
|
|
1338
|
+
->and($listener->sent[0][0])->toBe($driver)
|
|
1339
|
+
->and($listener->sent[0][1])->toBeInstanceOf(DriverShiftChanged::class);
|
|
1340
|
+
});
|
|
1341
|
+
|
|
1342
|
+
if (!function_exists('Fleetbase\FleetOps\Observers\event')) {
|
|
1343
|
+
eval('namespace Fleetbase\FleetOps\Observers; function event($event = null, $payload = null) { $GLOBALS["fleetopsObserverEvents"][] = [$event, $payload]; return []; }');
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
test('work order observer real helpers query maintenance schedules and events', function () {
|
|
1347
|
+
$connection = new Illuminate\Database\SQLiteConnection(new PDO('sqlite::memory:'));
|
|
1348
|
+
$resolver = new Illuminate\Database\ConnectionResolver(['default' => $connection, 'mysql' => $connection]);
|
|
1349
|
+
$resolver->setDefaultConnection('mysql');
|
|
1350
|
+
Illuminate\Database\Eloquent\Model::setConnectionResolver($resolver);
|
|
1351
|
+
if (!Illuminate\Database\Eloquent\Model::getEventDispatcher()) {
|
|
1352
|
+
Illuminate\Database\Eloquent\Model::setEventDispatcher(new Illuminate\Events\Dispatcher());
|
|
1353
|
+
}
|
|
1354
|
+
$schema = $connection->getSchemaBuilder();
|
|
1355
|
+
foreach (['maintenances' => ['uuid', 'public_id', 'company_uuid', 'work_order_uuid', 'maintainable_type', 'maintainable_uuid', 'type', 'status', 'scheduled_at', 'odometer', 'engine_hours', 'summary', '_key'], 'maintenance_schedules' => ['uuid', 'public_id', 'company_uuid', 'name', 'next_due_at', 'meta', '_key']] as $table => $columns) {
|
|
1356
|
+
$schema->create($table, function ($blueprint) use ($columns) {
|
|
1357
|
+
$blueprint->increments('id');
|
|
1358
|
+
foreach ($columns as $column) {
|
|
1359
|
+
$blueprint->string($column)->nullable();
|
|
1360
|
+
}
|
|
1361
|
+
$blueprint->timestamps();
|
|
1362
|
+
$blueprint->timestamp('deleted_at')->nullable();
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1365
|
+
session(['company' => 'company-1']);
|
|
1366
|
+
app()->instance('responsecache', new class {
|
|
1367
|
+
public function __call($method, $arguments)
|
|
1368
|
+
{
|
|
1369
|
+
return null;
|
|
1370
|
+
}
|
|
1371
|
+
});
|
|
1372
|
+
config()->set('activitylog.enabled', false);
|
|
1373
|
+
config()->set('activitylog.default_auth_driver', 'web');
|
|
1374
|
+
app()->bind(Illuminate\Contracts\Config\Repository::class, fn () => config());
|
|
1375
|
+
$connection->table('maintenances')->insert(['uuid' => 'mnt-obs-1', 'work_order_uuid' => 'wo-obs-1', 'status' => 'completed']);
|
|
1376
|
+
$connection->table('maintenance_schedules')->insert(['uuid' => 'sched-obs-1', 'company_uuid' => 'company-1', 'name' => 'Quarterly']);
|
|
1377
|
+
|
|
1378
|
+
$observer = new WorkOrderObserver();
|
|
1379
|
+
$helper = function (string $method, ...$arguments) use ($observer) {
|
|
1380
|
+
$reflection = new ReflectionMethod(WorkOrderObserver::class, $method);
|
|
1381
|
+
$reflection->setAccessible(true);
|
|
1382
|
+
|
|
1383
|
+
return $reflection->invoke($observer, ...$arguments);
|
|
1384
|
+
};
|
|
1385
|
+
|
|
1386
|
+
$workOrder = new WorkOrder();
|
|
1387
|
+
$workOrder->setRawAttributes(['uuid' => 'wo-obs-1', 'company_uuid' => 'company-1'], true);
|
|
1388
|
+
|
|
1389
|
+
// Real queries scope by work order and schedule identity
|
|
1390
|
+
expect($helper('hasMaintenanceRecord', $workOrder))->toBeTrue()
|
|
1391
|
+
->and($helper('findSchedule', 'sched-obs-1'))->toBeInstanceOf(MaintenanceSchedule::class)
|
|
1392
|
+
->and($helper('findSchedule', 'sched-missing'))->toBeNull();
|
|
1393
|
+
|
|
1394
|
+
// Maintenance creation persists rows through the observer helper
|
|
1395
|
+
$created = $helper('createMaintenance', ['company_uuid' => 'company-1', 'work_order_uuid' => 'wo-obs-2', 'status' => 'scheduled', 'type' => 'inspection']);
|
|
1396
|
+
expect($created)->toBeInstanceOf(Maintenance::class)
|
|
1397
|
+
->and($connection->table('maintenances')->count())->toBe(2);
|
|
1398
|
+
|
|
1399
|
+
// Completed events dispatch through the observer event shim
|
|
1400
|
+
$GLOBALS['fleetopsObserverEvents'] = [];
|
|
1401
|
+
$helper('dispatchCompletedEvent', $workOrder);
|
|
1402
|
+
expect($GLOBALS['fleetopsObserverEvents'][0][0])->toBe('work_order.completed');
|
|
1403
|
+
|
|
1404
|
+
// Schedule resets skip work orders without linked schedules
|
|
1405
|
+
$unlinked = new WorkOrder();
|
|
1406
|
+
$unlinked->setRawAttributes(['uuid' => 'wo-obs-3', 'company_uuid' => 'company-1', 'schedule_uuid' => null], true);
|
|
1407
|
+
$helper('resetSchedule', $unlinked);
|
|
1408
|
+
|
|
1409
|
+
// And skip quietly when the linked schedule row is missing
|
|
1410
|
+
$orphaned = new WorkOrder();
|
|
1411
|
+
$orphaned->setRawAttributes(['uuid' => 'wo-obs-4', 'company_uuid' => 'company-1', 'schedule_uuid' => 'sched-missing'], true);
|
|
1412
|
+
$helper('resetSchedule', $orphaned);
|
|
1413
|
+
expect(true)->toBeTrue();
|
|
1414
|
+
});
|