@fleetbase/fleetops-engine 0.6.69 → 0.6.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/RELEASE.md +21 -14
- package/addon/components/admin/telematics-settings.hbs +143 -0
- package/addon/components/admin/telematics-settings.js +145 -0
- package/addon/components/fuel-integration/hub.hbs +1 -1
- package/addon/components/layout/fleet-ops-sidebar.js +37 -17
- package/addon/components/map/leaflet-live-map.hbs +4 -242
- package/addon/components/map/leaflet-live-map.js +2 -1
- package/addon/components/map/marker-card/driver.hbs +57 -0
- package/addon/components/map/marker-card/driver.js +3 -0
- package/addon/components/map/marker-card/vehicle.hbs +78 -0
- package/addon/components/map/marker-card/vehicle.js +3 -0
- package/addon/components/order/details/activity.hbs +8 -6
- package/addon/components/order/details/activity.js +9 -0
- package/addon/components/order/details.hbs +29 -0
- package/addon/components/order/details.js +26 -0
- package/addon/components/order/form/details.hbs +30 -4
- package/addon/components/order/form/details.js +46 -0
- package/addon/components/order/form/route.hbs +4 -2
- package/addon/components/order/form/route.js +11 -0
- package/addon/components/order/form.hbs +12 -0
- package/addon/components/order/form.js +21 -1
- package/addon/components/order/kanban.js +72 -0
- package/addon/components/order-config-manager/activity-flow.js +45 -10
- package/addon/components/order-config-manager/lifecycle.hbs +250 -0
- package/addon/components/order-config-manager/lifecycle.js +358 -0
- package/addon/components/order-config-manager.js +5 -1
- package/addon/components/telematic/hub.hbs +1 -1
- package/addon/components/widget/live-fleet.hbs +8 -40
- package/addon/controllers/analytics/reports/index.js +15 -1
- package/addon/controllers/connectivity/devices/index/details.js +1 -0
- package/addon/controllers/connectivity/devices/index.js +12 -2
- package/addon/controllers/connectivity/events/index.js +31 -1
- package/addon/controllers/connectivity/fuel-providers/index.js +6 -4
- package/addon/controllers/connectivity/sensors/index/details.js +1 -1
- package/addon/controllers/connectivity/sensors/index.js +41 -1
- package/addon/controllers/connectivity/telematics/index.js +4 -0
- package/addon/controllers/maintenance/equipment/index/details.js +2 -2
- package/addon/controllers/maintenance/equipment/index.js +36 -10
- package/addon/controllers/maintenance/inspection-forms/index.js +32 -12
- package/addon/controllers/maintenance/inspection-submissions/index/details.js +2 -1
- package/addon/controllers/maintenance/inspection-submissions/index.js +56 -10
- package/addon/controllers/maintenance/maintenances/index/details.js +2 -0
- package/addon/controllers/maintenance/maintenances/index.js +24 -1
- package/addon/controllers/maintenance/parts/index/details.js +2 -2
- package/addon/controllers/maintenance/parts/index.js +36 -9
- package/addon/controllers/maintenance/schedules/index.js +48 -6
- package/addon/controllers/maintenance/work-orders/index/details.js +3 -3
- package/addon/controllers/maintenance/work-orders/index.js +47 -9
- package/addon/controllers/management/contacts/customers.js +13 -0
- package/addon/controllers/management/contacts/index.js +47 -1
- package/addon/controllers/management/drivers/index/details.js +1 -0
- package/addon/controllers/management/drivers/index.js +36 -2
- package/addon/controllers/management/fleets/index/details.js +1 -0
- package/addon/controllers/management/fleets/index.js +43 -1
- package/addon/controllers/management/fuel-reports/index.js +26 -2
- package/addon/controllers/management/fuel-transactions/index.js +45 -7
- package/addon/controllers/management/issues/index/details.js +1 -0
- package/addon/controllers/management/issues/index.js +26 -2
- package/addon/controllers/management/places/index.js +40 -1
- package/addon/controllers/management/trailers/index/details.js +1 -0
- package/addon/controllers/management/trailers/index.js +50 -2
- package/addon/controllers/management/vehicles/index/details.js +1 -0
- package/addon/controllers/management/vehicles/index.js +37 -2
- package/addon/controllers/management/vendors/index.js +30 -2
- package/addon/controllers/operations/orders/index/details.js +61 -5
- package/addon/controllers/operations/orders/index.js +66 -4
- package/addon/controllers/operations/service-rates/index.js +18 -1
- package/addon/controllers/settings/index.js +13 -0
- package/addon/controllers/settings/telematics.js +113 -0
- package/addon/extension.js +70 -6
- package/addon/routes/analytics/index.js +14 -1
- package/addon/routes/analytics/reports/index/details.js +1 -1
- package/addon/routes/analytics/reports/index/edit.js +1 -1
- package/addon/routes/analytics/reports/index/new.js +14 -1
- package/addon/routes/analytics/reports.js +14 -1
- package/addon/routes/connectivity/devices/index/new.js +14 -1
- package/addon/routes/connectivity/devices.js +14 -1
- package/addon/routes/connectivity/events.js +14 -1
- package/addon/routes/connectivity/fuel-providers/details/transactions.js +12 -0
- package/addon/routes/connectivity/fuel-providers/details.js +9 -0
- package/addon/routes/connectivity/fuel-providers/edit.js +9 -0
- package/addon/routes/connectivity/fuel-providers/new.js +14 -1
- package/addon/routes/connectivity/fuel-providers.js +14 -1
- package/addon/routes/connectivity/sensors/index/new.js +14 -1
- package/addon/routes/connectivity/sensors.js +14 -1
- package/addon/routes/connectivity/telematics/new.js +14 -1
- package/addon/routes/connectivity/telematics.js +14 -1
- package/addon/routes/connectivity/tracking.js +14 -1
- package/addon/routes/maintenance/equipment/index/details.js +2 -2
- package/addon/routes/maintenance/equipment/index/edit.js +2 -2
- package/addon/routes/maintenance/equipment/index/new.js +14 -1
- package/addon/routes/maintenance/equipment.js +14 -1
- package/addon/routes/maintenance/index.js +14 -1
- package/addon/routes/maintenance/inspection-forms/index/details.js +10 -1
- package/addon/routes/maintenance/inspection-forms/index/edit.js +10 -1
- package/addon/routes/maintenance/inspection-forms/index/new.js +14 -1
- package/addon/routes/maintenance/inspection-forms.js +14 -1
- package/addon/routes/maintenance/inspection-submissions/index/details.js +10 -1
- package/addon/routes/maintenance/inspection-submissions/index/edit.js +10 -1
- package/addon/routes/maintenance/inspection-submissions/index/new.js +14 -1
- package/addon/routes/maintenance/inspection-submissions.js +14 -1
- package/addon/routes/maintenance/maintenances/index/details.js +2 -2
- package/addon/routes/maintenance/maintenances/index/edit.js +2 -2
- package/addon/routes/maintenance/maintenances/index/new.js +14 -1
- package/addon/routes/maintenance/maintenances.js +14 -1
- package/addon/routes/maintenance/parts/index/details.js +2 -2
- package/addon/routes/maintenance/parts/index/edit.js +2 -2
- package/addon/routes/maintenance/parts/index/new.js +14 -1
- package/addon/routes/maintenance/parts.js +14 -1
- package/addon/routes/maintenance/schedules/index/details.js +2 -2
- package/addon/routes/maintenance/schedules/index/edit.js +2 -2
- package/addon/routes/maintenance/schedules/index/new.js +15 -1
- package/addon/routes/maintenance/schedules.js +15 -1
- package/addon/routes/maintenance/work-orders/index/details.js +2 -2
- package/addon/routes/maintenance/work-orders/index/edit.js +2 -2
- package/addon/routes/maintenance/work-orders/index/new.js +14 -1
- package/addon/routes/maintenance/work-orders.js +14 -1
- package/addon/routes/management/fuel-transactions/index/details.js +9 -0
- package/addon/routes/management/fuel-transactions.js +14 -1
- package/addon/routes/management/index.js +13 -0
- package/addon/routes/management/trailers.js +16 -0
- package/addon/routes/management/vendors/integrated/details.js +14 -1
- package/addon/routes/management/vendors/integrated/edit.js +14 -1
- package/addon/routes/management/vendors/integrated/new.js +14 -1
- package/addon/routes/management/vendors/integrated.js +14 -1
- package/addon/routes/operations/orders/index/details.js +1 -0
- package/addon/routes/operations/orders.js +40 -1
- package/addon/routes/operations/routes/index/details.js +14 -1
- package/addon/routes/operations/routes/index/new.js +13 -0
- package/addon/routes/operations/routes.js +14 -1
- package/addon/routes/operations/service-rates/index/new.js +11 -0
- package/addon/routes/operations/service-rates.js +14 -1
- package/addon/routes/settings/avatars.js +14 -1
- package/addon/routes/settings/custom-fields.js +14 -1
- package/addon/routes/settings/map.js +14 -1
- package/addon/routes/settings/notifications.js +11 -0
- package/addon/routes/settings/orchestrator.js +1 -1
- package/addon/routes/settings/payments/index.js +1 -1
- package/addon/routes/settings/routing.js +14 -1
- package/addon/routes/settings/scheduling.js +14 -1
- package/addon/routes/settings/telematics.js +21 -0
- package/addon/routes/virtual.js +11 -0
- package/addon/routes.js +1 -0
- package/addon/services/contact-actions.js +1 -0
- package/addon/services/customer-actions.js +2 -1
- package/addon/services/device-actions.js +1 -0
- package/addon/services/device-event-actions.js +1 -0
- package/addon/services/driver-actions.js +4 -13
- package/addon/services/equipment-actions.js +1 -0
- package/addon/services/fleet-actions.js +1 -0
- package/addon/services/fuel-report-actions.js +1 -0
- package/addon/services/inspection-form-actions.js +1 -0
- package/addon/services/inspection-submission-actions.js +1 -0
- package/addon/services/integrated-vendor-actions.js +1 -0
- package/addon/services/issue-actions.js +1 -0
- package/addon/services/maintenance-actions.js +1 -0
- package/addon/services/maintenance-schedule-actions.js +2 -1
- package/addon/services/order-actions.js +7 -0
- package/addon/services/order-presentation.js +129 -0
- package/addon/services/part-actions.js +1 -0
- package/addon/services/place-actions.js +1 -0
- package/addon/services/sensor-actions.js +1 -0
- package/addon/services/service-area-actions.js +1 -0
- package/addon/services/service-rate-actions.js +1 -0
- package/addon/services/telematic-actions.js +1 -0
- package/addon/services/trailer-actions.js +4 -14
- package/addon/services/vehicle-actions.js +4 -13
- package/addon/services/vendor-actions.js +1 -0
- package/addon/services/work-order-actions.js +1 -0
- package/addon/services/zone-actions.js +1 -0
- package/addon/templates/analytics/reports/index/details.hbs +1 -0
- package/addon/templates/analytics/reports/index.hbs +1 -0
- package/addon/templates/connectivity/devices/index/details.hbs +1 -0
- package/addon/templates/connectivity/devices/index.hbs +1 -0
- package/addon/templates/connectivity/events/index.hbs +1 -0
- package/addon/templates/connectivity/sensors/index/details.hbs +1 -0
- package/addon/templates/connectivity/sensors/index.hbs +1 -0
- package/addon/templates/maintenance/equipment/index/details.hbs +1 -0
- package/addon/templates/maintenance/equipment/index.hbs +2 -0
- package/addon/templates/maintenance/inspection-forms/index/details.hbs +1 -0
- package/addon/templates/maintenance/inspection-forms/index.hbs +1 -0
- package/addon/templates/maintenance/inspection-submissions/index/details.hbs +1 -0
- package/addon/templates/maintenance/inspection-submissions/index.hbs +1 -0
- package/addon/templates/maintenance/maintenances/index/details.hbs +1 -0
- package/addon/templates/maintenance/maintenances/index.hbs +1 -0
- package/addon/templates/maintenance/parts/index/details.hbs +1 -0
- package/addon/templates/maintenance/parts/index.hbs +2 -0
- package/addon/templates/maintenance/schedules/index/details.hbs +1 -0
- package/addon/templates/maintenance/schedules/index.hbs +2 -0
- package/addon/templates/maintenance/work-orders/index/details.hbs +1 -0
- package/addon/templates/maintenance/work-orders/index.hbs +1 -0
- package/addon/templates/management/contacts/customers/details.hbs +1 -0
- package/addon/templates/management/contacts/customers.hbs +1 -0
- package/addon/templates/management/contacts/index/details.hbs +1 -0
- package/addon/templates/management/contacts/index.hbs +1 -0
- package/addon/templates/management/contacts.hbs +1 -0
- package/addon/templates/management/drivers/index/details.hbs +1 -0
- package/addon/templates/management/drivers/index.hbs +2 -0
- package/addon/templates/management/fleets/index/details.hbs +1 -0
- package/addon/templates/management/fleets/index.hbs +1 -0
- package/addon/templates/management/fuel-reports/index/details.hbs +1 -0
- package/addon/templates/management/fuel-reports/index.hbs +1 -0
- package/addon/templates/management/fuel-transactions/index.hbs +1 -0
- package/addon/templates/management/issues/index/details.hbs +1 -0
- package/addon/templates/management/issues/index.hbs +1 -0
- package/addon/templates/management/places/index/details.hbs +1 -0
- package/addon/templates/management/places/index.hbs +1 -0
- package/addon/templates/management/trailers/index/details.hbs +1 -0
- package/addon/templates/management/trailers/index.hbs +2 -0
- package/addon/templates/management/vehicles/index/details.hbs +1 -0
- package/addon/templates/management/vehicles/index.hbs +2 -0
- package/addon/templates/management/vendors/index/details.hbs +1 -0
- package/addon/templates/management/vendors/index.hbs +2 -0
- package/addon/templates/management/vendors/integrated.hbs +1 -0
- package/addon/templates/operations/orders/index/details.hbs +1 -0
- package/addon/templates/operations/orders/index.hbs +1 -0
- package/addon/templates/operations/service-rates/index/details.hbs +1 -0
- package/addon/templates/operations/service-rates/index.hbs +1 -0
- package/addon/templates/settings/telematics.hbs +70 -0
- package/addon/utils/normalize-order-config-flow.js +6 -1
- package/app/components/admin/telematics-settings.js +1 -0
- package/app/components/map/marker-card/driver.js +1 -0
- package/app/components/map/marker-card/vehicle.js +1 -0
- package/app/controllers/settings/telematics.js +1 -0
- package/app/routes/settings/telematics.js +1 -0
- package/app/services/order-presentation.js +1 -0
- package/app/templates/settings/telematics.js +1 -0
- package/composer.json +2 -2
- package/docs/AFAQY.md +1 -1
- package/docs/TELEMATICS_QUEUES.md +1 -1
- package/docs/TELEMETRY_ARCHITECTURE.md +72 -1
- package/extension.json +1 -1
- package/package.json +3 -3
- package/server/config/telemetry.php +12 -0
- package/server/migrations/2026_09_23_000001_add_retention_index_to_device_events.php +40 -0
- package/server/migrations/2026_09_23_000002_add_retention_index_to_positions.php +40 -0
- package/server/migrations/2026_09_23_000003_add_retention_index_to_telematic_sync_runs.php +40 -0
- package/server/src/Auth/Schemas/FleetOps.php +104 -5
- package/server/src/Console/Commands/DrainTelematicInbox.php +3 -13
- package/server/src/Console/Commands/ProcessOperationalAlerts.php +3 -3
- package/server/src/Console/Commands/PruneTelematicsData.php +318 -0
- package/server/src/Http/Controllers/Api/v1/OrchestrationController.php +9 -0
- package/server/src/Http/Controllers/FleetOpsController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/ContactController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/CustomerController.php +14 -0
- package/server/src/Http/Controllers/Internal/v1/DeviceController.php +13 -0
- package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +22 -0
- package/server/src/Http/Controllers/Internal/v1/FuelProviderConnectionController.php +13 -0
- package/server/src/Http/Controllers/Internal/v1/FuelProviderTransactionController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/FuelReportController.php +9 -3
- package/server/src/Http/Controllers/Internal/v1/InspectionFormController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +16 -0
- package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/ManifestController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/MetricsController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +42 -1
- package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +12 -0
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +56 -4
- package/server/src/Http/Controllers/Internal/v1/PaymentController.php +13 -0
- package/server/src/Http/Controllers/Internal/v1/RadarController.php +19 -0
- package/server/src/Http/Controllers/Internal/v1/ServiceAreaController.php +9 -3
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +465 -14
- package/server/src/Http/Controllers/Internal/v1/TelematicController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/TrailerController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/VehicleController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/VendorController.php +17 -0
- package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +11 -0
- package/server/src/Jobs/DispatchTelematicsRetentionJobs.php +70 -0
- package/server/src/Jobs/PruneTelematicsDataJob.php +74 -0
- package/server/src/Listeners/NotifyDriverOnShiftChange.php +3 -3
- package/server/src/Mail/CustomerCredentialsMail.php +1 -1
- package/server/src/Models/Order.php +35 -3
- package/server/src/Models/OrderConfig.php +129 -0
- package/server/src/Models/TrackingNumber.php +8 -4
- package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +9 -1
- package/server/src/Providers/FleetOpsServiceProvider.php +3 -0
- package/server/src/Support/Analytics/LiveFleet.php +18 -2
- package/server/src/Support/Authorization.php +103 -0
- package/server/src/Support/Database/TableIndexes.php +66 -0
- package/server/src/Support/OrderTracker.php +2 -2
- package/server/src/Support/Reporting/FleetOpsReportSchema.php +476 -116
- package/server/src/Support/Telematics/Retention/RetentionPolicy.php +300 -0
- package/server/src/Support/Telematics/Retention/TelemetryActivity.php +40 -0
- package/server/src/Support/Telematics/TelematicService.php +12 -2
- package/server/src/Support/Telematics/Telemetry/Ingestor.php +4 -2
- package/server/src/Tracking/TrackingIntelligenceService.php +1 -1
- package/server/src/Tracking/TrackingOptions.php +2 -2
- package/server/src/Traits/AuthorizesMethods.php +37 -0
- package/server/src/routes.php +9 -1
- package/server/tests/AnalyticsRoutesTest.php +29 -2
- package/server/tests/Feature/Http/AfaqyRealtimeIngestionTest.php +16 -1
- package/server/tests/Feature/Http/Api/TelematicsRetentionIndexMigrationTest.php +115 -0
- package/server/tests/Feature/Http/Internal/OrderControllerActivityFlowsTest.php +72 -0
- package/server/tests/Feature/Http/Internal/OrderControllerCreateRecordTest.php +26 -0
- package/server/tests/Feature/Http/Internal/SettingControllerHelpersTest.php +71 -0
- package/server/tests/Feature/Http/Internal/TelematicsStorageDeadlinesTest.php +119 -0
- package/server/tests/InternalImportExportControllerContractsTest.php +5 -8
- package/server/tests/NavigatorControllerContractsTest.php +36 -4
- package/server/tests/NotificationAndMailContractsTest.php +31 -0
- package/server/tests/ObserverContractsTest.php +1 -1
- package/server/tests/OrchestratorConsumableApiTest.php +42 -0
- package/server/tests/OrderConfigLifecycleTest.php +120 -0
- package/server/tests/ProviderContractsTest.php +10 -0
- package/server/tests/ReportSchemaContractsTest.php +120 -6
- package/server/tests/SettingControllerContractsTest.php +429 -18
- package/server/tests/SmallControllerContractsTest.php +8 -5
- package/server/tests/Support/PruneTelematicsDataProbe.php +55 -0
- package/server/tests/Unit/Console/Commands/ProcessOperationalAlertsCommandTest.php +2 -2
- package/server/tests/Unit/Console/PruneTelematicsDataCommandTest.php +353 -0
- package/server/tests/Unit/Events/OrderDispatchFailedTest.php +2 -1
- package/server/tests/Unit/Jobs/DispatchTelematicsRetentionJobsTest.php +114 -0
- package/server/tests/Unit/Jobs/PruneTelematicsDataJobTest.php +60 -0
- package/server/tests/Unit/Orchestration/VroomEngineTransportAndSettingsTest.php +20 -0
- package/server/tests/Unit/Support/Analytics/LiveFleetTest.php +6 -0
- package/server/tests/Unit/Support/AuthorizationTest.php +142 -0
- package/server/tests/Unit/Support/MaintainableAndOperationalAlertsTest.php +12 -1
- package/server/tests/Unit/Support/MoreQuerySeamsTest.php +11 -2
- package/server/tests/Unit/Support/Telematics/Retention/RetentionPolicyTest.php +190 -0
- package/server/tests/Unit/Support/Telematics/Retention/TelemetryActivityTest.php +68 -0
- package/server/tests/Unit/Tracking/TrackingOptionsCompanySettingsTest.php +109 -0
- package/translations/en-us.yaml +108 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
|
|
4
4
|
|
|
5
|
+
use Fleetbase\Attributes\SkipAuthorizationCheck;
|
|
5
6
|
use Fleetbase\FleetOps\Exceptions\DeviceAlreadyAttachedException;
|
|
6
7
|
use Fleetbase\FleetOps\Exports\VehicleExport;
|
|
7
8
|
use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
|
|
@@ -25,6 +26,20 @@ use Maatwebsite\Excel\Facades\Excel;
|
|
|
25
26
|
|
|
26
27
|
class VehicleController extends FleetOpsController
|
|
27
28
|
{
|
|
29
|
+
/**
|
|
30
|
+
* Permissions for methods AuthorizationGuard cannot map to a schema action (see FleetOpsController).
|
|
31
|
+
*
|
|
32
|
+
* @var array<string, string|string[]>
|
|
33
|
+
*/
|
|
34
|
+
protected array $methodPermissions = [
|
|
35
|
+
'unassignDriver' => 'assign-driver-for vehicle',
|
|
36
|
+
'unassignOrders' => 'update vehicle',
|
|
37
|
+
'attachDevice' => 'update vehicle',
|
|
38
|
+
'detachDevice' => 'update vehicle',
|
|
39
|
+
'attachEquipment' => 'update vehicle',
|
|
40
|
+
'detachEquipment' => 'update vehicle',
|
|
41
|
+
];
|
|
42
|
+
|
|
28
43
|
/**
|
|
29
44
|
* The resource to query.
|
|
30
45
|
*
|
|
@@ -111,6 +126,7 @@ class VehicleController extends FleetOpsController
|
|
|
111
126
|
]);
|
|
112
127
|
}
|
|
113
128
|
|
|
129
|
+
#[SkipAuthorizationCheck]
|
|
114
130
|
public function unassignDriver(string $id): JsonResponse
|
|
115
131
|
{
|
|
116
132
|
$vehicle = $this->findVehicle($id);
|
|
@@ -143,6 +159,7 @@ class VehicleController extends FleetOpsController
|
|
|
143
159
|
]);
|
|
144
160
|
}
|
|
145
161
|
|
|
162
|
+
#[SkipAuthorizationCheck]
|
|
146
163
|
public function unassignOrders(Request $request, string $id): JsonResponse
|
|
147
164
|
{
|
|
148
165
|
$request->validate([
|
|
@@ -179,6 +196,7 @@ class VehicleController extends FleetOpsController
|
|
|
179
196
|
]);
|
|
180
197
|
}
|
|
181
198
|
|
|
199
|
+
#[SkipAuthorizationCheck]
|
|
182
200
|
public function attachDevice(Request $request, string $id): JsonResponse
|
|
183
201
|
{
|
|
184
202
|
$request->validate(['device' => 'required|string']);
|
|
@@ -219,6 +237,7 @@ class VehicleController extends FleetOpsController
|
|
|
219
237
|
]);
|
|
220
238
|
}
|
|
221
239
|
|
|
240
|
+
#[SkipAuthorizationCheck]
|
|
222
241
|
public function detachDevice(Request $request, string $id): JsonResponse
|
|
223
242
|
{
|
|
224
243
|
$request->validate(['device' => 'required|string']);
|
|
@@ -265,6 +284,7 @@ class VehicleController extends FleetOpsController
|
|
|
265
284
|
* Attach equipment to the vehicle. Equipment can only be equipped to one asset at a
|
|
266
285
|
* time, so attaching moves it from any previous vehicle or trailer.
|
|
267
286
|
*/
|
|
287
|
+
#[SkipAuthorizationCheck]
|
|
268
288
|
public function attachEquipment(Request $request, string $id): JsonResponse
|
|
269
289
|
{
|
|
270
290
|
$request->validate(['equipment' => 'required|string']);
|
|
@@ -292,6 +312,7 @@ class VehicleController extends FleetOpsController
|
|
|
292
312
|
]);
|
|
293
313
|
}
|
|
294
314
|
|
|
315
|
+
#[SkipAuthorizationCheck]
|
|
295
316
|
public function detachEquipment(Request $request, string $id): JsonResponse
|
|
296
317
|
{
|
|
297
318
|
$request->validate(['equipment' => 'required|string']);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
|
|
4
4
|
|
|
5
|
+
use Fleetbase\Attributes\SkipAuthorizationCheck;
|
|
5
6
|
use Fleetbase\FleetOps\Exports\VendorExport;
|
|
6
7
|
use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
|
|
7
8
|
use Fleetbase\FleetOps\Http\Resources\v1\Contact as ContactResource;
|
|
@@ -19,6 +20,18 @@ use Maatwebsite\Excel\Facades\Excel;
|
|
|
19
20
|
|
|
20
21
|
class VendorController extends FleetOpsController
|
|
21
22
|
{
|
|
23
|
+
/**
|
|
24
|
+
* Permissions for methods AuthorizationGuard cannot map to a schema action (see FleetOpsController).
|
|
25
|
+
*
|
|
26
|
+
* @var array<string, string|string[]>
|
|
27
|
+
*/
|
|
28
|
+
protected array $methodPermissions = [
|
|
29
|
+
'assignDriver' => 'update vendor',
|
|
30
|
+
'removeDriver' => 'update vendor',
|
|
31
|
+
'addVendorPersonnel' => 'update vendor',
|
|
32
|
+
'removeVendorPersonnel' => 'update vendor',
|
|
33
|
+
];
|
|
34
|
+
|
|
22
35
|
/**
|
|
23
36
|
* The resource to query.
|
|
24
37
|
*
|
|
@@ -128,6 +141,7 @@ class VendorController extends FleetOpsController
|
|
|
128
141
|
*
|
|
129
142
|
* @return \Illuminate\Http\Response
|
|
130
143
|
*/
|
|
144
|
+
#[SkipAuthorizationCheck]
|
|
131
145
|
public function assignDriver(string $id, Request $request)
|
|
132
146
|
{
|
|
133
147
|
// Validate only param
|
|
@@ -160,6 +174,7 @@ class VendorController extends FleetOpsController
|
|
|
160
174
|
*
|
|
161
175
|
* @return \Illuminate\Http\Response
|
|
162
176
|
*/
|
|
177
|
+
#[SkipAuthorizationCheck]
|
|
163
178
|
public function removeDriver(string $id, Request $request)
|
|
164
179
|
{
|
|
165
180
|
// Validate only param
|
|
@@ -197,6 +212,7 @@ class VendorController extends FleetOpsController
|
|
|
197
212
|
return response()->json(['personnels' => $personnels->values()]);
|
|
198
213
|
}
|
|
199
214
|
|
|
215
|
+
#[SkipAuthorizationCheck]
|
|
200
216
|
public function addVendorPersonnel(Request $request, string $vendorId)
|
|
201
217
|
{
|
|
202
218
|
$vendor = $this->findVendorByIdOrFail($vendorId);
|
|
@@ -220,6 +236,7 @@ class VendorController extends FleetOpsController
|
|
|
220
236
|
]);
|
|
221
237
|
}
|
|
222
238
|
|
|
239
|
+
#[SkipAuthorizationCheck]
|
|
223
240
|
public function removeVendorPersonnel(string $vendorId, string $contactId)
|
|
224
241
|
{
|
|
225
242
|
$vendor = $this->findVendorByIdOrFail($vendorId);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
|
|
4
4
|
|
|
5
|
+
use Fleetbase\Attributes\SkipAuthorizationCheck;
|
|
5
6
|
use Fleetbase\FleetOps\Exports\WorkOrderExport;
|
|
6
7
|
use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
|
|
7
8
|
use Fleetbase\FleetOps\Imports\WorkOrderImport;
|
|
@@ -16,6 +17,15 @@ use Maatwebsite\Excel\Facades\Excel;
|
|
|
16
17
|
|
|
17
18
|
class WorkOrderController extends FleetOpsController
|
|
18
19
|
{
|
|
20
|
+
/**
|
|
21
|
+
* Permissions for methods AuthorizationGuard cannot map to a schema action (see FleetOpsController).
|
|
22
|
+
*
|
|
23
|
+
* @var array<string, string|string[]>
|
|
24
|
+
*/
|
|
25
|
+
protected array $methodPermissions = [
|
|
26
|
+
'sendEmail' => 'update work-order',
|
|
27
|
+
];
|
|
28
|
+
|
|
19
29
|
/**
|
|
20
30
|
* The resource to query.
|
|
21
31
|
*
|
|
@@ -80,6 +90,7 @@ class WorkOrderController extends FleetOpsController
|
|
|
80
90
|
* Send a work order email to the assigned vendor.
|
|
81
91
|
* POST /work-orders/{id}/send.
|
|
82
92
|
*/
|
|
93
|
+
#[SkipAuthorizationCheck]
|
|
83
94
|
public function sendEmail(string $id): JsonResponse
|
|
84
95
|
{
|
|
85
96
|
$workOrder = $this->workOrderForEmail($id);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Jobs;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\FleetOps\Support\Telematics\Telemetry\Queue;
|
|
6
|
+
use Illuminate\Bus\Queueable;
|
|
7
|
+
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
|
8
|
+
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
9
|
+
use Illuminate\Foundation\Bus\Dispatchable;
|
|
10
|
+
use Illuminate\Queue\InteractsWithQueue;
|
|
11
|
+
use Illuminate\Support\Collection;
|
|
12
|
+
use Illuminate\Support\Facades\DB;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Fan out system-wide cleanup in small pages, without a session or membership scope.
|
|
16
|
+
* Each company has its own bounded prune job so one large backlog cannot prevent
|
|
17
|
+
* other organizations from being processed within a shared worker timeout.
|
|
18
|
+
*/
|
|
19
|
+
class DispatchTelematicsRetentionJobs implements ShouldQueue, ShouldBeUnique
|
|
20
|
+
{
|
|
21
|
+
use Dispatchable;
|
|
22
|
+
use InteractsWithQueue;
|
|
23
|
+
use Queueable;
|
|
24
|
+
|
|
25
|
+
public const PAGE_SIZE = 100;
|
|
26
|
+
|
|
27
|
+
public int $uniqueFor = 900;
|
|
28
|
+
public int $tries = 3;
|
|
29
|
+
public int $timeout = 60;
|
|
30
|
+
|
|
31
|
+
public function __construct(public int $afterCompanyId = 0, public int $maxBatches = 200)
|
|
32
|
+
{
|
|
33
|
+
$this->onQueue(config('telematics.telemetry.ingestion_queue', 'default'));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public function uniqueId(): string
|
|
37
|
+
{
|
|
38
|
+
return 'after-company:' . $this->afterCompanyId;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public function handle(): void
|
|
42
|
+
{
|
|
43
|
+
$companies = $this->companies();
|
|
44
|
+
foreach ($companies as $company) {
|
|
45
|
+
$this->queueJob(new PruneTelematicsDataJob($company->uuid, $this->maxBatches));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if ($companies->count() === self::PAGE_SIZE) {
|
|
49
|
+
$this->queueJob(new self((int) $companies->last()->id, $this->maxBatches));
|
|
50
|
+
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
$this->queueJob(new PruneTelematicsDataJob(null, $this->maxBatches, true));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
protected function companies(): Collection
|
|
58
|
+
{
|
|
59
|
+
return DB::table('companies')
|
|
60
|
+
->where('id', '>', $this->afterCompanyId)
|
|
61
|
+
->orderBy('id')
|
|
62
|
+
->limit(self::PAGE_SIZE)
|
|
63
|
+
->get(['id', 'uuid']);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
protected function queueJob(ShouldBeUnique $job): void
|
|
67
|
+
{
|
|
68
|
+
Queue::dispatch($job);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Jobs;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\FleetOps\Console\Commands\PruneTelematicsData;
|
|
6
|
+
use Illuminate\Bus\Queueable;
|
|
7
|
+
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
|
8
|
+
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
9
|
+
use Illuminate\Foundation\Bus\Dispatchable;
|
|
10
|
+
use Illuminate\Queue\InteractsWithQueue;
|
|
11
|
+
use Symfony\Component\Console\Input\ArrayInput;
|
|
12
|
+
use Symfony\Component\Console\Output\BufferedOutput;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Runs a bounded telematics prune for one company or orphaned data.
|
|
16
|
+
*
|
|
17
|
+
* The command is executed directly rather than through the console kernel so a
|
|
18
|
+
* worker started before this package version can still run it.
|
|
19
|
+
*/
|
|
20
|
+
class PruneTelematicsDataJob implements ShouldQueue, ShouldBeUnique
|
|
21
|
+
{
|
|
22
|
+
use Dispatchable;
|
|
23
|
+
use InteractsWithQueue;
|
|
24
|
+
use Queueable;
|
|
25
|
+
|
|
26
|
+
public int $uniqueFor = 900;
|
|
27
|
+
public int $tries = 1;
|
|
28
|
+
// Finish or fail before Laravel's baseline Redis retry_after of 90 seconds.
|
|
29
|
+
public int $timeout = 80;
|
|
30
|
+
public bool $failOnTimeout = true;
|
|
31
|
+
public bool $orphansOnly = false;
|
|
32
|
+
|
|
33
|
+
public function __construct(public ?string $companyUuid = null, public int $maxBatches = 200, bool $orphansOnly = false)
|
|
34
|
+
{
|
|
35
|
+
$this->orphansOnly = $orphansOnly;
|
|
36
|
+
$this->onQueue(config('telematics.telemetry.ingestion_queue', 'default'));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public function uniqueId(): string
|
|
40
|
+
{
|
|
41
|
+
return $this->orphansOnly ? 'orphans' : ($this->companyUuid ?? 'all');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @return array<string, mixed>
|
|
46
|
+
*/
|
|
47
|
+
public function parameters(): array
|
|
48
|
+
{
|
|
49
|
+
$parameters = ['--no-lock' => true, '--max-batches' => $this->maxBatches];
|
|
50
|
+
if ($this->companyUuid) {
|
|
51
|
+
$parameters['--company'] = $this->companyUuid;
|
|
52
|
+
}
|
|
53
|
+
if ($this->orphansOnly) {
|
|
54
|
+
$parameters['--orphans-only'] = true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return $parameters;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public function handle(): void
|
|
61
|
+
{
|
|
62
|
+
$command = $this->command();
|
|
63
|
+
$command->setLaravel(app());
|
|
64
|
+
$exitCode = $command->run(new ArrayInput($this->parameters()), new BufferedOutput());
|
|
65
|
+
if ($exitCode !== PruneTelematicsData::SUCCESS) {
|
|
66
|
+
throw new \RuntimeException('Telematics cleanup failed with exit code ' . $exitCode . '.');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
protected function command(): PruneTelematicsData
|
|
71
|
+
{
|
|
72
|
+
return app(PruneTelematicsData::class);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -48,7 +48,7 @@ class NotifyDriverOnShiftChange implements ShouldQueue
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// Check the company-level scheduling setting
|
|
51
|
-
$settings = $this->getSchedulingSettings();
|
|
51
|
+
$settings = $this->getSchedulingSettings($schedule->company_uuid);
|
|
52
52
|
$shouldNotify = (bool) data_get($settings, 'notify_drivers_on_shift_change', false);
|
|
53
53
|
if (!$shouldNotify) {
|
|
54
54
|
return;
|
|
@@ -66,9 +66,9 @@ class NotifyDriverOnShiftChange implements ShouldQueue
|
|
|
66
66
|
return $scheduleItem->schedule()->with('subject')->first();
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
protected function getSchedulingSettings(): array
|
|
69
|
+
protected function getSchedulingSettings(?string $companyUuid): array
|
|
70
70
|
{
|
|
71
|
-
return Setting::
|
|
71
|
+
return Setting::lookupForCompany($companyUuid, 'fleet-ops.scheduling-settings', []);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
protected function isCreatedEvent(object $event): bool
|
|
@@ -72,7 +72,7 @@ class CustomerCredentialsMail extends Mailable
|
|
|
72
72
|
*/
|
|
73
73
|
private function getCustomerPortalAccessUrl(): string
|
|
74
74
|
{
|
|
75
|
-
$customerPortalConfig = Setting::
|
|
75
|
+
$customerPortalConfig = Setting::lookupForCompany($this->customer->company_uuid, 'customer-portal-config');
|
|
76
76
|
$accessUrlSlug = data_get($customerPortalConfig, 'accessUrlSlug', 'customer-portal');
|
|
77
77
|
|
|
78
78
|
return Utils::consoleUrl($accessUrlSlug ?: 'customer-portal');
|
|
@@ -1346,10 +1346,11 @@ class Order extends Model
|
|
|
1346
1346
|
*/
|
|
1347
1347
|
public function cancel()
|
|
1348
1348
|
{
|
|
1349
|
-
|
|
1350
|
-
|
|
1349
|
+
// The canceled activity comes from the order config, which may define its own code.
|
|
1351
1350
|
$this->loadMissing('orderConfig');
|
|
1352
|
-
$
|
|
1351
|
+
$orderConfig = $this->orderConfig ?? $this->config();
|
|
1352
|
+
$canceledActivity = $orderConfig->getCanceledActivity();
|
|
1353
|
+
$this->status = $canceledActivity->code ?? 'canceled';
|
|
1353
1354
|
$this->updateActivity($canceledActivity);
|
|
1354
1355
|
|
|
1355
1356
|
if ($this->isIntegratedVendorOrder()) {
|
|
@@ -1783,6 +1784,37 @@ class Order extends Model
|
|
|
1783
1784
|
return (int) Utils::get($this, 'adhoc_distance', Utils::get($this, 'company.options.fleetops.adhoc_distance', 6000));
|
|
1784
1785
|
}
|
|
1785
1786
|
|
|
1787
|
+
/**
|
|
1788
|
+
* Returns the initial tracking status for a newly created order.
|
|
1789
|
+
*
|
|
1790
|
+
* Used by the tracking number on creation. Orders whose config defines its own
|
|
1791
|
+
* lifecycle start at the configured initial activity instead of `created`.
|
|
1792
|
+
*
|
|
1793
|
+
* @return array|null ['code', 'status', 'details'] or null to use the default created status
|
|
1794
|
+
*/
|
|
1795
|
+
public function getInitialTrackingStatus(): ?array
|
|
1796
|
+
{
|
|
1797
|
+
if (!$this->order_config_uuid) {
|
|
1798
|
+
return null;
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
$orderConfig = OrderConfig::where('uuid', $this->order_config_uuid)->first();
|
|
1802
|
+
if (!$orderConfig || !$orderConfig->hasConfiguredLifecycle()) {
|
|
1803
|
+
return null;
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
$activity = $orderConfig->getInitialActivity();
|
|
1807
|
+
if (!$activity) {
|
|
1808
|
+
return null;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
return [
|
|
1812
|
+
'code' => $activity->code,
|
|
1813
|
+
'status' => $this->resolveActivityTemplateString((string) $activity->get('status', '')),
|
|
1814
|
+
'details' => $this->resolveActivityTemplateString((string) $activity->get('details', '')),
|
|
1815
|
+
];
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1786
1818
|
/**
|
|
1787
1819
|
* Retrieves the OrderConfig associated with this order.
|
|
1788
1820
|
*
|
|
@@ -380,6 +380,125 @@ class OrderConfig extends Model
|
|
|
380
380
|
return $this->activities()->firstWhere('code', $code);
|
|
381
381
|
}
|
|
382
382
|
|
|
383
|
+
/**
|
|
384
|
+
* Returns the configured lifecycle semantics stored under `meta.lifecycle`.
|
|
385
|
+
*
|
|
386
|
+
* A configured lifecycle is opt-in. When absent the default dispatch lifecycle
|
|
387
|
+
* (created -> dispatched -> ... -> completed / canceled) applies unchanged.
|
|
388
|
+
*
|
|
389
|
+
* Supported keys:
|
|
390
|
+
* - `initial` (string) activity code new orders start at
|
|
391
|
+
* - `completed` (string) activity code that completes an order
|
|
392
|
+
* - `canceled` (string) activity code used when an order is canceled
|
|
393
|
+
* - `terminal` (string[]) activity codes after which no transition is allowed
|
|
394
|
+
* - `dispatch` (bool) false disables dispatch for orders using this config
|
|
395
|
+
* - `strict_transitions` (bool) true only allows moving to a configured child activity
|
|
396
|
+
*/
|
|
397
|
+
public function lifecycle(): array
|
|
398
|
+
{
|
|
399
|
+
$lifecycle = data_get($this->meta, 'lifecycle');
|
|
400
|
+
|
|
401
|
+
return is_array($lifecycle) ? $lifecycle : [];
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Determines if this config defines its own lifecycle semantics.
|
|
406
|
+
*/
|
|
407
|
+
public function hasConfiguredLifecycle(): bool
|
|
408
|
+
{
|
|
409
|
+
return !empty($this->lifecycle());
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Returns the activity new orders using this config start at.
|
|
414
|
+
*
|
|
415
|
+
* Without a configured lifecycle this is the `created` activity, if present in the flow.
|
|
416
|
+
*/
|
|
417
|
+
public function getInitialActivity(): ?Activity
|
|
418
|
+
{
|
|
419
|
+
$initialCode = data_get($this->lifecycle(), 'initial');
|
|
420
|
+
if ($initialCode) {
|
|
421
|
+
return $this->getActivityByCode($initialCode);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return $this->getCreatedActivity();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Returns the status code new orders using this config start at.
|
|
429
|
+
*/
|
|
430
|
+
public function getInitialStatusCode(): string
|
|
431
|
+
{
|
|
432
|
+
return data_get($this->lifecycle(), 'initial') ?: 'created';
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Determines if orders using this config may be dispatched.
|
|
437
|
+
*/
|
|
438
|
+
public function allowsDispatch(): bool
|
|
439
|
+
{
|
|
440
|
+
$dispatch = data_get($this->lifecycle(), 'dispatch', true);
|
|
441
|
+
|
|
442
|
+
return !in_array($dispatch, [false, 'false', 0, '0'], true);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Determines if activity updates must follow the configured flow graph.
|
|
447
|
+
*/
|
|
448
|
+
public function hasStrictTransitions(): bool
|
|
449
|
+
{
|
|
450
|
+
return (bool) data_get($this->lifecycle(), 'strict_transitions', false);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Returns the terminal activity codes of this config.
|
|
455
|
+
*/
|
|
456
|
+
public function getTerminalActivityCodes(): array
|
|
457
|
+
{
|
|
458
|
+
if (!$this->hasConfiguredLifecycle()) {
|
|
459
|
+
return ['completed', 'canceled'];
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
$terminal = data_get($this->lifecycle(), 'terminal', []);
|
|
463
|
+
$terminal = is_array($terminal) ? $terminal : [];
|
|
464
|
+
foreach (['completed', 'canceled'] as $semantic) {
|
|
465
|
+
$code = data_get($this->lifecycle(), $semantic);
|
|
466
|
+
if ($code) {
|
|
467
|
+
$terminal[] = $code;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return array_values(array_unique($terminal));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Determines if the given activity code is terminal for this config.
|
|
476
|
+
*/
|
|
477
|
+
public function isTerminalActivityCode(?string $code): bool
|
|
478
|
+
{
|
|
479
|
+
return $code !== null && in_array($code, $this->getTerminalActivityCodes(), true);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Determines if the configured flow permits moving from one activity code to another.
|
|
484
|
+
*
|
|
485
|
+
* Only the configured graph is consulted: the target must be listed as a child of the
|
|
486
|
+
* source activity, and terminal activities permit no further transition.
|
|
487
|
+
*/
|
|
488
|
+
public function canTransition(?string $fromCode, string $toCode): bool
|
|
489
|
+
{
|
|
490
|
+
if ($fromCode === null || $this->isTerminalActivityCode($fromCode)) {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
$from = $this->getActivityByCode($fromCode);
|
|
495
|
+
if (!$from) {
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
return $from->children()->contains(fn ($activity) => $activity->code === $toCode);
|
|
500
|
+
}
|
|
501
|
+
|
|
383
502
|
/**
|
|
384
503
|
* Creates an Activity instance representing a canceled order.
|
|
385
504
|
*
|
|
@@ -391,6 +510,11 @@ class OrderConfig extends Model
|
|
|
391
510
|
*/
|
|
392
511
|
public function getCanceledActivity()
|
|
393
512
|
{
|
|
513
|
+
$configuredCode = data_get($this->lifecycle(), 'canceled');
|
|
514
|
+
if ($configuredCode && ($configuredActivity = $this->getActivityByCode($configuredCode))) {
|
|
515
|
+
return $configuredActivity;
|
|
516
|
+
}
|
|
517
|
+
|
|
394
518
|
$canceledActivity = $this->activities()->firstWhere('code', 'canceled');
|
|
395
519
|
if ($canceledActivity) {
|
|
396
520
|
return $canceledActivity;
|
|
@@ -416,6 +540,11 @@ class OrderConfig extends Model
|
|
|
416
540
|
*/
|
|
417
541
|
public function getCompletedActivity()
|
|
418
542
|
{
|
|
543
|
+
$configuredCode = data_get($this->lifecycle(), 'completed');
|
|
544
|
+
if ($configuredCode && ($configuredActivity = $this->getActivityByCode($configuredCode))) {
|
|
545
|
+
return $configuredActivity;
|
|
546
|
+
}
|
|
547
|
+
|
|
419
548
|
$completedActivity = $this->activities()->firstWhere('code', 'completed');
|
|
420
549
|
if ($completedActivity) {
|
|
421
550
|
return $completedActivity;
|
|
@@ -291,13 +291,17 @@ class TrackingNumber extends Model
|
|
|
291
291
|
|
|
292
292
|
$ownerTypeName = class_basename($values['owner_type']);
|
|
293
293
|
|
|
294
|
+
// owners may define their own initial status (e.g. orders with a configured lifecycle)
|
|
295
|
+
$initialStatus = $owner && method_exists($owner, 'getInitialTrackingStatus') ? $owner->getInitialTrackingStatus() : null;
|
|
296
|
+
$initialCode = is_array($initialStatus) && !empty($initialStatus['code']) ? $initialStatus['code'] : null;
|
|
297
|
+
|
|
294
298
|
// create initial status
|
|
295
299
|
$trackingStatusId = static::createInitialTrackingStatus([
|
|
296
300
|
'tracking_number_uuid' => $uuid,
|
|
297
|
-
'status' => Str::title($ownerTypeName . ' created'),
|
|
298
|
-
'details' => 'New ' . Str::lower($ownerTypeName) . ' created.',
|
|
301
|
+
'status' => $initialCode ? $initialStatus['status'] : Str::title($ownerTypeName . ' created'),
|
|
302
|
+
'details' => $initialCode ? $initialStatus['details'] : 'New ' . Str::lower($ownerTypeName) . ' created.',
|
|
299
303
|
'location' => $values['location'] ?? Utils::parsePointToWkt(new Point(0, 0)),
|
|
300
|
-
'code' => 'CREATED',
|
|
304
|
+
'code' => $initialCode ? TrackingStatus::prepareCode($initialCode) : 'CREATED',
|
|
301
305
|
]);
|
|
302
306
|
|
|
303
307
|
// update status of tracking number
|
|
@@ -309,7 +313,7 @@ class TrackingNumber extends Model
|
|
|
309
313
|
// $model->update([ 'status' => 'created' ]);
|
|
310
314
|
|
|
311
315
|
// silent update
|
|
312
|
-
static::updateOwnerStatusColumn($owner, 'created');
|
|
316
|
+
static::updateOwnerStatusColumn($owner, $initialCode ?? 'created');
|
|
313
317
|
}
|
|
314
318
|
|
|
315
319
|
return $uuid;
|
|
@@ -37,6 +37,12 @@ use Illuminate\Support\Facades\Log;
|
|
|
37
37
|
*/
|
|
38
38
|
class VroomOrchestrationEngine implements OrchestrationEngineInterface
|
|
39
39
|
{
|
|
40
|
+
/**
|
|
41
|
+
* The company whose VROOM settings apply to the current allocation run.
|
|
42
|
+
* Resolved from the orders so queued runs work without a company session.
|
|
43
|
+
*/
|
|
44
|
+
protected ?string $companyUuid = null;
|
|
45
|
+
|
|
40
46
|
public function getName(): string
|
|
41
47
|
{
|
|
42
48
|
return 'VROOM';
|
|
@@ -59,6 +65,8 @@ class VroomOrchestrationEngine implements OrchestrationEngineInterface
|
|
|
59
65
|
*/
|
|
60
66
|
public function allocate(Collection $orders, Collection $vehicles, array $options = []): array
|
|
61
67
|
{
|
|
68
|
+
$this->companyUuid = data_get($orders->first(), 'company_uuid');
|
|
69
|
+
|
|
62
70
|
if (($options['allocation_strategy'] ?? null) === 'capacity_only') {
|
|
63
71
|
return $this->allocateCapacityOnly($orders, $vehicles, $options);
|
|
64
72
|
}
|
|
@@ -520,7 +528,7 @@ class VroomOrchestrationEngine implements OrchestrationEngineInterface
|
|
|
520
528
|
protected function resolveVroomSetting(string $key, $default = null)
|
|
521
529
|
{
|
|
522
530
|
try {
|
|
523
|
-
$organizationValue = data_get(Setting::
|
|
531
|
+
$organizationValue = data_get(Setting::lookupForCompany($this->companyUuid ?? session('company'), 'vroom', []), $key);
|
|
524
532
|
if ($this->hasConfiguredValue($organizationValue)) {
|
|
525
533
|
return $organizationValue;
|
|
526
534
|
}
|
|
@@ -77,6 +77,7 @@ class FleetOpsServiceProvider extends CoreServiceProvider
|
|
|
77
77
|
\Fleetbase\FleetOps\Console\Commands\ProcessOperationalAlerts::class,
|
|
78
78
|
\Fleetbase\FleetOps\Console\Commands\SyncTelematics::class,
|
|
79
79
|
\Fleetbase\FleetOps\Console\Commands\DrainTelematicInbox::class,
|
|
80
|
+
\Fleetbase\FleetOps\Console\Commands\PruneTelematicsData::class,
|
|
80
81
|
];
|
|
81
82
|
|
|
82
83
|
/**
|
|
@@ -153,6 +154,8 @@ class FleetOpsServiceProvider extends CoreServiceProvider
|
|
|
153
154
|
// leave the default 24-hour overlap lease blocking telemetry recovery.
|
|
154
155
|
$schedule->command('fleetops:sync-telematics')->everyMinute()->withoutOverlapping(2)->storeOutputInDb();
|
|
155
156
|
$schedule->command('fleetops:drain-telematic-inbox')->everyMinute()->withoutOverlapping(2);
|
|
157
|
+
// Bounded batches per company and table; a capped run simply continues on the next tick.
|
|
158
|
+
$schedule->command('fleetops:prune-telematics-data')->everyFifteenMinutes()->withoutOverlapping(14)->storeOutputInDb();
|
|
156
159
|
});
|
|
157
160
|
$this->registerNotifications();
|
|
158
161
|
$this->registerAiCapabilities();
|
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Support\Analytics;
|
|
4
4
|
|
|
5
|
+
use Fleetbase\FleetOps\Http\Resources\v1\Index\Driver as DriverIndexResource;
|
|
6
|
+
use Fleetbase\FleetOps\Http\Resources\v1\Index\Vehicle as VehicleIndexResource;
|
|
5
7
|
use Fleetbase\FleetOps\Models\Driver;
|
|
6
8
|
use Fleetbase\FleetOps\Models\Order;
|
|
7
9
|
use Fleetbase\FleetOps\Models\Vehicle;
|
|
8
10
|
use Fleetbase\FleetOps\Support\Metrics\OrdersInProgressMetric;
|
|
11
|
+
use Illuminate\Http\Resources\Json\JsonResource;
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Real-time fleet snapshot used as the initial-state payload for Live Fleet Map.
|
|
@@ -23,7 +26,8 @@ class LiveFleet extends AbstractAnalytics
|
|
|
23
26
|
|
|
24
27
|
// Driver.name is a virtual attribute backed by users.name — eager-load the
|
|
25
28
|
// user so the accessor resolves cleanly without a per-record query.
|
|
26
|
-
|
|
29
|
+
// The user and vehicle also feed each marker's card (see card()).
|
|
30
|
+
$drivers = Driver::with(['user', 'vehicle'])
|
|
27
31
|
->where('drivers.company_uuid', $companyUuid)
|
|
28
32
|
->whereNotNull('drivers.location')
|
|
29
33
|
->where(function ($q) {
|
|
@@ -33,7 +37,8 @@ class LiveFleet extends AbstractAnalytics
|
|
|
33
37
|
|
|
34
38
|
// Vehicles tracked independently of drivers (telematics-connected rigs may
|
|
35
39
|
// report position without an active driver session).
|
|
36
|
-
$vehicles = Vehicle::
|
|
40
|
+
$vehicles = Vehicle::with(['devices', 'driver', 'currentTrailers'])
|
|
41
|
+
->where('company_uuid', $companyUuid)
|
|
37
42
|
->whereNotNull('location')
|
|
38
43
|
->get();
|
|
39
44
|
|
|
@@ -79,6 +84,7 @@ class LiveFleet extends AbstractAnalytics
|
|
|
79
84
|
'lat' => $lat,
|
|
80
85
|
'lng' => $lng,
|
|
81
86
|
'updated_at' => $d->last_location_update_at,
|
|
87
|
+
'card' => $this->card(new DriverIndexResource($d)),
|
|
82
88
|
];
|
|
83
89
|
}
|
|
84
90
|
|
|
@@ -98,9 +104,19 @@ class LiveFleet extends AbstractAnalytics
|
|
|
98
104
|
'heading' => (float) ($v->heading ?? 0),
|
|
99
105
|
'lat' => $lat,
|
|
100
106
|
'lng' => $lng,
|
|
107
|
+
'card' => $this->card(new VehicleIndexResource($v)),
|
|
101
108
|
];
|
|
102
109
|
}
|
|
103
110
|
|
|
111
|
+
/**
|
|
112
|
+
* What the operational live map shows in a marker's popup and tooltip: the same index
|
|
113
|
+
* resource its live endpoints return, so the dashboard widget renders identical cards.
|
|
114
|
+
*/
|
|
115
|
+
private function card(JsonResource $resource): array
|
|
116
|
+
{
|
|
117
|
+
return $resource->resolve(request());
|
|
118
|
+
}
|
|
119
|
+
|
|
104
120
|
/**
|
|
105
121
|
* Pull [lat, lng] out of whatever shape the spatial accessor handed us.
|
|
106
122
|
* Supports Point objects, [lat, lng] arrays, and {lat, lng} hashes.
|