@fleetbase/fleetops-engine 0.6.8 → 0.6.9

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.
Files changed (42) hide show
  1. package/addon/components/activity-event-selector.js +4 -0
  2. package/addon/components/display-place.hbs +27 -3
  3. package/addon/components/route-list.hbs +3 -3
  4. package/addon/controllers/operations/orders/index.js +0 -4
  5. package/addon/routes/operations/orders/index/view.js +18 -1
  6. package/addon/services/movement-tracker.js +1 -1
  7. package/addon/styles/fleetops-engine.css +7 -0
  8. package/addon/templates/operations/orders/index/new.hbs +2 -2
  9. package/addon/templates/operations/orders/index/view.hbs +5 -1
  10. package/addon/templates/operations/orders/index.hbs +6 -1
  11. package/addon/templates/settings/notifications.hbs +9 -1
  12. package/composer.json +1 -1
  13. package/extension.json +1 -1
  14. package/package.json +1 -1
  15. package/server/src/Console/Commands/TrackOrderDistanceAndTime.php +2 -2
  16. package/server/src/Events/OrderCanceled.php +6 -0
  17. package/server/src/Events/OrderCompleted.php +6 -0
  18. package/server/src/Events/OrderDispatched.php +6 -0
  19. package/server/src/Events/OrderFailed.php +6 -0
  20. package/server/src/Events/WaypointActivityChanged.php +119 -0
  21. package/server/src/Events/WaypointCompleted.php +119 -0
  22. package/server/src/Flow/Activity.php +28 -10
  23. package/server/src/Flow/Event.php +26 -2
  24. package/server/src/Http/Controllers/Api/v1/DriverController.php +19 -2
  25. package/server/src/Http/Controllers/Api/v1/OrderController.php +274 -164
  26. package/server/src/Http/Controllers/Internal/v1/OrderController.php +15 -8
  27. package/server/src/Http/Filter/OrderFilter.php +4 -4
  28. package/server/src/Http/Resources/v1/Payload.php +1 -1
  29. package/server/src/Listeners/HandleOrderCanceled.php +0 -10
  30. package/server/src/Listeners/NotifyOrderEvent.php +4 -4
  31. package/server/src/Models/OrderConfig.php +50 -35
  32. package/server/src/Models/Payload.php +26 -7
  33. package/server/src/Models/Waypoint.php +10 -0
  34. package/server/src/Notifications/OrderAssigned.php +3 -5
  35. package/server/src/Notifications/OrderCanceled.php +32 -12
  36. package/server/src/Notifications/OrderCompleted.php +31 -11
  37. package/server/src/Notifications/OrderDispatchFailed.php +3 -5
  38. package/server/src/Notifications/OrderDispatched.php +31 -11
  39. package/server/src/Notifications/OrderFailed.php +32 -12
  40. package/server/src/Notifications/OrderPing.php +2 -6
  41. package/server/src/Notifications/OrderSplit.php +1 -1
  42. package/server/src/Notifications/WaypointCompleted.php +157 -0
@@ -45,6 +45,10 @@ export default class ActivityEventSelectorComponent extends Component {
45
45
  name: 'order.canceled',
46
46
  description: 'Triggers when an order is canceled by a user, driver, or system process.',
47
47
  },
48
+ 'order.completed': {
49
+ name: 'order.completed',
50
+ description: 'Triggers when an order is completed by a driver, or system process.',
51
+ },
48
52
  };
49
53
 
