@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
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import Component from '@glimmer/component';
|
|
2
2
|
import { tracked } from '@glimmer/tracking';
|
|
3
3
|
import { inject as service } from '@ember/service';
|
|
4
|
+
import { action, get } from '@ember/object';
|
|
4
5
|
import { task } from 'ember-concurrency';
|
|
6
|
+
import config from 'ember-get-config';
|
|
7
|
+
import { buildServiceStopsFromPayload } from '../../utils/route-visualization';
|
|
5
8
|
|
|
6
9
|
export default class ModalsUpdateOrderActivityComponent extends Component {
|
|
7
10
|
@service fetch;
|
|
11
|
+
@service intl;
|
|
8
12
|
@service notifications;
|
|
9
13
|
@service modalsManager;
|
|
10
14
|
@tracked activityOptions = [];
|
|
11
15
|
@tracked order;
|
|
12
16
|
@tracked selectedActivity;
|
|
13
|
-
@tracked customActivity;
|
|
17
|
+
@tracked customActivity = {};
|
|
18
|
+
@tracked proofFiles = [];
|
|
14
19
|
|
|
15
20
|
constructor(owner, { options = {} }) {
|
|
16
21
|
super(...arguments);
|
|
@@ -18,9 +23,95 @@ export default class ModalsUpdateOrderActivityComponent extends Component {
|
|
|
18
23
|
this.loadActivity.perform();
|
|
19
24
|
}
|
|
20
25
|
|
|
26
|
+
get waypoints() {
|
|
27
|
+
const waypoints = this.order?.payload?.waypoints;
|
|
28
|
+
if (typeof waypoints?.toArray === 'function') {
|
|
29
|
+
return waypoints.toArray();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return Array.isArray(waypoints) ? waypoints : Array.from(waypoints ?? []);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get serviceStops() {
|
|
36
|
+
return buildServiceStopsFromPayload(this.order?.payload);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get activeStopId() {
|
|
40
|
+
const activeStop = this.order?.tracker_data?.active_stop;
|
|
41
|
+
|
|
42
|
+
return activeStop?.uuid ?? activeStop?.public_id ?? this.order?.payload?.current_waypoint_uuid ?? this.order?.payload?.current_waypoint;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get isMultipleWaypointOrder() {
|
|
46
|
+
return this.waypoints.length > 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get orderHasStarted() {
|
|
50
|
+
const status = this.order?.status;
|
|
51
|
+
|
|
52
|
+
return Boolean(this.order?.started || this.order?.started_at || (status && !['created', 'dispatched'].includes(status)));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get shouldUseWaypointActivity() {
|
|
56
|
+
return this.isMultipleWaypointOrder && this.orderHasStarted;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get currentWaypoint() {
|
|
60
|
+
if (!this.shouldUseWaypointActivity) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const currentWaypointId = this.activeStopId;
|
|
65
|
+
|
|
66
|
+
if (currentWaypointId) {
|
|
67
|
+
const stop = this.serviceStops.find(({ place }) => {
|
|
68
|
+
return [place?.id, place?.uuid, place?.public_id, place?.waypoint_public_id].includes(currentWaypointId);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (stop?.place) {
|
|
72
|
+
return stop.place;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return this.serviceStops.find(({ place }) => !place?.complete)?.place ?? this.serviceStops[0]?.place;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get currentWaypointId() {
|
|
80
|
+
const waypoint = this.currentWaypoint;
|
|
81
|
+
|
|
82
|
+
return waypoint?.id ?? waypoint?.public_id ?? waypoint?.uuid;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get currentWaypointProofSubjectId() {
|
|
86
|
+
const waypoint = this.currentWaypoint;
|
|
87
|
+
|
|
88
|
+
return waypoint?.waypoint_public_id ?? waypoint?.id ?? waypoint?.public_id ?? waypoint?.uuid;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get selectedActivityRecord() {
|
|
92
|
+
if (this.selectedActivity === 'custom') {
|
|
93
|
+
return this.customActivity;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return this.activityOptions[this.selectedActivity];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get selectedActivityRequiresPod() {
|
|
100
|
+
return Boolean(this.selectedActivityRecord?.require_pod);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get acceptedProofFileTypes() {
|
|
104
|
+
return ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
|
105
|
+
}
|
|
106
|
+
|
|
21
107
|
@task *loadActivity() {
|
|
108
|
+
if (!this.order?.id) {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
|
|
22
112
|
try {
|
|
23
|
-
const
|
|
113
|
+
const params = this.shouldUseWaypointActivity && this.currentWaypointId ? { waypoint: this.currentWaypointId } : {};
|
|
114
|
+
const activityOptions = yield this.fetch.get(`orders/next-activity/${this.order.id}`, params);
|
|
24
115
|
this.activityOptions = activityOptions;
|
|
25
116
|
return activityOptions;
|
|
26
117
|
} catch (err) {
|
|
@@ -31,21 +122,68 @@ export default class ModalsUpdateOrderActivityComponent extends Component {
|
|
|
31
122
|
@task *submitActivity(modal) {
|
|
32
123
|
modal.startLoading();
|
|
33
124
|
|
|
34
|
-
const activity = this.
|
|
125
|
+
const activity = this.selectedActivityRecord;
|
|
35
126
|
if (this.selectedActivity === 'custom' && !activity.status && !activity.details && !activity.code) {
|
|
36
127
|
modal.stopLoading();
|
|
37
128
|
return this.notifications.warning(this.intl.t('fleet-ops.operations.orders.index.view.invalid-warning'));
|
|
38
129
|
}
|
|
39
130
|
|
|
131
|
+
if (this.selectedActivityRequiresPod && this.proofFiles.length === 0) {
|
|
132
|
+
modal.stopLoading();
|
|
133
|
+
return this.notifications.warning('Photo proof of delivery is required for this activity.');
|
|
134
|
+
}
|
|
135
|
+
|
|
40
136
|
try {
|
|
41
|
-
yield this.
|
|
137
|
+
const proof = this.selectedActivityRequiresPod ? yield this.capturePhotoProof.perform() : null;
|
|
138
|
+
yield this.fetch.patch(`orders/update-activity/${this.order.id}`, { activity, proof: proof?.id ?? proof?.public_id });
|
|
139
|
+
|
|
140
|
+
if (typeof this.order?.reload === 'function') {
|
|
141
|
+
yield this.order.reload();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (typeof this.order?.loadTrackerData === 'function') {
|
|
145
|
+
if (typeof this.order.set === 'function') {
|
|
146
|
+
this.order.set('tracker_data', null);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
yield this.order.loadTrackerData();
|
|
150
|
+
}
|
|
151
|
+
|
|
42
152
|
this.modalsManager.setOption('activityCreated', activity);
|
|
43
153
|
this.notifications.success(`Order activity has been updated to ${activity.status}`);
|
|
154
|
+
modal.done();
|
|
44
155
|
} catch (error) {
|
|
45
156
|
this.notifications.serverError(error);
|
|
46
157
|
} finally {
|
|
47
158
|
modal.stopLoading();
|
|
48
|
-
modal.done();
|
|
49
159
|
}
|
|
50
160
|
}
|
|
161
|
+
|
|
162
|
+
@task *capturePhotoProof() {
|
|
163
|
+
const [proofFile] = this.proofFiles;
|
|
164
|
+
const headers = this.fetch.getHeaders();
|
|
165
|
+
delete headers['Content-Type'];
|
|
166
|
+
|
|
167
|
+
const subjectId = this.currentWaypointProofSubjectId;
|
|
168
|
+
const subjectPath = subjectId ? `/${subjectId}` : '';
|
|
169
|
+
const url = [get(config, 'API.host'), get(config, 'API.namespace'), `orders/${this.order.id}/capture-photo${subjectPath}`].filter(Boolean).join('/');
|
|
170
|
+
|
|
171
|
+
const response = yield proofFile.upload(url, {
|
|
172
|
+
data: {
|
|
173
|
+
remarks: 'Verified by Photo',
|
|
174
|
+
},
|
|
175
|
+
headers,
|
|
176
|
+
withCredentials: true,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return response.json();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
@action setProofFile(file) {
|
|
183
|
+
if (!file) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
this.proofFiles = [file];
|
|
188
|
+
}
|
|
51
189
|
}
|
|
@@ -130,6 +130,27 @@
|
|
|
130
130
|
</InputGroup>
|
|
131
131
|
{{/if}}
|
|
132
132
|
|
|
133
|
+
{{#if this.shouldShowVehiclePacking}}
|
|
134
|
+
<InputGroup @name={{t "orchestrator.vehicle-packing"}}>
|
|
135
|
+
<div class="grid grid-cols-2 gap-1">
|
|
136
|
+
{{#each this.vehiclePackingOptions as |opt|}}
|
|
137
|
+
<button
|
|
138
|
+
type="button"
|
|
139
|
+
class="flex items-center justify-center gap-1.5 px-2 py-1.5 rounded border text-xs transition-colors
|
|
140
|
+
{{if
|
|
141
|
+
(eq this.draftPhase.vehiclePacking opt.value)
|
|
142
|
+
'bg-indigo-50 dark:bg-indigo-900/30 border-indigo-400 dark:border-indigo-600 text-indigo-700 dark:text-indigo-300'
|
|
143
|
+
'border-gray-200 dark:border-gray-600 text-gray-600 dark:text-gray-400 hover:border-gray-300 dark:hover:border-gray-500'
|
|
144
|
+
}}"
|
|
145
|
+
{{on "click" (fn this.setDraftOption "vehiclePacking" opt.value)}}
|
|
146
|
+
>
|
|
147
|
+
{{opt.label}}
|
|
148
|
+
</button>
|
|
149
|
+
{{/each}}
|
|
150
|
+
</div>
|
|
151
|
+
</InputGroup>
|
|
152
|
+
{{/if}}
|
|
153
|
+
|
|
133
154
|
{{! Constraint toggles }}
|
|
134
155
|
<InputGroup @name={{t "orchestrator.constraints"}}>
|
|
135
156
|
<div class="space-y-1.5">
|
|
@@ -51,6 +51,7 @@ export default class OrchestratorPhaseBuilderComponent extends Component {
|
|
|
51
51
|
label: this.intl.t(`orchestrator.mode-${mode.replace(/_/g, '-')}`),
|
|
52
52
|
engine: 'greedy',
|
|
53
53
|
allocationStrategy: 'route_aware',
|
|
54
|
+
vehiclePacking: 'minimize_vehicles',
|
|
54
55
|
orderStatuses: ['created'],
|
|
55
56
|
balanceWorkload: false,
|
|
56
57
|
respectSkills: true,
|
|
@@ -130,6 +131,7 @@ export default class OrchestratorPhaseBuilderComponent extends Component {
|
|
|
130
131
|
...this.draftPhase,
|
|
131
132
|
engine,
|
|
132
133
|
allocationStrategy: engine === 'capacity' ? 'capacity_only' : (this.draftPhase.allocationStrategy ?? 'route_aware'),
|
|
134
|
+
vehiclePacking: this.draftPhase.vehiclePacking ?? 'minimize_vehicles',
|
|
133
135
|
};
|
|
134
136
|
}
|
|
135
137
|
|
|
@@ -158,10 +160,21 @@ export default class OrchestratorPhaseBuilderComponent extends Component {
|
|
|
158
160
|
];
|
|
159
161
|
}
|
|
160
162
|
|
|
163
|
+
get vehiclePackingOptions() {
|
|
164
|
+
return [
|
|
165
|
+
{ value: 'minimize_vehicles', label: this.intl.t('orchestrator.vehicle-packing-minimize-vehicles') },
|
|
166
|
+
{ value: 'balanced', label: this.intl.t('orchestrator.vehicle-packing-balanced') },
|
|
167
|
+
];
|
|
168
|
+
}
|
|
169
|
+
|
|
161
170
|
get shouldShowAllocationStrategy() {
|
|
162
171
|
return this.draftPhase?.mode === 'assign_vehicles' && this.draftPhase?.engine === 'vroom';
|
|
163
172
|
}
|
|
164
173
|
|
|
174
|
+
get shouldShowVehiclePacking() {
|
|
175
|
+
return this.shouldShowAllocationStrategy && this.draftPhase?.allocationStrategy === 'capacity_only';
|
|
176
|
+
}
|
|
177
|
+
|
|
165
178
|
get shouldShowRouteOptions() {
|
|
166
179
|
return this.draftPhase?.engine !== 'capacity' && this.draftPhase?.allocationStrategy !== 'capacity_only';
|
|
167
180
|
}
|
|
@@ -69,16 +69,6 @@
|
|
|
69
69
|
}}"
|
|
70
70
|
{{on "click" (fn this.setVehicleFilter "all")}}
|
|
71
71
|
>{{t "orchestrator.filter-all"}}</button>
|
|
72
|
-
<button
|
|
73
|
-
type="button"
|
|
74
|
-
class="px-2 py-0.5 rounded text-xs transition-colors
|
|
75
|
-
{{if
|
|
76
|
-
(eq this.vehicleFilter 'active')
|
|
77
|
-
'bg-indigo-500 text-white'
|
|
78
|
-
'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600'
|
|
79
|
-
}}"
|
|
80
|
-
{{on "click" (fn this.setVehicleFilter "active")}}
|
|
81
|
-
>{{t "orchestrator.filter-active"}}</button>
|
|
82
72
|
<button
|
|
83
73
|
type="button"
|
|
84
74
|
class="px-2 py-0.5 rounded text-xs transition-colors
|
|
@@ -59,12 +59,10 @@ export default class OrchestratorResourcePanelComponent extends Component {
|
|
|
59
59
|
);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
if (this.vehicleFilter === '
|
|
63
|
-
vehicles = vehicles.filter((v) => v.status === 'active');
|
|
64
|
-
} else if (this.vehicleFilter === 'no-driver') {
|
|
62
|
+
if (this.vehicleFilter === 'no-driver') {
|
|
65
63
|
vehicles = vehicles.filter((v) => !v.driver?.id);
|
|
66
64
|
} else if (this.vehicleFilter === 'available') {
|
|
67
|
-
vehicles = vehicles.filter((v) => v.status === '
|
|
65
|
+
vehicles = vehicles.filter((v) => v.status === 'available' && !v.driver?.current_job);
|
|
68
66
|
}
|
|
69
67
|
|
|
70
68
|
return vehicles;
|
|
@@ -271,6 +271,7 @@ export default class OrchestratorWorkbenchComponent extends Component {
|
|
|
271
271
|
options: {
|
|
272
272
|
engine: phase.engine ?? 'greedy',
|
|
273
273
|
allocation_strategy: phase.allocationStrategy ?? 'route_aware',
|
|
274
|
+
vehicle_packing: phase.vehiclePacking ?? 'minimize_vehicles',
|
|
274
275
|
balance_workload: phase.balanceWorkload ?? false,
|
|
275
276
|
respect_skills: phase.respectSkills ?? true,
|
|
276
277
|
respect_capacity: phase.respectCapacity ?? true,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div class="order-activity-list space-y-2">
|
|
2
|
-
{{#each @resource.tracking_statuses as |trackingStatus|}}
|
|
2
|
+
{{#each (or @activity @resource.tracking_statuses) as |trackingStatus|}}
|
|
3
3
|
<div class="order-activity-list-item flex flex-row justify-between">
|
|
4
4
|
<div class="flex flex-row">
|
|
5
5
|
<div class="w-8 pt-1">
|
|
@@ -31,4 +31,4 @@
|
|
|
31
31
|
</div>
|
|
32
32
|
</div>
|
|
33
33
|
{{/each}}
|
|
34
|
-
</div>
|
|
34
|
+
</div>
|
|
@@ -1,33 +1,35 @@
|
|
|
1
|
-
{{#
|
|
2
|
-
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
<div class="flex flex-col space-y-
|
|
6
|
-
<div class="
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
{{#let (or @activity @resource.tracking_statuses) as |activity|}}
|
|
2
|
+
{{#if activity.length}}
|
|
3
|
+
<Timeline @activity={{activity}} @arrowClass="bg-gray-600 border border-gray-900 shadow-md" as |TimelineItem|>
|
|
4
|
+
<TimelineItem @activeStatus={{@resource.status}} as |trackingStatus|>
|
|
5
|
+
<div class="flex flex-col px-3 py-2 rounded text-sm leading-4 space-y-2 bg-gray-100 dark:bg-gray-900 dark:text-white">
|
|
6
|
+
<div class="flex flex-col space-y-1">
|
|
7
|
+
<div class="text-xs font-semibold truncate">{{trackingStatus.status}}</div>
|
|
8
|
+
<div class="text-xs truncate">{{n-a trackingStatus.details}}</div>
|
|
9
|
+
<div class="text-xs">{{format-date-fns trackingStatus.created_at "d MMM HH:mm"}}</div>
|
|
10
|
+
</div>
|
|
11
|
+
<Attach::Tooltip @class="clean" @animation="scale" @placement="top">
|
|
12
|
+
<InputInfo>
|
|
13
|
+
<div class="text-xs">{{or trackingStatus.details trackingStatus.status}}</div>
|
|
14
|
+
<div class="text-xs">{{format-date-fns trackingStatus.created_at "d MMM yyyy HH:mm"}}</div>
|
|
15
|
+
</InputInfo>
|
|
16
|
+
</Attach::Tooltip>
|
|
9
17
|
</div>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<FaIcon @icon="layer-group" @size="2x" class="text-gray-400 mb-2" />
|
|
24
|
-
<div class="text-sm text-gray-600 dark:text-gray-400 font-medium">
|
|
25
|
-
No order activity
|
|
26
|
-
</div>
|
|
27
|
-
<div class="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
|
28
|
-
Dispatch or update the order to create activity
|
|
18
|
+
</TimelineItem>
|
|
19
|
+
</Timeline>
|
|
20
|
+
{{else}}
|
|
21
|
+
<div class="min-h-24 p-4">
|
|
22
|
+
<div class="flex items-center justify-center border border-dashed border-gray-300 dark:border-gray-600 p-6 rounded-xl bg-gray-50 dark:bg-gray-800">
|
|
23
|
+
<div class="text-center">
|
|
24
|
+
<FaIcon @icon="layer-group" @size="2x" class="text-gray-400 mb-2" />
|
|
25
|
+
<div class="text-sm text-gray-600 dark:text-gray-400 font-medium">
|
|
26
|
+
No order activity
|
|
27
|
+
</div>
|
|
28
|
+
<div class="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
|
29
|
+
Dispatch or update the order to create activity
|
|
30
|
+
</div>
|
|
29
31
|
</div>
|
|
30
32
|
</div>
|
|
31
33
|
</div>
|
|
32
|
-
|
|
33
|
-
{{/
|
|
34
|
+
{{/if}}
|
|
35
|
+
{{/let}}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
@wrapperClass="bordered-top"
|
|
7
7
|
>
|
|
8
8
|
{{#if (eq this.layout "timeline")}}
|
|
9
|
-
<Order::ActivityTimeline @resource={{@resource}} />
|
|
9
|
+
<Order::ActivityTimeline @resource={{@resource}} @activity={{this.parentOrderActivity}} />
|
|
10
10
|
{{else}}
|
|
11
|
-
<Order::ActivityList @resource={{@resource}} />
|
|
11
|
+
<Order::ActivityList @resource={{@resource}} @activity={{this.parentOrderActivity}} />
|
|
12
12
|
{{/if}}
|
|
13
|
-
</ContentPanel>
|
|
13
|
+
</ContentPanel>
|
|
@@ -9,6 +9,17 @@ export default class OrderDetailsActivityComponent extends Component {
|
|
|
9
9
|
@service intl;
|
|
10
10
|
@tracked layout = this.appCache.get('fleetops:order:activity:layout', 'timeline');
|
|
11
11
|
|
|
12
|
+
get parentOrderActivity() {
|
|
13
|
+
const orderTrackingNumberUuid = this.args.resource?.tracking_number_uuid;
|
|
14
|
+
const activity = this.args.resource?.tracking_statuses ?? [];
|
|
15
|
+
|
|
16
|
+
if (!orderTrackingNumberUuid) {
|
|
17
|
+
return activity;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return activity.filter((trackingStatus) => trackingStatus.tracking_number_uuid === orderTrackingNumberUuid);
|
|
21
|
+
}
|
|
22
|
+
|
|
12
23
|
/* eslint-disable ember/no-side-effects */
|
|
13
24
|
get actionButtons() {
|
|
14
25
|
return [
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
{{#each @resource.purchase_rate.service_quote.items as |item|}}
|
|
13
13
|
<tr class="border-b border-gray-100 dark:border-gray-800 last:border-0">
|
|
14
14
|
<td class="py-1 pr-2 text-gray-700 dark:text-gray-300">
|
|
15
|
-
{{
|
|
15
|
+
{{item.details}}
|
|
16
16
|
</td>
|
|
17
17
|
<td class="py-1 pl-2 text-right font-medium text-gray-700 dark:text-gray-300 whitespace-nowrap">
|
|
18
18
|
{{format-currency item.amount @resource.purchase_rate.service_quote.currency}}
|
|
@@ -33,4 +33,4 @@
|
|
|
33
33
|
</table>
|
|
34
34
|
</div>
|
|
35
35
|
</ContentPanel>
|
|
36
|
-
{{/if}}
|
|
36
|
+
{{/if}}
|
|
@@ -26,17 +26,25 @@
|
|
|
26
26
|
|
|
27
27
|
{{#if @resource.hasIntermediateWaypoints}}
|
|
28
28
|
<div>
|
|
29
|
-
<RouteList
|
|
29
|
+
<RouteList
|
|
30
|
+
@order={{@resource}}
|
|
31
|
+
@eta={{if this.showRouteEtaData @resource.eta}}
|
|
32
|
+
@showEta={{this.showRouteEtaData}}
|
|
33
|
+
@waypointActions={{hash
|
|
34
|
+
viewStopActivity=(hash label="View activity" fn=this.viewStopActivity)
|
|
35
|
+
viewWaypointLabel=(hash label=(t "order.fields.get-label") fn=this.viewWaypointLabel)
|
|
36
|
+
}}
|
|
37
|
+
/>
|
|
30
38
|
</div>
|
|
31
39
|
{{else}}
|
|
32
40
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4 lg:gap-2">
|
|
33
41
|
<div class="field-info-container">
|
|
34
42
|
<label class="field-name">{{t "order.fields.pickup"}}</label>
|
|
35
|
-
<DisplayPlace @place={{@resource.payload.pickup}} @eta={{get @resource.eta @resource.payload.pickup.id}} />
|
|
43
|
+
<DisplayPlace @place={{@resource.payload.pickup}} @eta={{if this.showRouteEtaData (get @resource.eta @resource.payload.pickup.id)}} />
|
|
36
44
|
</div>
|
|
37
45
|
<div class="field-info-container">
|
|
38
46
|
<label class="field-name">{{t "order.fields.dropoff"}}</label>
|
|
39
|
-
<DisplayPlace @place={{@resource.payload.dropoff}} @eta={{get @resource.eta @resource.payload.dropoff.id}} />
|
|
47
|
+
<DisplayPlace @place={{@resource.payload.dropoff}} @eta={{if this.showRouteEtaData (get @resource.eta @resource.payload.dropoff.id)}} />
|
|
40
48
|
</div>
|
|
41
49
|
<div class="field-info-container">
|
|
42
50
|
<label class="field-name">{{t "order.fields.return"}}</label>
|
|
@@ -41,23 +41,44 @@ export default class OrderDetailsRouteComponent extends Component {
|
|
|
41
41
|
isLoading: this.optimizeRoute.isRunning,
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
icon: 'ellipsis-h',
|
|
45
|
+
prefix: 'fas',
|
|
46
|
+
triggerClass: 'fleetops-btn-xxs',
|
|
47
|
+
items: [
|
|
48
|
+
{
|
|
49
|
+
text: 'Edit route',
|
|
50
|
+
icon: 'pencil',
|
|
51
|
+
disabled: !this.args.resource.hasActiveStatus,
|
|
52
|
+
onClick: () => {
|
|
53
|
+
this.orderActions.editRoute(this.args.resource);
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
this.isMultipleWaypointOrder
|
|
57
|
+
? {
|
|
58
|
+
text: 'Change destination',
|
|
59
|
+
icon: 'location-dot',
|
|
60
|
+
disabled: !this.args.resource.hasActiveStatus,
|
|
61
|
+
onClick: () => {
|
|
62
|
+
this.changeDestination();
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
: null,
|
|
66
|
+
].filter(Boolean),
|
|
53
67
|
},
|
|
54
|
-
];
|
|
68
|
+
].filter(Boolean);
|
|
55
69
|
}
|
|
56
70
|
|
|
57
71
|
get canOptimizeRoute() {
|
|
58
72
|
return canOptimizeIntermediateWaypoints(this.args.resource?.payload);
|
|
59
73
|
}
|
|
60
74
|
|
|
75
|
+
get isMultipleWaypointOrder() {
|
|
76
|
+
const waypoints = this.args.resource?.payload?.waypoints;
|
|
77
|
+
const waypointCount = typeof waypoints?.toArray === 'function' ? waypoints.toArray().length : Array.isArray(waypoints) ? waypoints.length : (waypoints?.length ?? 0);
|
|
78
|
+
|
|
79
|
+
return Boolean(this.args.resource?.hasIntermediateWaypoints || waypointCount > 0);
|
|
80
|
+
}
|
|
81
|
+
|
|
61
82
|
get showOptimizationSelect() {
|
|
62
83
|
return this.routeOptimization.availableEngines.length > 1;
|
|
63
84
|
}
|
|
@@ -66,6 +87,17 @@ export default class OrderDetailsRouteComponent extends Component {
|
|
|
66
87
|
return this.args.resource?.tracker_data;
|
|
67
88
|
}
|
|
68
89
|
|
|
90
|
+
get showRouteEtaData() {
|
|
91
|
+
if (this.trackerData?.lifecycle?.show_live_eta !== undefined) {
|
|
92
|
+
return Boolean(this.trackerData.lifecycle.show_live_eta);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const status = String(this.args.resource?.status ?? 'created').toLowerCase();
|
|
96
|
+
const hasStarted = Boolean(this.args.resource?.started ?? this.args.resource?.started_at ?? status === 'started');
|
|
97
|
+
|
|
98
|
+
return hasStarted && !['completed', 'canceled'].includes(status);
|
|
99
|
+
}
|
|
100
|
+
|
|
69
101
|
get hasTrackingRouteSummary() {
|
|
70
102
|
return Boolean(this.trackerData?.route || this.trackerData?.eta);
|
|
71
103
|
}
|
|
@@ -75,7 +107,7 @@ export default class OrderDetailsRouteComponent extends Component {
|
|
|
75
107
|
}
|
|
76
108
|
|
|
77
109
|
get hasCompletionEta() {
|
|
78
|
-
return Boolean(this.trackerData?.eta?.completion_at);
|
|
110
|
+
return this.showRouteEtaData && Boolean(this.trackerData?.eta?.completion_at);
|
|
79
111
|
}
|
|
80
112
|
|
|
81
113
|
get routeStopsCount() {
|
|
@@ -83,10 +115,14 @@ export default class OrderDetailsRouteComponent extends Component {
|
|
|
83
115
|
}
|
|
84
116
|
|
|
85
117
|
get hasTrackingDuration() {
|
|
86
|
-
return this.trackerData?.route?.duration_in_traffic_s !== null && this.trackerData?.route?.duration_in_traffic_s !== undefined;
|
|
118
|
+
return this.showRouteEtaData && this.trackerData?.route?.duration_in_traffic_s !== null && this.trackerData?.route?.duration_in_traffic_s !== undefined;
|
|
87
119
|
}
|
|
88
120
|
|
|
89
121
|
get trackingDurationSeconds() {
|
|
122
|
+
if (!this.showRouteEtaData) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
90
126
|
return this.trackerData?.route?.duration_in_traffic_s ?? this.trackerData?.route?.duration_s;
|
|
91
127
|
}
|
|
92
128
|
|
|
@@ -150,7 +186,48 @@ export default class OrderDetailsRouteComponent extends Component {
|
|
|
150
186
|
yield this.hostRouter.refresh();
|
|
151
187
|
}
|
|
152
188
|
|
|
153
|
-
@action
|
|
189
|
+
@action changeDestination() {
|
|
190
|
+
this.modalsManager.show('modals/order-change-destination', {
|
|
191
|
+
title: 'Change destination',
|
|
192
|
+
order: this.args.resource,
|
|
193
|
+
acceptButtonText: 'Change destination',
|
|
194
|
+
declineButtonText: 'Close',
|
|
195
|
+
onChange: async () => {
|
|
196
|
+
if (typeof this.args.resource?.reload === 'function') {
|
|
197
|
+
await this.args.resource.reload();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (typeof this.args.resource?.set === 'function') {
|
|
201
|
+
this.args.resource.set('tracker_data', null);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (typeof this.args.resource?.loadTrackerData === 'function') {
|
|
205
|
+
await this.args.resource.loadTrackerData();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
await this.hostRouter.refresh();
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
@action viewStopActivity(stop) {
|
|
214
|
+
this.modalsManager.show('modals/stop-activity', {
|
|
215
|
+
title: 'Stop activity',
|
|
216
|
+
stop,
|
|
217
|
+
order: this.args.resource,
|
|
218
|
+
hideAcceptButton: true,
|
|
219
|
+
declineButtonText: 'Close',
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
@action async viewWaypointLabel(stop) {
|
|
224
|
+
const waypoint = stop?.place ?? stop;
|
|
225
|
+
const waypointId = waypoint?.waypoint_public_id ?? stop?.waypoint_public_id;
|
|
226
|
+
if (!waypointId) {
|
|
227
|
+
this.notifications.warning('Labels are only available for waypoint stops.');
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
154
231
|
this.modalsManager.show(`modals/order-label`, {
|
|
155
232
|
title: 'Waypoint Label',
|
|
156
233
|
modalClass: 'modal-xl',
|
|
@@ -161,7 +238,7 @@ export default class OrderDetailsRouteComponent extends Component {
|
|
|
161
238
|
try {
|
|
162
239
|
// eslint-disable-next-line no-undef
|
|
163
240
|
const fileReader = new FileReader();
|
|
164
|
-
const { data: pdfStream } = await this.fetch.get(`orders/label/${
|
|
241
|
+
const { data: pdfStream } = await this.fetch.get(`orders/label/${waypointId}?format=base64`);
|
|
165
242
|
// eslint-disable-next-line no-undef
|
|
166
243
|
const base64 = await fetch(`data:application/pdf;base64,${pdfStream}`);
|
|
167
244
|
const blob = await base64.blob();
|