@fleetbase/fleetops-engine 0.6.11 → 0.6.12

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.
@@ -1,6 +1,16 @@
1
1
  import MarkerLayer from 'ember-leaflet/components/marker-layer';
2
2
  import { isArray } from '@ember/array';
3
3
 
4
+ const __draggingHotfix = (layer) => {
5
+ if (!layer.dragging) {
6
+ layer.dragging = {
7
+ enabled: () => false,
8
+ enable: () => (layer.options.draggable = true),
9
+ disable: () => (layer.options.draggable = false),
10
+ };
11
+ }
12
+ };
13
+
4
14
  const arrayFromLatLng = (latlng) => {
5
15
  if (isArray(latlng)) {
6
16
  return latlng;
@@ -52,6 +62,7 @@ L.TrackingMarker = L.Marker.extend({
52
62
  this._slideKeepAtCenter = false;
53
63
  this._slideDraggingWasAllowed = false;
54
64
  this._slideFrame = 0;
65
+ __draggingHotfix(this);
55
66
  },
56
67
 
57
68
  slideTo: function (latlng, options = {}) {
@@ -69,6 +80,7 @@ L.TrackingMarker = L.Marker.extend({
69
80
  this._nextPosition = arrayFromLatLng(latlng);
70
81
  this._slideKeepAtCenter = !!options.keepAtCenter;
71
82
  this._slideDraggingWasAllowed = this._slideDraggingWasAllowed !== undefined ? this._slideDraggingWasAllowed : this._map.dragging.enabled();
83
+ __draggingHotfix(this);
72
84
 
73
85
  if (this._slideKeepAtCenter) {
74
86
  this._map.dragging.disable();
@@ -245,6 +257,13 @@ export default class LeafletTrackingMarkerComponent extends MarkerLayer {
245
257
  */
246
258
  rotationAngle = 0;
247
259
 
260
+ /**
261
+ * Default value for the draggable prop.
262
+ *
263
+ * @memberof LeafletTrackingMarkerComponent
264
+ */
265
+ draggable = false;
266
+
248
267
  getOption(key, defaultValue = null) {
249
268
  const value = this.options[key] ?? this[key];
250
269
  if (value === undefined) {
@@ -38,6 +38,7 @@
38
38
  @icon={{icon iconUrl=driver.vehicle_avatar iconSize=(array 24 24)}}
39
39
  @onAdd={{fn this.triggerAction "onDriverAdded" driver}}
40
40
  @onClick={{fn this.triggerAction "onDriverClicked" driver}}
41
+ @draggable={{false}}
41
42
  as |marker|
42
43
  >
43
44
  <marker.popup @maxWidth="500" @minWidth="225">
@@ -77,6 +78,7 @@
77
78
  @icon={{icon iconUrl=driver.vehicle_avatar iconSize=(array 24 24)}}
78
79
  @onAdd={{fn this.triggerAction "onDriverAdded" driver}}
79
80
  @onClick={{fn this.triggerAction "onDriverClicked" driver}}
81
+ @draggable={{false}}
80
82
  as |marker|
81
83
  >
82
84
  <marker.popup @maxWidth="500" @minWidth="225">
@@ -114,6 +116,7 @@
114
116
  @icon={{icon iconUrl=vehicle.avatar_url iconSize=(array 24 24)}}
115
117
  @onAdd={{fn this.triggerAction "onVehicleAdded" vehicle}}
116
118
  @onClick={{fn this.triggerAction "onVehicleClicked" vehicle}}
119
+ @draggable={{false}}
117
120
  as |marker|
118
121
  >
119
122
  <marker.popup @permanent={{false}} @sticky={{true}}>
@@ -150,6 +153,7 @@
150
153
  @icon={{icon iconUrl=vehicle.avatar_url iconSize=(array 24 24)}}
151
154
  @onAdd={{fn this.triggerAction "onVehicleAdded" vehicle}}
152
155
  @onClick={{fn this.triggerAction "onVehicleClicked" vehicle}}
156
+ @draggable={{false}}
153
157
  as |marker|
154
158
  >
155
159
  <marker.popup @permanent={{false}} @sticky={{true}}>
@@ -189,6 +193,7 @@
189
193
  @alt={{place.address}}
190
194
  @onAdd={{fn this.triggerAction "onPlaceAdded" place}}
191
195
  @onClick={{fn this.triggerAction "onPlaceClicked" place}}
196
+ @draggable={{false}}
192
197
  as |marker|
193
198
  >
194
199
  <marker.popup>
@@ -677,7 +677,7 @@ export default class OperationsOrdersIndexNewController extends BaseController {
677
677
 
678
678
  @action resetInterface() {
679
679
  if (this.leafletMap && this.leafletMap.liveMap) {
680
- this.leafletMap.liveMap.show(['drivers', 'vehicles', 'routes']);
680
+ this.leafletMap.liveMap.showAll();
681
681
  }
682
682
  }
683
683
 
@@ -709,31 +709,35 @@ export default class OperationsOrdersIndexNewController extends BaseController {
709
709
  }
710
710
 
711
711
  @action removeRoutingControlPreview() {
712
- const leafletMap = this.leafletMap;
713
- const previewRouteControl = this.previewRouteControl;
712
+ return new Promise((resolve) => {
713
+ const leafletMap = this.leafletMap;
714
+ const previewRouteControl = this.previewRouteControl;
714
715
 
715
- let removed = false;
716
+ let removed = false;
716
717
 
717
- if (leafletMap && previewRouteControl instanceof RoutingControl) {
718
- try {
719
- previewRouteControl.remove();
720
- removed = true;
721
- } catch (e) {
722
- // silent
723
- }
724
-
725
- if (!removed) {
718
+ if (leafletMap && previewRouteControl instanceof RoutingControl) {
726
719
  try {
727
- leafletMap.removeControl(previewRouteControl);
720
+ previewRouteControl.remove();
721
+ removed = true;
728
722
  } catch (e) {
729
723
  // silent
730
724
  }
725
+
726
+ if (!removed) {
727
+ try {
728
+ leafletMap.removeControl(previewRouteControl);
729
+ } catch (e) {
730
+ // silent
731
+ }
732
+ }
731
733
  }
732
- }
733
734
 
734
- if (!removed) {
735
- this.forceRemoveRoutePreview();
736
- }
735
+ if (!removed) {
736
+ this.forceRemoveRoutePreview();
737
+ }
738
+
739
+ resolve(true);
740
+ });
737
741
  }
738
742
 
739
743
  @action forceRemoveRoutePreview() {
@@ -1060,7 +1064,7 @@ export default class OperationsOrdersIndexNewController extends BaseController {
1060
1064
  }
1061
1065
  }
1062
1066
 
1063
- @action resetForm() {
1067
+ @action async resetForm() {
1064
1068
  const order = this.store.createRecord('order', { meta: [] });
1065
1069
  const payload = this.store.createRecord('payload');
1066
1070
  const driversQuery = {};
@@ -1080,8 +1084,6 @@ export default class OperationsOrdersIndexNewController extends BaseController {
1080
1084
  const customFields = [];
1081
1085
  const customFieldValues = {};
1082
1086
 
1083
- this.removeRoutingControlPreview();
1084
- this.removeOptimizedRoute();
1085
1087
  this.setProperties({
1086
1088
  order,
1087
1089
  payload,
@@ -1102,6 +1104,9 @@ export default class OperationsOrdersIndexNewController extends BaseController {
1102
1104
  customFields,
1103
1105
  customFieldValues,
1104
1106
  });
1107
+
1108
+ await this.removeRoutingControlPreview();
1109
+ this.removeOptimizedRoute();
1105
1110
  this.resetInterface();
1106
1111
  }
1107
1112
 
@@ -243,39 +243,41 @@ export default class OperationsOrdersIndexViewController extends BaseController
243
243
  this.customFieldGroups = customFieldGroups;
244
244
  }
245
245
 
246
- @action resetView() {
247
- this.removeRoutingControlPreview();
246
+ @action async resetView() {
247
+ await this.removeRoutingControlPreview();
248
248
  this.resetInterface();
249
249
  }
250
250
 
251
251
  @action resetInterface() {
252
- const liveMap = this.leafletMap ? this.leafletMap.liveMap : null;
253
- if (liveMap) {
254
- liveMap.reload();
255
- liveMap.showAll();
252
+ if (this.leafletMap && this.leafletMap.liveMap) {
253
+ this.leafletMap.liveMap.showAll();
254
+ this.leafletMap.liveMap.reload();
256
255
  }
257
256
  }
258
257
 
259
258
  @action removeRoutingControlPreview() {
260
- const { leafletMap, routeControl } = this;
259
+ return new Promise((resolve) => {
260
+ const { leafletMap, routeControl } = this;
261
261
 
262
- if (routeControl instanceof RoutingControl) {
263
- try {
264
- routeControl.remove();
265
- } catch (e) {
266
- // silent
262
+ if (routeControl instanceof RoutingControl) {
263
+ try {
264
+ routeControl.remove();
265
+ } catch (e) {
266
+ // silent
267
+ }
267
268
  }
268
- }
269
269
 
270
- if (leafletMap instanceof L.Map) {
271
- try {
272
- leafletMap.removeControl(routeControl);
273
- } catch (e) {
274
- // silent
270
+ if (leafletMap instanceof L.Map) {
271
+ try {
272
+ leafletMap.removeControl(routeControl);
273
+ } catch (e) {
274
+ // silent
275
+ }
275
276
  }
276
- }
277
277
 
278
- this.forceRemoveRoutePreview();
278
+ this.forceRemoveRoutePreview();
279
+ resolve(true);
280
+ });
279
281
  }
280
282
 
281
283
  @action forceRemoveRoutePreview() {
package/composer.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbase/fleetops-api",
3
- "version": "0.6.11",
3
+ "version": "0.6.12",
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.11",
3
+ "version": "0.6.12",
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.11",
3
+ "version": "0.6.12",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "fleetbase": {
6
6
  "route": "fleet-ops"
@@ -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
- $tracker = new OrderTracker($order);
35
- dd($tracker->getOrderProgressPercentage());
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
  }
@@ -66,7 +66,9 @@ class ServiceAreaController extends Controller
66
66
  try {
67
67
  $serviceArea = ServiceArea::create($input);
68
68
  } catch (\Throwable $e) {
69
- dd($e->getMessage());
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
- // notify driver if assigned
171
- $order->notifyDriverAssigned();
170
+ // Run background processes on queue
171
+ dispatch(function () use ($order, $serviceQuote): void {
172
+ // notify driver if assigned
173
+ $order->notifyDriverAssigned();
172
174
 
173
- // set driving distance and time
174
- $order->setPreliminaryDistanceAndTime();
175
+ // set driving distance and time
176
+ $order->setPreliminaryDistanceAndTime();
175
177
 
176
- // if service quote attached purchase
177
- $order->purchaseServiceQuote($serviceQuote);
178
+ // if service quote attached purchase
179
+ $order->purchaseServiceQuote($serviceQuote);
178
180
 
179
- // dispatch if flagged true
180
- $order->firstDispatchWithActivity();
181
+ // dispatch if flagged true
182
+ $order->firstDispatchWithActivity();
181
183
 
182
- // load tracking number
183
- $order->load(['trackingNumber']);
184
+ // Trigger order created event
185
+ event(new OrderReady($order));
186
+ })->afterCommit();
184
187
  }
185
188
  );
186
189
 
187
- // Trigger order created event
188
- event(new OrderReady($record));
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) {
@@ -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([
@@ -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,
@@ -1395,8 +1395,6 @@ class Order extends Model
1395
1395
  $activity = $flow->firstWhere('code', $code);
1396
1396
  }
1397
1397
 
1398
- // dd($activity);
1399
-
1400
1398
  if (!Utils::isActivity($activity)) {
1401
1399
  return false;
1402
1400
  }
@@ -1760,23 +1758,55 @@ class Order extends Model
1760
1758
  */
1761
1759
  public function resolveDynamicProperty(string $property)
1762
1760
  {
1763
- $snakedProperty = Str::snake($property);
1761
+ // Special payload shortcuts
1762
+ $root = Str::before($property, '.'); // e.g. "pickup" in "pickup.address"
1763
+ $payloadMap = [
1764
+ 'pickup' => 'payload.pickup',
1765
+ 'dropoff' => 'payload.dropoff',
1766
+ 'waypoint' => 'payload.currentWaypointMarker',
1767
+ 'currentWaypoint' => 'payload.currentWaypointMarker',
1768
+ 'currentWaypointMarker' => 'payload.currentWaypointMarker',
1769
+ ];
1770
+
1771
+ if (isset($payloadMap[$root])) {
1772
+ $this->loadMissing($payloadMap[$root]);
1773
+ $target = data_get($this, $payloadMap[$root]);
1774
+
1775
+ // “pickup”, “dropoff”, or “currentWaypoint” on their own
1776
+ if ($property === $root) {
1777
+ return $target;
1778
+ }
1779
+
1780
+ // e.g. "address.city" part of "pickup.address.city"
1781
+ $subKey = Str::after($property, $root . '.');
1782
+
1783
+ // if waypoint we can do "waypoint.place.address" or "waypoint.address" for resolution
1784
+ $isWaypointMarker = Str::startsWith($root, 'currentWaypoint') || $root === 'waypoint';
1785
+ if ($isWaypointMarker && $target instanceof Waypoint) {
1786
+ $target->loadMissing('place');
1787
+
1788
+ return data_get($target, $subKey) ?? data_get($target->place, $subKey);
1789
+ }
1790
+
1791
+ return data_get($target, $subKey);
1792
+ }
1764
1793
 
1765
- // check if existing property
1766
- if ($this->{$snakedProperty}) {
1767
- return $this->{$snakedProperty};
1794
+ // Direct attribute on the model
1795
+ $snake = Str::snake($property);
1796
+ if (array_key_exists($snake, $this->getAttributes())) {
1797
+ return $this->getAttribute($snake);
1768
1798
  }
1769
1799
 
1770
- // Check if custom field property
1800
+ // Custom-field / meta look-ups
1771
1801
  if ($this->isCustomField($property)) {
1772
1802
  return $this->getCustomFieldValueByKey($property);
1773
1803
  }
1774
1804
 
1775
- // Check if meta attribute
1776
1805
  if ($this->hasMeta($property)) {
1777
1806
  return $this->getMeta($property);
1778
1807
  }
1779
1808
 
1809
+ // Fallback deep-path access
1780
1810
  return data_get($this, $property);
1781
1811
  }
1782
1812
 
@@ -185,6 +185,14 @@ class Payload extends Model
185
185
  return $this->belongsTo(Place::class, 'current_waypoint_uuid')->withoutGlobalScopes();
186
186
  }
187
187
 
188
+ /**
189
+ * The current waypoint of the payload in progress.
190
+ */
191
+ public function currentWaypointMarker()
192
+ {
193
+ return $this->belongsTo(Waypoint::class, 'current_waypoint_uuid', 'place_uuid')->withoutGlobalScopes();
194
+ }
195
+
188
196
  /**
189
197
  * Waypoints between start and end.
190
198
  *
@@ -305,7 +313,7 @@ class Payload extends Model
305
313
  }
306
314
 
307
315
  foreach ($waypoints as $index => $attributes) {
308
- $waypoint = ['payload_uuid' => $this->payload_uuid];
316
+ $waypoint = ['payload_uuid' => $this->payload_uuid, 'type' => data_get($attributes, 'type', 'dropoff')];
309
317
 
310
318
  if (Utils::isset($attributes, 'place') && is_array(Utils::get($attributes, 'place'))) {
311
319
  $attributes = Utils::get($attributes, 'place');
@@ -355,7 +363,7 @@ class Payload extends Model
355
363
  }
356
364
 
357
365
  foreach ($waypoints as $index => $attributes) {
358
- $waypoint = ['payload_uuid' => $this->uuid, 'order' => $index];
366
+ $waypoint = ['payload_uuid' => $this->uuid, 'order' => $index, 'type' => data_get($attributes, 'type', 'dropoff')];
359
367
 
360
368
  if (Utils::isset($attributes, 'place') && is_array(Utils::get($attributes, 'place'))) {
361
369
  $placeAttributes = Utils::get($attributes, 'place');
@@ -209,8 +209,6 @@ class Geocoding
209
209
  throw $e;
210
210
  }
211
211
 
212
- // dd($reverseQueryResults, $geodingQueryResults);
213
-
214
212
  return $reverseQueryResults->merge($geodingQueryResults)->unique('street1');
215
213
  }
216
214