50
54
  /**
@@ -11,9 +11,33 @@
11
11
  </span>
12
12
  </div>
13
13
  {{else}}
14
- {{#if @eta}}
15
- <Badge @status="warning" @hideStatusDot={{true}} class="my-1"><span class="font-bold">ETA:</span> {{format-duration @eta}}</Badge>
16
- {{/if}}
14
+ <div class="flex flex-row item-center space-x-2 {{if (or place.status_code @eta) 'mb-2'}}">
15
+ {{#if place.status_code}}
16
+ <Badge @status={{place.status_code}} />
17
+ {{/if}}
18
+ {{#if @eta}}
19
+ <Badge @status="warning" @hideStatusDot={{true}}><span class="font-bold">ETA:</span> {{format-duration @eta}}</Badge>
20
+ {{/if}}
21
+ {{#if @waypointActions}}
22
+ <DropdownButton @iconClass="icon-text-height" @size="xs" @buttonClass="fleetops-btn-xxs" @icon="ellipsis-h" @iconPrefix="fas" @contentClass="dropdown-menu" as |dd|>
23
+ <div class="next-dd-menu mt-1 mx-0" aria-labelledby="user-menu">
24
+ <div class="px-1">
25
+ <div class="text-sm flex flex-row items-center px-3 py-1 rounded-md my-1 text-gray-300">
26
+ {{t "fleet-ops.operations.orders.index.view.waypoint-actions"}}
27
+ </div>
28
+ </div>
29
+ <div class="next-dd-menu-seperator"></div>
30
+ {{#each-in @waypointActions as |actionId action|}}
31
+ <div class="px-1">
32
+ <a href="javascript:;" class="next-dd-item" disabled={{cannot "fleet-ops view order"}} {{on "click" (fn action.fn place dd)}}>
33
+ {{action.label}}
34
+ </a>
35
+ </div>
36
+ {{/each-in}}
37
+ </div>
38
+ </DropdownButton>
39
+ {{/if}}
40
+ </div>
17
41
  <address class={{@addressClass}}>
18
42
  {{#if place.name}}
19
43
  {{place.name}}<br />
@@ -6,7 +6,7 @@
6
6
  <div class="index-count">1</div>
7
7
  </div>
8
8
  <div class="order-route-location {{@routeLocationClass}} dark:text-gray-100">
9
- <DisplayPlace @place={{@order.payload.firstWaypoint}} @eta={{get @eta @order.payload.firstWaypoint.id}} />
9
+ <DisplayPlace @place={{@order.payload.firstWaypoint}} @eta={{get @eta @order.payload.firstWaypoint.id}} @waypointActions={{@waypointActions}} />
10
10
  </div>
11
11
  </div>
12
12
  {{/if}}
@@ -28,7 +28,7 @@
28
28
  <div class="index-count">{{add index 2}}</div>
29
29
  </div>
30
30
  <div class="order-route-location {{@routeLocationClass}} dark:text-gray-100">
31
- <DisplayPlace @place={{waypoint}} @eta={{get @eta waypoint.id}} />
31
+ <DisplayPlace @place={{waypoint}} @eta={{get @eta waypoint.id}} @waypointActions={{@waypointActions}} />
32
32
  </div>
33
33
  </div>
34
34
  {{/each}}
@@ -41,7 +41,7 @@
41
41
  <div class="index-count">{{add @order.payload.middleWaypoints.length 2}}</div>
42
42
  </div>
43
43
  <div class="order-route-location {{@routeLocationClass}} dark:text-gray-100">
44
- <DisplayPlace @place={{@order.payload.lastWaypoint}} @eta={{get @eta @order.payload.lastWaypoint.id}} />
44
+ <DisplayPlace @place={{@order.payload.lastWaypoint}} @eta={{get @eta @order.payload.lastWaypoint.id}} @waypointActions={{@waypointActions}} />
45
45
  </div>
46
46
  </div>
47
47
  {{/if}}
@@ -1047,7 +1047,6 @@ export default class OperationsOrdersIndexController extends BaseController {
1047
1047
  selected = selected.length > 0 ? selected : this.table.selectedRows;
1048
1048
 
1049
1049
  this.crud.bulkDelete(selected, {
1050
- modelNamePath: `public_id`,
1051
1050
  acceptButtonText: 'Delete Orders',
1052
1051
  resolveModelName: (model) => `${model.get('tracking_number.tracking_number')} - ${model.get('public_id')}`,
1053
1052
  onSuccess: async () => {
@@ -1075,7 +1074,6 @@ export default class OperationsOrdersIndexController extends BaseController {
1075
1074
  acceptButtonText: 'Cancel Orders',
1076
1075
  acceptButtonScheme: 'danger',
1077
1076
  acceptButtonIcon: 'ban',
1078
- modelNamePath: `public_id`,
1079
1077
  actionPath: `orders/bulk-cancel`,
1080
1078
  actionMethod: `PATCH`,
1081
1079
  resolveModelName: (model) => `${model.get('tracking_number.tracking_number')} - ${model.get('public_id')}`,
@@ -1109,7 +1107,6 @@ export default class OperationsOrdersIndexController extends BaseController {
1109
1107
  acceptButtonText: 'Dispatch Orders',
1110
1108
  acceptButtonScheme: 'magic',
1111
1109
  acceptButtonIcon: 'rocket',
1112
- modelNamePath: 'public_id',
1113
1110
  actionPath: 'orders/bulk-dispatch',
1114
1111
  actionMethod: 'POST',
1115
1112
  resolveModelName: (model) => `${model.get('tracking_number.tracking_number')} - ${model.get('public_id')}`,
@@ -1152,7 +1149,6 @@ export default class OperationsOrdersIndexController extends BaseController {
1152
1149
  acceptButtonScheme: 'magic',
1153
1150
  acceptButtonIcon: 'user-plus',
1154
1151
  acceptButtonDisabled: true,
1155
- modelNamePath: 'public_id',
1156
1152
  actionPath: 'orders/bulk-assign-driver',
1157
1153
  actionMethod: 'PATCH',
1158
1154
  driverAssigned: null,
@@ -1,6 +1,7 @@
1
1
  import Route from '@ember/routing/route';
2
2
  import { inject as service } from '@ember/service';
3
3
  import { action } from '@ember/object';
4
+ import { debug } from '@ember/debug';
4
5
 
5
6
  export default class OperationsOrdersIndexViewRoute extends Route {
6
7
  @service currentUser;
@@ -66,7 +67,23 @@ export default class OperationsOrdersIndexViewRoute extends Route {
66
67
  // Listen for channel subscription
67
68
  (async () => {
68
69
  for await (let output of channel) {
69
- this.refresh();
70
+ const { event, data } = output;
71
+
72
+ // debug output
73
+ debug(`Socket Event : ${event} : ${JSON.stringify(output)}`);
74
+
75
+ // Only reload if the order has a status change stemming from an updated event OR
76
+ // if a waypoint has been completed which will trigger `order.completed`
77
+ const statusChanged = event === 'order.updated' && data.status !== model.status;
78
+ const shouldReload = ['order.completed', 'waypoint.activity', 'order.created'].includes(event);
79
+ if (statusChanged || shouldReload) {
80
+ this.refresh();
81
+
82
+ // reload the controller stuff as well
83
+ if (this.controller) {
84
+ this.controller.loadOrderRelations.perform(model);
85
+ }
86
+ }
70
87
 
71
88
  if (typeof this.onOrderEvent === 'function') {
72
89
  this.onOrderEvent(output);
@@ -155,7 +155,7 @@ export default class MovementTrackerService extends Service {
155
155
 
156
156
  if (event === `${type}.location_changed` || event === `${type}.simulated_location_changed`) {
157
157
  eventBuffer.add(output);
158
- debug(`Incoming socket event added to buffer: ${event}`);
158
+ debug(`Socket Event : ${event} : Added to EventBuffer : ${JSON.stringify(output)}`);
159
159
  }
160
160
  }
161
161
  })();
@@ -1623,3 +1623,10 @@ body[data-theme='dark']
1623
1623
  .justify-end-i {
1624
1624
  justify-content: end !important;
1625
1625
  }
1626
+
1627
+ button.fleetops-btn-xxs.btn,
1628
+ button.fleetops-btn-xxs,
1629
+ .fleetops-btn-xxs {
1630
+ padding-top: 0.2rem !important;
1631
+ padding-bottom: 0.2rem !important;
1632
+ }
@@ -405,7 +405,7 @@
405
405
  </div>
406
406
  <div>
407
407
  <div class="flex flex-row items-center space-x-4 text-sm mt-2">
408
- <div class={{if (eq waypoint.type "dropoff") 'is-checked'}}>
408
+ <div class={{if (eq waypoint.type "dropoff") "is-checked"}}>
409
409
  <div class="flex flex-row items-center">
410
410
  <RadioButton
411
411
  @radioClass="focus:ring-blue-500 h-4 w-4 text-blue-500"
@@ -418,7 +418,7 @@
418
418
  <label for={{concat "waypoint_" index "_dropoff"}} class="ml-2">Dropoff</label>
419
419
  </div>
420
420
  </div>
421
- <div class={{if (eq waypoint.type "pickup") 'is-checked'}}>
421
+ <div class={{if (eq waypoint.type "pickup") "is-checked"}}>
422
422
  <div class="flex flex-row items-center">
423
423
  <RadioButton
424
424
  @radioClass="focus:ring-blue-500 h-4 w-4 text-blue-500"
@@ -579,7 +579,11 @@
579
579
  >
580
580
  {{#if @model.payload.isMultiDrop}}
581
581
  <div>
582
- <RouteList @order={{@model}} @eta={{@model.eta}} />
582
+ <RouteList
583
+ @order={{@model}}
584
+ @eta={{@model.eta}}
585
+ @waypointActions={{hash viewWaypointLabel=(hash label=(t "fleet-ops.operations.orders.index.view.get-label") fn=this.viewWaypointLabel)}}
586
+ />
583
587
  </div>
584
588
  {{else}}
585
589
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-4 lg:gap-2">
@@ -72,7 +72,12 @@
72
72
  <h4>Bulk Search</h4>
73
73
  </div>
74
74
  <div class="filters-dropdown-body">
75
- <Textarea @value={{this.bulkSearchValue}} class="form-input w-full" rows="8" placeholder="Input comma delimited order ID's or tracking numbers to perform a bulk search" />
75
+ <Textarea
76
+ @value={{this.bulkSearchValue}}
77
+ class="form-input w-full"
78
+ rows="8"
79
+ placeholder="Input comma delimited order ID's or tracking numbers to perform a bulk search"
80
+ />
76
81
  </div>
77
82
  <div class="filters-dropdown-footer space-x-2">
78
83
  <Button @text="Clear" @icon="trash" @size="xs" @onClick={{dropdown-fn dd this.removeBulkQuery}} />
@@ -1,5 +1,13 @@
1
1
  <Layout::Section::Header @title={{t "fleet-ops.settings.notifications.fleet-ops-notification-settings"}}>
2
- <Button @type="primary" @size="sm" @icon="save" @text={{t "common.save-button-text"}} @onClick={{perform this.saveSettings}} @disabled={{this.saveSettings.isRunning}} @isLoading={{or this.saveSettings.isRunning this.getSettings.isRunning}} />
2
+ <Button
3
+ @type="primary"
4
+ @size="sm"
5
+ @icon="save"
6
+ @text={{t "common.save-button-text"}}
7
+ @onClick={{perform this.saveSettings}}
8
+ @disabled={{this.saveSettings.isRunning}}
9
+ @isLoading={{or this.saveSettings.isRunning this.getSettings.isRunning}}
10
+ />
3
11
  </Layout::Section::Header>
4
12
 
5
13
  <Layout::Section::Body class="overflow-y-scroll h-full">
package/composer.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbase/fleetops-api",
3
- "version": "0.6.8",
3
+ "version": "0.6.9",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "keywords": [
6
6
  "fleetbase-extension",
package/extension.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "Fleet-Ops",
3
- "version": "0.6.8",
3
+ "version": "0.6.9",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "repository": "https://github.com/fleetbase/fleetops",
6
6
  "license": "AGPL-3.0-or-later",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleetbase/fleetops-engine",
3
- "version": "0.6.8",
3
+ "version": "0.6.9",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "fleetbase": {
6
6
  "route": "fleet-ops"
@@ -69,7 +69,7 @@ class TrackOrderDistanceAndTime extends Command
69
69
  * - Not in 'completed' or 'canceled' status.
70
70
  * - Not marked as deleted (`deleted_at` is null).
71
71
  * - Associated with a company (`company_uuid` is not null).
72
- * - The order process has started (`started` is not null).
72
+ * - The order process has started (`started_at` is not null).
73
73
  * - Contains a payload (`payload` relationship exists).
74
74
  * - Created within the past month.
75
75
  *
@@ -85,7 +85,7 @@ class TrackOrderDistanceAndTime extends Command
85
85
  return Order::whereNotIn('status', ['completed', 'canceled'])
86
86
  ->whereNull('deleted_at')
87
87
  ->whereNotNull('company_uuid')
88
- ->whereNotNull('started')
88
+ ->whereNotNull('started_at')
89
89
  ->where('created_at', '>=', $oneMonthAgo)
90
90
  ->whereHas('payload')
91
91
  ->with(['payload', 'payload.waypoints', 'payload.pickup', 'payload.dropoff'])
@@ -4,6 +4,7 @@ namespace Fleetbase\FleetOps\Events;
4
4
 
5
5
  use Fleetbase\Events\ResourceLifecycleEvent;
6
6
  use Fleetbase\FleetOps\Flow\Activity;
7
+ use Fleetbase\FleetOps\Models\Waypoint;
7
8
 
8
9
  class OrderCanceled extends ResourceLifecycleEvent
9
10
  {
@@ -18,4 +19,9 @@ class OrderCanceled extends ResourceLifecycleEvent
18
19
  * Assosciated activity which triggered the event.
19
20
  */
