@fleetbase/fleetops-engine 0.6.68 → 0.6.70
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 +44 -9
- package/addon/components/admin/telematics-settings.hbs +143 -0
- package/addon/components/admin/telematics-settings.js +145 -0
- package/addon/components/contact/form.hbs +13 -2
- package/addon/components/customer/details.hbs +17 -17
- package/addon/components/customer/form.hbs +13 -2
- package/addon/components/customer/form.js +0 -56
- package/addon/components/driver/details.hbs +13 -19
- package/addon/components/driver/form.hbs +20 -35
- package/addon/components/driver/form.js +0 -58
- 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/modals/driver-form.hbs +2 -2
- package/addon/components/modals/reset-profile-credentials.hbs +23 -0
- package/addon/components/modals/reset-profile-credentials.js +70 -0
- package/addon/components/profile-identity-hint.hbs +13 -0
- package/addon/components/profile-identity-hint.js +49 -0
- package/addon/components/telematic/hub.hbs +1 -1
- package/addon/components/widget/live-fleet.hbs +8 -40
- package/addon/controllers/analytics/reports/index.js +5 -0
- package/addon/controllers/connectivity/devices/index.js +4 -0
- package/addon/controllers/connectivity/fuel-providers/index.js +6 -4
- package/addon/controllers/connectivity/sensors/index.js +4 -0
- package/addon/controllers/connectivity/telematics/index.js +4 -0
- package/addon/controllers/maintenance/equipment/index.js +11 -4
- package/addon/controllers/maintenance/inspection-forms/index.js +2 -2
- package/addon/controllers/maintenance/inspection-submissions/index.js +8 -2
- package/addon/controllers/maintenance/maintenances/index.js +4 -0
- package/addon/controllers/maintenance/parts/index.js +11 -4
- package/addon/controllers/maintenance/schedules/index.js +17 -4
- package/addon/controllers/maintenance/work-orders/index.js +11 -4
- package/addon/controllers/management/contacts/index.js +4 -0
- package/addon/controllers/management/drivers/index.js +8 -0
- package/addon/controllers/management/fleets/index.js +4 -0
- package/addon/controllers/management/fuel-reports/index.js +4 -0
- package/addon/controllers/management/fuel-transactions/index.js +9 -7
- package/addon/controllers/management/issues/index.js +4 -0
- package/addon/controllers/management/places/index.js +4 -0
- package/addon/controllers/management/vehicles/index.js +4 -0
- package/addon/controllers/management/vendors/index.js +4 -0
- package/addon/controllers/operations/orders/index/details.js +30 -1
- package/addon/controllers/operations/orders/index.js +7 -0
- package/addon/controllers/operations/service-rates/index.js +3 -0
- package/addon/controllers/settings/index.js +13 -0
- package/addon/controllers/settings/telematics.js +113 -0
- package/addon/extension.js +42 -8
- 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.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 +50 -89
- package/addon/services/driver-actions.js +98 -0
- package/addon/templates/settings/telematics.hbs +70 -0
- package/addon/utils/profile-login-actions.js +172 -0
- package/app/components/admin/telematics-settings.js +1 -0
- package/app/components/{modals/reset-customer-credentials.js → map/marker-card/driver.js} +1 -1
- package/app/components/map/marker-card/vehicle.js +1 -0
- package/app/components/modals/reset-profile-credentials.js +1 -0
- package/app/components/profile-identity-hint.js +1 -0
- package/app/controllers/settings/telematics.js +1 -0
- package/app/routes/settings/telematics.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/scripts/pest-bootstrap.php +12 -0
- package/server/config/telemetry.php +12 -0
- package/server/migrations/2026_09_21_000001_convert_profile_only_users_to_managed_accounts.php +132 -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/resources/views/mail/driver-credentials.blade.php +21 -0
- package/server/src/Auth/Schemas/FleetOps.php +104 -5
- package/server/src/Console/Commands/DrainTelematicInbox.php +3 -13
- package/server/src/Console/Commands/FixCustomerCompanies.php +1 -1
- package/server/src/Console/Commands/FixDriverCompanies.php +1 -1
- package/server/src/Console/Commands/ProcessOperationalAlerts.php +3 -3
- package/server/src/Console/Commands/PruneTelematicsData.php +318 -0
- package/server/src/Exceptions/ProfileIdentityConflictException.php +34 -0
- package/server/src/Http/Controllers/Api/v1/CustomerController.php +14 -0
- package/server/src/Http/Controllers/Api/v1/DriverController.php +56 -39
- 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 +16 -17
- package/server/src/Http/Controllers/Internal/v1/CustomerController.php +54 -4
- 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 +204 -162
- package/server/src/Http/Controllers/Internal/v1/FleetOpsLookupController.php +47 -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 +178 -27
- 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/Http/Requests/CreateDriverRequest.php +6 -2
- package/server/src/Http/Requests/Internal/CreateDriverRequest.php +9 -18
- package/server/src/Http/Resources/v1/Contact.php +3 -0
- package/server/src/Http/Resources/v1/Driver.php +3 -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/Mail/DriverCredentialsMail.php +55 -0
- package/server/src/Models/Contact.php +55 -90
- package/server/src/Models/Sensor.php +3 -5
- package/server/src/Observers/ContactObserver.php +2 -22
- package/server/src/Observers/DriverObserver.php +5 -6
- package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +9 -1
- package/server/src/Providers/FleetOpsServiceProvider.php +18 -0
- package/server/src/Support/Ai/Capabilities/AbstractFleetOpsAICapability.php +62 -5
- package/server/src/Support/Ai/Capabilities/AssetStatusCapability.php +24 -5
- package/server/src/Support/Ai/Capabilities/CreateOrderPreviewCapability.php +6 -2
- package/server/src/Support/Ai/Capabilities/OrderInsightsCapability.php +40 -7
- package/server/src/Support/Ai/Capabilities/SearchResourcesCapability.php +86 -24
- package/server/src/Support/Ai/FleetOpsAiConsoleCommands.php +122 -0
- package/server/src/Support/Ai/Tools/CreateOrderTool.php +86 -0
- package/server/src/Support/Ai/Tools/ImportOrdersTool.php +53 -0
- package/server/src/Support/Ai/Tools/OptimizeOrderRouteTool.php +70 -0
- package/server/src/Support/Ai/Tools/SearchResourcesTool.php +73 -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/ProfileAccountManager.php +405 -0
- 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 +14 -1
- package/server/tests/AiOperationalQueryCapabilityTest.php +1 -0
- package/server/tests/AnalyticsRoutesTest.php +29 -2
- package/server/tests/ApiCustomerControllerContractsTest.php +21 -0
- package/server/tests/ApiDriverControllerContractsTest.php +102 -20
- package/server/tests/CommandContractsTest.php +4 -4
- package/server/tests/ControllerHelperContractsTest.php +3 -11
- package/server/tests/Feature/Http/AfaqyRealtimeIngestionTest.php +21 -1
- package/server/tests/Feature/Http/Api/DriverControllerAuthFlowsTest.php +36 -0
- package/server/tests/Feature/Http/Api/DriverControllerSessionHelpersTest.php +19 -6
- package/server/tests/Feature/Http/Api/ProfileOnlyUserConversionMigrationTest.php +201 -0
- package/server/tests/Feature/Http/Api/TelematicsRetentionIndexMigrationTest.php +115 -0
- package/server/tests/Feature/Http/Internal/ContactControllerEndpointsTest.php +6 -4
- package/server/tests/Feature/Http/Internal/CustomerControllerCredentialsTest.php +6 -2
- package/server/tests/Feature/Http/Internal/DriverControllerContractsTest.php +23 -0
- package/server/tests/Feature/Http/Internal/DriverControllerCreateRecordTest.php +42 -17
- package/server/tests/Feature/Http/Internal/DriverControllerExistingUserAdoptionTest.php +168 -277
- package/server/tests/Feature/Http/Internal/DriverControllerLoginManagementTest.php +716 -0
- package/server/tests/Feature/Http/Internal/OrderControllerContractsTest.php +10 -3
- package/server/tests/Feature/Http/Internal/OrderControllerImportFromFilesTest.php +18 -0
- package/server/tests/Feature/Http/Internal/OrderControllerTenantScopingTest.php +411 -0
- package/server/tests/Feature/Http/Internal/OrderControllerUpstreamNotFoundTest.php +8 -20
- package/server/tests/Feature/Http/Internal/SettingControllerHelpersTest.php +71 -0
- package/server/tests/Feature/Http/Internal/TelematicsStorageDeadlinesTest.php +119 -0
- package/server/tests/InternalCustomerControllerContractsTest.php +32 -1
- package/server/tests/InternalImportExportControllerContractsTest.php +5 -8
- package/server/tests/ModelAccessorContractsTest.php +82 -20
- package/server/tests/NavigatorControllerContractsTest.php +36 -4
- package/server/tests/NotificationAndMailContractsTest.php +31 -0
- package/server/tests/ObserverContractsTest.php +28 -3
- package/server/tests/OrchestratorConsumableApiTest.php +42 -0
- package/server/tests/ProviderContractsTest.php +10 -0
- package/server/tests/ReportSchemaContractsTest.php +120 -6
- package/server/tests/RequestContractsTest.php +19 -11
- 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/SupportJobAndAiCoverageTest.php +3 -3
- package/server/tests/TelematicControllerContractsTest.php +22 -4
- package/server/tests/Unit/Console/Commands/ProcessOperationalAlertsCommandTest.php +2 -2
- package/server/tests/Unit/Console/PruneTelematicsDataCommandTest.php +353 -0
- package/server/tests/Unit/Jobs/DispatchTelematicsRetentionJobsTest.php +114 -0
- package/server/tests/Unit/Jobs/PruneTelematicsDataJobTest.php +60 -0
- package/server/tests/Unit/Models/ContactCustomerUserTest.php +90 -14
- package/server/tests/Unit/Models/ContactTest.php +48 -5
- package/server/tests/Unit/Models/SensorTest.php +2 -2
- package/server/tests/Unit/Models/SmallModelSurfacesTest.php +31 -32
- package/server/tests/Unit/Observers/ObserverListenerSeamsTest.php +7 -2
- package/server/tests/Unit/Orchestration/VroomEngineTransportAndSettingsTest.php +20 -0
- package/server/tests/Unit/Providers/FleetOpsAiRegistrationTest.php +15 -2
- package/server/tests/Unit/Support/Ai/AssetStatusCapabilityQueriesTest.php +42 -0
- package/server/tests/Unit/Support/Ai/Capabilities/OrderInsightsCapabilityTest.php +19 -1
- package/server/tests/Unit/Support/Ai/Capabilities/SearchResourcesCapabilityTest.php +85 -1
- package/server/tests/Unit/Support/Ai/FleetOpsAiConsoleCommandsTest.php +31 -0
- package/server/tests/Unit/Support/Ai/Tools/FleetOpsAiToolsTest.php +246 -0
- package/server/tests/Unit/Support/AiCapabilityPermissionsTest.php +3 -3
- 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/ProfileAccountManagerTest.php +643 -0
- 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 +85 -2
- package/translations/uk-ua.yaml +3475 -0
- package/addon/components/modals/reset-customer-credentials.hbs +0 -18
- package/addon/components/modals/reset-customer-credentials.js +0 -55
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
use Fleetbase\FleetOps\Support\Database\TableIndexes;
|
|
4
|
+
use Illuminate\Database\SQLiteConnection;
|
|
5
|
+
use Illuminate\Support\Facades\Schema;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The retention sweep ranges over (company_uuid, created_at) and
|
|
9
|
+
* (telematic_uuid, updated_at); these migrations add those indexes once,
|
|
10
|
+
* skip equivalent existing ones, and roll back only what they created.
|
|
11
|
+
*/
|
|
12
|
+
function fleetopsRetentionIndexDatabase(): SQLiteConnection
|
|
13
|
+
{
|
|
14
|
+
$connection = new SQLiteConnection(new PDO('sqlite::memory:'), ':memory:', '', ['driver' => 'sqlite']);
|
|
15
|
+
Schema::swap($connection->getSchemaBuilder());
|
|
16
|
+
|
|
17
|
+
return $connection;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function fleetopsRetentionIndexMigrations(): array
|
|
21
|
+
{
|
|
22
|
+
$migrations = [];
|
|
23
|
+
foreach (glob(dirname(__DIR__, 4) . '/migrations/2026_09_23_00000*_add_retention_index_to_*.php') as $path) {
|
|
24
|
+
$migrations[basename($path)] = fn () => require $path;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return $migrations;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
test('retention index migrations add composite indexes once and roll them back', function () {
|
|
31
|
+
fleetopsRetentionIndexDatabase();
|
|
32
|
+
Schema::create('device_events', function ($table) {
|
|
33
|
+
$table->increments('id');
|
|
34
|
+
$table->uuid('company_uuid')->nullable();
|
|
35
|
+
$table->timestamps();
|
|
36
|
+
});
|
|
37
|
+
Schema::create('positions', function ($table) {
|
|
38
|
+
$table->increments('id');
|
|
39
|
+
$table->uuid('company_uuid')->nullable();
|
|
40
|
+
$table->timestamps();
|
|
41
|
+
});
|
|
42
|
+
Schema::create('telematic_sync_runs', function ($table) {
|
|
43
|
+
$table->uuid('uuid')->primary();
|
|
44
|
+
$table->uuid('telematic_uuid')->index();
|
|
45
|
+
$table->timestamps();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
$expected = [
|
|
49
|
+
'device_events' => ['device_events_company_created_at_index', ['company_uuid', 'created_at']],
|
|
50
|
+
'positions' => ['positions_company_created_at_index', ['company_uuid', 'created_at']],
|
|
51
|
+
'telematic_sync_runs' => ['telematic_sync_runs_telematic_updated_at_index', ['telematic_uuid', 'updated_at']],
|
|
52
|
+
];
|
|
53
|
+
$migrations = fleetopsRetentionIndexMigrations();
|
|
54
|
+
expect($migrations)->toHaveCount(3);
|
|
55
|
+
foreach ($migrations as $load) {
|
|
56
|
+
$load()->up();
|
|
57
|
+
$load()->up();
|
|
58
|
+
}
|
|
59
|
+
foreach ($expected as $table => [$name, $columns]) {
|
|
60
|
+
expect(TableIndexes::for($table)[$name] ?? null)->toBe($columns)
|
|
61
|
+
->and(TableIndexes::covers($table, $columns))->toBeTrue()
|
|
62
|
+
->and(TableIndexes::covers($table, ['created_at']))->toBeFalse();
|
|
63
|
+
}
|
|
64
|
+
// The existing single-column index on telematic_uuid does not cover the composite.
|
|
65
|
+
expect(count(array_filter(TableIndexes::for('telematic_sync_runs'), fn ($columns) => $columns === ['telematic_uuid'])))->toBe(1);
|
|
66
|
+
|
|
67
|
+
foreach ($migrations as $load) {
|
|
68
|
+
$load()->down();
|
|
69
|
+
}
|
|
70
|
+
foreach ($expected as $table => [$name]) {
|
|
71
|
+
expect(TableIndexes::for($table))->not->toHaveKey($name);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('retention index migrations skip missing tables, missing columns and equivalent indexes', function () {
|
|
76
|
+
fleetopsRetentionIndexDatabase();
|
|
77
|
+
$migrations = fleetopsRetentionIndexMigrations();
|
|
78
|
+
|
|
79
|
+
// No tables at all: nothing to do either way.
|
|
80
|
+
foreach ($migrations as $load) {
|
|
81
|
+
$load()->up();
|
|
82
|
+
$load()->down();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
Schema::create('device_events', fn ($table) => $table->increments('id'));
|
|
86
|
+
Schema::create('positions', function ($table) {
|
|
87
|
+
$table->increments('id');
|
|
88
|
+
$table->uuid('company_uuid')->nullable();
|
|
89
|
+
$table->timestamps();
|
|
90
|
+
$table->index(['company_uuid', 'created_at', 'id'], 'positions_existing_company_created');
|
|
91
|
+
});
|
|
92
|
+
Schema::create('telematic_sync_runs', function ($table) {
|
|
93
|
+
$table->uuid('uuid')->primary();
|
|
94
|
+
$table->uuid('telematic_uuid');
|
|
95
|
+
$table->timestamps();
|
|
96
|
+
$table->index(['telematic_uuid', 'updated_at'], 'telematic_sync_runs_telematic_updated_at_index');
|
|
97
|
+
});
|
|
98
|
+
Schema::table('telematic_sync_runs', fn ($table) => $table->index('updated_at', 'unrelated_updated_at'));
|
|
99
|
+
|
|
100
|
+
foreach ($migrations as $load) {
|
|
101
|
+
$load()->up();
|
|
102
|
+
}
|
|
103
|
+
expect(TableIndexes::for('device_events'))->toBe([])
|
|
104
|
+
->and(array_keys(TableIndexes::for('positions')))->toBe(['positions_existing_company_created'])
|
|
105
|
+
->and(TableIndexes::for('telematic_sync_runs'))->toHaveKeys(['telematic_sync_runs_telematic_updated_at_index', 'unrelated_updated_at']);
|
|
106
|
+
|
|
107
|
+
// Rolling back never drops an index the migration did not create, even under the reserved name when its shape differs.
|
|
108
|
+
Schema::table('telematic_sync_runs', fn ($table) => $table->dropIndex('telematic_sync_runs_telematic_updated_at_index'));
|
|
109
|
+
Schema::table('telematic_sync_runs', fn ($table) => $table->index('updated_at', 'telematic_sync_runs_telematic_updated_at_index'));
|
|
110
|
+
foreach ($migrations as $load) {
|
|
111
|
+
$load()->down();
|
|
112
|
+
}
|
|
113
|
+
expect(array_keys(TableIndexes::for('positions')))->toBe(['positions_existing_company_created'])
|
|
114
|
+
->and(TableIndexes::for('telematic_sync_runs')['telematic_sync_runs_telematic_updated_at_index'])->toBe(['updated_at']);
|
|
115
|
+
});
|
|
@@ -252,10 +252,12 @@ test('contact update guards types resolve users and portal seams persist', funct
|
|
|
252
252
|
$probe->callProtected('assertContactInputIsValid', [$request, &$input, $contact]);
|
|
253
253
|
})->toThrow(Exception::class);
|
|
254
254
|
|
|
255
|
-
//
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
255
|
+
// The login account is managed by the profile, so user references are dropped
|
|
256
|
+
$userInput = ['name' => 'Seam Contact', 'user_uuid' => '88888888-8888-4888-8888-888888888881', 'user' => 'user_contactseam'];
|
|
257
|
+
Closure::bind(function (array &$input) {
|
|
258
|
+
$this->resolveUserInput(Request::create('/x', 'PUT', []), $input);
|
|
259
|
+
}, $probe, ContactController::class)($userInput);
|
|
260
|
+
expect($userInput)->toBe(['name' => 'Seam Contact']);
|
|
259
261
|
|
|
260
262
|
// Portal seams read users, mint passwords, and persist meta quietly
|
|
261
263
|
expect($probe->callProtected('contactUser', [$contact])?->uuid)->toBe('88888888-8888-4888-8888-888888888881')
|
|
@@ -125,7 +125,9 @@ function fleetopsCustomerCredentialsBoot(): SQLiteConnection
|
|
|
125
125
|
'contacts' => ['uuid', 'public_id', 'company_uuid', 'user_uuid', 'name', 'email', 'phone', 'type', 'title', 'meta', 'photo_uuid', 'place_uuid', 'slug', '_key'],
|
|
126
126
|
'users' => ['uuid', 'public_id', 'company_uuid', 'name', 'email', 'phone', 'password', 'type', 'status', 'timezone', 'slug', 'username', 'avatar_uuid', 'meta', '_key'],
|
|
127
127
|
'companies' => ['uuid', 'public_id', 'name', 'country'],
|
|
128
|
-
|
|
128
|
+
// session_status reads the user's membership of the session company
|
|
129
|
+
'company_users' => ['uuid', 'company_uuid', 'user_uuid', 'status'],
|
|
130
|
+
'files' => ['uuid', 'public_id', 'company_uuid', 'subject_uuid', 'subject_type', 'name', 'path', 'disk', 'type', '_key'],
|
|
129
131
|
];
|
|
130
132
|
foreach ($tables as $table => $columns) {
|
|
131
133
|
$schema->create($table, function ($blueprint) use ($columns) {
|
|
@@ -192,5 +194,7 @@ test('customer resolution and payload helpers expose user details', function ()
|
|
|
192
194
|
|
|
193
195
|
$payload = $probe->callHelper('customerPayload', $customer);
|
|
194
196
|
expect($payload['uuid'])->toBe('55555555-5555-4555-8555-555555555555')
|
|
195
|
-
->and($payload)->
|
|
197
|
+
->and($payload['user']['uuid'])->toBe('user-1')
|
|
198
|
+
->and($payload['is_staff_linked'])->toBeFalse()
|
|
199
|
+
->and($payload['login_status'])->toBe('active');
|
|
196
200
|
});
|
|
@@ -1131,6 +1131,29 @@ test('internal driver controller verify code returns driver resource and handles
|
|
|
1131
1131
|
]);
|
|
1132
1132
|
});
|
|
1133
1133
|
|
|
1134
|
+
test('internal driver controller refuses phone login and code verification for deactivated drivers', function () {
|
|
1135
|
+
FleetOpsInternalDriverAuthControllerProbe::resetProbe();
|
|
1136
|
+
app()->instance('request', Request::create('/', 'POST', ['phone' => '15551234567']));
|
|
1137
|
+
|
|
1138
|
+
$deactivated = fleetopsInternalDriverAuthUser();
|
|
1139
|
+
$deactivated->setAttribute('status', 'inactive');
|
|
1140
|
+
FleetOpsInternalDriverAuthControllerProbe::$loginUser = $deactivated;
|
|
1141
|
+
FleetOpsInternalDriverAuthControllerProbe::$verificationUser = $deactivated;
|
|
1142
|
+
FleetOpsInternalDriverAuthControllerProbe::$verificationExists = true;
|
|
1143
|
+
|
|
1144
|
+
$controller = new FleetOpsInternalDriverAuthControllerProbe();
|
|
1145
|
+
$login = $controller->loginWithPhone();
|
|
1146
|
+
$verify = $controller->verifyCode(new Request(['identity' => '+15551234567', 'code' => '111111']));
|
|
1147
|
+
|
|
1148
|
+
expect($login->getStatusCode())->toBe(403)
|
|
1149
|
+
->and($login->getData(true))->toBe(['error' => 'This driver login has been deactivated.'])
|
|
1150
|
+
->and($verify->getStatusCode())->toBe(403)
|
|
1151
|
+
->and($verify->getData(true))->toBe(['error' => 'This driver login has been deactivated.'])
|
|
1152
|
+
// No code is sent and no token is issued
|
|
1153
|
+
->and(FleetOpsInternalDriverAuthControllerProbe::$verifications)->toBe([])
|
|
1154
|
+
->and(FleetOpsInternalDriverAuthControllerProbe::$tokens)->toBe([]);
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1134
1157
|
test('internal driver controller delegates login and create driver verification flows to api controller', function () {
|
|
1135
1158
|
$request = new Request(['for' => 'create_driver']);
|
|
1136
1159
|
|
|
@@ -10,11 +10,12 @@ use Illuminate\Http\Request;
|
|
|
10
10
|
/**
|
|
11
11
|
* Covers the internal DriverController createRecord and updateRecord flows
|
|
12
12
|
* against an in-memory SQLite fixture. The creation closure executes end to
|
|
13
|
-
* end: company resolution,
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* end: company resolution, managed account creation with driver typing
|
|
14
|
+
* through ProfileAccountManager, and the exception-to-error-response
|
|
15
|
+
* branches. Role assignment requires the full spatie permission boot, which
|
|
16
|
+
* this fixture leaves out, so flows settle in the documented error branch
|
|
17
|
+
* after the user record is persisted (see
|
|
18
|
+
* DriverControllerExistingUserAdoptionTest for the full flow).
|
|
18
19
|
*/
|
|
19
20
|
if (!function_exists('Fleetbase\Support\session')) {
|
|
20
21
|
eval('namespace Fleetbase\Support; function session($key = null, $default = null) { if ($key === null) { return new class { public function has($k) { return \session($k) !== null; } public function get($k, $d = null) { return \session($k, $d); } }; } return \session($key, $default); }');
|
|
@@ -101,6 +102,28 @@ function fleetopsInternalDriverCreateBoot(): SQLiteConnection
|
|
|
101
102
|
}
|
|
102
103
|
});
|
|
103
104
|
Illuminate\Support\Facades\DB::clearResolvedInstance('db');
|
|
105
|
+
app()->instance('hash', new class implements Illuminate\Contracts\Hashing\Hasher {
|
|
106
|
+
public function info($hashedValue): array
|
|
107
|
+
{
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public function make($value, array $options = []): string
|
|
112
|
+
{
|
|
113
|
+
return 'hashed:' . $value;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public function check($value, $hashedValue, array $options = []): bool
|
|
117
|
+
{
|
|
118
|
+
return 'hashed:' . $value === $hashedValue;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public function needsRehash($hashedValue, array $options = []): bool
|
|
122
|
+
{
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
Illuminate\Support\Facades\Hash::clearResolvedInstance('hash');
|
|
104
127
|
|
|
105
128
|
$schema = $connection->getSchemaBuilder();
|
|
106
129
|
$tables = [
|
|
@@ -158,31 +181,33 @@ test('create record provisions a driver-typed user before role assignment', func
|
|
|
158
181
|
->and($connection->table('company_users')->count())->toBeGreaterThanOrEqual(0);
|
|
159
182
|
});
|
|
160
183
|
|
|
161
|
-
test('create record
|
|
184
|
+
test('create record ignores a picked user account and resolves the login from the email', function () {
|
|
162
185
|
$connection = fleetopsInternalDriverCreateBoot();
|
|
163
|
-
$connection->table('users')->insert(['uuid' => '11111111-1111-4111-8111-111111111111', 'company_uuid' => 'company-1', 'name' => 'Existing', 'type' => 'driver']);
|
|
164
|
-
$connection->table('drivers')->insert(['uuid' => 'driver-1', 'company_uuid' => 'company-1', 'user_uuid' => '11111111-1111-4111-8111-111111111111']);
|
|
186
|
+
$connection->table('users')->insert(['uuid' => '11111111-1111-4111-8111-111111111111', 'company_uuid' => 'company-1', 'name' => 'Existing', 'email' => 'existing@example.com', 'type' => 'driver']);
|
|
165
187
|
|
|
166
|
-
|
|
167
|
-
'name' => '
|
|
188
|
+
(new DriverController())->createRecord(fleetopsInternalDriverCreateRequest([
|
|
189
|
+
'name' => 'Someone Else',
|
|
190
|
+
'email' => 'someone@example.com',
|
|
168
191
|
'user_uuid' => '11111111-1111-4111-8111-111111111111',
|
|
169
192
|
]));
|
|
170
193
|
|
|
171
|
-
|
|
172
|
-
|
|
194
|
+
// The login account is managed by the profile: a new driver account is
|
|
195
|
+
// created for the email rather than the picked account being taken over
|
|
196
|
+
expect($connection->table('users')->count())->toBe(2)
|
|
197
|
+
->and($connection->table('users')->where('email', 'someone@example.com')->value('type'))->toBe('driver')
|
|
198
|
+
->and($connection->table('users')->where('uuid', '11111111-1111-4111-8111-111111111111')->value('name'))->toBe('Existing');
|
|
173
199
|
});
|
|
174
200
|
|
|
175
|
-
test('create record
|
|
201
|
+
test('create record applies photo avatars to the new driver account', function () {
|
|
176
202
|
$connection = fleetopsInternalDriverCreateBoot();
|
|
177
|
-
$connection->table('users')->insert(['uuid' => '11111111-1111-4111-8111-111111111111', 'company_uuid' => 'company-1', 'name' => 'Adoptable', 'type' => 'driver']);
|
|
178
203
|
|
|
179
204
|
$result = (new DriverController())->createRecord(fleetopsInternalDriverCreateRequest([
|
|
180
|
-
'name' => '
|
|
181
|
-
'user_uuid' => '11111111-1111-4111-8111-111111111111',
|
|
205
|
+
'name' => 'Photo Driver',
|
|
182
206
|
'photo_uuid' => '22222222-2222-4222-8222-222222222222',
|
|
183
207
|
]));
|
|
184
208
|
|
|
185
|
-
// Avatar
|
|
209
|
+
// Avatar is set when the account is created, before the harness
|
|
210
|
+
// role-assignment limitation.
|
|
186
211
|
expect($connection->table('users')->value('avatar_uuid'))->toBe('22222222-2222-4222-8222-222222222222')
|
|
187
212
|
->and($result)->toBeInstanceOf(JsonResponse::class)
|
|
188
213
|
->and($result->getData(true))->toHaveKey('error');
|