@fleetbase/fleetops-engine 0.6.11 → 0.6.13
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/orders.js +6 -8
- package/addon/components/layout/fleet-ops-sidebar.js +8 -0
- package/addon/components/leaflet-tracking-marker.js +19 -0
- package/addon/components/live-map.hbs +5 -0
- package/addon/components/live-map.js +6 -8
- package/addon/components/order-config/fields-editor.js +1 -1
- package/addon/components/route-optimization-engine-select-button.hbs +25 -0
- package/addon/components/route-optimization-engine-select-button.js +13 -0
- package/addon/controllers/operations/orders/index/new.js +78 -171
- package/addon/controllers/operations/orders/index/view.js +30 -29
- package/addon/controllers/settings/routing.js +47 -0
- package/addon/engine.js +27 -0
- package/addon/routes/application.js +8 -0
- package/addon/routes/operations/orders/index/view.js +12 -3
- package/addon/routes/settings/routing.js +3 -0
- package/addon/routes.js +1 -0
- package/addon/services/leaflet-router-control.js +64 -0
- package/addon/services/osrm.js +46 -0
- package/addon/services/route-optimization-interface.js +9 -0
- package/addon/services/route-optimization.js +67 -0
- package/addon/templates/operations/orders/index/new.hbs +21 -16
- package/addon/templates/settings/routing.hbs +32 -0
- package/app/components/route-optimization-engine-select-button.js +1 -0
- package/app/controllers/settings/routing.js +1 -0
- package/app/routes/settings/routing.js +1 -0
- package/app/services/leaflet-router-control.js +1 -0
- package/app/services/osrm.js +1 -0
- package/app/services/route-optimization-interface.js +1 -0
- package/app/services/route-optimization.js +1 -0
- package/app/templates/settings/routing.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +2 -2
- package/server/config/api.php +10 -1
- package/server/src/Auth/Schemas/FleetOps.php +5 -0
- package/server/src/Console/Commands/DebugOrderTracker.php +5 -5
- package/server/src/Events/EntityActivityChanged.php +118 -0
- package/server/src/Events/EntityCompleted.php +118 -0
- package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +3 -1
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +16 -13
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +31 -1
- package/server/src/Http/Resources/v1/Waypoint.php +1 -1
- package/server/src/Models/Order.php +44 -8
- package/server/src/Models/Payload.php +29 -10
- package/server/src/Models/Place.php +49 -13
- package/server/src/Support/Geocoding.php +0 -2
- package/server/src/routes.php +2 -0
- package/translations/en-us.yaml +5 -0
package/server/config/api.php
CHANGED
|
@@ -10,14 +10,15 @@ return [
|
|
|
10
10
|
'events' => [
|
|
11
11
|
// order events
|
|
12
12
|
'order.created',
|
|
13
|
+
'order.ready',
|
|
13
14
|
'order.updated',
|
|
14
15
|
'order.deleted',
|
|
15
16
|
'order.dispatched',
|
|
16
17
|
'order.dispatch_failed',
|
|
17
|
-
'order.completed',
|
|
18
18
|
'order.failed',
|
|
19
19
|
'order.driver_assigned',
|
|
20
20
|
'order.completed',
|
|
21
|
+
'order.canceled',
|
|
21
22
|
|
|
22
23
|
// payload events
|
|
23
24
|
'payload.created',
|
|
@@ -29,12 +30,19 @@ return [
|
|
|
29
30
|
'entity.updated',
|
|
30
31
|
'entity.deleted',
|
|
31
32
|
'entity.driver_assigned',
|
|
33
|
+
'entity.activity',
|
|
34
|
+
'entity.completed',
|
|
35
|
+
|
|
36
|
+
// waypoint events
|
|
37
|
+
'waypoint.activity',
|
|
38
|
+
'waypoint.completed',
|
|
32
39
|
|
|
33
40
|
// driver events
|
|
34
41
|
'driver.created',
|
|
35
42
|
'driver.updated',
|
|
36
43
|
'driver.deleted',
|
|
37
44
|
'driver.assigned',
|
|
45
|
+
'driver.location_changed',
|
|
38
46
|
// 'driver.entered_zone',
|
|
39
47
|
// 'driver.exited_zone',
|
|
40
48
|
|
|
@@ -87,6 +95,7 @@ return [
|
|
|
87
95
|
'vehicle.created',
|
|
88
96
|
'vehicle.updated',
|
|
89
97
|
'vehicle.deleted',
|
|
98
|
+
'vehicle.location_changed',
|
|
90
99
|
|
|
91
100
|
// vendor events
|
|
92
101
|
'vendor.created',
|
|
@@ -29,11 +29,11 @@ class DebugOrderTracker extends Command
|
|
|
29
29
|
*/
|
|
30
30
|
public function handle()
|
|
31
31
|
{
|
|
32
|
-
$order = Order::where('public_id', 'order_n227274')->first();
|
|
33
|
-
if ($order) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
32
|
+
// $order = Order::where('public_id', 'order_n227274')->first();
|
|
33
|
+
// if ($order) {
|
|
34
|
+
// $tracker = new OrderTracker($order);
|
|
35
|
+
// dd($tracker->getOrderProgressPercentage());
|
|
36
|
+
// }
|
|
37
37
|
|
|
38
38
|
return Command::SUCCESS;
|
|
39
39
|
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Events;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\FleetOps\Flow\Activity;
|
|
6
|
+
use Fleetbase\FleetOps\Models\Entity;
|
|
7
|
+
use Fleetbase\FleetOps\Models\Order;
|
|
8
|
+
use Illuminate\Broadcasting\Channel;
|
|
9
|
+
use Illuminate\Broadcasting\InteractsWithSockets;
|
|
10
|
+
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
|
11
|
+
use Illuminate\Foundation\Events\Dispatchable;
|
|
12
|
+
use Illuminate\Queue\SerializesModels;
|
|
13
|
+
use Illuminate\Support\Carbon;
|
|
14
|
+
|
|
15
|
+
class EntityActivityChanged implements ShouldBroadcast
|
|
16
|
+
{
|
|
17
|
+
use Dispatchable;
|
|
18
|
+
use InteractsWithSockets;
|
|
19
|
+
use SerializesModels;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The entity which has new activity.
|
|
23
|
+
*/
|
|
24
|
+
public Entity $entity;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The activity which triggered the waypoint completed.
|
|
28
|
+
*/
|
|
29
|
+
public Activity $activity;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The event id.
|
|
33
|
+
*
|
|
34
|
+
* @var string
|
|
35
|
+
*/
|
|
36
|
+
public $eventId;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The datetime instance the broadcast ws triggered.
|
|
40
|
+
*
|
|
41
|
+
* @var string
|
|
42
|
+
*/
|
|
43
|
+
public $sentAt;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Create a new event instance.
|
|
47
|
+
*
|
|
48
|
+
* @return void
|
|
49
|
+
*/
|
|
50
|
+
public function __construct(Entity $entity, Activity $activity)
|
|
51
|
+
{
|
|
52
|
+
$this->entity = $entity;
|
|
53
|
+
$this->activity = $activity;
|
|
54
|
+
$this->eventId = uniqid('event_');
|
|
55
|
+
$this->sentAt = Carbon::now()->toDateTimeString();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get the channels the event should broadcast on.
|
|
60
|
+
*
|
|
61
|
+
* @return Channel|array
|
|
62
|
+
*/
|
|
63
|
+
public function broadcastOn()
|
|
64
|
+
{
|
|
65
|
+
$channels = [
|
|
66
|
+
new Channel('api.' . session('api_credential')),
|
|
67
|
+
new Channel('entity.' . $this->entity->public_id),
|
|
68
|
+
new Channel('entity.' . $this->entity->uuid),
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
$order = $this->getModelRecord();
|
|
72
|
+
if ($order) {
|
|
73
|
+
$channels[] = new Channel('company.' . session('company', data_get($order, 'company.uuid')));
|
|
74
|
+
$channels[] = new Channel('company.' . data_get($order, 'company.public_id'));
|
|
75
|
+
$channels[] = new Channel('order.' . $order->uuid);
|
|
76
|
+
$channels[] = new Channel('order.' . $order->public_id);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return $channels;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The event's broadcast name.
|
|
84
|
+
*
|
|
85
|
+
* @return string
|
|
86
|
+
*/
|
|
87
|
+
public function broadcastAs()
|
|
88
|
+
{
|
|
89
|
+
return 'entity.activity';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get the data to broadcast.
|
|
94
|
+
*
|
|
95
|
+
* @return array
|
|
96
|
+
*/
|
|
97
|
+
public function broadcastWith()
|
|
98
|
+
{
|
|
99
|
+
return [
|
|
100
|
+
'id' => $this->eventId,
|
|
101
|
+
'api_version' => config('api.version'),
|
|
102
|
+
'event' => $this->broadcastAs(),
|
|
103
|
+
'created_at' => $this->sentAt,
|
|
104
|
+
'data' => [
|
|
105
|
+
'entity' => $this->entity->public_id,
|
|
106
|
+
'activity' => $this->activity->toArray(),
|
|
107
|
+
],
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get the assosciated order model record for this waypoint.
|
|
113
|
+
*/
|
|
114
|
+
public function getModelRecord(): ?Order
|
|
115
|
+
{
|
|
116
|
+
return Order::where('payload_uuid', $this->entity->payload_uuid)->first();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Events;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\FleetOps\Flow\Activity;
|
|
6
|
+
use Fleetbase\FleetOps\Models\Entity;
|
|
7
|
+
use Fleetbase\FleetOps\Models\Order;
|
|
8
|
+
use Illuminate\Broadcasting\Channel;
|
|
9
|
+
use Illuminate\Broadcasting\InteractsWithSockets;
|
|
10
|
+
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
|
11
|
+
use Illuminate\Foundation\Events\Dispatchable;
|
|
12
|
+
use Illuminate\Queue\SerializesModels;
|
|
13
|
+
use Illuminate\Support\Carbon;
|
|
14
|
+
|
|
15
|
+
class EntityCompleted implements ShouldBroadcast
|
|
16
|
+
{
|
|
17
|
+
use Dispatchable;
|
|
18
|
+
use InteractsWithSockets;
|
|
19
|
+
use SerializesModels;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The entity which is completed.
|
|
23
|
+
*/
|
|
24
|
+
public Entity $entity;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The activity which triggered the waypoint completed.
|
|
28
|
+
*/
|
|
29
|
+
public Activity $activity;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The event id.
|
|
33
|
+
*
|
|
34
|
+
* @var string
|
|
35
|
+
*/
|
|
36
|
+
public $eventId;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The datetime instance the broadcast ws triggered.
|
|
40
|
+
*
|
|
41
|
+
* @var string
|
|
42
|
+
*/
|
|
43
|
+
public $sentAt;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Create a new event instance.
|
|
47
|
+
*
|
|
48
|
+
* @return void
|
|
49
|
+
*/
|
|
50
|
+
public function __construct(Entity $entity, Activity $activity)
|
|
51
|
+
{
|
|
52
|
+
$this->entity = $entity;
|
|
53
|
+
$this->activity = $activity;
|
|
54
|
+
$this->eventId = uniqid('event_');
|
|
55
|
+
$this->sentAt = Carbon::now()->toDateTimeString();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get the channels the event should broadcast on.
|
|
60
|
+
*
|
|
61
|
+
* @return Channel|array
|
|
62
|
+
*/
|
|
63
|
+
public function broadcastOn()
|
|
64
|
+
{
|
|
65
|
+
$channels = [
|
|
66
|
+
new Channel('api.' . session('api_credential')),
|
|
67
|
+
new Channel('entity.' . $this->entity->public_id),
|
|
68
|
+
new Channel('entity.' . $this->entity->uuid),
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
$order = $this->getModelRecord();
|
|
72
|
+
if ($order) {
|
|
73
|
+
$channels[] = new Channel('company.' . session('company', data_get($order, 'company.uuid')));
|
|
74
|
+
$channels[] = new Channel('company.' . data_get($order, 'company.public_id'));
|
|
75
|
+
$channels[] = new Channel('order.' . $order->uuid);
|
|
76
|
+
$channels[] = new Channel('order.' . $order->public_id);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return $channels;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The event's broadcast name.
|
|
84
|
+
*
|
|
85
|
+
* @return string
|
|
86
|
+
*/
|
|
87
|
+
public function broadcastAs()
|
|
88
|
+
{
|
|
89
|
+
return 'entity.completed';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get the data to broadcast.
|
|
94
|
+
*
|
|
95
|
+
* @return array
|
|
96
|
+
*/
|
|
97
|
+
public function broadcastWith()
|
|
98
|
+
{
|
|
99
|
+
return [
|
|
100
|
+
'id' => $this->eventId,
|
|
101
|
+
'api_version' => config('api.version'),
|
|
102
|
+
'event' => $this->broadcastAs(),
|
|
103
|
+
'created_at' => $this->sentAt,
|
|
104
|
+
'data' => [
|
|
105
|
+
'entity' => $this->entity->public_id,
|
|
106
|
+
'activity' => $this->activity->toArray(),
|
|
107
|
+
],
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get the assosciated order model record for this waypoint.
|
|
113
|
+
*/
|
|
114
|
+
public function getModelRecord(): ?Order
|
|
115
|
+
{
|
|
116
|
+
return Order::where('payload_uuid', $this->entity->payload_uuid)->first();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -66,7 +66,9 @@ class ServiceAreaController extends Controller
|
|
|
66
66
|
try {
|
|
67
67
|
$serviceArea = ServiceArea::create($input);
|
|
68
68
|
} catch (\Throwable $e) {
|
|
69
|
-
|
|
69
|
+
logger()->error('Unable to create service area.', ['error' => $e->getMessage()]);
|
|
70
|
+
|
|
71
|
+
return response()->apiError('Failed to create service area.');
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
// response the driver resource
|
|
@@ -167,25 +167,28 @@ class OrderController extends FleetOpsController
|
|
|
167
167
|
);
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
//
|
|
171
|
-
$order
|
|
170
|
+
// Run background processes on queue
|
|
171
|
+
dispatch(function () use ($order, $serviceQuote): void {
|
|
172
|
+
// notify driver if assigned
|
|
173
|
+
$order->notifyDriverAssigned();
|
|
172
174
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
+
// set driving distance and time
|
|
176
|
+
$order->setPreliminaryDistanceAndTime();
|
|
175
177
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
+
// if service quote attached purchase
|
|
179
|
+
$order->purchaseServiceQuote($serviceQuote);
|
|
178
180
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
+
// dispatch if flagged true
|
|
182
|
+
$order->firstDispatchWithActivity();
|
|
181
183
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
+
// Trigger order created event
|
|
185
|
+
event(new OrderReady($order));
|
|
186
|
+
})->afterCommit();
|
|
184
187
|
}
|
|
185
188
|
);
|
|
186
189
|
|
|
187
|
-
//
|
|
188
|
-
|
|
190
|
+
// Reload payload and tracking number
|
|
191
|
+
$record->load(['payload', 'trackingNumber']);
|
|
189
192
|
|
|
190
193
|
return ['order' => new $this->resource($record)];
|
|
191
194
|
} catch (\Exception $e) {
|
|
@@ -351,7 +354,7 @@ class OrderController extends FleetOpsController
|
|
|
351
354
|
*/
|
|
352
355
|
public function bulkCancel(BulkActionRequest $request)
|
|
353
356
|
{
|
|
354
|
-
/** @var
|
|
357
|
+
/** @var \Illuminate\Database\Eloquent\Collection $orders */
|
|
355
358
|
$orders = Order::whereIn('uuid', $request->input('ids'))->get();
|
|
356
359
|
|
|
357
360
|
$count = $orders->count();
|
|
@@ -150,7 +150,7 @@ class SettingController extends Controller
|
|
|
150
150
|
if (!is_array($notificationSettings)) {
|
|
151
151
|
throw new \Exception('Invalid notification settings data.');
|
|
152
152
|
}
|
|
153
|
-
$currentNotificationSettings = Setting::lookupCompany('notification_settings');
|
|
153
|
+
$currentNotificationSettings = Setting::lookupCompany('notification_settings', []);
|
|
154
154
|
Setting::configureCompany('notification_settings', array_merge($currentNotificationSettings, $notificationSettings));
|
|
155
155
|
|
|
156
156
|
return response()->json([
|
|
@@ -174,4 +174,34 @@ class SettingController extends Controller
|
|
|
174
174
|
'notificationSettings' => $notificationSettings,
|
|
175
175
|
]);
|
|
176
176
|
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Save routing settings.
|
|
180
|
+
*
|
|
181
|
+
* @param Request $request the HTTP request object containing the routing settings data
|
|
182
|
+
*
|
|
183
|
+
* @return \Illuminate\Http\JsonResponse a JSON response
|
|
184
|
+
*/
|
|
185
|
+
public function saveRoutingSettings(Request $request)
|
|
186
|
+
{
|
|
187
|
+
$router = $request->input('router');
|
|
188
|
+
Setting::configureCompany('routing', ['router' => $router]);
|
|
189
|
+
|
|
190
|
+
return response()->json([
|
|
191
|
+
'status' => 'ok',
|
|
192
|
+
'message' => 'Routing settings succesfully saved.',
|
|
193
|
+
]);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Retrieve and return the routing settings.
|
|
198
|
+
*
|
|
199
|
+
* @return \Illuminate\Http\JsonResponse
|
|
200
|
+
*/
|
|
201
|
+
public function getRoutingSettings()
|
|
202
|
+
{
|
|
203
|
+
$routingSettings = Setting::lookupCompany('routing', ['router' => 'osrm']);
|
|
204
|
+
|
|
205
|
+
return response()->json($routingSettings);
|
|
206
|
+
}
|
|
177
207
|
}
|
|
@@ -58,7 +58,7 @@ class Waypoint extends FleetbaseResource
|
|
|
58
58
|
'owner' => $this->when(!Http::isInternalRequest(), Resolve::resourceForMorph($this->owner_type, $this->owner_uuid)),
|
|
59
59
|
'tracking_number' => $this->whenLoaded('trackingNumber', $waypoint->trackingNumber),
|
|
60
60
|
'customer' => $this->setCustomerType(Resolve::resourceForMorph($waypoint->customer_type, $waypoint->customer_uuid)),
|
|
61
|
-
'type' => $this->type,
|
|
61
|
+
'type' => $waypoint->type ?? $this->type,
|
|
62
62
|
'meta' => data_get($this, 'meta', Utils::createObject()),
|
|
63
63
|
'eta' => $this->eta,
|
|
64
64
|
'updated_at' => $this->updated_at,
|
|
@@ -1173,6 +1173,12 @@ class Order extends Model
|
|
|
1173
1173
|
{
|
|
1174
1174
|
$this->status = 'canceled';
|
|
1175
1175
|
|
|
1176
|
+
// if saving update the status and add the cancel activity
|
|
1177
|
+
$this->loadMissing('orderConfig');
|
|
1178
|
+
$canceledActivity = $this->orderConfig->getCanceledActivity();
|
|
1179
|
+
$this->updateActivity($canceledActivity);
|
|
1180
|
+
|
|
1181
|
+
// trigger integrated vendor cancelation
|
|
1176
1182
|
if ($this->isIntegratedVendorOrder()) {
|
|
1177
1183
|
$api = $this->facilitator->api();
|
|
1178
1184
|
|
|
@@ -1395,8 +1401,6 @@ class Order extends Model
|
|
|
1395
1401
|
$activity = $flow->firstWhere('code', $code);
|
|
1396
1402
|
}
|
|
1397
1403
|
|
|
1398
|
-
// dd($activity);
|
|
1399
|
-
|
|
1400
1404
|
if (!Utils::isActivity($activity)) {
|
|
1401
1405
|
return false;
|
|
1402
1406
|
}
|
|
@@ -1760,23 +1764,55 @@ class Order extends Model
|
|
|
1760
1764
|
*/
|
|
1761
1765
|
public function resolveDynamicProperty(string $property)
|
|
1762
1766
|
{
|
|
1763
|
-
|
|
1767
|
+
// Special payload shortcuts
|
|
1768
|
+
$root = Str::before($property, '.'); // e.g. "pickup" in "pickup.address"
|
|
1769
|
+
$payloadMap = [
|
|
1770
|
+
'pickup' => 'payload.pickup',
|
|
1771
|
+
'dropoff' => 'payload.dropoff',
|
|
1772
|
+
'waypoint' => 'payload.currentWaypointMarker',
|
|
1773
|
+
'currentWaypoint' => 'payload.currentWaypointMarker',
|
|
1774
|
+
'currentWaypointMarker' => 'payload.currentWaypointMarker',
|
|
1775
|
+
];
|
|
1776
|
+
|
|
1777
|
+
if (isset($payloadMap[$root])) {
|
|
1778
|
+
$this->loadMissing($payloadMap[$root]);
|
|
1779
|
+
$target = data_get($this, $payloadMap[$root]);
|
|
1780
|
+
|
|
1781
|
+
// “pickup”, “dropoff”, or “currentWaypoint” on their own
|
|
1782
|
+
if ($property === $root) {
|
|
1783
|
+
return $target;
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
// e.g. "address.city" part of "pickup.address.city"
|
|
1787
|
+
$subKey = Str::after($property, $root . '.');
|
|
1788
|
+
|
|
1789
|
+
// if waypoint we can do "waypoint.place.address" or "waypoint.address" for resolution
|
|
1790
|
+
$isWaypointMarker = Str::startsWith($root, 'currentWaypoint') || $root === 'waypoint';
|
|
1791
|
+
if ($isWaypointMarker && $target instanceof Waypoint) {
|
|
1792
|
+
$target->loadMissing('place');
|
|
1793
|
+
|
|
1794
|
+
return data_get($target, $subKey) ?? data_get($target->place, $subKey);
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
return data_get($target, $subKey);
|
|
1798
|
+
}
|
|
1764
1799
|
|
|
1765
|
-
//
|
|
1766
|
-
|
|
1767
|
-
|
|
1800
|
+
// Direct attribute on the model
|
|
1801
|
+
$snake = Str::snake($property);
|
|
1802
|
+
if (array_key_exists($snake, $this->getAttributes())) {
|
|
1803
|
+
return $this->getAttribute($snake);
|
|
1768
1804
|
}
|
|
1769
1805
|
|
|
1770
|
-
//
|
|
1806
|
+
// Custom-field / meta look-ups
|
|
1771
1807
|
if ($this->isCustomField($property)) {
|
|
1772
1808
|
return $this->getCustomFieldValueByKey($property);
|
|
1773
1809
|
}
|
|
1774
1810
|
|
|
1775
|
-
// Check if meta attribute
|
|
1776
1811
|
if ($this->hasMeta($property)) {
|
|
1777
1812
|
return $this->getMeta($property);
|
|
1778
1813
|
}
|
|
1779
1814
|
|
|
1815
|
+
// Fallback deep-path access
|
|
1780
1816
|
return data_get($this, $property);
|
|
1781
1817
|
}
|
|
1782
1818
|
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Models;
|
|
4
4
|
|
|
5
5
|
use Fleetbase\Casts\Json;
|
|
6
|
+
use Fleetbase\FleetOps\Events\EntityActivityChanged;
|
|
7
|
+
use Fleetbase\FleetOps\Events\EntityCompleted;
|
|
6
8
|
use Fleetbase\FleetOps\Events\WaypointActivityChanged;
|
|
7
9
|
use Fleetbase\FleetOps\Events\WaypointCompleted;
|
|
8
10
|
use Fleetbase\FleetOps\Flow\Activity;
|
|
@@ -185,6 +187,14 @@ class Payload extends Model
|
|
|
185
187
|
return $this->belongsTo(Place::class, 'current_waypoint_uuid')->withoutGlobalScopes();
|
|
186
188
|
}
|
|
187
189
|
|
|
190
|
+
/**
|
|
191
|
+
* The current waypoint of the payload in progress.
|
|
192
|
+
*/
|
|
193
|
+
public function currentWaypointMarker()
|
|
194
|
+
{
|
|
195
|
+
return $this->belongsTo(Waypoint::class, 'current_waypoint_uuid', 'place_uuid')->withoutGlobalScopes();
|
|
196
|
+
}
|
|
197
|
+
|
|
188
198
|
/**
|
|
189
199
|
* Waypoints between start and end.
|
|
190
200
|
*
|
|
@@ -305,7 +315,7 @@ class Payload extends Model
|
|
|
305
315
|
}
|
|
306
316
|
|
|
307
317
|
foreach ($waypoints as $index => $attributes) {
|
|
308
|
-
$waypoint = ['payload_uuid' => $this->payload_uuid];
|
|
318
|
+
$waypoint = ['payload_uuid' => $this->payload_uuid, 'type' => data_get($attributes, 'type', 'dropoff')];
|
|
309
319
|
|
|
310
320
|
if (Utils::isset($attributes, 'place') && is_array(Utils::get($attributes, 'place'))) {
|
|
311
321
|
$attributes = Utils::get($attributes, 'place');
|
|
@@ -329,11 +339,13 @@ class Payload extends Model
|
|
|
329
339
|
}
|
|
330
340
|
|
|
331
341
|
// Handle customer assosciation for waypoint
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
342
|
+
$customerId = data_get($attributes, 'customer_uuid');
|
|
343
|
+
$customerType = data_get($attributes, 'customer_type', 'fleetops:contact');
|
|
344
|
+
if ($customerId && $customerType) {
|
|
345
|
+
$customerTypeNamespace = Utils::getMutationType($customerType);
|
|
346
|
+
$customerExists = app($customerTypeNamespace)->where('uuid', $customerId)->exists();
|
|
335
347
|
if ($customerExists) {
|
|
336
|
-
$waypoint['customer_uuid'] = $
|
|
348
|
+
$waypoint['customer_uuid'] = $customerId;
|
|
337
349
|
$waypoint['customer_type'] = $customerTypeNamespace;
|
|
338
350
|
}
|
|
339
351
|
}
|
|
@@ -355,7 +367,7 @@ class Payload extends Model
|
|
|
355
367
|
}
|
|
356
368
|
|
|
357
369
|
foreach ($waypoints as $index => $attributes) {
|
|
358
|
-
$waypoint = ['payload_uuid' => $this->uuid, 'order' => $index];
|
|
370
|
+
$waypoint = ['payload_uuid' => $this->uuid, 'order' => $index, 'type' => data_get($attributes, 'type', 'dropoff')];
|
|
359
371
|
|
|
360
372
|
if (Utils::isset($attributes, 'place') && is_array(Utils::get($attributes, 'place'))) {
|
|
361
373
|
$placeAttributes = Utils::get($attributes, 'place');
|
|
@@ -384,11 +396,13 @@ class Payload extends Model
|
|
|
384
396
|
}
|
|
385
397
|
|
|
386
398
|
// Handle customer assosciation for waypoint
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
399
|
+
$customerId = data_get($attributes, 'customer_uuid');
|
|
400
|
+
$customerType = data_get($attributes, 'customer_type', 'fleetops:contact');
|
|
401
|
+
if ($customerId && $customerType) {
|
|
402
|
+
$customerTypeNamespace = Utils::getMutationType($customerType);
|
|
403
|
+
$customerExists = app($customerTypeNamespace)->where('uuid', $customerId)->exists();
|
|
390
404
|
if ($customerExists) {
|
|
391
|
-
$waypoint['customer_uuid'] = $
|
|
405
|
+
$waypoint['customer_uuid'] = $customerId;
|
|
392
406
|
$waypoint['customer_type'] = $customerTypeNamespace;
|
|
393
407
|
}
|
|
394
408
|
}
|
|
@@ -784,6 +798,11 @@ class Payload extends Model
|
|
|
784
798
|
$entities = $this->entities->where('destination_uuid', $this->current_waypoint_uuid);
|
|
785
799
|
foreach ($entities as $entity) {
|
|
786
800
|
$entity->insertActivity($activity, $location, $proof);
|
|
801
|
+
if ($activity && $activity->complete()) {
|
|
802
|
+
event(new EntityCompleted($entity, $activity));
|
|
803
|
+
} else {
|
|
804
|
+
event(new EntityActivityChanged($entity, $activity));
|
|
805
|
+
}
|
|
787
806
|
}
|
|
788
807
|
|
|
789
808
|
// if this activity completes the waypoint notify waypoint customer
|