20
21
  public ?Activity $activity;
22
+
23
+ /**
24
+ * Assosciated order waypoint which event is for.
25
+ */
26
+ public ?Waypoint $waypoint;
21
27
  }
@@ -4,6 +4,7 @@ namespace Fleetbase\FleetOps\Events;
4
4
 
5
5
  use Fleetbase\Events\ResourceLifecycleEvent;
6
6
  use Fleetbase\FleetOps\Flow\Activity;
7
+ use Fleetbase\FleetOps\Models\Waypoint;
7
8
 
8
9
  class OrderCompleted extends ResourceLifecycleEvent
9
10
  {
@@ -18,4 +19,9 @@ class OrderCompleted extends ResourceLifecycleEvent
18
19
  * Assosciated activity which triggered the event.
19
20
  */
20
21
  public ?Activity $activity;
22
+
23
+ /**
24
+ * Assosciated order waypoint which event is for.
25
+ */
26
+ public ?Waypoint $waypoint;
21
27
  }
@@ -4,6 +4,7 @@ namespace Fleetbase\FleetOps\Events;
4
4
 
5
5
  use Fleetbase\Events\ResourceLifecycleEvent;
6
6
  use Fleetbase\FleetOps\Flow\Activity;
7
+ use Fleetbase\FleetOps\Models\Waypoint;
7
8
 
