@fleetbase/fleetops-engine 0.6.51 → 0.6.53
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 +0 -2
- package/addon/components/cell/telematic-provider.hbs +16 -0
- package/addon/components/cell/telematic-provider.js +36 -0
- package/addon/components/cell/telematic-status.hbs +1 -0
- package/addon/components/cell/telematic-status.js +39 -0
- package/addon/components/device/manager.hbs +5 -6
- package/addon/components/device/manager.js +12 -15
- package/addon/components/driver/details.hbs +1 -1
- package/addon/components/fleet/vehicle-listing.js +1 -0
- package/addon/components/fuel-integration/form.hbs +200 -0
- package/addon/components/fuel-integration/form.js +242 -0
- package/addon/components/fuel-integration/hub.hbs +154 -0
- package/addon/components/fuel-integration/hub.js +165 -0
- package/addon/components/fuel-integration/matching-priority.hbs +76 -0
- package/addon/components/fuel-integration/matching-priority.js +145 -0
- package/addon/components/fuel-report/details.hbs +13 -1
- package/addon/components/issue/details.hbs +3 -57
- package/addon/components/issue/details.js +0 -96
- package/addon/components/layout/fleet-ops-sidebar/operations-monitor.hbs +201 -0
- package/addon/components/layout/fleet-ops-sidebar/operations-monitor.js +589 -0
- package/addon/components/layout/fleet-ops-sidebar.hbs +19 -233
- package/addon/components/layout/fleet-ops-sidebar.js +287 -376
- package/addon/components/maintenance-schedule/form.js +1 -0
- package/addon/components/map/drawer/device-event-listing.hbs +12 -2
- package/addon/components/map/drawer/driver-listing.hbs +14 -1
- package/addon/components/map/drawer/place-listing.hbs +14 -1
- package/addon/components/map/drawer/position-listing.hbs +12 -2
- package/addon/components/map/drawer/vehicle-listing.hbs +14 -1
- package/addon/components/modals/assigned-orders.hbs +40 -0
- package/addon/components/modals/attach-device.hbs +4 -3
- package/addon/components/modals/attach-telematic-device.hbs +25 -0
- package/addon/components/modals/attach-telematic-device.js +3 -0
- package/addon/components/modals/driver-assign-order.hbs +7 -58
- package/addon/components/modals/driver-assign-vehicle.hbs +10 -2
- package/addon/components/modals/fleet-assign-driver.hbs +18 -0
- package/addon/components/modals/fleet-assign-driver.js +3 -0
- package/addon/components/modals/fleet-assign-vehicle.hbs +18 -0
- package/addon/components/modals/fleet-assign-vehicle.js +3 -0
- package/addon/components/modals/telematic-connection-diagnostics.hbs +75 -0
- package/addon/components/modals/telematic-connection-diagnostics.js +287 -0
- package/addon/components/modals/vehicle-details.hbs +6 -1
- package/addon/components/modals/vehicle-form.hbs +8 -1
- package/addon/components/order/card.hbs +106 -0
- package/addon/components/order/card.js +257 -0
- package/addon/components/order/form/payload.js +3 -1
- package/addon/components/order/form/service-rate.hbs +2 -0
- package/addon/components/service-rate/form.hbs +3 -2
- package/addon/components/telematic/details.hbs +98 -87
- package/addon/components/telematic/details.js +230 -1
- package/addon/components/telematic/form.hbs +303 -72
- package/addon/components/telematic/form.js +519 -3
- package/addon/components/telematic/hub.hbs +149 -0
- package/addon/components/telematic/hub.js +142 -0
- package/addon/components/telematic/settings.hbs +152 -0
- package/addon/components/telematic/settings.js +45 -0
- package/addon/components/telematic/tab-empty-state.hbs +29 -0
- package/addon/components/telematic/tab-empty-state.js +33 -0
- package/addon/components/vehicle/details.hbs +6 -1
- package/addon/components/vehicle/form.hbs +2 -1
- package/addon/components/widget/fuel-providers.hbs +43 -0
- package/addon/components/widget/fuel-providers.js +27 -0
- package/addon/controllers/connectivity/devices/index/details.js +27 -1
- package/addon/controllers/connectivity/devices/index.js +18 -1
- package/addon/controllers/connectivity/fuel-providers/details/sync.js +18 -0
- package/addon/controllers/connectivity/fuel-providers/details/transactions.js +24 -0
- package/addon/controllers/connectivity/fuel-providers/details.js +69 -0
- package/addon/controllers/connectivity/fuel-providers/edit.js +24 -0
- package/addon/controllers/connectivity/fuel-providers/index.js +177 -0
- package/addon/controllers/connectivity/fuel-providers/new.js +37 -0
- package/addon/controllers/connectivity/telematics/details/attachments.js +247 -0
- package/addon/controllers/connectivity/telematics/details/devices.js +368 -0
- package/addon/controllers/connectivity/telematics/details/events.js +244 -0
- package/addon/controllers/connectivity/telematics/details/index.js +3 -0
- package/addon/controllers/connectivity/telematics/details/logs.js +43 -0
- package/addon/controllers/connectivity/telematics/details/sensors.js +270 -0
- package/addon/controllers/connectivity/telematics/details.js +149 -0
- package/addon/controllers/connectivity/telematics/{index/edit.js → edit.js} +15 -4
- package/addon/controllers/connectivity/telematics/index.js +25 -5
- package/addon/controllers/connectivity/telematics/{index/new.js → new.js} +8 -2
- package/addon/controllers/maintenance/index.js +100 -0
- package/addon/controllers/management/drivers/index/details.js +78 -1
- package/addon/controllers/management/drivers/index.js +39 -0
- package/addon/controllers/management/fleets/index/details.js +23 -1
- package/addon/controllers/management/fleets/index.js +6 -1
- package/addon/controllers/management/fuel-reports/index.js +37 -1
- package/addon/controllers/management/fuel-transactions/index/details.js +70 -0
- package/addon/controllers/management/fuel-transactions/index.js +240 -0
- package/addon/controllers/management/index.js +88 -0
- package/addon/controllers/management/vehicles/index/details.js +32 -0
- package/addon/controllers/management/vehicles/index.js +26 -0
- package/addon/controllers/operations/orders/index.js +4 -0
- package/addon/controllers/settings/index.js +142 -0
- package/addon/controllers/settings/payments/index.js +5 -0
- package/addon/extension.js +31 -0
- package/addon/routes/analytics/index.js +3 -0
- package/addon/routes/connectivity/devices/index.js +3 -0
- package/addon/routes/connectivity/fuel-providers/details/index.js +7 -0
- package/addon/routes/connectivity/fuel-providers/details/matching.js +7 -0
- package/addon/routes/connectivity/fuel-providers/details/settings.js +7 -0
- package/addon/routes/connectivity/fuel-providers/details/sync.js +18 -0
- package/addon/routes/connectivity/fuel-providers/details/transactions.js +14 -0
- package/addon/routes/connectivity/fuel-providers/details.js +18 -0
- package/addon/routes/connectivity/fuel-providers/edit.js +18 -0
- package/addon/routes/connectivity/fuel-providers/index.js +20 -0
- package/addon/routes/connectivity/fuel-providers/new.js +3 -0
- package/addon/routes/connectivity/fuel-providers.js +3 -0
- package/addon/routes/connectivity/telematics/details/attachments.js +28 -0
- package/addon/routes/connectivity/telematics/details/devices.js +30 -0
- package/addon/routes/connectivity/telematics/details/events.js +33 -0
- package/addon/routes/connectivity/telematics/details/index.js +3 -0
- package/addon/routes/connectivity/telematics/details/logs.js +17 -0
- package/addon/routes/connectivity/telematics/details/sensors.js +29 -0
- package/addon/routes/connectivity/telematics/{index/details.js → details.js} +1 -1
- package/addon/routes/connectivity/telematics/{index/edit.js → edit.js} +1 -1
- package/addon/routes/connectivity/telematics/new.js +3 -0
- package/addon/routes/maintenance/index.js +3 -0
- package/addon/routes/maintenance/work-orders/index.js +2 -0
- package/addon/routes/management/drivers/index/details/activity.js +3 -0
- package/addon/routes/management/fuel-reports/index.js +2 -0
- package/addon/routes/management/fuel-transactions/index/details.js +18 -0
- package/addon/routes/management/fuel-transactions/index.js +21 -0
- package/addon/routes/management/fuel-transactions.js +3 -0
- package/addon/routes/settings/index.js +3 -0
- package/addon/routes.js +28 -9
- package/addon/services/device-actions.js +64 -1
- package/addon/services/device-event-actions.js +12 -1
- package/addon/services/driver-actions.js +147 -11
- package/addon/services/fleet-actions.js +66 -1
- package/addon/services/fuel-integration-actions.js +31 -0
- package/addon/services/issue-actions.js +1 -1
- package/addon/services/telematic-actions.js +9 -3
- package/addon/services/vehicle-actions.js +125 -0
- package/addon/styles/fleetops-engine.css +2237 -162
- package/addon/templates/analytics/index.hbs +14 -0
- package/addon/templates/analytics/reports/index.hbs +19 -1
- package/addon/templates/connectivity/devices/index.hbs +19 -1
- package/addon/templates/connectivity/events/index.hbs +16 -1
- package/addon/templates/connectivity/fuel-providers/details/index.hbs +38 -0
- package/addon/templates/connectivity/fuel-providers/details/matching.hbs +13 -0
- package/addon/templates/connectivity/fuel-providers/details/settings.hbs +11 -0
- package/addon/templates/connectivity/fuel-providers/details/sync.hbs +48 -0
- package/addon/templates/connectivity/fuel-providers/details/transactions.hbs +21 -0
- package/addon/templates/connectivity/fuel-providers/details.hbs +51 -0
- package/addon/templates/connectivity/fuel-providers/edit.hbs +24 -0
- package/addon/templates/connectivity/fuel-providers/index.hbs +12 -0
- package/addon/templates/connectivity/fuel-providers/new.hbs +22 -0
- package/addon/templates/connectivity/fuel-providers.hbs +1 -0
- package/addon/templates/connectivity/sensors/index.hbs +19 -1
- package/addon/templates/connectivity/telematics/details/attachments.hbs +163 -0
- package/addon/templates/connectivity/telematics/details/devices.hbs +88 -0
- package/addon/templates/connectivity/telematics/details/events.hbs +101 -0
- package/addon/templates/connectivity/telematics/{index/details → details}/index.hbs +0 -1
- package/addon/templates/connectivity/telematics/details/logs.hbs +69 -0
- package/addon/templates/connectivity/telematics/details/sensors.hbs +88 -0
- package/addon/templates/connectivity/telematics/details.hbs +53 -0
- package/addon/templates/connectivity/telematics/edit.hbs +27 -0
- package/addon/templates/connectivity/telematics/index.hbs +6 -8
- package/addon/templates/connectivity/telematics/new.hbs +24 -0
- package/addon/templates/maintenance/equipment/index.hbs +19 -1
- package/addon/templates/maintenance/index.hbs +113 -0
- package/addon/templates/maintenance/maintenances/index.hbs +15 -1
- package/addon/templates/maintenance/parts/index.hbs +19 -1
- package/addon/templates/maintenance/schedules/index.hbs +19 -1
- package/addon/templates/maintenance/work-orders/index.hbs +19 -1
- package/addon/templates/management/contacts/customers.hbs +15 -1
- package/addon/templates/management/contacts/index.hbs +19 -1
- package/addon/templates/management/drivers/index/details/activity.hbs +1 -0
- package/addon/templates/management/drivers/index.hbs +19 -1
- package/addon/templates/management/fleets/index.hbs +19 -1
- package/addon/templates/management/fuel-reports/index.hbs +19 -1
- package/addon/templates/management/fuel-transactions/index/details.hbs +73 -0
- package/addon/templates/management/fuel-transactions/index.hbs +58 -0
- package/addon/templates/management/fuel-transactions.hbs +1 -0
- package/addon/templates/management/index.hbs +109 -73
- package/addon/templates/management/issues/index.hbs +19 -1
- package/addon/templates/management/places/index.hbs +19 -1
- package/addon/templates/management/vehicles/index.hbs +19 -1
- package/addon/templates/management/vendors/index.hbs +19 -1
- package/addon/templates/management/vendors/integrated.hbs +13 -1
- package/addon/templates/operations/orders/index.hbs +19 -1
- package/addon/templates/operations/service-rates/index.hbs +19 -1
- package/addon/templates/settings/index.hbs +83 -0
- package/addon/templates/settings/payments/index.hbs +15 -1
- package/addon/templates/settings/routing.hbs +2 -2
- package/addon/utils/fleet-ops-options.js +3 -0
- package/app/components/cell/telematic-provider.js +1 -0
- package/app/components/cell/telematic-status.js +1 -0
- package/app/components/fuel-integration/form.js +1 -0
- package/app/components/fuel-integration/hub.js +1 -0
- package/app/components/fuel-integration/matching-priority.js +1 -0
- package/app/components/modals/assigned-orders.js +1 -0
- package/app/components/modals/attach-telematic-device.js +1 -0
- package/app/components/modals/fleet-assign-driver.js +1 -0
- package/app/components/modals/fleet-assign-vehicle.js +1 -0
- package/app/components/modals/telematic-connection-diagnostics.js +1 -0
- package/app/components/order/card.js +1 -0
- package/app/components/telematic/hub.js +1 -0
- package/app/components/telematic/settings.js +1 -0
- package/app/components/telematic/tab-empty-state.js +1 -0
- package/app/components/widget/fuel-providers.js +1 -0
- package/app/controllers/connectivity/fuel-providers/details/sync.js +1 -0
- package/app/controllers/connectivity/{telematics/index/details/devices.js → fuel-providers/details/transactions.js} +1 -1
- package/app/controllers/connectivity/{telematics/index → fuel-providers}/details.js +1 -1
- package/app/controllers/connectivity/{telematics/index → fuel-providers}/edit.js +1 -1
- package/app/controllers/connectivity/{telematics/index/details → fuel-providers}/index.js +1 -1
- package/app/controllers/connectivity/{telematics/index → fuel-providers}/new.js +1 -1
- package/app/controllers/connectivity/telematics/details/attachments.js +1 -0
- package/app/controllers/connectivity/telematics/details/devices.js +1 -0
- package/app/controllers/connectivity/telematics/details/events.js +1 -0
- package/app/controllers/connectivity/telematics/details/index.js +1 -0
- package/app/controllers/connectivity/telematics/details/logs.js +1 -0
- package/app/controllers/connectivity/telematics/details/sensors.js +1 -0
- package/app/controllers/connectivity/telematics/details.js +1 -0
- package/app/controllers/connectivity/telematics/edit.js +1 -0
- package/app/controllers/connectivity/telematics/new.js +1 -0
- package/app/controllers/maintenance/index.js +1 -0
- package/app/controllers/management/fuel-transactions/index/details.js +1 -0
- package/app/controllers/management/fuel-transactions/index.js +1 -0
- package/app/controllers/management/index.js +1 -0
- package/app/controllers/settings/index.js +1 -0
- package/app/routes/analytics/index.js +1 -0
- package/app/routes/connectivity/{telematics/index → fuel-providers}/details/index.js +1 -1
- package/app/routes/connectivity/{telematics/index/details/events.js → fuel-providers/details/matching.js} +1 -1
- package/app/routes/connectivity/fuel-providers/details/settings.js +1 -0
- package/app/routes/connectivity/fuel-providers/details/sync.js +1 -0
- package/app/routes/connectivity/{telematics/index/details/devices.js → fuel-providers/details/transactions.js} +1 -1
- package/app/routes/connectivity/{telematics/index → fuel-providers}/details.js +1 -1
- package/app/routes/connectivity/{telematics/index → fuel-providers}/edit.js +1 -1
- package/app/routes/connectivity/fuel-providers/index.js +1 -0
- package/app/routes/connectivity/{telematics/index → fuel-providers}/new.js +1 -1
- package/app/routes/connectivity/fuel-providers.js +1 -0
- package/app/routes/connectivity/telematics/details/attachments.js +1 -0
- package/app/routes/connectivity/telematics/details/devices.js +1 -0
- package/app/routes/connectivity/telematics/details/events.js +1 -0
- package/app/routes/connectivity/telematics/details/index.js +1 -0
- package/app/routes/connectivity/telematics/details/logs.js +1 -0
- package/app/routes/connectivity/telematics/details/sensors.js +1 -0
- package/app/routes/connectivity/telematics/details.js +1 -0
- package/app/routes/connectivity/telematics/edit.js +1 -0
- package/app/routes/connectivity/telematics/new.js +1 -0
- package/app/routes/maintenance/index.js +1 -0
- package/app/routes/management/drivers/index/details/activity.js +1 -0
- package/app/routes/management/fuel-transactions/index/details.js +1 -0
- package/app/routes/management/fuel-transactions/index.js +1 -0
- package/app/routes/management/fuel-transactions.js +1 -0
- package/app/routes/settings/index.js +1 -0
- package/app/services/fuel-integration-actions.js +1 -0
- package/app/templates/analytics/index.js +1 -0
- package/app/templates/connectivity/{telematics/index → fuel-providers}/details/index.js +1 -1
- package/app/templates/connectivity/{telematics/index/details/events.js → fuel-providers/details/matching.js} +1 -1
- package/app/templates/connectivity/fuel-providers/details/settings.js +1 -0
- package/app/templates/connectivity/fuel-providers/details/sync.js +1 -0
- package/app/templates/connectivity/{telematics/index/details/devices.js → fuel-providers/details/transactions.js} +1 -1
- package/app/templates/connectivity/{telematics/index → fuel-providers}/details.js +1 -1
- package/app/templates/connectivity/{telematics/index → fuel-providers}/edit.js +1 -1
- package/app/templates/connectivity/fuel-providers/index.js +1 -0
- package/app/templates/connectivity/{telematics/index → fuel-providers}/new.js +1 -1
- package/app/templates/connectivity/fuel-providers.js +1 -0
- package/app/templates/connectivity/telematics/details/attachments.js +1 -0
- package/app/templates/connectivity/telematics/details/devices.js +1 -0
- package/app/templates/connectivity/telematics/details/events.js +1 -0
- package/app/templates/connectivity/telematics/details/index.js +1 -0
- package/app/templates/connectivity/telematics/details/logs.js +1 -0
- package/app/templates/connectivity/telematics/details/sensors.js +1 -0
- package/app/templates/connectivity/telematics/details.js +1 -0
- package/app/templates/connectivity/telematics/edit.js +1 -0
- package/app/templates/connectivity/telematics/new.js +1 -0
- package/app/templates/maintenance/index.js +1 -0
- package/app/templates/management/drivers/index/details/activity.js +1 -0
- package/app/templates/management/fuel-transactions/index/details.js +1 -0
- package/app/templates/management/fuel-transactions/index.js +1 -0
- package/app/templates/management/fuel-transactions.js +1 -0
- package/app/templates/management/index.js +1 -0
- package/app/templates/settings/index.js +1 -0
- package/assets/images/telematics/providers/afaqy.webp +0 -0
- package/assets/images/telematics/providers/default.webp +0 -0
- package/assets/images/telematics/providers/flespi.webp +0 -0
- package/assets/images/telematics/providers/geotab.webp +0 -0
- package/assets/images/telematics/providers/safee.webp +0 -0
- package/assets/images/telematics/providers/samsara.webp +0 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +4 -4
- package/server/config/fuel-providers.php +42 -0
- package/server/config/telematics.php +139 -130
- package/server/migrations/2026_06_06_000001_harden_device_events_telematics_contract.php +59 -0
- package/server/migrations/2026_06_08_000001_create_fuel_provider_connections_table.php +37 -0
- package/server/migrations/2026_06_08_000002_create_fuel_provider_transactions_table.php +53 -0
- package/server/migrations/2026_06_08_000003_create_fuel_provider_sync_runs_table.php +40 -0
- package/server/migrations/2026_06_10_000001_add_fuel_card_number_to_vehicles_table.php +25 -0
- package/server/migrations/2026_06_10_000002_add_vehicle_identity_columns_to_fuel_provider_transactions_table.php +39 -0
- package/server/migrations/2026_06_15_000001_normalize_device_attachable_vehicle_morph_types.php +30 -0
- package/server/src/Console/Commands/FixInvalidPolymorphicRelationTypeNamespaces.php +1 -0
- package/server/src/Contracts/FuelProvider.php +30 -0
- package/server/src/Contracts/TelematicProviderDescriptor.php +3 -1
- package/server/src/Events/FuelProviderTransactionImported.php +17 -0
- package/server/src/Events/FuelProviderTransactionMatched.php +17 -0
- package/server/src/Events/FuelProviderTransactionUnmatched.php +17 -0
- package/server/src/Events/FuelReportCreatedFromProvider.php +18 -0
- package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +6 -0
- package/server/src/Http/Controllers/Internal/v1/DeviceController.php +140 -2
- package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +44 -0
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +158 -7
- package/server/src/Http/Controllers/Internal/v1/FuelProviderConnectionController.php +124 -0
- package/server/src/Http/Controllers/Internal/v1/FuelProviderSyncRunController.php +10 -0
- package/server/src/Http/Controllers/Internal/v1/FuelProviderTransactionController.php +76 -0
- package/server/src/Http/Controllers/Internal/v1/HubController.php +300 -0
- package/server/src/Http/Controllers/Internal/v1/SearchController.php +506 -0
- package/server/src/Http/Controllers/Internal/v1/SensorController.php +1 -1
- package/server/src/Http/Controllers/Internal/v1/TelematicController.php +179 -16
- package/server/src/Http/Controllers/Internal/v1/VehicleController.php +249 -0
- package/server/src/Http/Controllers/TelematicWebhookController.php +103 -19
- package/server/src/Http/Filter/DeviceFilter.php +74 -0
- package/server/src/Http/Filter/DriverFilter.php +6 -0
- package/server/src/Http/Filter/FuelProviderConnectionFilter.php +33 -0
- package/server/src/Http/Filter/FuelProviderSyncRunFilter.php +28 -0
- package/server/src/Http/Filter/FuelProviderTransactionFilter.php +59 -0
- package/server/src/Http/Filter/FuelReportFilter.php +10 -0
- package/server/src/Http/Filter/VehicleFilter.php +6 -0
- package/server/src/Http/Resources/v1/Driver.php +15 -0
- package/server/src/Http/Resources/v1/FuelProviderConnection.php +30 -0
- package/server/src/Http/Resources/v1/FuelProviderSyncRun.php +36 -0
- package/server/src/Http/Resources/v1/FuelProviderTransaction.php +54 -0
- package/server/src/Http/Resources/v1/FuelReport.php +28 -22
- package/server/src/Http/Resources/v1/Index/Driver.php +26 -20
- package/server/src/Http/Resources/v1/Index/Vehicle.php +29 -22
- package/server/src/Http/Resources/v1/Vehicle.php +17 -0
- package/server/src/Http/Resources/v1/VehicleWithoutDriver.php +2 -0
- package/server/src/Jobs/SyncFuelProviderTransactionsJob.php +57 -0
- package/server/src/Jobs/SyncTelematicDevicesJob.php +105 -17
- package/server/src/Jobs/TestTelematicConnectionJob.php +9 -22
- package/server/src/Models/Asset.php +2 -1
- package/server/src/Models/Contact.php +2 -1
- package/server/src/Models/Device.php +27 -4
- package/server/src/Models/DeviceEvent.php +40 -3
- package/server/src/Models/Driver.php +3 -2
- package/server/src/Models/Equipment.php +2 -1
- package/server/src/Models/Fleet.php +2 -1
- package/server/src/Models/FuelProviderConnection.php +60 -0
- package/server/src/Models/FuelProviderSyncRun.php +58 -0
- package/server/src/Models/FuelProviderTransaction.php +119 -0
- package/server/src/Models/FuelReport.php +16 -1
- package/server/src/Models/Part.php +2 -1
- package/server/src/Models/Sensor.php +21 -4
- package/server/src/Models/ServiceRate.php +39 -2
- package/server/src/Models/Vehicle.php +14 -2
- package/server/src/Models/Vendor.php +2 -1
- package/server/src/Providers/FleetOpsServiceProvider.php +20 -0
- package/server/src/Support/Analytics/FuelProviderSummary.php +42 -0
- package/server/src/Support/FuelProviders/FuelProviderDescriptor.php +55 -0
- package/server/src/Support/FuelProviders/FuelProviderRegistry.php +75 -0
- package/server/src/Support/FuelProviders/FuelProviderService.php +447 -0
- package/server/src/Support/FuelProviders/Providers/AbstractFuelProvider.php +98 -0
- package/server/src/Support/FuelProviders/Providers/PetroAppFuelProvider.php +167 -0
- package/server/src/Support/Telematics/Providers/AbstractProvider.php +27 -6
- package/server/src/Support/Telematics/Providers/AfaqyProvider.php +105 -38
- package/server/src/Support/Telematics/Providers/FlespiProvider.php +1 -0
- package/server/src/Support/Telematics/Providers/GeotabProvider.php +1 -0
- package/server/src/Support/Telematics/Providers/SafeeProvider.php +32 -22
- package/server/src/Support/Telematics/Providers/SamsaraProvider.php +3 -1
- package/server/src/Support/Telematics/TelematicService.php +340 -21
- package/server/src/routes.php +50 -4
- package/server/tests/FuelProviderRegistryTest.php +416 -0
- package/server/tests/HubRoutesTest.php +62 -0
- package/server/tests/ServiceRateAlgorithmWeightVariablesTest.php +44 -0
- package/server/tests/TelematicsHardeningTest.php +359 -0
- package/server/tests/VehicleDriverAssignmentTest.php +51 -0
- package/translations/ar-ae.yml +23 -1
- package/translations/bg-bg.yaml +72 -0
- package/translations/en-us.yaml +83 -0
- package/translations/es-pa.yaml +72 -0
- package/translations/fr-fr.yaml +72 -0
- package/translations/mn-mn.yaml +72 -0
- package/translations/pt-br.yaml +72 -0
- package/translations/ru-ru.yaml +72 -0
- package/translations/vi-vn.yaml +98 -1
- package/addon/controllers/connectivity/telematics/index/details/devices.js +0 -3
- package/addon/controllers/connectivity/telematics/index/details/events.js +0 -3
- package/addon/controllers/connectivity/telematics/index/details/index.js +0 -3
- package/addon/controllers/connectivity/telematics/index/details/sensors.js +0 -3
- package/addon/controllers/connectivity/telematics/index/details.js +0 -24
- package/addon/routes/connectivity/telematics/index/details/devices.js +0 -3
- package/addon/routes/connectivity/telematics/index/details/events.js +0 -3
- package/addon/routes/connectivity/telematics/index/details/index.js +0 -3
- package/addon/routes/connectivity/telematics/index/details/sensors.js +0 -3
- package/addon/routes/connectivity/telematics/index/new.js +0 -3
- package/addon/templates/connectivity/telematics/index/details/devices.hbs +0 -1
- package/addon/templates/connectivity/telematics/index/details/events.hbs +0 -1
- package/addon/templates/connectivity/telematics/index/details/sensors.hbs +0 -1
- package/addon/templates/connectivity/telematics/index/details.hbs +0 -14
- package/addon/templates/connectivity/telematics/index/edit.hbs +0 -12
- package/addon/templates/connectivity/telematics/index/new.hbs +0 -12
- package/app/controllers/connectivity/telematics/index/details/events.js +0 -1
- package/app/controllers/connectivity/telematics/index/details/sensors.js +0 -1
- package/app/routes/connectivity/telematics/index/details/sensors.js +0 -1
- package/app/templates/connectivity/telematics/index/details/sensors.js +0 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
|
|
6
|
+
use Fleetbase\FleetOps\Jobs\SyncFuelProviderTransactionsJob;
|
|
7
|
+
use Fleetbase\FleetOps\Models\FuelProviderConnection;
|
|
8
|
+
use Fleetbase\FleetOps\Support\FuelProviders\FuelProviderService;
|
|
9
|
+
use Illuminate\Http\JsonResponse;
|
|
10
|
+
use Illuminate\Http\Request;
|
|
11
|
+
use Illuminate\Support\Carbon;
|
|
12
|
+
use Illuminate\Validation\ValidationException;
|
|
13
|
+
|
|
14
|
+
class FuelProviderConnectionController extends FleetOpsController
|
|
15
|
+
{
|
|
16
|
+
public $resource = 'fuel_provider_connection';
|
|
17
|
+
|
|
18
|
+
public function __construct(protected FuelProviderService $fuelProviderService)
|
|
19
|
+
{
|
|
20
|
+
parent::__construct();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public function providers(): JsonResponse
|
|
24
|
+
{
|
|
25
|
+
return response()->json($this->fuelProviderService->providers());
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public function onBeforeCreate(Request $request, array &$input)
|
|
29
|
+
{
|
|
30
|
+
$this->validateConnectionInput($input);
|
|
31
|
+
$this->normalizeConnectionInput($input);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public function onBeforeUpdate(Request $request, FuelProviderConnection $connection, array &$input)
|
|
35
|
+
{
|
|
36
|
+
$candidate = array_merge($connection->toArray(), $input);
|
|
37
|
+
$this->validateConnectionInput($candidate, $connection);
|
|
38
|
+
$this->normalizeConnectionInput($input, $connection);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public function testCredentials(Request $request, string $provider): JsonResponse
|
|
42
|
+
{
|
|
43
|
+
$request->validate([
|
|
44
|
+
'credentials' => 'required|array',
|
|
45
|
+
'environment' => 'nullable|string|in:production,sandbox',
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
$result = $this->fuelProviderService->testCredentials(
|
|
49
|
+
$provider,
|
|
50
|
+
$request->array('credentials'),
|
|
51
|
+
$request->input('environment', 'production')
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
return response()->json($result, data_get($result, 'success') ? 200 : 422);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public function testConnection(Request $request, string $id): JsonResponse
|
|
58
|
+
{
|
|
59
|
+
$connection = $this->findConnection($id);
|
|
60
|
+
$result = $this->fuelProviderService->testConnection($connection);
|
|
61
|
+
|
|
62
|
+
return response()->json($result, data_get($result, 'success') ? 200 : 422);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public function sync(Request $request, string $id): JsonResponse
|
|
66
|
+
{
|
|
67
|
+
$connection = $this->findConnection($id);
|
|
68
|
+
$async = $request->boolean('async', true);
|
|
69
|
+
$from = $request->input('from') ? Carbon::parse($request->input('from')) : null;
|
|
70
|
+
$to = $request->input('to') ? Carbon::parse($request->input('to')) : null;
|
|
71
|
+
$options = $request->array('options', []);
|
|
72
|
+
$syncRun = $this->fuelProviderService->createSyncRun($connection, $from, $to, $async ? 'queued' : 'running');
|
|
73
|
+
|
|
74
|
+
if ($async) {
|
|
75
|
+
SyncFuelProviderTransactionsJob::dispatch($connection->uuid, $from?->toIso8601String(), $to?->toIso8601String(), $options, $syncRun->uuid);
|
|
76
|
+
|
|
77
|
+
return response()->json(['status' => 'ok', 'message' => 'Fuel provider sync queued.', 'sync_run' => $syncRun], 202);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
$summary = $this->fuelProviderService->syncTransactions($connection, $from, $to, $options, $syncRun);
|
|
81
|
+
|
|
82
|
+
return response()->json(['status' => 'ok', 'summary' => $summary, 'sync_run' => $syncRun->fresh()]);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
protected function validateConnectionInput(array $input, ?FuelProviderConnection $connection = null): void
|
|
86
|
+
{
|
|
87
|
+
$provider = data_get($input, 'provider');
|
|
88
|
+
if (!$provider) {
|
|
89
|
+
throw ValidationException::withMessages(['provider' => 'Fuel integration provider is required.']);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
$descriptor = $this->fuelProviderService->providers()->firstWhere('key', $provider);
|
|
93
|
+
if (!$descriptor) {
|
|
94
|
+
throw ValidationException::withMessages(['provider' => 'Fuel integration provider is not registered.']);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
foreach ((array) data_get($descriptor, 'required_fields', []) as $field) {
|
|
98
|
+
if (data_get($field, 'required') && blank(data_get($input, 'credentials.' . data_get($field, 'name')))) {
|
|
99
|
+
throw ValidationException::withMessages(['credentials.' . data_get($field, 'name') => data_get($field, 'label', data_get($field, 'name')) . ' is required.']);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
protected function normalizeConnectionInput(array &$input, ?FuelProviderConnection $connection = null): void
|
|
105
|
+
{
|
|
106
|
+
$input['company_uuid'] ??= session('company');
|
|
107
|
+
$input['environment'] ??= 'production';
|
|
108
|
+
$input['status'] = $connection?->status && $connection->status !== 'draft' ? $connection->status : ($input['status'] ?? 'configured');
|
|
109
|
+
$input['sync_settings'] = array_merge([
|
|
110
|
+
'window_days' => 7,
|
|
111
|
+
'matching_order' => ['plate_number', 'internal_id', 'vin', 'serial_number', 'call_sign', 'fuel_card_number', 'trip_number'],
|
|
112
|
+
'auto_create_fuel_reports' => true,
|
|
113
|
+
], (array) data_get($input, 'sync_settings', []));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
protected function findConnection(string $id): FuelProviderConnection
|
|
117
|
+
{
|
|
118
|
+
return FuelProviderConnection::where(function ($query) use ($id) {
|
|
119
|
+
$query->where('uuid', $id)->orWhere('public_id', $id);
|
|
120
|
+
})
|
|
121
|
+
->where('company_uuid', session('company'))
|
|
122
|
+
->firstOrFail();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
|
|
6
|
+
use Fleetbase\FleetOps\Models\FuelProviderTransaction;
|
|
7
|
+
use Fleetbase\FleetOps\Support\FuelProviders\FuelProviderService;
|
|
8
|
+
use Illuminate\Http\JsonResponse;
|
|
9
|
+
use Illuminate\Http\Request;
|
|
10
|
+
|
|
11
|
+
class FuelProviderTransactionController extends FleetOpsController
|
|
12
|
+
{
|
|
13
|
+
public $resource = 'fuel_provider_transaction';
|
|
14
|
+
|
|
15
|
+
public function __construct(protected FuelProviderService $fuelProviderService)
|
|
16
|
+
{
|
|
17
|
+
parent::__construct();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public static function onQueryRecord($query, $request): void
|
|
21
|
+
{
|
|
22
|
+
$query->with(['vehicle', 'driver', 'fuelReport']);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public function matchVehicle(Request $request, string $id): JsonResponse
|
|
26
|
+
{
|
|
27
|
+
$request->validate(['vehicle' => 'required|string']);
|
|
28
|
+
$transaction = $this->findTransaction($id);
|
|
29
|
+
|
|
30
|
+
return response()->json([
|
|
31
|
+
'status' => 'ok',
|
|
32
|
+
'transaction' => $this->fuelProviderService->matchVehicle($transaction, $request->input('vehicle')),
|
|
33
|
+
]);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public function matchOrder(Request $request, string $id): JsonResponse
|
|
37
|
+
{
|
|
38
|
+
$request->validate(['order' => 'required|string']);
|
|
39
|
+
$transaction = $this->findTransaction($id);
|
|
40
|
+
|
|
41
|
+
return response()->json([
|
|
42
|
+
'status' => 'ok',
|
|
43
|
+
'transaction' => $this->fuelProviderService->matchOrder($transaction, $request->input('order')),
|
|
44
|
+
]);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public function reprocess(Request $request, string $id): JsonResponse
|
|
48
|
+
{
|
|
49
|
+
$transaction = $this->findTransaction($id);
|
|
50
|
+
|
|
51
|
+
return response()->json([
|
|
52
|
+
'status' => 'ok',
|
|
53
|
+
'transaction' => $this->fuelProviderService->reprocessTransaction($transaction),
|
|
54
|
+
]);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public function review(Request $request, string $id): JsonResponse
|
|
58
|
+
{
|
|
59
|
+
$request->validate(['status' => 'required|string|in:reviewed,ignored']);
|
|
60
|
+
$transaction = $this->findTransaction($id);
|
|
61
|
+
|
|
62
|
+
return response()->json([
|
|
63
|
+
'status' => 'ok',
|
|
64
|
+
'transaction' => $this->fuelProviderService->reviewTransaction($transaction, $request->input('status')),
|
|
65
|
+
]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
protected function findTransaction(string $id): FuelProviderTransaction
|
|
69
|
+
{
|
|
70
|
+
return FuelProviderTransaction::where(function ($query) use ($id) {
|
|
71
|
+
$query->where('uuid', $id)->orWhere('public_id', $id);
|
|
72
|
+
})
|
|
73
|
+
->where('company_uuid', session('company'))
|
|
74
|
+
->firstOrFail();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\FleetOps\Models\Contact;
|
|
6
|
+
use Fleetbase\FleetOps\Models\Device;
|
|
7
|
+
use Fleetbase\FleetOps\Models\Driver;
|
|
8
|
+
use Fleetbase\FleetOps\Models\Equipment;
|
|
9
|
+
use Fleetbase\FleetOps\Models\Fleet;
|
|
10
|
+
use Fleetbase\FleetOps\Models\FuelProviderTransaction;
|
|
11
|
+
use Fleetbase\FleetOps\Models\FuelReport;
|
|
12
|
+
use Fleetbase\FleetOps\Models\Issue;
|
|
13
|
+
use Fleetbase\FleetOps\Models\Maintenance;
|
|
14
|
+
use Fleetbase\FleetOps\Models\MaintenanceSchedule;
|
|
15
|
+
use Fleetbase\FleetOps\Models\Part;
|
|
16
|
+
use Fleetbase\FleetOps\Models\Place;
|
|
17
|
+
use Fleetbase\FleetOps\Models\Vehicle;
|
|
18
|
+
use Fleetbase\FleetOps\Models\Vendor;
|
|
19
|
+
use Fleetbase\FleetOps\Models\WorkOrder;
|
|
20
|
+
use Fleetbase\Http\Controllers\Controller;
|
|
21
|
+
use Illuminate\Database\Eloquent\Builder;
|
|
22
|
+
use Illuminate\Http\Request;
|
|
23
|
+
use Illuminate\Support\Carbon;
|
|
24
|
+
|
|
25
|
+
class HubController extends Controller
|
|
26
|
+
{
|
|
27
|
+
public function resources(Request $request)
|
|
28
|
+
{
|
|
29
|
+
$company = $this->companyUuid($request);
|
|
30
|
+
|
|
31
|
+
$counts = [
|
|
32
|
+
'drivers' => $this->count(Driver::query(), $company),
|
|
33
|
+
'vehicles' => $this->count(Vehicle::query(), $company),
|
|
34
|
+
'fleets' => $this->count(Fleet::query()->whereNull('parent_fleet_uuid'), $company),
|
|
35
|
+
'vendors' => $this->count(Vendor::query(), $company),
|
|
36
|
+
'contacts' => $this->count(Contact::query(), $company),
|
|
37
|
+
'places' => $this->count(Place::query(), $company),
|
|
38
|
+
'issues' => $this->count(Issue::query()->whereNotIn('status', ['resolved', 'closed']), $company),
|
|
39
|
+
'drivers_without_vehicles' => $this->count(Driver::query()->whereNull('vehicle_uuid'), $company),
|
|
40
|
+
'vehicles_without_drivers' => $this->count(Vehicle::query()->whereDoesntHave('driver'), $company),
|
|
41
|
+
'vehicles_without_devices' => $this->count(Vehicle::query()->whereDoesntHave('devices'), $company),
|
|
42
|
+
'unattached_devices' => $this->count(Device::query()->whereNull('attachable_uuid'), $company),
|
|
43
|
+
'resource_issues' => $this->count(Issue::query()->whereNotIn('status', ['resolved', 'closed'])->where(function ($query) {
|
|
44
|
+
$query->whereNotNull('vehicle_uuid')->orWhereNotNull('driver_uuid');
|
|
45
|
+
}), $company),
|
|
46
|
+
'overdue_vehicle_schedules' => $this->count(MaintenanceSchedule::query()->where('subject_type', Vehicle::class)->where('status', 'active')->whereNotNull('next_due_date')->where('next_due_date', '<', Carbon::now()), $company),
|
|
47
|
+
'upcoming_vehicle_schedules' => $this->count(MaintenanceSchedule::query()->where('subject_type', Vehicle::class)->where('status', 'active')->whereBetween('next_due_date', [Carbon::now(), Carbon::now()->addDays(7)]), $company),
|
|
48
|
+
'open_resource_work_orders' => $this->count(WorkOrder::query()->whereIn('target_type', [Vehicle::class, Equipment::class])->whereIn('status', ['open', 'in_progress']), $company),
|
|
49
|
+
'overdue_resource_work_orders' => $this->count(WorkOrder::query()->whereIn('target_type', [Vehicle::class, Equipment::class])->whereNotIn('status', ['closed', 'canceled'])->whereNotNull('due_at')->where('due_at', '<', Carbon::now()), $company),
|
|
50
|
+
'low_stock_parts' => $this->count(Part::query()->where('quantity_on_hand', '>', 0)->where('quantity_on_hand', '<=', 5), $company),
|
|
51
|
+
'unmatched_fuel_transactions' => $this->count(FuelProviderTransaction::query()->where('sync_status', 'unmatched'), $company),
|
|
52
|
+
'fuel_reports' => $this->count(FuelReport::query(), $company),
|
|
53
|
+
'fuel_transactions' => $this->count(FuelProviderTransaction::query(), $company),
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
$fuelRecords = $counts['fuel_reports'] + $counts['fuel_transactions'];
|
|
57
|
+
|
|
58
|
+
return response()->json([
|
|
59
|
+
'kpis' => [
|
|
60
|
+
$this->kpi('drivers', 'Drivers', $counts['drivers'], $counts['drivers'] > 0 ? 'Driver profiles available for dispatch.' : 'Add driver profiles before dispatching work.', 'blue', 'id-card', 'management.drivers'),
|
|
61
|
+
$this->kpi('vehicles', 'Vehicles', $counts['vehicles'], $counts['vehicles'] > 0 ? 'Vehicles ready for assignment and tracking.' : 'Add vehicles so dispatch has assignable assets.', 'green', 'truck', 'management.vehicles'),
|
|
62
|
+
$this->kpi('issues', 'Open Issues', $counts['issues'], $counts['issues'] > 0 ? 'Issues need review before they affect service quality.' : 'No open issues are visible right now.', $counts['issues'] > 0 ? 'rose' : 'green', 'triangle-exclamation', 'management.issues'),
|
|
63
|
+
$this->kpi('fuel_records', 'Fuel Records', $fuelRecords, $fuelRecords > 0 ? 'Fuel activity is available for review.' : 'Fuel records will appear as reports or transactions arrive.', 'amber', 'gas-pump', $counts['fuel_transactions'] > $counts['fuel_reports'] ? 'management.fuel-transactions' : 'management.fuel-reports'),
|
|
64
|
+
],
|
|
65
|
+
'actions' => $this->resourceActions($counts, $fuelRecords),
|
|
66
|
+
'sections' => [
|
|
67
|
+
[
|
|
68
|
+
'key' => 'people_assets',
|
|
69
|
+
'title' => 'People And Assets',
|
|
70
|
+
'description' => 'Keep dispatchable drivers, vehicles, and fleet groupings ready for live work.',
|
|
71
|
+
'links' => [
|
|
72
|
+
$this->link('Drivers', 'management.drivers', 'id-card', $counts['drivers'], 'Manage driver profiles, assignments, and schedules.'),
|
|
73
|
+
$this->link('Vehicles', 'management.vehicles', 'truck', $counts['vehicles'], 'Track vehicles, device links, equipment, and service context.'),
|
|
74
|
+
$this->link('Fleets', 'management.fleets', 'user-group', $counts['fleets'], 'Group drivers and vehicles by team, region, or service type.'),
|
|
75
|
+
],
|
|
76
|
+
],
|
|
77
|
+
[
|
|
78
|
+
'key' => 'network',
|
|
79
|
+
'title' => 'Operating Network',
|
|
80
|
+
'description' => 'Maintain the partners, contacts, and places used while creating and dispatching orders.',
|
|
81
|
+
'links' => [
|
|
82
|
+
$this->link('Vendors', 'management.vendors', 'warehouse', $counts['vendors'], 'Service partners connected to operational work.'),
|
|
83
|
+
$this->link('Contacts', 'management.contacts', 'address-book', $counts['contacts'], 'Customer and contact records for order workflows.'),
|
|
84
|
+
$this->link('Places', 'management.places', 'location-dot', $counts['places'], 'Reusable locations, zones, and address context.'),
|
|
85
|
+
],
|
|
86
|
+
],
|
|
87
|
+
[
|
|
88
|
+
'key' => 'exceptions',
|
|
89
|
+
'title' => 'Fuel And Exceptions',
|
|
90
|
+
'description' => 'Review fuel activity and operational issues before they affect service quality.',
|
|
91
|
+
'links' => [
|
|
92
|
+
$this->link('Fuel Reports', 'management.fuel-reports', 'gas-pump', $counts['fuel_reports'], 'Review reported fuel activity and costs.'),
|
|
93
|
+
$this->link('Fuel Transactions', 'management.fuel-transactions', 'credit-card', $counts['fuel_transactions'], 'Inspect transaction-level fueling data and matching context.'),
|
|
94
|
+
$this->link('Issues', 'management.issues', 'triangle-exclamation', $counts['issues'], 'Track incidents, service issues, and follow-up work.'),
|
|
95
|
+
],
|
|
96
|
+
],
|
|
97
|
+
],
|
|
98
|
+
'docs' => [
|
|
99
|
+
$this->doc('Drivers', 'id-card', 'fleet-ops/resources/drivers/overview', 'Drivers guide', 'Create driver profiles, app access, assignment context, and operating status.'),
|
|
100
|
+
$this->doc('Vehicles', 'truck', 'fleet-ops/resources/vehicles/overview', 'Vehicles guide', 'Track fleet assets, assignment readiness, and vehicle operating details.'),
|
|
101
|
+
$this->doc('Fleets', 'user-group', 'fleet-ops/resources/fleets/overview', 'Fleets guide', 'Group drivers and vehicles by team, region, or service coverage.'),
|
|
102
|
+
$this->doc('Contacts', 'address-book', 'fleet-ops/resources/contacts/overview', 'Contacts guide', 'Manage people and organizations used across orders and operational records.'),
|
|
103
|
+
$this->doc('Places', 'location-dot', 'fleet-ops/resources/places/overview', 'Places guide', 'Manage reusable pickup, dropoff, hub, and facility locations.'),
|
|
104
|
+
$this->doc('Issues', 'triangle-exclamation', 'fleet-ops/resources/issues/overview', 'Issues guide', 'Track incidents, service exceptions, and operational follow-up.'),
|
|
105
|
+
],
|
|
106
|
+
]);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public function maintenance(Request $request)
|
|
110
|
+
{
|
|
111
|
+
$company = $this->companyUuid($request);
|
|
112
|
+
$now = Carbon::now();
|
|
113
|
+
$next7 = Carbon::now()->addDays(7);
|
|
114
|
+
|
|
115
|
+
$overdueSchedules = $this->count(MaintenanceSchedule::query()->where('status', 'active')->whereNotNull('next_due_date')->where('next_due_date', '<', $now), $company);
|
|
116
|
+
$upcomingSchedules = $this->count(MaintenanceSchedule::query()->where('status', 'active')->whereBetween('next_due_date', [$now, $next7]), $company);
|
|
117
|
+
$openWorkOrders = $this->count(WorkOrder::query()->whereIn('status', ['open', 'in_progress']), $company);
|
|
118
|
+
$overdueWorkOrders = $this->count(WorkOrder::query()->whereNotIn('status', ['closed', 'canceled'])->whereNotNull('due_at')->where('due_at', '<', $now), $company);
|
|
119
|
+
$openMaintenance = $this->count(Maintenance::query()->whereNotIn('status', ['completed', 'canceled']), $company);
|
|
120
|
+
$highPriorityMaintenance = $this->count(Maintenance::query()->whereNotIn('status', ['completed', 'canceled'])->whereIn('priority', ['high', 'urgent', 'critical']), $company);
|
|
121
|
+
$lowStockParts = $this->count(Part::query()->where('quantity_on_hand', '>', 0)->where('quantity_on_hand', '<=', 5), $company);
|
|
122
|
+
$equipment = $this->count(Equipment::query(), $company);
|
|
123
|
+
|
|
124
|
+
return response()->json([
|
|
125
|
+
'kpis' => [
|
|
126
|
+
$this->kpi('overdue_schedules', 'Overdue Schedules', $overdueSchedules, $overdueSchedules > 0 ? 'Recurring service needs attention.' : 'No recurring service is overdue.', $overdueSchedules > 0 ? 'rose' : 'green', 'calendar-xmark', 'maintenance.schedules'),
|
|
127
|
+
$this->kpi('upcoming_schedules', 'Due This Week', $upcomingSchedules, 'Maintenance schedules due in the next 7 days.', 'blue', 'calendar-day', 'maintenance.schedules'),
|
|
128
|
+
$this->kpi('open_work_orders', 'Open Work Orders', $openWorkOrders, $openWorkOrders > 0 ? 'Active work needs assignment or closure.' : 'No open work orders right now.', $openWorkOrders > 0 ? 'amber' : 'green', 'clipboard-list', 'maintenance.work-orders'),
|
|
129
|
+
$this->kpi('low_stock_parts', 'Low Stock Parts', $lowStockParts, $lowStockParts > 0 ? 'Parts inventory may need replenishment.' : 'No low-stock parts detected.', $lowStockParts > 0 ? 'amber' : 'green', 'cog', 'maintenance.parts'),
|
|
130
|
+
],
|
|
131
|
+
'actions' => $this->maintenanceActions($overdueSchedules, $upcomingSchedules, $openWorkOrders, $overdueWorkOrders, $highPriorityMaintenance, $lowStockParts, $equipment),
|
|
132
|
+
'sections' => [
|
|
133
|
+
[
|
|
134
|
+
'key' => 'planning',
|
|
135
|
+
'title' => 'Planning',
|
|
136
|
+
'description' => 'Schedule recurring service before work turns urgent.',
|
|
137
|
+
'links' => [
|
|
138
|
+
$this->link('Schedules', 'maintenance.schedules', 'calendar-alt', $upcomingSchedules + $overdueSchedules, 'Recurring maintenance intervals and service windows.'),
|
|
139
|
+
$this->link('Work Orders', 'maintenance.work-orders', 'clipboard-list', $openWorkOrders, 'Repair tasks, assignments, vendor work, and closure.'),
|
|
140
|
+
],
|
|
141
|
+
],
|
|
142
|
+
[
|
|
143
|
+
'key' => 'records',
|
|
144
|
+
'title' => 'Records',
|
|
145
|
+
'description' => 'Keep the maintenance history and serviceable asset catalog current.',
|
|
146
|
+
'links' => [
|
|
147
|
+
$this->link('Maintenances', 'maintenance.maintenances', 'history', $openMaintenance, 'Maintenance records and service history by asset.'),
|
|
148
|
+
$this->link('Equipment', 'maintenance.equipment', 'trailer', $equipment, 'Assigned equipment and serviceable operational assets.'),
|
|
149
|
+
$this->link('Parts', 'maintenance.parts', 'cog', $lowStockParts, 'Parts inventory visibility for repair planning.'),
|
|
150
|
+
],
|
|
151
|
+
],
|
|
152
|
+
],
|
|
153
|
+
'docs' => [
|
|
154
|
+
$this->doc('Schedules', 'calendar-alt', 'fleet-ops/maintenance/schedules/overview', 'Maintenance schedules guide', 'Plan recurring service windows and convert due schedules into work orders.'),
|
|
155
|
+
$this->doc('Work Orders', 'clipboard-list', 'fleet-ops/maintenance/work-orders/overview', 'Work orders guide', 'Coordinate assigned maintenance work, vendors, due dates, and completion.'),
|
|
156
|
+
$this->doc('Equipment', 'trailer', 'fleet-ops/maintenance/equipment/overview', 'Equipment guide', 'Track serviceable equipment that participates in maintenance operations.'),
|
|
157
|
+
$this->doc('Parts', 'cog', 'fleet-ops/maintenance/parts/overview', 'Parts guide', 'Manage parts inventory and restocking signals used by maintenance teams.'),
|
|
158
|
+
],
|
|
159
|
+
]);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
protected function resourceActions(array $counts, int $fuelRecords): array
|
|
163
|
+
{
|
|
164
|
+
$actions = [];
|
|
165
|
+
|
|
166
|
+
if ($counts['drivers'] === 0) {
|
|
167
|
+
$actions[] = $this->action('add_drivers', 'Add driver profiles', 'Drivers are required before dispatch can assign live orders.', 'warning', 'id-card', 'management.drivers');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if ($counts['vehicles'] === 0) {
|
|
171
|
+
$actions[] = $this->action('add_vehicles', 'Add vehicles', 'Vehicles make assignment, tracking, and service context usable.', 'warning', 'truck', 'management.vehicles');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if ($counts['drivers_without_vehicles'] > 0 && $counts['vehicles'] > 0) {
|
|
175
|
+
$actions[] = $this->action('assign_vehicles_to_drivers', 'Assign vehicles to drivers', "{$counts['drivers_without_vehicles']} driver" . ($counts['drivers_without_vehicles'] === 1 ? ' does' : 's do') . ' not have an assigned vehicle.', 'warning', 'id-card', 'management.drivers', ['vehicle' => 'unassigned']);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if ($counts['vehicles_without_drivers'] > 0 && $counts['drivers'] > 0) {
|
|
179
|
+
$actions[] = $this->action('assign_drivers_to_vehicles', 'Assign drivers to vehicles', "{$counts['vehicles_without_drivers']} vehicle" . ($counts['vehicles_without_drivers'] === 1 ? ' does' : 's do') . ' not have an assigned driver.', 'warning', 'truck', 'management.vehicles', ['driver' => 'unassigned']);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if ($counts['vehicles_without_devices'] > 0 && $counts['unattached_devices'] > 0) {
|
|
183
|
+
$actions[] = $this->action('attach_devices_to_vehicles', 'Attach devices to vehicles', "{$counts['unattached_devices']} device" . ($counts['unattached_devices'] === 1 ? ' is' : 's are') . ' ready to attach to vehicles without telemetry hardware.', 'info', 'satellite-dish', 'connectivity.devices', ['attachment_state' => 'unattached']);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if ($counts['resource_issues'] > 0) {
|
|
187
|
+
$actions[] = $this->action('review_resource_issues', 'Review vehicle and driver issues', "{$counts['resource_issues']} issue" . ($counts['resource_issues'] === 1 ? ' is' : 's are') . ' linked to drivers or vehicles.', 'warning', 'triangle-exclamation', 'management.issues', ['status' => 'open']);
|
|
188
|
+
} elseif ($counts['issues'] > 0) {
|
|
189
|
+
$actions[] = $this->action('review_issues', 'Review open issues', "{$counts['issues']} issue" . ($counts['issues'] === 1 ? ' needs' : 's need') . ' follow-up.', 'warning', 'triangle-exclamation', 'management.issues', ['status' => 'open']);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (($counts['overdue_vehicle_schedules'] + $counts['upcoming_vehicle_schedules']) > 0) {
|
|
193
|
+
$serviceCount = $counts['overdue_vehicle_schedules'] + $counts['upcoming_vehicle_schedules'];
|
|
194
|
+
$actions[] = $this->action('prepare_vehicle_maintenance', 'Prepare upcoming maintenance', "{$serviceCount} vehicle schedule" . ($serviceCount === 1 ? ' needs' : 's need') . ' maintenance planning.', $counts['overdue_vehicle_schedules'] > 0 ? 'warning' : 'info', 'calendar-day', 'maintenance.schedules', ['status' => 'active']);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if ($counts['overdue_resource_work_orders'] > 0) {
|
|
198
|
+
$actions[] = $this->action('close_overdue_work_orders', 'Close overdue work orders', "{$counts['overdue_resource_work_orders']} resource work order" . ($counts['overdue_resource_work_orders'] === 1 ? ' is' : 's are') . ' past due.', 'warning', 'clipboard-list', 'maintenance.work-orders', ['status' => 'open']);
|
|
199
|
+
} elseif ($counts['open_resource_work_orders'] > 0) {
|
|
200
|
+
$actions[] = $this->action('review_open_work_orders', 'Review open work orders', "{$counts['open_resource_work_orders']} resource work order" . ($counts['open_resource_work_orders'] === 1 ? ' is' : 's are') . ' open for vehicles or equipment.', 'info', 'clipboard-list', 'maintenance.work-orders', ['status' => 'open']);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if ($counts['low_stock_parts'] > 0) {
|
|
204
|
+
$actions[] = $this->action('replenish_low_stock_parts', 'Replenish low-stock parts', "{$counts['low_stock_parts']} stocked part" . ($counts['low_stock_parts'] === 1 ? ' is' : 's are') . ' at or below the default threshold.', 'warning', 'cog', 'maintenance.parts', ['status' => 'in_stock']);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if ($counts['unmatched_fuel_transactions'] > 0) {
|
|
208
|
+
$actions[] = $this->action('review_unmatched_fuel_transactions', 'Review unmatched fuel transactions', "{$counts['unmatched_fuel_transactions']} fuel transaction" . ($counts['unmatched_fuel_transactions'] === 1 ? ' needs' : 's need') . ' resource matching.', 'warning', 'gas-pump', 'management.fuel-transactions', ['sync_status' => 'unmatched']);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if ($counts['fleets'] === 0 && $counts['drivers'] > 0 && $counts['vehicles'] > 0) {
|
|
212
|
+
$actions[] = $this->action('create_fleets', 'Create fleet groups', 'Group active drivers and vehicles by team, region, or service type.', 'info', 'user-group', 'management.fleets');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if ($counts['places'] === 0) {
|
|
216
|
+
$actions[] = $this->action('add_operating_places', 'Add operating places', 'Places keep recurring pickup, dropoff, facility, and service locations ready.', 'info', 'location-dot', 'management.places');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if ($counts['vendors'] === 0) {
|
|
220
|
+
$actions[] = $this->action('add_service_vendors', 'Add vendors for service work', 'Vendors connect maintenance, service work, and operating partners to resources.', 'info', 'warehouse', 'management.vendors');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if ($counts['contacts'] === 0) {
|
|
224
|
+
$actions[] = $this->action('add_contacts', 'Add operating contacts', 'Contacts connect customers, partners, and service people to order workflows.', 'info', 'address-book', 'management.contacts');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if ($fuelRecords === 0) {
|
|
228
|
+
$actions[] = $this->action('review_fuel', 'Open fuel records', 'Fuel activity will appear here once reports or transactions are captured.', 'info', 'gas-pump', 'management.fuel-reports');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return $actions ? array_slice($actions, 0, 6) : [$this->action('ready', 'Core resources look ready', 'Drivers, vehicles, issues, and supporting records are in a healthy operating posture.', 'success', 'check-circle', null)];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
protected function maintenanceActions(int $overdueSchedules, int $upcomingSchedules, int $openWorkOrders, int $overdueWorkOrders, int $highPriorityMaintenance, int $lowStockParts, int $equipment): array
|
|
235
|
+
{
|
|
236
|
+
$actions = [];
|
|
237
|
+
|
|
238
|
+
if ($overdueSchedules > 0) {
|
|
239
|
+
$actions[] = $this->action('overdue_schedules', 'Review overdue schedules', "{$overdueSchedules} recurring service schedule" . ($overdueSchedules === 1 ? ' is' : 's are') . ' overdue.', 'warning', 'calendar-xmark', 'maintenance.schedules');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if ($overdueWorkOrders > 0) {
|
|
243
|
+
$actions[] = $this->action('overdue_work_orders', 'Close overdue work orders', "{$overdueWorkOrders} work order" . ($overdueWorkOrders === 1 ? ' is' : 's are') . ' past due.', 'warning', 'clipboard-list', 'maintenance.work-orders');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if ($highPriorityMaintenance > 0) {
|
|
247
|
+
$actions[] = $this->action('high_priority_maintenance', 'Prioritize critical maintenance', "{$highPriorityMaintenance} high-priority maintenance record" . ($highPriorityMaintenance === 1 ? ' needs' : 's need') . ' review.', 'warning', 'wrench', 'maintenance.maintenances');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if ($upcomingSchedules > 0) {
|
|
251
|
+
$actions[] = $this->action('upcoming_service', 'Prepare upcoming service', "{$upcomingSchedules} schedule" . ($upcomingSchedules === 1 ? ' is' : 's are') . ' due in the next 7 days.', 'info', 'calendar-day', 'maintenance.schedules');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if ($openWorkOrders === 0) {
|
|
255
|
+
$actions[] = $this->action('no_open_work_orders', 'No open work orders', 'Create work orders when scheduled service or asset issues need assignment.', 'success', 'check-circle', 'maintenance.work-orders');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if ($lowStockParts > 0) {
|
|
259
|
+
$actions[] = $this->action('low_stock_parts', 'Replenish low-stock parts', "{$lowStockParts} stocked part" . ($lowStockParts === 1 ? ' is' : 's are') . ' at or below the default threshold.', 'warning', 'cog', 'maintenance.parts');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if ($equipment === 0) {
|
|
263
|
+
$actions[] = $this->action('add_equipment', 'Add serviceable equipment', 'Equipment records make maintenance planning more complete.', 'info', 'trailer', 'maintenance.equipment');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return array_slice($actions, 0, 5);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
protected function count(Builder $query, ?string $companyUuid): int
|
|
270
|
+
{
|
|
271
|
+
return (int) $query->when($companyUuid, fn ($query) => $query->where('company_uuid', $companyUuid))->count();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
protected function companyUuid(Request $request): ?string
|
|
275
|
+
{
|
|
276
|
+
return session('company') ?? $request->user()?->company_uuid ?? $request->user()?->company?->uuid;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
protected function kpi(string $key, string $label, int $value, string $caption, string $tone, string $icon, string $route): array
|
|
280
|
+
{
|
|
281
|
+
return compact('key', 'label', 'value', 'caption', 'tone', 'icon', 'route');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
protected function action(string $key, string $label, string $description, string $tone, string $icon, ?string $route, array $query = []): array
|
|
285
|
+
{
|
|
286
|
+
$query = (object) $query;
|
|
287
|
+
|
|
288
|
+
return compact('key', 'label', 'description', 'tone', 'icon', 'route', 'query');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
protected function link(string $label, string $route, string $icon, int $count, string $description): array
|
|
292
|
+
{
|
|
293
|
+
return compact('label', 'route', 'icon', 'count', 'description');
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
protected function doc(string $label, string $icon, string $slug, string $title, string $description = ''): array
|
|
297
|
+
{
|
|
298
|
+
return compact('label', 'icon', 'slug', 'title', 'description');
|
|
299
|
+
}
|
|
300
|
+
}
|