@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
|
@@ -25,12 +25,13 @@ use Illuminate\Support\MessageBag;
|
|
|
25
25
|
use Illuminate\Support\Str;
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Covers the internal DriverController createRecord
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
28
|
+
* Covers how the internal DriverController createRecord resolves the new
|
|
29
|
+
* driver's login account through ProfileAccountManager against SQLite with
|
|
30
|
+
* real spatie roles: creating a managed driver account without an invite,
|
|
31
|
+
* linking a staff member of the organization without touching their role,
|
|
32
|
+
* linking a managed driver account of another organization, rejecting an
|
|
33
|
+
* email/phone held by another organization's staff, another profile type or
|
|
34
|
+
* an existing driver of the organization, and returning validation failures.
|
|
34
35
|
*/
|
|
35
36
|
if (!function_exists('Fleetbase\Observers\event')) {
|
|
36
37
|
eval('namespace Fleetbase\Observers; function event($event = null, $payload = []) { return []; }');
|
|
@@ -212,6 +213,28 @@ function fleetopsDriverAdoptionBoot(array $validatorErrors): SQLiteConnection
|
|
|
212
213
|
}
|
|
213
214
|
});
|
|
214
215
|
Illuminate\Support\Facades\DB::clearResolvedInstance('db');
|
|
216
|
+
app()->instance('hash', new class implements Illuminate\Contracts\Hashing\Hasher {
|
|
217
|
+
public function info($hashedValue): array
|
|
218
|
+
{
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
public function make($value, array $options = []): string
|
|
223
|
+
{
|
|
224
|
+
return 'hashed:' . $value;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
public function check($value, $hashedValue, array $options = []): bool
|
|
228
|
+
{
|
|
229
|
+
return 'hashed:' . $value === $hashedValue;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
public function needsRehash($hashedValue, array $options = []): bool
|
|
233
|
+
{
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
Illuminate\Support\Facades\Hash::clearResolvedInstance('hash');
|
|
215
238
|
|
|
216
239
|
$schema = $connection->getSchemaBuilder();
|
|
217
240
|
$tables = [
|
|
@@ -327,66 +350,121 @@ function fleetopsDriverAdoptionRequest(array $driver): Request
|
|
|
327
350
|
return Request::create('/int/v1/drivers', 'POST', ['driver' => $driver]);
|
|
328
351
|
}
|
|
329
352
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
$connection->table('
|
|
333
|
-
|
|
353
|
+
function fleetopsDriverAdoptionRoles(SQLiteConnection $connection, string $userUuid): array
|
|
354
|
+
{
|
|
355
|
+
return $connection->table('model_has_roles')
|
|
356
|
+
->join('roles', 'roles.id', '=', 'model_has_roles.role_id')
|
|
357
|
+
->join('company_users', 'company_users.uuid', '=', 'model_has_roles.model_uuid')
|
|
358
|
+
->where('company_users.user_uuid', $userUuid)
|
|
359
|
+
->pluck('roles.name')
|
|
360
|
+
->unique()
|
|
361
|
+
->values()
|
|
362
|
+
->all();
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
test('a new driver gets a managed driver account added to the company without an invite', function () {
|
|
366
|
+
$connection = fleetopsDriverAdoptionBoot([]);
|
|
334
367
|
|
|
335
368
|
$result = (new DriverController())->createRecord(fleetopsDriverAdoptionRequest([
|
|
336
|
-
'name'
|
|
337
|
-
'
|
|
369
|
+
'name' => 'New Driver',
|
|
370
|
+
'email' => 'New.Driver@Example.com',
|
|
371
|
+
'phone' => '+65 9123-0000',
|
|
372
|
+
'password' => 'chosen-secret',
|
|
338
373
|
]));
|
|
339
374
|
|
|
375
|
+
$user = $connection->table('users')->first();
|
|
376
|
+
|
|
340
377
|
expect($result)->toBeArray()
|
|
341
|
-
->and($result['driver']->resource->user_uuid)->toBe(
|
|
342
|
-
->and($
|
|
343
|
-
->and($
|
|
378
|
+
->and($result['driver']->resource->user_uuid)->toBe($user->uuid)
|
|
379
|
+
->and($user->type)->toBe('driver')
|
|
380
|
+
->and($user->status)->toBe('active')
|
|
381
|
+
->and($user->email)->toBe('new.driver@example.com')
|
|
382
|
+
->and($user->phone)->toBe('+6591230000')
|
|
383
|
+
->and($user->password)->toBe('hashed:chosen-secret')
|
|
384
|
+
->and($connection->table('company_users')->where(['company_uuid' => 'company-1', 'user_uuid' => $user->uuid])->count())->toBe(1)
|
|
385
|
+
->and(fleetopsDriverAdoptionRoles($connection, $user->uuid))->toBe(['Driver'])
|
|
386
|
+
->and($connection->table('invites')->count())->toBe(0);
|
|
344
387
|
});
|
|
345
388
|
|
|
346
|
-
test('
|
|
347
|
-
$connection = fleetopsDriverAdoptionBoot([
|
|
348
|
-
|
|
349
|
-
// Same conflict as above, but with no company_users row the user is not yet
|
|
350
|
-
// an organization member, so adoption must also attach them to the company
|
|
351
|
-
$connection->table('users')->insert(['uuid' => '11111111-1111-4111-8111-111111111112', 'name' => 'Outsider', 'phone' => '+6591234568', 'slug' => 'outsider', 'type' => 'driver']);
|
|
352
|
-
|
|
353
|
-
expect($connection->table('company_users')->count())->toBe(0);
|
|
389
|
+
test('a staff member of the organization is linked without changing their account or role', function () {
|
|
390
|
+
$connection = fleetopsDriverAdoptionBoot([]);
|
|
391
|
+
$connection->table('users')->insert(['uuid' => '11111111-1111-4111-8111-111111111111', 'company_uuid' => 'company-1', 'name' => 'Staff Member', 'email' => 'staff@example.com', 'phone' => '+6590001111', 'slug' => 'staff', 'type' => 'user']);
|
|
354
392
|
|
|
355
393
|
$result = (new DriverController())->createRecord(fleetopsDriverAdoptionRequest([
|
|
356
|
-
'name' => '
|
|
357
|
-
'
|
|
394
|
+
'name' => 'Different Name',
|
|
395
|
+
'email' => 'staff@example.com',
|
|
396
|
+
'phone' => '+6599998888',
|
|
358
397
|
]));
|
|
359
398
|
|
|
399
|
+
$staff = $connection->table('users')->where('uuid', '11111111-1111-4111-8111-111111111111')->first();
|
|
400
|
+
|
|
360
401
|
expect($result)->toBeArray()
|
|
361
|
-
->and($result['driver']->resource->user_uuid)->toBe('11111111-1111-4111-8111-
|
|
362
|
-
->and($connection->table('
|
|
363
|
-
|
|
364
|
-
->and($
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
402
|
+
->and($result['driver']->resource->user_uuid)->toBe('11111111-1111-4111-8111-111111111111')
|
|
403
|
+
->and($connection->table('users')->count())->toBe(1)
|
|
404
|
+
->and($staff->type)->toBe('user')
|
|
405
|
+
->and($staff->phone)->toBe('+6590001111')
|
|
406
|
+
->and($staff->name)->toBe('Staff Member')
|
|
407
|
+
->and($connection->table('model_has_roles')->count())->toBe(0)
|
|
408
|
+
->and($connection->table('drivers')->value('company_uuid'))->toBe('company-1');
|
|
368
409
|
});
|
|
369
410
|
|
|
370
|
-
test('
|
|
371
|
-
$connection = fleetopsDriverAdoptionBoot([
|
|
372
|
-
$connection->table('users')->insert(['uuid' => '11111111-1111-4111-8111-
|
|
373
|
-
$connection->table('drivers')->insert(['uuid' => 'driver-
|
|
411
|
+
test('a managed driver account of another organization is linked and joins the company', function () {
|
|
412
|
+
$connection = fleetopsDriverAdoptionBoot([]);
|
|
413
|
+
$connection->table('users')->insert(['uuid' => '11111111-1111-4111-8111-111111111112', 'company_uuid' => 'company-2', 'name' => 'Shared Driver', 'phone' => '+6591234568', 'slug' => 'shared', 'type' => 'driver']);
|
|
414
|
+
$connection->table('drivers')->insert(['uuid' => 'driver-elsewhere', 'company_uuid' => 'company-2', 'user_uuid' => '11111111-1111-4111-8111-111111111112']);
|
|
374
415
|
|
|
375
416
|
$result = (new DriverController())->createRecord(fleetopsDriverAdoptionRequest([
|
|
376
|
-
'name' => '
|
|
377
|
-
'
|
|
417
|
+
'name' => 'Shared Driver',
|
|
418
|
+
'phone' => '+6591234568',
|
|
378
419
|
]));
|
|
379
420
|
|
|
380
421
|
expect($result)->toBeArray()
|
|
381
|
-
->and($result['driver']->resource->
|
|
382
|
-
->and($connection->table('drivers')->count())->toBe(1)
|
|
422
|
+
->and($result['driver']->resource->user_uuid)->toBe('11111111-1111-4111-8111-111111111112')
|
|
423
|
+
->and($connection->table('drivers')->where('company_uuid', 'company-1')->count())->toBe(1)
|
|
424
|
+
->and($connection->table('company_users')->where(['company_uuid' => 'company-1', 'user_uuid' => '11111111-1111-4111-8111-111111111112'])->count())->toBe(1)
|
|
425
|
+
->and(fleetopsDriverAdoptionRoles($connection, '11111111-1111-4111-8111-111111111112'))->toBe(['Driver'])
|
|
426
|
+
->and($connection->table('invites')->count())->toBe(0);
|
|
383
427
|
});
|
|
384
428
|
|
|
385
|
-
test('
|
|
429
|
+
test('an email or phone that cannot be linked is rejected with a 422', function (array $user, ?array $driver, array $input, string $message) {
|
|
430
|
+
$connection = fleetopsDriverAdoptionBoot([]);
|
|
431
|
+
$connection->table('users')->insert(array_merge(['uuid' => '11111111-1111-4111-8111-111111111111', 'name' => 'Existing'], $user));
|
|
432
|
+
if ($driver) {
|
|
433
|
+
$connection->table('drivers')->insert($driver);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
$result = (new DriverController())->createRecord(fleetopsDriverAdoptionRequest(array_merge(['name' => 'New Driver'], $input)));
|
|
437
|
+
|
|
438
|
+
expect($result)->toBeInstanceOf(Illuminate\Http\JsonResponse::class)
|
|
439
|
+
->and($result->getStatusCode())->toBe(422)
|
|
440
|
+
->and($result->getData(true)['error'])->toBe($message)
|
|
441
|
+
->and($connection->table('drivers')->where('company_uuid', 'company-1')->where('user_uuid', '!=', '11111111-1111-4111-8111-111111111111')->count())->toBe(0)
|
|
442
|
+
->and($connection->table('users')->count())->toBe(1);
|
|
443
|
+
})->with([
|
|
444
|
+
'staff of another organization' => [
|
|
445
|
+
['company_uuid' => 'company-2', 'email' => 'outsider@example.com', 'type' => 'admin'],
|
|
446
|
+
null,
|
|
447
|
+
['email' => 'outsider@example.com'],
|
|
448
|
+
'This email is already in use by another account.',
|
|
449
|
+
],
|
|
450
|
+
'a customer account' => [
|
|
451
|
+
['company_uuid' => 'company-1', 'phone' => '+6591112222', 'type' => 'customer'],
|
|
452
|
+
null,
|
|
453
|
+
['phone' => '+6591112222'],
|
|
454
|
+
'This phone number is already used by a customer.',
|
|
455
|
+
],
|
|
456
|
+
'an existing driver of the organization' => [
|
|
457
|
+
['company_uuid' => 'company-1', 'email' => 'member@example.com', 'type' => 'driver'],
|
|
458
|
+
['uuid' => 'driver-1', 'company_uuid' => 'company-1', 'user_uuid' => '11111111-1111-4111-8111-111111111111'],
|
|
459
|
+
['email' => 'member@example.com'],
|
|
460
|
+
'A driver with this email already exists.',
|
|
461
|
+
],
|
|
462
|
+
]);
|
|
463
|
+
|
|
464
|
+
test('validation failures return the error response', function () {
|
|
386
465
|
fleetopsDriverAdoptionBoot(['name' => ['The name field is required.']]);
|
|
387
466
|
|
|
388
|
-
// The error response seam raises the validation failure
|
|
389
|
-
// fall-through branch executes
|
|
467
|
+
// The error response seam raises the validation failure
|
|
390
468
|
$failure = null;
|
|
391
469
|
|
|
392
470
|
try {
|
|
@@ -398,104 +476,67 @@ test('non phone or email conflicts fall through to the error response', function
|
|
|
398
476
|
expect($failure?->errors())->toBe(['name' => ['The name field is required.']]);
|
|
399
477
|
});
|
|
400
478
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
'phone' => '+6590001111',
|
|
410
|
-
]));
|
|
479
|
+
function fleetopsDriverAdoptionThrowingHasher(Throwable $exception): void
|
|
480
|
+
{
|
|
481
|
+
$GLOBALS['fleetopsDriverAdoptionHashException'] = $exception;
|
|
482
|
+
app()->instance('hash', new class implements Illuminate\Contracts\Hashing\Hasher {
|
|
483
|
+
public function info($hashedValue): array
|
|
484
|
+
{
|
|
485
|
+
return [];
|
|
486
|
+
}
|
|
411
487
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
});
|
|
488
|
+
public function make($value, array $options = []): string
|
|
489
|
+
{
|
|
490
|
+
throw $GLOBALS['fleetopsDriverAdoptionHashException'];
|
|
491
|
+
}
|
|
417
492
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
$request = Request::create('/int/v1/drivers/driver_updone1', 'PUT', ['driver' => [
|
|
424
|
-
'name' => 'New Name',
|
|
425
|
-
'status' => 'active',
|
|
426
|
-
]]);
|
|
427
|
-
$request->setRouteResolver(function () {
|
|
428
|
-
return new class {
|
|
429
|
-
public function getAction($key = null)
|
|
430
|
-
{
|
|
431
|
-
return $key === null ? ['controller' => DriverController::class . '@updateRecord'] : DriverController::class . '@updateRecord';
|
|
432
|
-
}
|
|
493
|
+
public function check($value, $hashedValue, array $options = []): bool
|
|
494
|
+
{
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
433
497
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
498
|
+
public function needsRehash($hashedValue, array $options = []): bool
|
|
499
|
+
{
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
Illuminate\Support\Facades\Hash::clearResolvedInstance('hash');
|
|
504
|
+
}
|
|
438
505
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}
|
|
506
|
+
test('create record reports a missing organization', function () {
|
|
507
|
+
fleetopsDriverAdoptionBoot([]);
|
|
508
|
+
session(['company' => 'company-missing']);
|
|
443
509
|
|
|
444
|
-
|
|
445
|
-
{
|
|
446
|
-
return 'int/v1/drivers/{id}';
|
|
447
|
-
}
|
|
510
|
+
$result = (new DriverController())->createRecord(fleetopsDriverAdoptionRequest(['name' => 'Nowhere Driver']));
|
|
448
511
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
return ['id' => 'driver_updone1'];
|
|
452
|
-
}
|
|
512
|
+
expect($result->getData(true))->toBe(['error' => 'Unable to create driver.']);
|
|
513
|
+
});
|
|
453
514
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
}
|
|
458
|
-
};
|
|
459
|
-
});
|
|
515
|
+
test('create record syncs custom field values onto the new driver', function () {
|
|
516
|
+
$connection = fleetopsDriverAdoptionBoot([]);
|
|
517
|
+
$connection->table('custom_fields')->insert(['uuid' => 'dddddddd-dddd-4ddd-8ddd-dddddddddddd', 'company_uuid' => 'company-1', 'name' => 'badge', 'label' => 'Badge']);
|
|
460
518
|
|
|
461
|
-
$result = (new DriverController())->
|
|
519
|
+
$result = (new DriverController())->createRecord(Request::create('/int/v1/drivers', 'POST', ['driver' => [
|
|
520
|
+
'name' => 'Badged Driver',
|
|
521
|
+
'custom_field_values' => [['custom_field_uuid' => 'dddddddd-dddd-4ddd-8ddd-dddddddddddd', 'value' => 'B-12']],
|
|
522
|
+
]]));
|
|
462
523
|
|
|
463
|
-
expect($result)->toBeArray()
|
|
464
|
-
->and($connection->table('
|
|
465
|
-
->and($connection->table('drivers')->value('status'))->toBe('available');
|
|
524
|
+
expect($result)->toBeArray()
|
|
525
|
+
->and($connection->table('custom_field_values')->where('subject_uuid', $result['driver']->resource->uuid)->value('value'))->toBe('B-12');
|
|
466
526
|
});
|
|
467
527
|
|
|
468
|
-
test('create
|
|
528
|
+
test('create record reports database and request validation failures', function () {
|
|
469
529
|
$connection = fleetopsDriverAdoptionBoot([]);
|
|
470
|
-
|
|
530
|
+
$connection->getSchemaBuilder()->drop('drivers');
|
|
471
531
|
|
|
472
|
-
//
|
|
473
|
-
$
|
|
474
|
-
|
|
475
|
-
'name' => 'Provisioned Driver',
|
|
476
|
-
'email' => 'provisioned@example.com',
|
|
477
|
-
'phone' => '+6591112222',
|
|
478
|
-
'photo_uuid' => '99999999-9999-4999-8999-999999999902',
|
|
479
|
-
]));
|
|
480
|
-
expect($created)->toBeArray()->toHaveKey('driver')
|
|
481
|
-
->and($connection->table('users')->where('email', 'provisioned@example.com')->count())->toBe(1)
|
|
482
|
-
->and($connection->table('users')->where('email', 'provisioned@example.com')->value('avatar_uuid'))->toBe('99999999-9999-4999-8999-999999999902');
|
|
483
|
-
|
|
484
|
-
// Users already holding a driver profile in the company are rejected
|
|
485
|
-
$existingUserUuid = $connection->table('users')->where('email', 'provisioned@example.com')->value('uuid');
|
|
486
|
-
$conflict = (new DriverController())->createRecord(fleetopsDriverAdoptionRequest([
|
|
487
|
-
'user_uuid' => $existingUserUuid,
|
|
488
|
-
'name' => 'Duplicate Driver',
|
|
489
|
-
]));
|
|
490
|
-
expect($conflict->getData(true)['error'] ?? '')->toContain('already belongs');
|
|
532
|
+
// The account is created before the driver row fails to insert
|
|
533
|
+
$queryFailure = (new DriverController())->createRecord(fleetopsDriverAdoptionRequest(['name' => 'Tableless Driver']));
|
|
534
|
+
expect($queryFailure->getData(true)['error'])->toContain('drivers');
|
|
491
535
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
]));
|
|
497
|
-
expect($noCompany->getData(true)['error'] ?? '')->toContain('Unable to create driver');
|
|
498
|
-
session(['company' => 'company-1']);
|
|
536
|
+
fleetopsDriverAdoptionThrowingHasher(new Fleetbase\Exceptions\FleetbaseRequestValidationException(['password' => ['The password is too weak.']]));
|
|
537
|
+
$validationFailure = (new DriverController())->createRecord(fleetopsDriverAdoptionRequest(['name' => 'Weak Password', 'password' => 'weak-password']));
|
|
538
|
+
|
|
539
|
+
expect($validationFailure->getData(true))->toBe(['error' => ['password' => ['The password is too weak.']]]);
|
|
499
540
|
});
|
|
500
541
|
|
|
501
542
|
test('auth can resolves real permissions for requests and ping guards', function () {
|
|
@@ -558,153 +599,3 @@ test('auth can resolves real permissions for requests and ping guards', function
|
|
|
558
599
|
|
|
559
600
|
session(['user' => null]);
|
|
560
601
|
});
|
|
561
|
-
|
|
562
|
-
function fleetopsDriverAdoptionUpdateRequest(string $publicId, array $driver): Request
|
|
563
|
-
{
|
|
564
|
-
$request = Request::create('/int/v1/drivers/' . $publicId, 'PUT', ['driver' => $driver]);
|
|
565
|
-
$request->setRouteResolver(function () use ($publicId) {
|
|
566
|
-
return new class($publicId) {
|
|
567
|
-
public function __construct(private string $publicId)
|
|
568
|
-
{
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
public function getAction($key = null)
|
|
572
|
-
{
|
|
573
|
-
return $key === null ? ['controller' => DriverController::class . '@updateRecord'] : DriverController::class . '@updateRecord';
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
public function getActionMethod()
|
|
577
|
-
{
|
|
578
|
-
return 'updateRecord';
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
public function getName()
|
|
582
|
-
{
|
|
583
|
-
return 'internal.drivers.update';
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
public function uri()
|
|
587
|
-
{
|
|
588
|
-
return 'int/v1/drivers/{id}';
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
public function parameters()
|
|
592
|
-
{
|
|
593
|
-
return ['id' => $this->publicId];
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
public function parameter($name = null, $default = null)
|
|
597
|
-
{
|
|
598
|
-
return $name === 'id' ? $this->publicId : $default;
|
|
599
|
-
}
|
|
600
|
-
};
|
|
601
|
-
});
|
|
602
|
-
|
|
603
|
-
return $request;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
test('creation applies photo avatars and syncs custom field values', function () {
|
|
607
|
-
$connection = fleetopsDriverAdoptionBoot([]);
|
|
608
|
-
$connection->table('custom_fields')->insert(['uuid' => '33333333-3333-4333-8333-333333333301', 'company_uuid' => 'company-1', 'name' => 'badge_number', 'label' => 'Badge Number']);
|
|
609
|
-
|
|
610
|
-
$result = (new DriverController())->createRecord(fleetopsDriverAdoptionRequest([
|
|
611
|
-
'name' => 'Photographed Driver',
|
|
612
|
-
'email' => 'photographed@example.com',
|
|
613
|
-
'phone' => '+6590002222',
|
|
614
|
-
'photo_uuid' => '44444444-4444-4444-8444-444444444401',
|
|
615
|
-
'custom_field_values' => [
|
|
616
|
-
['custom_field_uuid' => '33333333-3333-4333-8333-333333333301', 'value' => 'BADGE-7', 'value_type' => 'text'],
|
|
617
|
-
],
|
|
618
|
-
]));
|
|
619
|
-
|
|
620
|
-
expect($result)->toBeArray()->toHaveKey('driver')
|
|
621
|
-
->and($connection->table('users')->where('email', 'photographed@example.com')->value('avatar_uuid'))->toBe('44444444-4444-4444-8444-444444444401')
|
|
622
|
-
->and($connection->table('custom_field_values')->where('value', 'BADGE-7')->count())->toBe(1);
|
|
623
|
-
});
|
|
624
|
-
|
|
625
|
-
test('creation maps query and validation failures onto error responses', function () {
|
|
626
|
-
fleetopsDriverAdoptionBoot([]);
|
|
627
|
-
|
|
628
|
-
// Query failures from the persistence pipeline report a generic message
|
|
629
|
-
$queryFailure = new DriverController();
|
|
630
|
-
$queryFailure->model = new class extends Fleetbase\FleetOps\Models\Driver {
|
|
631
|
-
public function createRecordFromRequest($request, ?callable $onBefore = null, ?callable $onAfter = null, array $options = [])
|
|
632
|
-
{
|
|
633
|
-
throw new Illuminate\Database\QueryException('mysql', 'insert into drivers', [], new RuntimeException('constraint violation'));
|
|
634
|
-
}
|
|
635
|
-
};
|
|
636
|
-
$queryResponse = $queryFailure->createRecord(fleetopsDriverAdoptionRequest(['name' => 'Query Failure']));
|
|
637
|
-
expect($queryResponse->getData(true)['error'] ?? '')->not->toBeEmpty();
|
|
638
|
-
|
|
639
|
-
// Validation exceptions surface their individual error messages
|
|
640
|
-
$validationFailure = new DriverController();
|
|
641
|
-
$validationFailure->model = new class extends Fleetbase\FleetOps\Models\Driver {
|
|
642
|
-
public function createRecordFromRequest($request, ?callable $onBefore = null, ?callable $onAfter = null, array $options = [])
|
|
643
|
-
{
|
|
644
|
-
throw new Fleetbase\Exceptions\FleetbaseRequestValidationException(['The name field is required.']);
|
|
645
|
-
}
|
|
646
|
-
};
|
|
647
|
-
$validationResponse = $validationFailure->createRecord(fleetopsDriverAdoptionRequest(['name' => 'Validation Failure']));
|
|
648
|
-
expect($validationResponse->getData(true)['error'])->toBe(['The name field is required.']);
|
|
649
|
-
});
|
|
650
|
-
|
|
651
|
-
test('updates apply photo avatars and sync custom field values', function () {
|
|
652
|
-
$connection = fleetopsDriverAdoptionBoot([]);
|
|
653
|
-
$connection->table('users')->insert(['uuid' => '11111111-1111-4111-8111-111111111121', 'company_uuid' => 'company-1', 'name' => 'Photo Driver', 'email' => 'photodriver@example.com', 'type' => 'driver']);
|
|
654
|
-
$connection->table('drivers')->insert(['uuid' => '22222222-2222-4222-8222-222222222221', 'public_id' => 'driver_photoone', 'company_uuid' => 'company-1', 'user_uuid' => '11111111-1111-4111-8111-111111111121']);
|
|
655
|
-
$connection->table('custom_fields')->insert(['uuid' => '33333333-3333-4333-8333-333333333302', 'company_uuid' => 'company-1', 'name' => 'route_code', 'label' => 'Route Code']);
|
|
656
|
-
|
|
657
|
-
$result = (new DriverController())->updateRecord(fleetopsDriverAdoptionUpdateRequest('driver_photoone', [
|
|
658
|
-
'name' => 'Photo Driver Updated',
|
|
659
|
-
'photo_uuid' => '44444444-4444-4444-8444-444444444402',
|
|
660
|
-
'custom_field_values' => [
|
|
661
|
-
['custom_field_uuid' => '33333333-3333-4333-8333-333333333302', 'value' => 'ROUTE-9', 'value_type' => 'text'],
|
|
662
|
-
],
|
|
663
|
-
]), 'driver_photoone');
|
|
664
|
-
|
|
665
|
-
expect($result)->toBeArray()->toHaveKey('driver')
|
|
666
|
-
->and($connection->table('users')->where('uuid', '11111111-1111-4111-8111-111111111121')->value('avatar_uuid'))->toBe('44444444-4444-4444-8444-444444444402')
|
|
667
|
-
->and($connection->table('custom_field_values')->where('value', 'ROUTE-9')->count())->toBe(1);
|
|
668
|
-
});
|
|
669
|
-
|
|
670
|
-
test('updates map validation and generic failures onto error responses', function () {
|
|
671
|
-
fleetopsDriverAdoptionBoot([]);
|
|
672
|
-
|
|
673
|
-
// Validation exceptions from the pipeline surface their error list
|
|
674
|
-
$validationFailure = new DriverController();
|
|
675
|
-
$validationFailure->model = new class extends Fleetbase\FleetOps\Models\Driver {
|
|
676
|
-
public function updateRecordFromRequest(Request $request, $id, ?callable $onBefore = null, ?callable $onAfter = null, array $options = [])
|
|
677
|
-
{
|
|
678
|
-
throw new Fleetbase\Exceptions\FleetbaseRequestValidationException(['The status field is invalid.']);
|
|
679
|
-
}
|
|
680
|
-
};
|
|
681
|
-
$validationResponse = $validationFailure->updateRecord(fleetopsDriverAdoptionUpdateRequest('driver_missing1', ['name' => 'Validation Failure']), 'driver_missing1');
|
|
682
|
-
expect($validationResponse->getData(true)['error'])->toBe(['The status field is invalid.']);
|
|
683
|
-
|
|
684
|
-
// Any other failure reports its own message
|
|
685
|
-
$genericFailure = new DriverController();
|
|
686
|
-
$genericFailure->model = new class extends Fleetbase\FleetOps\Models\Driver {
|
|
687
|
-
public function updateRecordFromRequest(Request $request, $id, ?callable $onBefore = null, ?callable $onAfter = null, array $options = [])
|
|
688
|
-
{
|
|
689
|
-
throw new Exception('Driver profile is locked.');
|
|
690
|
-
}
|
|
691
|
-
};
|
|
692
|
-
$genericResponse = $genericFailure->updateRecord(fleetopsDriverAdoptionUpdateRequest('driver_missing1', ['name' => 'Generic Failure']), 'driver_missing1');
|
|
693
|
-
expect($genericResponse->getData(true)['error'] ?? '')->toBe('Driver profile is locked.');
|
|
694
|
-
});
|
|
695
|
-
|
|
696
|
-
test('update rejects requests that fail validation before persistence', function () {
|
|
697
|
-
fleetopsDriverAdoptionBoot(['status' => ['The selected status is invalid.']]);
|
|
698
|
-
|
|
699
|
-
// The error-response seam raises the validation failure once the rejection
|
|
700
|
-
// branch executes, so the request never reaches persistence
|
|
701
|
-
$failure = null;
|
|
702
|
-
|
|
703
|
-
try {
|
|
704
|
-
(new DriverController())->updateRecord(fleetopsDriverAdoptionUpdateRequest('driver_missing1', ['status' => 'bogus']), 'driver_missing1');
|
|
705
|
-
} catch (Illuminate\Validation\ValidationException $exception) {
|
|
706
|
-
$failure = $exception;
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
expect($failure?->errors())->toBe(['status' => ['The selected status is invalid.']]);
|
|
710
|
-
});
|