8
9
  class OrderDispatched extends ResourceLifecycleEvent
9
10
  {
@@ -18,4 +19,9 @@ class OrderDispatched extends ResourceLifecycleEvent
18
19
  * Assosciated activity which triggered the event.
19
20
  */
20
21
  public ?Activity $activity;
22
+
23
+ /**
24
+ * Assosciated order waypoint which event is for.
25
+ */
26
+ public ?Waypoint $waypoint;
21
27
  }
@@ -4,6 +4,7 @@ namespace Fleetbase\FleetOps\Events;
4
4
 
5
5
  use Fleetbase\Events\ResourceLifecycleEvent;
6
6
  use Fleetbase\FleetOps\Flow\Activity;
7
+ use Fleetbase\FleetOps\Models\Waypoint;
7
8
 
8
9
  class OrderFailed extends ResourceLifecycleEvent
9
10
  {
@@ -18,4 +19,9 @@ class OrderFailed extends ResourceLifecycleEvent
18
19
  * Assosciated activity which triggered the event.
19
20
  */
20
21
  public ?Activity $activity;
22
+
23
+ /**
24
+ * Assosciated order waypoint which event is for.
25
+ */
26
+ public ?Waypoint $waypoint;
21
27
  }
@@ -0,0 +1,119 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Events;
4
+
5
+ use Fleetbase\FleetOps\Flow\Activity;
6
+ use Fleetbase\FleetOps\Models\Order;
7
+ use Fleetbase\FleetOps\Models\Waypoint;
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 WaypointActivityChanged implements ShouldBroadcast
16
+ {
17
+ use Dispatchable;
18
+ use InteractsWithSockets;
19
+ use SerializesModels;
20
+
21
+ /**
22
+ * The waypoint which is completed.
23
+ */
24
+ public Waypoint $waypoint;
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(Waypoint $waypoint, Activity $activity)
51
+ {
52
+ $this->waypoint = $waypoint;
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('waypoint.' . $this->waypoint->public_id),
68
+ new Channel('waypoint.' . $this->waypoint->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 'waypoint.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
+ 'waypoint' => $this->waypoint->public_id,
106
+ 'place' => data_get($this->waypoint, 'place.public_id'),
107
+ 'activity' => $this->activity->toArray(),
108
+ ],
109
+ ];
110
+ }
111
+
112
+ /**
113
+ * Get the assosciated order model record for this waypoint.
114
+ */
115
+ public function getModelRecord(): ?Order
116
+ {
117
+ return Order::where('payload_uuid', $this->waypoint->payload_uuid)->first();
118
+ }
119
+ }
@@ -0,0 +1,119 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Events;
4
+
5
+ use Fleetbase\FleetOps\Flow\Activity;
6
+ use Fleetbase\FleetOps\Models\Order;
7
+ use Fleetbase\FleetOps\Models\Waypoint;
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 WaypointCompleted implements ShouldBroadcast
16
+ {
17
+ use Dispatchable;
18
+ use InteractsWithSockets;
19
+ use SerializesModels;
20
+
21
+ /**
22
+ * The waypoint which is completed.
23
+ */
24
+ public Waypoint $waypoint;
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(Waypoint $waypoint, Activity $activity)
51
+ {
52
+ $this->waypoint = $waypoint;
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('waypoint.' . $this->waypoint->public_id),
68
+ new Channel('waypoint.' . $this->waypoint->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 'waypoint.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
+ 'waypoint' => $this->waypoint->public_id,
106
+ 'place' => data_get($this->waypoint, 'place.public_id'),
107
+ 'activity' => $this->activity->toArray(),
108
+ ],
109
+ ];
110
+ }
111
+
112
+ /**
113
+ * Get the assosciated order model record for this waypoint.
114
+ */
115
+ public function getModelRecord(): ?Order
116
+ {
117
+ return Order::where('payload_uuid', $this->waypoint->payload_uuid)->first();
118
+ }
119
+ }
@@ -3,6 +3,7 @@
3
3
  namespace Fleetbase\FleetOps\Flow;
