@fleetbase/fleetops-engine 0.6.48 → 0.6.50
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/addon/components/customer/create-order-form.hbs +2 -2
- package/addon/components/customer/form.hbs +2 -2
- package/addon/components/customer/order-form.hbs +2 -2
- package/addon/components/customer/orders.hbs +2 -2
- package/addon/components/display-place.hbs +2 -2
- package/addon/components/driver/details.hbs +5 -1
- package/addon/components/driver/form.hbs +11 -1
- package/addon/components/fleet-listing-panel.hbs +2 -2
- package/addon/components/fleet-listing-panel.js +10 -0
- package/addon/components/map/google-live-map.js +18 -75
- package/addon/components/map/leaflet-live-map.hbs +187 -37
- package/addon/components/map/leaflet-live-map.js +184 -20
- package/addon/components/modals/order-change-destination.hbs +46 -0
- package/addon/components/modals/order-change-destination.js +106 -0
- package/addon/components/modals/stop-activity.hbs +28 -0
- package/addon/components/modals/stop-activity.js +52 -0
- package/addon/components/modals/update-order-activity.hbs +45 -3
- package/addon/components/modals/update-order-activity.js +143 -5
- package/addon/components/orchestrator/phase-builder.hbs +21 -0
- package/addon/components/orchestrator/phase-builder.js +13 -0
- package/addon/components/orchestrator/resource-panel.hbs +0 -10
- package/addon/components/orchestrator/resource-panel.js +2 -4
- package/addon/components/orchestrator-workbench.js +1 -0
- package/addon/components/order/activity-list.hbs +2 -2
- package/addon/components/order/activity-timeline.hbs +31 -29
- package/addon/components/order/details/activity.hbs +3 -3
- package/addon/components/order/details/activity.js +11 -0
- package/addon/components/order/details/documents.js +2 -0
- package/addon/components/order/details/purchase-rate.hbs +2 -2
- package/addon/components/order/details/route.hbs +11 -3
- package/addon/components/order/details/route.js +91 -14
- package/addon/components/order/details/tracking.hbs +101 -72
- package/addon/components/order/details/tracking.js +149 -2
- package/addon/components/order/form/details.hbs +3 -3
- package/addon/components/order/form/documents.js +11 -4
- package/addon/components/order/form/route.hbs +108 -104
- package/addon/components/order/form/route.js +37 -1
- package/addon/components/order/form/service-rate.hbs +2 -2
- package/addon/components/order/form.hbs +2 -2
- package/addon/components/order-config-manager/activity-flow.hbs +4 -1
- package/addon/components/order-config-manager/activity-flow.js +178 -12
- package/addon/components/place/address.js +1 -1
- package/addon/components/route-list.hbs +17 -17
- package/addon/components/route-list.js +42 -10
- package/addon/components/service-rate/details.hbs +41 -0
- package/addon/components/service-rate/form.hbs +118 -0
- package/addon/components/service-rate/form.js +55 -0
- package/addon/components/vehicle/form.js +1 -1
- package/addon/components/vehicle/pill.hbs +1 -1
- package/addon/components/widget/fleet-ops-key-metrics.hbs +19 -17
- package/addon/components/widget/fleet-ops-key-metrics.js +26 -0
- package/addon/components/widget/fuel-efficiency.hbs +26 -0
- package/addon/components/widget/fuel-efficiency.js +43 -0
- package/addon/components/widget/geofence-violations.hbs +44 -0
- package/addon/components/widget/geofence-violations.js +55 -0
- package/addon/components/widget/issues-insights.hbs +43 -0
- package/addon/components/widget/issues-insights.js +62 -0
- package/addon/components/widget/kpi-active-orders.hbs +10 -0
- package/addon/components/widget/kpi-active-orders.js +5 -0
- package/addon/components/widget/kpi-aov.hbs +10 -0
- package/addon/components/widget/kpi-aov.js +5 -0
- package/addon/components/widget/kpi-distance.hbs +10 -0
- package/addon/components/widget/kpi-distance.js +5 -0
- package/addon/components/widget/kpi-drivers-online.hbs +10 -0
- package/addon/components/widget/kpi-drivers-online.js +5 -0
- package/addon/components/widget/kpi-earnings.hbs +10 -0
- package/addon/components/widget/kpi-earnings.js +5 -0
- package/addon/components/widget/kpi-open-issues.hbs +11 -0
- package/addon/components/widget/kpi-open-issues.js +5 -0
- package/addon/components/widget/kpi-tile.hbs +59 -0
- package/addon/components/widget/kpi-tile.js +168 -0
- package/addon/components/widget/live-fleet.hbs +122 -0
- package/addon/components/widget/live-fleet.js +365 -0
- package/addon/components/widget/maintenance-overview.hbs +45 -0
- package/addon/components/widget/maintenance-overview.js +40 -0
- package/addon/components/widget/on-time-delivery.hbs +27 -0
- package/addon/components/widget/on-time-delivery.js +73 -0
- package/addon/components/widget/operations-pulse.hbs +51 -0
- package/addon/components/widget/operations-pulse.js +173 -0
- package/addon/components/widget/orders-by-status.hbs +26 -0
- package/addon/components/widget/orders-by-status.js +54 -0
- package/addon/components/widget/revenue-trend.hbs +34 -0
- package/addon/components/widget/revenue-trend.js +67 -0
- package/addon/components/widget/top-drivers.hbs +44 -0
- package/addon/components/widget/top-drivers.js +54 -0
- package/addon/controllers/management/vehicles/index/new.js +1 -1
- package/addon/controllers/operations/orders/index/details.js +4 -4
- package/addon/controllers/operations/orders/index.js +14 -0
- package/addon/controllers/settings/routing.js +26 -0
- package/addon/extension.js +172 -3
- package/addon/helpers/place-address-html.js +2 -2
- package/addon/routes/operations/service-rates/index.js +1 -1
- package/addon/services/geofence.js +163 -19
- package/addon/services/leaflet-contextmenu-manager.js +27 -0
- package/addon/services/map-adapter/google.js +13 -2
- package/addon/services/vehicle-actions.js +1 -1
- package/addon/styles/fleetops-engine.css +205 -88
- package/addon/templates/maintenance/equipment/index.hbs +1 -1
- package/addon/templates/maintenance/parts/index.hbs +1 -1
- package/addon/templates/maintenance/schedules/index.hbs +1 -1
- package/addon/templates/management/vehicles/index.hbs +1 -1
- package/addon/templates/settings/avatars.hbs +1 -1
- package/addon/templates/settings/custom-fields.hbs +1 -1
- package/addon/templates/settings/map.hbs +1 -1
- package/addon/templates/settings/navigator-app.hbs +1 -1
- package/addon/templates/settings/notifications.hbs +1 -1
- package/addon/templates/settings/orchestrator.hbs +1 -1
- package/addon/templates/settings/payments/index.hbs +1 -1
- package/addon/templates/settings/payments/onboard.hbs +1 -1
- package/addon/templates/settings/routing.hbs +22 -2
- package/addon/templates/settings/scheduling.hbs +1 -1
- package/addon/utils/fleet-ops-options.js +2 -1
- package/addon/utils/live-map-card-content.js +171 -0
- package/addon/utils/normalize-order-config-flow.js +41 -0
- package/addon/utils/place-address-html.js +3 -2
- package/addon/utils/route-visualization.js +54 -7
- package/app/components/modals/order-change-destination.js +1 -0
- package/app/components/modals/stop-activity.js +1 -0
- package/app/components/widget/fuel-efficiency.js +1 -0
- package/app/components/widget/geofence-violations.js +1 -0
- package/app/components/widget/issues-insights.js +1 -0
- package/app/components/widget/kpi-active-orders.js +1 -0
- package/app/components/widget/kpi-aov.js +1 -0
- package/app/components/widget/kpi-distance.js +1 -0
- package/app/components/widget/kpi-drivers-online.js +1 -0
- package/app/components/widget/kpi-earnings.js +1 -0
- package/app/components/widget/kpi-open-issues.js +1 -0
- package/app/components/widget/kpi-tile.js +1 -0
- package/app/components/widget/live-fleet.js +1 -0
- package/app/components/widget/maintenance-overview.js +1 -0
- package/app/components/widget/on-time-delivery.js +1 -0
- package/app/components/widget/operations-pulse.js +1 -0
- package/app/components/widget/orders-by-status.js +1 -0
- package/app/components/widget/revenue-trend.js +1 -0
- package/app/components/widget/top-drivers.js +1 -0
- package/app/utils/live-map-card-content.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +3 -3
- package/pnpm-workspace.yaml +1 -0
- package/server/config/telematics.php +111 -1
- package/server/migrations/2026_05_18_000001_add_license_expiry_to_drivers_table.php +25 -0
- package/server/migrations/2026_05_21_000001_add_geographic_rules_to_service_rate_fees_table.php +37 -0
- package/server/migrations/2026_05_25_000001_add_endpoint_tracking_refs_to_payloads_table.php +50 -0
- package/server/migrations/2026_05_27_000001_default_driver_vehicle_statuses_to_available.php +48 -0
- package/server/resources/views/labels/default.php +57 -49
- package/server/resources/views/labels/waypoint-label.php +27 -20
- package/server/seeders/Testing/Concerns/SeedsTestingData.php +183 -0
- package/server/seeders/Testing/ConnectivitySeeder.php +213 -0
- package/server/seeders/Testing/FleetSeeder.php +341 -0
- package/server/seeders/Testing/MaintenanceSeeder.php +238 -0
- package/server/seeders/Testing/NetworkSeeder.php +250 -0
- package/server/seeders/Testing/OrdersSeeder.php +198 -0
- package/server/seeders/Testing/TestingSeeder.php +40 -0
- package/server/seeders/{VroomOrchestrationSeeder.php → Testing/VroomOrchestrationSeeder.php} +29 -22
- package/server/src/Console/Commands/AuditCustomerUserConflicts.php +75 -0
- package/server/src/Console/Commands/ProcessOperationalAlerts.php +279 -0
- package/server/src/Exceptions/CustomerUserConflictException.php +13 -0
- package/server/src/Http/Controllers/Api/v1/ContactController.php +17 -2
- package/server/src/Http/Controllers/Api/v1/CustomerController.php +876 -0
- package/server/src/Http/Controllers/Api/v1/DriverController.php +1 -1
- package/server/src/Http/Controllers/Api/v1/OrderConfigController.php +54 -0
- package/server/src/Http/Controllers/Api/v1/OrderController.php +98 -70
- package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +2 -2
- package/server/src/Http/Controllers/Api/v1/VehicleController.php +20 -3
- package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +119 -0
- package/server/src/Http/Controllers/Internal/v1/ContactController.php +19 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +101 -66
- package/server/src/Http/Controllers/Internal/v1/MetricsController.php +82 -3
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +441 -32
- package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +1 -1
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +46 -1
- package/server/src/Http/Controllers/Internal/v1/VehicleController.php +54 -1
- package/server/src/Http/Middleware/AuthenticateCustomerToken.php +34 -0
- package/server/src/Http/Requests/CreateCustomerOrderRequest.php +63 -0
- package/server/src/Http/Requests/CreateCustomerRequest.php +48 -0
- package/server/src/Http/Requests/CreateDriverRequest.php +1 -1
- package/server/src/Http/Requests/CreateVehicleRequest.php +25 -1
- package/server/src/Http/Requests/Internal/CreateDriverRequest.php +1 -1
- package/server/src/Http/Requests/VerifyCreateCustomerRequest.php +29 -0
- package/server/src/Http/Resources/Internal/v1/OrderConfig.php +41 -0
- package/server/src/Http/Resources/v1/Customer.php +79 -0
- package/server/src/Http/Resources/v1/Driver.php +2 -0
- package/server/src/Http/Resources/v1/Fleet.php +4 -0
- package/server/src/Http/Resources/v1/Index/Driver.php +48 -0
- package/server/src/Http/Resources/v1/Index/Vehicle.php +74 -1
- package/server/src/Http/Resources/v1/OrderConfig.php +74 -0
- package/server/src/Http/Resources/v1/Payload.php +23 -20
- package/server/src/Http/Resources/v1/ServiceArea.php +33 -19
- package/server/src/Http/Resources/v1/ServiceRateFee.php +7 -0
- package/server/src/Listeners/HandleOrderDispatched.php +2 -2
- package/server/src/Models/Contact.php +92 -15
- package/server/src/Models/Customer.php +64 -0
- package/server/src/Models/Driver.php +14 -3
- package/server/src/Models/Entity.php +2 -2
- package/server/src/Models/Order.php +29 -4
- package/server/src/Models/OrderConfig.php +14 -11
- package/server/src/Models/Payload.php +17 -1
- package/server/src/Models/ServiceRate.php +273 -1
- package/server/src/Models/ServiceRateFee.php +39 -9
- package/server/src/Models/TrackingNumber.php +8 -2
- package/server/src/Models/Vehicle.php +18 -2
- package/server/src/Models/Waypoint.php +2 -2
- package/server/src/Notifications/LateDeparture.php +48 -0
- package/server/src/Notifications/ProlongedStoppage.php +48 -0
- package/server/src/Notifications/RouteDeviation.php +48 -0
- package/server/src/Observers/ContactObserver.php +2 -0
- package/server/src/Observers/ServiceRateObserver.php +6 -6
- package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +29 -2
- package/server/src/Providers/FleetOpsServiceProvider.php +6 -0
- package/server/src/Providers/NotificationServiceProvider.php +3 -0
- package/server/src/Support/Analytics/AbstractAnalytics.php +77 -0
- package/server/src/Support/Analytics/FuelEfficiency.php +83 -0
- package/server/src/Support/Analytics/GeofenceViolations.php +63 -0
- package/server/src/Support/Analytics/IssuesInsights.php +67 -0
- package/server/src/Support/Analytics/LiveFleet.php +127 -0
- package/server/src/Support/Analytics/MaintenanceOverview.php +70 -0
- package/server/src/Support/Analytics/OnTimeDelivery.php +75 -0
- package/server/src/Support/Analytics/OperationsPulse.php +86 -0
- package/server/src/Support/Analytics/OrdersByStatus.php +64 -0
- package/server/src/Support/Analytics/RevenueTrend.php +78 -0
- package/server/src/Support/Analytics/TopDrivers.php +92 -0
- package/server/src/Support/CustomerAuth.php +98 -0
- package/server/src/Support/LabelPdf.php +52 -0
- package/server/src/Support/Metrics/AbstractMetric.php +170 -0
- package/server/src/Support/Metrics/ActiveLiveOrdersMetric.php +28 -0
- package/server/src/Support/Metrics/AvgOrderValueMetric.php +53 -0
- package/server/src/Support/Metrics/DriversOnlineMetric.php +30 -0
- package/server/src/Support/Metrics/EarningsMetric.php +30 -0
- package/server/src/Support/Metrics/FuelCostsMetric.php +30 -0
- package/server/src/Support/Metrics/MoneyMetric.php +30 -0
- package/server/src/Support/Metrics/OpenIssuesMetric.php +35 -0
- package/server/src/Support/Metrics/OrdersCanceledMetric.php +35 -0
- package/server/src/Support/Metrics/OrdersCompletedMetric.php +35 -0
- package/server/src/Support/Metrics/OrdersInProgressMetric.php +51 -0
- package/server/src/Support/Metrics/OrdersScheduledMetric.php +37 -0
- package/server/src/Support/Metrics/Registry.php +46 -0
- package/server/src/Support/Metrics/ResolvedIssuesMetric.php +35 -0
- package/server/src/Support/Metrics/TotalCustomersMetric.php +29 -0
- package/server/src/Support/Metrics/TotalDistanceTraveledMetric.php +35 -0
- package/server/src/Support/Metrics/TotalDriversMetric.php +28 -0
- package/server/src/Support/Metrics/TotalTimeTraveledMetric.php +35 -0
- package/server/src/Support/Metrics.php +46 -249
- package/server/src/Support/ResolvesOrderServiceStops.php +512 -0
- package/server/src/Support/Telematics/Providers/AfaqyProvider.php +290 -0
- package/server/src/Support/Telematics/Providers/SafeeProvider.php +333 -0
- package/server/src/Tracking/TrackingContextBuilder.php +41 -38
- package/server/src/Tracking/TrackingIntelligenceService.php +109 -9
- package/server/src/Tracking/TrackingStop.php +13 -11
- package/server/src/routes.php +50 -0
- package/server/tests/AnalyticsRoutesTest.php +41 -0
- package/server/tests/CapacityAllocationEngineTest.php +10 -10
- package/server/tests/CustomerContactIdentitySafetyTest.php +54 -0
- package/server/tests/CustomerEndpointTest.php +199 -0
- package/server/tests/DriverVehicleStatusDefaultTest.php +39 -0
- package/server/tests/LabelPdfRenderingTest.php +23 -0
- package/server/tests/LiveControllerViewportTest.php +60 -0
- package/server/tests/MetricsRegistryTest.php +84 -0
- package/server/tests/OrchestrationPayloadBuilderTest.php +2 -2
- package/server/tests/OrderConfigEndpointTest.php +86 -0
- package/server/tests/OrderFileAttachmentTest.php +20 -0
- package/server/tests/ServiceAreaZoneApiShapeTest.php +34 -0
- package/server/tests/VehicleDriverAssignmentTest.php +18 -0
- package/server/tests/VroomOrchestrationEngineTest.php +91 -0
- package/translations/en-us.yaml +38 -0
- package/server/migrations/2026_05_13_000001_repair_customer_contact_user_types.php +0 -86
|
@@ -5,10 +5,12 @@ namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
|
|
|
5
5
|
use Fleetbase\FleetOps\Exports\VehicleExport;
|
|
6
6
|
use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
|
|
7
7
|
use Fleetbase\FleetOps\Imports\VehicleImport;
|
|
8
|
+
use Fleetbase\FleetOps\Models\Driver;
|
|
8
9
|
use Fleetbase\FleetOps\Models\Vehicle;
|
|
9
10
|
use Fleetbase\Http\Requests\ExportRequest;
|
|
10
11
|
use Fleetbase\Http\Requests\ImportRequest;
|
|
11
12
|
use Illuminate\Http\Request;
|
|
13
|
+
use Illuminate\Support\Arr;
|
|
12
14
|
use Illuminate\Support\Facades\DB;
|
|
13
15
|
use Illuminate\Support\Str;
|
|
14
16
|
use Maatwebsite\Excel\Facades\Excel;
|
|
@@ -25,14 +27,65 @@ class VehicleController extends FleetOpsController
|
|
|
25
27
|
/**
|
|
26
28
|
* Handle post save transactions.
|
|
27
29
|
*/
|
|
28
|
-
public function afterSave(Request $request, Vehicle $vehicle)
|
|
30
|
+
public function afterSave(Request $request, Vehicle $vehicle, array $input = [])
|
|
29
31
|
{
|
|
32
|
+
if ($this->hasDriverInput($request)) {
|
|
33
|
+
$this->syncDriverAssignment($vehicle, $this->driverIdentifierFromRequest($request));
|
|
34
|
+
}
|
|
35
|
+
|
|
30
36
|
$customFieldValues = $request->array('vehicle.custom_field_values');
|
|
31
37
|
if ($customFieldValues) {
|
|
32
38
|
$vehicle->syncCustomFieldValues($customFieldValues);
|
|
33
39
|
}
|
|
34
40
|
}
|
|
35
41
|
|
|
42
|
+
protected function hasDriverInput(Request $request): bool
|
|
43
|
+
{
|
|
44
|
+
$payload = $request->all();
|
|
45
|
+
|
|
46
|
+
return Arr::has($payload, 'vehicle.driver_uuid')
|
|
47
|
+
|| Arr::has($payload, 'vehicle.driver.uuid')
|
|
48
|
+
|| Arr::has($payload, 'vehicle.driver.id')
|
|
49
|
+
|| Arr::has($payload, 'driver_uuid')
|
|
50
|
+
|| Arr::has($payload, 'driver');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
protected function driverIdentifierFromRequest(Request $request): ?string
|
|
54
|
+
{
|
|
55
|
+
$payload = $request->all();
|
|
56
|
+
$driver = data_get($payload, 'vehicle.driver') ?? data_get($payload, 'driver');
|
|
57
|
+
|
|
58
|
+
return data_get($payload, 'vehicle.driver_uuid')
|
|
59
|
+
?? data_get($payload, 'vehicle.driver.uuid')
|
|
60
|
+
?? data_get($payload, 'vehicle.driver.id')
|
|
61
|
+
?? (is_string($driver) ? $driver : null)
|
|
62
|
+
?? data_get($payload, 'driver_uuid')
|
|
63
|
+
?? data_get($payload, 'driver.uuid')
|
|
64
|
+
?? data_get($payload, 'driver.id');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
protected function syncDriverAssignment(Vehicle $vehicle, ?string $identifier): void
|
|
68
|
+
{
|
|
69
|
+
if (empty($identifier)) {
|
|
70
|
+
$vehicle->unassignDriver();
|
|
71
|
+
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
$driver = Driver::withoutGlobalScopes()
|
|
76
|
+
->whereNull('deleted_at')
|
|
77
|
+
->where(function ($query) use ($identifier) {
|
|
78
|
+
$query->where('uuid', $identifier)->orWhere('public_id', $identifier);
|
|
79
|
+
})
|
|
80
|
+
->when(session('company'), fn ($query, $company) => $query->where('company_uuid', $company))
|
|
81
|
+
->first();
|
|
82
|
+
|
|
83
|
+
if ($driver) {
|
|
84
|
+
$vehicle->assignDriver($driver);
|
|
85
|
+
$vehicle->setRelation('driver', $driver);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
36
89
|
/**
|
|
37
90
|
* Get all status options for an vehicle.
|
|
38
91
|
*
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Http\Middleware;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\FleetOps\Support\CustomerAuth;
|
|
6
|
+
use Illuminate\Http\Request;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Enforce that a Customer-Token header is present and resolves to a
|
|
10
|
+
* customer-type Contact that belongs to the same company as the request's
|
|
11
|
+
* API credential.
|
|
12
|
+
*
|
|
13
|
+
* Apply this middleware to authenticated `/v1/customers/...` routes. The
|
|
14
|
+
* public sign-up / login routes do NOT use it.
|
|
15
|
+
*/
|
|
16
|
+
class AuthenticateCustomerToken
|
|
17
|
+
{
|
|
18
|
+
public function handle(Request $request, \Closure $next)
|
|
19
|
+
{
|
|
20
|
+
$customer = CustomerAuth::resolveFromHeader($request);
|
|
21
|
+
if (!$customer) {
|
|
22
|
+
return response()->apiError('Customer token is missing or invalid.', 401);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
$sessionCompany = session('company');
|
|
26
|
+
if ($sessionCompany && $customer->company_uuid !== $sessionCompany) {
|
|
27
|
+
return response()->apiError('Customer does not belong to this company.', 403);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
CustomerAuth::setCurrent($customer);
|
|
31
|
+
|
|
32
|
+
return $next($request);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Http\Requests;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Http\Requests\FleetbaseRequest;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Validates the body of `POST /v1/customers/orders`.
|
|
9
|
+
*
|
|
10
|
+
* Mirrors the canonical Fleet-Ops Order create shape used by the operator
|
|
11
|
+
* `POST /v1/orders` endpoint: `type` / `order_config`, `scheduled_at`,
|
|
12
|
+
* `notes`, `meta`, and either a nested `payload` or top-level
|
|
13
|
+
* `pickup` / `dropoff` / `return` / `waypoints` / `entities`. Place and
|
|
14
|
+
* Entity sub-objects accept the standard Fleet-Ops Place / Entity field
|
|
15
|
+
* shapes — no client-portal aliases are recognized.
|
|
16
|
+
*
|
|
17
|
+
* `customer` is intentionally not accepted: the controller forces
|
|
18
|
+
* `customer_uuid` from the authenticated Customer-Token. `status`,
|
|
19
|
+
* `driver`, `vehicle`, `facilitator`, `dispatch` and similar operator-tier
|
|
20
|
+
* fields are also out of scope for the customer surface.
|
|
21
|
+
*/
|
|
22
|
+
class CreateCustomerOrderRequest extends FleetbaseRequest
|
|
23
|
+
{
|
|
24
|
+
public function authorize(): bool
|
|
25
|
+
{
|
|
26
|
+
return request()->session()->has('api_credential')
|
|
27
|
+
|| request()->session()->has('is_sanctum_token');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public function rules(): array
|
|
31
|
+
{
|
|
32
|
+
return [
|
|
33
|
+
'type' => 'nullable|string',
|
|
34
|
+
'order_config' => 'nullable|string',
|
|
35
|
+
'scheduled_at' => 'nullable|date',
|
|
36
|
+
'notes' => 'nullable|string|max:2000',
|
|
37
|
+
'internal_id' => 'nullable|string|max:191',
|
|
38
|
+
'meta' => 'nullable|array',
|
|
39
|
+
// Optional ServiceQuote reference (uuid or `sqte_…` public_id).
|
|
40
|
+
// Resolved server-side via `ServiceQuote::resolveFromRequest` and
|
|
41
|
+
// consumed by `$order->purchaseServiceQuote()` after creation.
|
|
42
|
+
'service_quote' => 'nullable|string',
|
|
43
|
+
|
|
44
|
+
// payload may be an object OR a payload public_id string
|
|
45
|
+
'payload' => 'nullable',
|
|
46
|
+
|
|
47
|
+
// Top-level alternatives when `payload` is not provided. Each
|
|
48
|
+
// Place sub-object accepts the standard Place fillable shape.
|
|
49
|
+
'pickup' => 'nullable',
|
|
50
|
+
'dropoff' => 'nullable',
|
|
51
|
+
'return' => 'nullable',
|
|
52
|
+
'waypoints' => 'nullable|array',
|
|
53
|
+
'entities' => 'nullable|array',
|
|
54
|
+
'entities.*.name' => 'nullable|string',
|
|
55
|
+
'entities.*.description' => 'nullable|string',
|
|
56
|
+
'entities.*.weight' => 'nullable|numeric|min:0',
|
|
57
|
+
'entities.*.weight_unit' => 'nullable|string',
|
|
58
|
+
'entities.*.declared_value' => 'nullable|numeric|min:0',
|
|
59
|
+
'entities.*.currency' => 'nullable|string|size:3',
|
|
60
|
+
'entities.*.meta' => 'nullable|array',
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Http\Requests;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Http\Requests\FleetbaseRequest;
|
|
6
|
+
use Illuminate\Validation\Rule;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Validates the body of `POST /v1/customers` (final account creation step).
|
|
10
|
+
*
|
|
11
|
+
* Expects the verification code previously requested via
|
|
12
|
+
* `POST /v1/customers/request-creation-code`.
|
|
13
|
+
*/
|
|
14
|
+
class CreateCustomerRequest extends FleetbaseRequest
|
|
15
|
+
{
|
|
16
|
+
public function authorize(): bool
|
|
17
|
+
{
|
|
18
|
+
return request()->session()->has('api_credential')
|
|
19
|
+
|| request()->session()->has('is_sanctum_token');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public function rules(): array
|
|
23
|
+
{
|
|
24
|
+
return [
|
|
25
|
+
'identity' => 'required|string',
|
|
26
|
+
'code' => 'required|exists:verification_codes,code',
|
|
27
|
+
'name' => 'required|string',
|
|
28
|
+
'password' => 'required|string|min:8',
|
|
29
|
+
'email' => [
|
|
30
|
+
'email', 'nullable',
|
|
31
|
+
Rule::unique('contacts')->where(function ($query) {
|
|
32
|
+
$query->where('company_uuid', session('company'));
|
|
33
|
+
|
|
34
|
+
return $query->whereNull('deleted_at');
|
|
35
|
+
}),
|
|
36
|
+
],
|
|
37
|
+
'phone' => [
|
|
38
|
+
'nullable', 'string',
|
|
39
|
+
Rule::unique('contacts')->where(function ($query) {
|
|
40
|
+
$query->where('company_uuid', session('company'));
|
|
41
|
+
|
|
42
|
+
return $query->whereNull('deleted_at');
|
|
43
|
+
}),
|
|
44
|
+
],
|
|
45
|
+
'meta' => 'nullable|array',
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -35,7 +35,7 @@ class CreateDriverRequest extends FleetbaseRequest
|
|
|
35
35
|
'country' => 'nullable|size:2',
|
|
36
36
|
'city' => 'nullable|string',
|
|
37
37
|
'vehicle' => 'nullable|string|starts_with:vehicle_|exists:vehicles,public_id',
|
|
38
|
-
'status' => 'nullable|string|in:active,inactive',
|
|
38
|
+
'status' => 'nullable|string|in:active,available,inactive',
|
|
39
39
|
'vendor' => 'nullable|exists:vendors,public_id',
|
|
40
40
|
'job' => 'nullable|exists:orders,public_id',
|
|
41
41
|
'location' => ['nullable', new ResolvablePoint()],
|
|
@@ -4,6 +4,7 @@ namespace Fleetbase\FleetOps\Http\Requests;
|
|
|
4
4
|
|
|
5
5
|
use Fleetbase\FleetOps\Rules\ResolvablePoint;
|
|
6
6
|
use Fleetbase\Http\Requests\FleetbaseRequest;
|
|
7
|
+
use Illuminate\Validation\Rule;
|
|
7
8
|
|
|
8
9
|
class CreateVehicleRequest extends FleetbaseRequest
|
|
9
10
|
{
|
|
@@ -25,7 +26,30 @@ class CreateVehicleRequest extends FleetbaseRequest
|
|
|
25
26
|
public function rules()
|
|
26
27
|
{
|
|
27
28
|
return [
|
|
28
|
-
'status' =>
|
|
29
|
+
'status' => [
|
|
30
|
+
'nullable',
|
|
31
|
+
Rule::in([
|
|
32
|
+
'active',
|
|
33
|
+
'available',
|
|
34
|
+
'in_use',
|
|
35
|
+
'maintenance',
|
|
36
|
+
'out_of_service',
|
|
37
|
+
'reserved',
|
|
38
|
+
'retired',
|
|
39
|
+
'staging',
|
|
40
|
+
'on_route',
|
|
41
|
+
'idle',
|
|
42
|
+
'cleaning',
|
|
43
|
+
'awaiting_parts',
|
|
44
|
+
'inspection_due',
|
|
45
|
+
'inspection_failed',
|
|
46
|
+
'accident',
|
|
47
|
+
'compliance_hold',
|
|
48
|
+
'stolen',
|
|
49
|
+
'operational',
|
|
50
|
+
'decommissioned',
|
|
51
|
+
]),
|
|
52
|
+
],
|
|
29
53
|
'vendor' => 'nullable|exists:vendors,public_id',
|
|
30
54
|
'driver' => 'nullable|exists:drivers,public_id',
|
|
31
55
|
'location' => ['nullable', new ResolvablePoint()],
|
|
@@ -51,7 +51,7 @@ class CreateDriverRequest extends CreateDriverApiRequest
|
|
|
51
51
|
'country' => 'nullable|string|size:2',
|
|
52
52
|
'city' => 'nullable|string|max:255',
|
|
53
53
|
'vehicle' => ['nullable', new ResolvableVehicle()],
|
|
54
|
-
'status' => 'nullable|string|in:active,inactive',
|
|
54
|
+
'status' => 'nullable|string|in:active,available,inactive',
|
|
55
55
|
'vendor' => 'nullable|exists:vendors,public_id',
|
|
56
56
|
'job' => 'nullable|exists:orders,public_id',
|
|
57
57
|
'location' => ['nullable', new ResolvablePoint()],
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Http\Requests;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Http\Requests\FleetbaseRequest;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Validates the body of `POST /v1/customers/request-creation-code`.
|
|
9
|
+
*/
|
|
10
|
+
class VerifyCreateCustomerRequest extends FleetbaseRequest
|
|
11
|
+
{
|
|
12
|
+
public function authorize(): bool
|
|
13
|
+
{
|
|
14
|
+
return request()->session()->has('api_credential')
|
|
15
|
+
|| request()->session()->has('is_sanctum_token');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public function rules(): array
|
|
19
|
+
{
|
|
20
|
+
return [
|
|
21
|
+
'mode' => 'required|in:email,sms',
|
|
22
|
+
'identity' => 'required|string',
|
|
23
|
+
// Optional profile context — when provided, used to greet the
|
|
24
|
+
// customer in the verification email and pre-seed the User row.
|
|
25
|
+
'name' => 'nullable|string|max:255',
|
|
26
|
+
'phone' => 'nullable|string|max:32',
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Http\Resources\Internal\v1;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Http\Resources\FleetbaseResource;
|
|
6
|
+
|
|
7
|
+
class OrderConfig extends FleetbaseResource
|
|
8
|
+
{
|
|
9
|
+
/**
|
|
10
|
+
* Transform the resource into an array.
|
|
11
|
+
*
|
|
12
|
+
* @param \Illuminate\Http\Request $request
|
|
13
|
+
*/
|
|
14
|
+
public function toArray($request): array
|
|
15
|
+
{
|
|
16
|
+
return [
|
|
17
|
+
'id' => $this->id,
|
|
18
|
+
'uuid' => $this->uuid,
|
|
19
|
+
'public_id' => $this->public_id,
|
|
20
|
+
'company_uuid' => $this->company_uuid,
|
|
21
|
+
'author_uuid' => $this->author_uuid,
|
|
22
|
+
'category_uuid' => $this->category_uuid,
|
|
23
|
+
'icon_uuid' => $this->icon_uuid,
|
|
24
|
+
'name' => $this->name,
|
|
25
|
+
'namespace' => $this->namespace,
|
|
26
|
+
'description' => $this->description,
|
|
27
|
+
'key' => $this->key,
|
|
28
|
+
'status' => $this->status,
|
|
29
|
+
'version' => $this->version,
|
|
30
|
+
'core_service' => (bool) $this->core_service,
|
|
31
|
+
'flow' => $this->flow ?? [],
|
|
32
|
+
'entities' => $this->entities ?? [],
|
|
33
|
+
'tags' => $this->tags ?? [],
|
|
34
|
+
'meta' => $this->meta ?? [],
|
|
35
|
+
'created_at' => $this->created_at,
|
|
36
|
+
'updated_at' => $this->updated_at,
|
|
37
|
+
'deleted_at' => $this->deleted_at,
|
|
38
|
+
'type' => 'order-config',
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Http\Resources\v1;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\FleetOps\Models\Order;
|
|
6
|
+
use Fleetbase\FleetOps\Support\Utils;
|
|
7
|
+
use Fleetbase\Http\Resources\FleetbaseResource;
|
|
8
|
+
use Fleetbase\Models\Company;
|
|
9
|
+
use Fleetbase\Support\Http;
|
|
10
|
+
use Illuminate\Http\Request;
|
|
11
|
+
use Illuminate\Support\Str;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Public API resource for FleetOps customers.
|
|
15
|
+
*
|
|
16
|
+
* Wraps a {@see \Fleetbase\FleetOps\Models\Contact} of `type='customer'` and
|
|
17
|
+
* exposes the auth `token` field that login/signup endpoints attach.
|
|
18
|
+
*/
|
|
19
|
+
class Customer extends FleetbaseResource
|
|
20
|
+
{
|
|
21
|
+
public function toArray($request): array
|
|
22
|
+
{
|
|
23
|
+
$this->loadMissing(['place', 'places']);
|
|
24
|
+
|
|
25
|
+
return [
|
|
26
|
+
'id' => $this->when(Http::isInternalRequest(), $this->id, Str::replaceFirst('contact', 'customer', $this->public_id)),
|
|
27
|
+
'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
|
|
28
|
+
'user_uuid' => $this->when(Http::isInternalRequest(), $this->user_uuid),
|
|
29
|
+
'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid),
|
|
30
|
+
'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
|
|
31
|
+
'internal_id' => $this->internal_id,
|
|
32
|
+
'name' => $this->name,
|
|
33
|
+
'title' => $this->title,
|
|
34
|
+
'photo_url' => $this->photo_url,
|
|
35
|
+
'email' => $this->email,
|
|
36
|
+
'phone' => $this->phone,
|
|
37
|
+
'address' => data_get($this, 'place.address'),
|
|
38
|
+
'addresses' => $this->whenLoaded('places', fn () => Place::collection($this->places)),
|
|
39
|
+
'token' => $this->when($this->token, $this->token),
|
|
40
|
+
'orders_count' => $this->getOrdersCount($request),
|
|
41
|
+
'company' => $this->when($this->company_uuid, fn () => $this->buildCompanyPayload()),
|
|
42
|
+
'meta' => data_get($this, 'meta', Utils::createObject()),
|
|
43
|
+
'slug' => $this->slug,
|
|
44
|
+
'created_at' => $this->created_at,
|
|
45
|
+
'updated_at' => $this->updated_at,
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private function getOrdersCount(Request $request): int
|
|
50
|
+
{
|
|
51
|
+
return Order::where('customer_uuid', $this->uuid)
|
|
52
|
+
->whereNull('deleted_at')
|
|
53
|
+
->withoutGlobalScopes()
|
|
54
|
+
->count();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Public-safe projection of the customer's company. Returns the same
|
|
59
|
+
* fields any caller could fetch through other public endpoints — name,
|
|
60
|
+
* resolved currency, country, phone — plus the company's public id.
|
|
61
|
+
* Currency falls back through company.currency → ledger base_currency
|
|
62
|
+
* → "USD" via {@see Utils::getCompanyTransactionCurrency}.
|
|
63
|
+
*/
|
|
64
|
+
private function buildCompanyPayload(): ?array
|
|
65
|
+
{
|
|
66
|
+
$company = Company::find($this->company_uuid);
|
|
67
|
+
if (!$company) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return [
|
|
72
|
+
'id' => $company->public_id,
|
|
73
|
+
'name' => $company->name,
|
|
74
|
+
'currency' => Utils::getCompanyTransactionCurrency($company),
|
|
75
|
+
'country' => $company->country,
|
|
76
|
+
'phone' => $company->phone,
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -38,6 +38,7 @@ class Driver extends FleetbaseResource
|
|
|
38
38
|
'email' => $this->email,
|
|
39
39
|
'phone' => $this->phone,
|
|
40
40
|
'drivers_license_number' => $this->drivers_license_number,
|
|
41
|
+
'license_expiry' => $this->license_expiry,
|
|
41
42
|
'photo_url' => $this->photo_url,
|
|
42
43
|
'avatar_url' => $this->avatar_url,
|
|
43
44
|
'avatar_value' => $this->when(Http::isInternalRequest(), $this->getOriginal('avatar_url')),
|
|
@@ -94,6 +95,7 @@ class Driver extends FleetbaseResource
|
|
|
94
95
|
'email' => $this->email,
|
|
95
96
|
'phone' => $this->phone,
|
|
96
97
|
'photo_url' => $this->photo_url,
|
|
98
|
+
'license_expiry' => $this->license_expiry,
|
|
97
99
|
'vehicle' => data_get($this, 'vehicle.public_id'),
|
|
98
100
|
'current_job' => data_get($this, 'currentJob.public_id'),
|
|
99
101
|
'vendor' => data_get($this, 'vendor.public_id'),
|
|
@@ -23,6 +23,10 @@ class Fleet extends FleetbaseResource
|
|
|
23
23
|
}, $request->array('with'));
|
|
24
24
|
|
|
25
25
|
$this->load($with);
|
|
26
|
+
|
|
27
|
+
if (in_array('subfleets', $with, true) && in_array('vehicles', $with, true)) {
|
|
28
|
+
$this->loadMissing('subFleets.vehicles');
|
|
29
|
+
}
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
return $this->withCustomFields([
|
|
@@ -33,6 +33,7 @@ class Driver extends FleetbaseResource
|
|
|
33
33
|
'current_job_uuid'=> $this->when($isInternal, $this->current_job_uuid),
|
|
34
34
|
'name' => $this->name,
|
|
35
35
|
'vehicle_name' => $this->when($isInternal, $this->vehicle_name),
|
|
36
|
+
'email' => $this->email,
|
|
36
37
|
'phone' => $this->phone,
|
|
37
38
|
'photo_url' => $this->photo_url,
|
|
38
39
|
'status' => $this->status,
|
|
@@ -41,6 +42,53 @@ class Driver extends FleetbaseResource
|
|
|
41
42
|
'altitude' => (int) data_get($this, 'altitude', 0),
|
|
42
43
|
'speed' => (int) data_get($this, 'speed', 0),
|
|
43
44
|
'online' => data_get($this, 'online', false),
|
|
45
|
+
'meta' => [
|
|
46
|
+
'_index_resource' => true,
|
|
47
|
+
'location_coordinates' => $this->locationCoordinates(),
|
|
48
|
+
'current_order_reference' => $this->currentOrderReference(),
|
|
49
|
+
'speed_label' => $this->speedLabel(),
|
|
50
|
+
'heading_label' => $this->headingLabel(),
|
|
51
|
+
'status_label' => $this->statusLabel(),
|
|
52
|
+
],
|
|
44
53
|
];
|
|
45
54
|
}
|
|
55
|
+
|
|
56
|
+
protected function currentOrderReference(): ?string
|
|
57
|
+
{
|
|
58
|
+
$this->loadMissing('currentOrder');
|
|
59
|
+
$order = data_get($this, 'currentOrder');
|
|
60
|
+
|
|
61
|
+
return data_get($order, 'tracking') ?? data_get($order, 'public_id');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
protected function locationCoordinates(): ?string
|
|
65
|
+
{
|
|
66
|
+
$location = Utils::castPoint($this->location);
|
|
67
|
+
|
|
68
|
+
return $location ? $this->formatCoordinate($location->getLat()) . ' ' . $this->formatCoordinate($location->getLng()) : null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
protected function speedLabel(): string
|
|
72
|
+
{
|
|
73
|
+
$speed = data_get($this, 'speed');
|
|
74
|
+
|
|
75
|
+
return is_numeric($speed) ? ((int) $speed) . ' km/h' : '-';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
protected function headingLabel(): string
|
|
79
|
+
{
|
|
80
|
+
$heading = data_get($this, 'heading');
|
|
81
|
+
|
|
82
|
+
return is_numeric($heading) ? ((int) $heading) . ' deg' : '-';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
protected function statusLabel(): ?string
|
|
86
|
+
{
|
|
87
|
+
return $this->status ? str($this->status)->replace(['_', '-'], ' ')->headline()->toString() : null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
protected function formatCoordinate(float $coordinate): string
|
|
91
|
+
{
|
|
92
|
+
return (string) round($coordinate, 4);
|
|
93
|
+
}
|
|
46
94
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Http\Resources\v1\Index;
|
|
4
4
|
|
|
5
|
+
use Fleetbase\FleetOps\Models\Order;
|
|
5
6
|
use Fleetbase\FleetOps\Support\Utils;
|
|
6
7
|
use Fleetbase\Http\Resources\FleetbaseResource;
|
|
7
8
|
use Fleetbase\Support\Http;
|
|
@@ -28,8 +29,12 @@ class Vehicle extends FleetbaseResource
|
|
|
28
29
|
'company_uuid' => $this->when($isInternal, $this->company_uuid),
|
|
29
30
|
'vendor_uuid' => $this->when($isInternal, $this->vendor_uuid),
|
|
30
31
|
'photo_uuid' => $this->when($isInternal, $this->photo_uuid),
|
|
32
|
+
'internal_id' => $this->internal_id,
|
|
31
33
|
'display_name' => $this->display_name,
|
|
34
|
+
'driver_name' => $this->driver_name,
|
|
32
35
|
'plate_number' => $this->plate_number,
|
|
36
|
+
'serial_number' => $this->serial_number,
|
|
37
|
+
'vin' => $this->vin,
|
|
33
38
|
'make' => $this->make,
|
|
34
39
|
'model' => $this->model,
|
|
35
40
|
'year' => $this->year,
|
|
@@ -43,8 +48,76 @@ class Vehicle extends FleetbaseResource
|
|
|
43
48
|
|
|
44
49
|
// Meta flag to indicate this is an index resource
|
|
45
50
|
'meta' => [
|
|
46
|
-
'_index_resource'
|
|
51
|
+
'_index_resource' => true,
|
|
52
|
+
'current_order_reference' => $this->currentOrderReference(),
|
|
53
|
+
'location_coordinates' => $this->locationCoordinates(),
|
|
54
|
+
'speed_label' => $this->speedLabel(),
|
|
55
|
+
'heading_label' => $this->headingLabel(),
|
|
56
|
+
'status_label' => $this->statusLabel(),
|
|
47
57
|
],
|
|
48
58
|
];
|
|
49
59
|
}
|
|
60
|
+
|
|
61
|
+
protected function currentOrderReference(): ?string
|
|
62
|
+
{
|
|
63
|
+
$this->loadMissing('driver.currentOrder');
|
|
64
|
+
$order = data_get($this, 'driver.currentOrder') ?? $this->currentPositionOrder() ?? $this->currentVehicleOrder();
|
|
65
|
+
|
|
66
|
+
return data_get($order, 'tracking') ?? data_get($order, 'public_id');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
protected function locationCoordinates(): ?string
|
|
70
|
+
{
|
|
71
|
+
$location = Utils::castPoint($this->location);
|
|
72
|
+
|
|
73
|
+
return $location ? $this->formatCoordinate($location->getLat()) . ' ' . $this->formatCoordinate($location->getLng()) : null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
protected function speedLabel(): string
|
|
77
|
+
{
|
|
78
|
+
$speed = data_get($this->lastKnownPosition(), 'speed', data_get($this, 'speed'));
|
|
79
|
+
|
|
80
|
+
return is_numeric($speed) ? ((int) $speed) . ' km/h' : '-';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
protected function headingLabel(): string
|
|
84
|
+
{
|
|
85
|
+
$heading = data_get($this->lastKnownPosition(), 'heading', data_get($this, 'heading'));
|
|
86
|
+
|
|
87
|
+
return is_numeric($heading) ? ((int) $heading) . ' deg' : '-';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
protected function statusLabel(): ?string
|
|
91
|
+
{
|
|
92
|
+
return $this->status ? str($this->status)->replace(['_', '-'], ' ')->headline()->toString() : null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
protected function currentPositionOrder(): ?Order
|
|
96
|
+
{
|
|
97
|
+
$orderUuid = data_get($this->lastKnownPosition(), 'order_uuid');
|
|
98
|
+
|
|
99
|
+
return $orderUuid ? Order::where('uuid', $orderUuid)->first() : null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
protected function currentVehicleOrder(): ?Order
|
|
103
|
+
{
|
|
104
|
+
return Order::where('vehicle_assigned_uuid', $this->uuid)
|
|
105
|
+
->whereNotIn('status', ['completed', 'canceled', 'cancelled'])
|
|
106
|
+
->latest()
|
|
107
|
+
->first();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
protected function lastKnownPosition()
|
|
111
|
+
{
|
|
112
|
+
if (!$this->resource->relationLoaded('last_known_position')) {
|
|
113
|
+
$this->resource->setRelation('last_known_position', $this->getLastKnownPosition());
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return $this->resource->getRelation('last_known_position');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
protected function formatCoordinate(float $coordinate): string
|
|
120
|
+
{
|
|
121
|
+
return (string) round($coordinate, 4);
|
|
122
|
+
}
|
|
50
123
|
}
|