4
4
 
5
5
  use Fleetbase\FleetOps\Models\Order;
6
+ use Fleetbase\FleetOps\Models\Waypoint;
6
7
  use Fleetbase\FleetOps\Support\Utils;
7
8
 
8
9
  class Activity extends FlowResource
@@ -100,10 +101,10 @@ class Activity extends FlowResource
100
101
  *
101
102
  * @param Order $order the order object to be passed to each event
102
103
  */
103
- public function fireEvents(Order $order)
104
+ public function fireEvents(Order $order, ?Waypoint $waypoint = null)
104
105
  {
105
106
  foreach ($this->events as $event) {
106
- $event->fire($order, $this);
107
+ $event->fire($order, $this, $waypoint);
107
108
  }
108
109
  }
109
110
 
@@ -112,12 +113,22 @@ class Activity extends FlowResource
112
113
  *
113
114
  * @return \Illuminate\Support\Collection a collection of child activities
114
115
  */
115
- public function getChildActivities()
116
+ public function getChildActivities(Order|Waypoint|null $context = null)
116
117
  {
117
- $children = collect();
118
- if (is_array($this->activities)) {
119
- foreach ($this->activities as $childActivityCode) {
118
+ $children = collect();
119
+ $activities = $this->activities;
120
+
121
+ // if waypoint provided
122
+ $waypointContext = $context instanceof Waypoint;
123
+
124
+ if (is_array($activities)) {
125
+ foreach ($activities as $childActivityCode) {
120
126
  $childActivity = $this->flow->getActivity($childActivityCode);
127
+ // if waypoint context skip `created` - `started` - `dispatched`
128
+ if ($waypointContext && in_array($childActivity->code, ['created', 'started', 'dispatched'])) {
129
+ return $childActivity->getChildActivities($context);
130
+ }
131
+
121
132
  if ($childActivity) {
122
133
  $children->push($childActivity);
123
134
  }
@@ -158,15 +169,19 @@ class Activity extends FlowResource
158
169
  /**
159
170
  * Determines the next set of activities based on the provided Order.
160
171
  *
161
- * @param Order $order the order to determine the next activities for
162
- *
163
172
  * @return \Illuminate\Support\Collection a collection of the next activities
164
173
  */
165
- public function getNext(Order $order)
174
+ public function getNext(Order|Waypoint $context)
166
175
  {
167
- $children = $this->getChildActivities();
176
+ $children = $this->getChildActivities($context);
168
177
  $nextActivities = collect();
169
178
 
179
+ // if context is a waypoint get the waypoint order
180
+ $order = $context;
181
+ if ($context instanceof Waypoint) {
182
+ $order = Order::where('payload_uuid', $context->payload_uuid)->first();
183
+ }
184
+
170
185
  foreach ($children as $childActivity) {
171
186
  if ($childActivity->passes($order)) {
172
187
  $nextActivities->push($childActivity);
@@ -237,6 +252,9 @@ class Activity extends FlowResource
237
252
  return $this->complete();
238
253
  }
239
254
 
255
+ /**
256
+ * Checks if this activiy has been completed within the order already.
257
+ */
240
258
  public function isCompleted(Order $order): bool
241
259
  {
242
260
  return $order->hasCompletedActivity($this);