@fleetbase/fleetops-engine 0.3.7 → 0.3.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 (113) hide show
  1. package/addon/components/contact-form-panel.hbs +4 -1
  2. package/addon/components/contact-panel.hbs +1 -1
  3. package/addon/components/driver-form-panel.hbs +5 -12
  4. package/addon/components/driver-panel.hbs +4 -1
  5. package/addon/components/fleet-form-panel.hbs +4 -1
  6. package/addon/components/fleet-listing-panel.hbs +2 -2
  7. package/addon/components/fleet-panel.hbs +1 -1
  8. package/addon/components/fuel-report-form-panel.hbs +4 -1
  9. package/addon/components/fuel-report-panel.hbs +4 -1
  10. package/addon/components/issue-form-panel.hbs +4 -1
  11. package/addon/components/issue-panel.hbs +4 -1
  12. package/addon/components/layout/fleet-ops-sidebar/driver-listing.hbs +5 -0
  13. package/addon/components/layout/fleet-ops-sidebar/driver-listing.js +122 -0
  14. package/addon/components/layout/fleet-ops-sidebar/fleet-listing.hbs +5 -1
  15. package/addon/components/layout/fleet-ops-sidebar/fleet-listing.js +118 -1
  16. package/addon/components/layout/fleet-ops-sidebar.hbs +5 -1
  17. package/addon/components/layout/fleet-ops-sidebar.js +4 -2
  18. package/addon/components/live-map.hbs +90 -9
  19. package/addon/components/live-map.js +28 -11
  20. package/addon/components/map-container/toolbar/zones-panel.js +16 -13
  21. package/addon/components/place-form-panel.hbs +4 -1
  22. package/addon/components/place-panel.hbs +4 -1
  23. package/addon/components/settings-window.hbs +1 -1
  24. package/addon/components/vehicle-form-panel.hbs +4 -1
  25. package/addon/components/vehicle-panel.hbs +4 -1
  26. package/addon/components/vendor-form-panel.hbs +4 -1
  27. package/addon/components/vendor-panel.hbs +4 -1
  28. package/addon/controllers/management/drivers/index.js +10 -90
  29. package/addon/controllers/management/vehicles/index.js +11 -21
  30. package/addon/controllers/operations/orders/index/new.js +5 -5
  31. package/addon/controllers/operations/orders/index/view.js +9 -13
  32. package/addon/helpers/format-point.js +5 -2
  33. package/addon/helpers/point-to-coordinates.js +6 -2
  34. package/addon/services/context-panel.js +23 -18
  35. package/addon/services/driver-actions.js +107 -0
  36. package/addon/services/vehicle-actions.js +42 -0
  37. package/addon/styles/fleetops-engine.css +27 -0
  38. package/addon/templates/operations/orders/index/new.hbs +3 -3
  39. package/addon/templates/operations/service-rates/index/new.hbs +1 -1
  40. package/addon/utils/fly-to-leaflet-layer.js +7 -0
  41. package/app/components/layout/fleet-ops-sidebar/driver-listing.js +1 -0
  42. package/app/services/driver-actions.js +1 -0
  43. package/app/services/vehicle-actions.js +1 -0
  44. package/composer.json +2 -2
  45. package/extension.json +1 -1
  46. package/package.json +4 -4
  47. package/server/src/Casts/MultiPolygon.php +14 -3
  48. package/server/src/Casts/Point.php +12 -2
  49. package/server/src/Casts/Polygon.php +19 -4
  50. package/server/src/Exceptions/IntegratedVendorException.php +45 -1
  51. package/server/src/Http/Controllers/Api/v1/DriverController.php +29 -14
  52. package/server/src/Http/Controllers/Api/v1/EntityController.php +36 -1
  53. package/server/src/Http/Controllers/Api/v1/LabelController.php +2 -2
  54. package/server/src/Http/Controllers/Api/v1/OrderController.php +139 -59
  55. package/server/src/Http/Controllers/Api/v1/PayloadController.php +20 -12
  56. package/server/src/Http/Controllers/Api/v1/PlaceController.php +25 -3
  57. package/server/src/Http/Controllers/Api/v1/PurchaseRateController.php +1 -1
  58. package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +71 -3
  59. package/server/src/Http/Controllers/Api/v1/ServiceQuoteController.php +1 -1
  60. package/server/src/Http/Controllers/Api/v1/ServiceRateController.php +3 -2
  61. package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +2 -2
  62. package/server/src/Http/Controllers/Api/v1/TrackingStatusController.php +2 -2
  63. package/server/src/Http/Controllers/Api/v1/VehicleController.php +22 -2
  64. package/server/src/Http/Controllers/Api/v1/ZoneController.php +59 -3
  65. package/server/src/Http/Controllers/Internal/v1/DriverController.php +25 -4
  66. package/server/src/Http/Controllers/Internal/v1/LiveController.php +3 -10
  67. package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +1 -1
  68. package/server/src/Http/Controllers/Internal/v1/OrderController.php +11 -1
  69. package/server/src/Http/Filter/TrackingStatusFilter.php +10 -0
  70. package/server/src/Http/Requests/CancelOrderRequest.php +1 -2
  71. package/server/src/Http/Requests/CreateContactRequest.php +5 -4
  72. package/server/src/Http/Requests/CreateDriverRequest.php +13 -11
  73. package/server/src/Http/Requests/CreateEntityRequest.php +7 -4
  74. package/server/src/Http/Requests/CreateOrderRequest.php +2 -2
  75. package/server/src/Http/Requests/CreatePayloadRequest.php +1 -1
  76. package/server/src/Http/Requests/CreatePlaceRequest.php +46 -4
  77. package/server/src/Http/Requests/CreatePurchaseRateRequest.php +3 -2
  78. package/server/src/Http/Requests/CreateServiceAreaRequest.php +24 -4
  79. package/server/src/Http/Requests/CreateServiceRateRequest.php +22 -21
  80. package/server/src/Http/Requests/CreateTrackingStatusRequest.php +9 -8
  81. package/server/src/Http/Requests/CreateVehicleRequest.php +6 -4
  82. package/server/src/Http/Requests/CreateZoneRequest.php +24 -5
  83. package/server/src/Http/Requests/QueryServiceQuotesRequest.php +11 -10
  84. package/server/src/Http/Requests/ScheduleOrderRequest.php +32 -0
  85. package/server/src/Http/Requests/UpdateContactRequest.php +0 -13
  86. package/server/src/Http/Requests/UpdateServiceAreaRequest.php +1 -23
  87. package/server/src/Http/Requests/UpdateServiceQuoteRequest.php +1 -23
  88. package/server/src/Http/Requests/UpdateServiceRateRequest.php +1 -23
  89. package/server/src/Http/Requests/UpdateTrackingStatusRequest.php +1 -26
  90. package/server/src/Http/Resources/v1/DeletedResource.php +2 -9
  91. package/server/src/Http/Resources/v1/Entity.php +47 -44
  92. package/server/src/Http/Resources/v1/Order.php +1 -1
  93. package/server/src/Http/Resources/v1/ServiceArea.php +2 -2
  94. package/server/src/Http/Resources/v1/Vehicle.php +1 -3
  95. package/server/src/Http/Resources/v1/Zone.php +2 -4
  96. package/server/src/Models/Entity.php +99 -3
  97. package/server/src/Models/Order.php +75 -7
  98. package/server/src/Models/Payload.php +104 -33
  99. package/server/src/Models/Place.php +56 -17
  100. package/server/src/Models/ServiceArea.php +285 -18
  101. package/server/src/Models/ServiceRate.php +10 -6
  102. package/server/src/Models/TrackingNumber.php +18 -24
  103. package/server/src/Models/TrackingStatus.php +2 -6
  104. package/server/src/Models/Vehicle.php +2 -2
  105. package/server/src/Models/Waypoint.php +0 -10
  106. package/server/src/Models/Zone.php +132 -5
  107. package/server/src/Support/Flow.php +17 -3
  108. package/server/src/Support/Utils.php +143 -9
  109. package/server/src/routes.php +4 -3
  110. package/addon/helpers/extract-coordinates.js +0 -6
  111. package/addon/utils/extract-coordinates.js +0 -1
  112. package/app/helpers/extract-coordinates.js +0 -1
  113. package/app/utils/extract-coordinates.js +0 -1
@@ -12,6 +12,7 @@ use Fleetbase\Traits\HasPublicId;
12
12
  use Fleetbase\Traits\HasUuid;
13
13
  use Fleetbase\Traits\TracksApiCredential;
14
14
  use Grimzy\LaravelMysqlSpatial\Types\Point;
15
+ use Illuminate\Support\Facades\DB;
15
16
  use Illuminate\Support\Str;
16
17
 
17
18
  class Payload extends Model
@@ -183,16 +184,6 @@ class Payload extends Model
183
184
  return $this->hasManyThrough(Place::class, Waypoint::class, 'payload_uuid', 'uuid', 'uuid', 'place_uuid')->whereNull('waypoints.deleted_at')->withoutGlobalScopes();
184
185
  }
185
186
 
186
- /**
187
- * Waypoints between start and end.
188
- *
189
- * @return \Illuminate\Database\Eloquent\Concerns\HasManyThrough
190
- */
191
- public function waypointsCompleted()
192
- {
193
- return $this->hasManyThrough(Place::class, WaypointCompleted::class, 'payload_uuid', 'uuid', 'uuid', 'place_uuid')->withoutGlobalScopes();
194
- }
195
-
196
187
  /**
197
188
  * Always convert fee and rate to integer before insert.
198
189
  */
@@ -216,20 +207,16 @@ class Payload extends Model
216
207
  }
217
208
  }
218
209
 
219
- // confirm destination_uuid is indeed a place record
220
- if (isset($attributes['destination_uuid']) && Place::where('uuid', $attributes['destination_uuid'])->doesntExist()) {
221
- // search waypoints for search_uuid if any
222
- $destination = Place::where('meta->search_uuid', $attributes['destination_uuid'])->first();
223
-
210
+ // if a destination or waypoint is explicitly set
211
+ if (empty($attributes['destination_uuid'])) {
212
+ $destinationKey = Utils::or($attributes, ['waypoint', 'destination']);
213
+ $destination = $this->findDestinationFromKey($destinationKey);
224
214
  if ($destination instanceof Place) {
225
215
  $attributes['destination_uuid'] = $destination->uuid;
226
- } else {
227
- unset($attributes['destination_uuid']);
228
216
  }
229
217
  }
230
218
 
231
219
  $entity = new Entity($attributes);
232
-
233
220
  $this->entities()->save($entity);
234
221
  }
235
222
 
@@ -253,15 +240,12 @@ class Payload extends Model
253
240
  }
254
241
  }
255
242
 
256
- // confirm destination_uuid is indeed a place record
257
- if (isset($attributes['destination_uuid']) && Place::where('uuid', $attributes['destination_uuid'])->doesntExist()) {
258
- // search waypoints for search_uuid if any
259
- $destination = Place::where('meta->search_uuid', $attributes['destination_uuid'])->first();
260
-
243
+ // if a destination or waypoint is explicitly set
244
+ if (empty($attributes['destination_uuid'])) {
245
+ $destinationKey = Utils::or($attributes, ['waypoint', 'destination']);
246
+ $destination = $this->findDestinationFromKey($destinationKey);
261
247
  if ($destination instanceof Place) {
262
248
  $attributes['destination_uuid'] = $destination->uuid;
263
- } else {
264
- unset($attributes['destination_uuid']);
265
249
  }
266
250
  }
267
251
 
@@ -277,8 +261,8 @@ class Payload extends Model
277
261
  {
278
262
  $this->current_waypoint_uuid = $destination->uuid;
279
263
 
280
- if ($this->save) {
281
- $this->save();
264
+ if ($save) {
265
+ DB::table($this->getTable())->where('uuid', $this->uuid)->update(['current_waypoint_uuid' => $destination->uuid]);
282
266
  }
283
267
 
284
268
  return $this;
@@ -429,7 +413,7 @@ class Payload extends Model
429
413
  }
430
414
 
431
415
  if ($this->waypoints()->count()) {
432
- return $this->waypoints->first();
416
+ return $this->waypoints->last();
433
417
  }
434
418
 
435
419
  return null;
@@ -449,7 +433,7 @@ class Payload extends Model
449
433
  }
450
434
 
451
435
  if ($this->waypoints()->count()) {
452
- return $this->waypoints->last();
436
+ return $this->waypoints->first();
453
437
  }
454
438
 
455
439
  return null;
@@ -529,6 +513,19 @@ class Payload extends Model
529
513
  }
530
514
  }
531
515
 
516
+ // ensure all stops/waypoints are instances of Place
517
+ $stops = $stops->map(function ($place) {
518
+ if (is_array($place)) {
519
+ return new Place($place);
520
+ }
521
+
522
+ if ($place instanceof Place) {
523
+ return $place;
524
+ }
525
+
526
+ return null;
527
+ });
528
+
532
529
  return $stops->filter();
533
530
  }
534
531
 
@@ -557,10 +554,6 @@ class Payload extends Model
557
554
 
558
555
  public function setPlace($property, Place $place, array $options = [])
559
556
  {
560
- if (!$place) {
561
- return;
562
- }
563
-
564
557
  $attr = $property . '_uuid';
565
558
  $instance = Place::createFromMixed($place);
566
559
  $save = data_get($options, 'save', false);
@@ -596,16 +589,28 @@ class Payload extends Model
596
589
  return;
597
590
  }
598
591
 
592
+ if (!$place instanceof Place) {
593
+ $place = Place::createFromMixed($place);
594
+ }
595
+
599
596
  return $this->setPlace('pickup', $place, $options);
600
597
  }
601
598
 
602
599
  public function setDropoff($place, array $options = [])
603
600
  {
601
+ if (!$place instanceof Place) {
602
+ $place = Place::createFromMixed($place);
603
+ }
604
+
604
605
  return $this->setPlace('dropoff', $place, $options);
605
606
  }
606
607
 
607
608
  public function setReturn($place, array $options = [])
608
609
  {
610
+ if (!$place instanceof Place) {
611
+ $place = Place::createFromMixed($place);
612
+ }
613
+
609
614
  return $this->setPlace('return', $place, $options);
610
615
  }
611
616
 
@@ -714,4 +719,70 @@ class Payload extends Model
714
719
 
715
720
  return null;
716
721
  }
722
+
723
+ public function findDestinationFromKey(string $destinationKey = null): ?Place
724
+ {
725
+ if ($destinationKey === null) {
726
+ return null;
727
+ }
728
+
729
+ // if waypoint index provided
730
+ if (is_numeric($destinationKey)) {
731
+ $waypoint = $this->waypoints->values()->get($destinationKey);
732
+
733
+ if ($waypoint) {
734
+ return $waypoint;
735
+ }
736
+ }
737
+
738
+ // if explicitly set to pickup
739
+ if ($destinationKey === 'pickup' && $this->pickup) {
740
+ return $this->pickup;
741
+ }
742
+
743
+ // if explicitly set to dropoff
744
+ if ($destinationKey === 'dropoff' && $this->dropoff) {
745
+ return $this->dropoff;
746
+ }
747
+
748
+ // if waypoint public_id
749
+ if (Utils::isPublicId($destinationKey)) {
750
+ $waypoint = $this->waypoints->firstWhere('public_id', $destinationKey);
751
+
752
+ // if no waypoint found from public_id check pickup/dropoff
753
+ if (!$waypoint) {
754
+ $waypoint = collect([$this->pickup, $this->dropoff])->firstWhere('public_id', $destinationKey);
755
+ }
756
+
757
+ if ($waypoint) {
758
+ return $waypoint;
759
+ }
760
+ }
761
+
762
+ // if waypoint uuid
763
+ if (Str::isUuid($destinationKey)) {
764
+ $waypoint = $this->waypoints->firstWhere('uuid', $destinationKey);
765
+
766
+ // if no waypoint found from uuid check pickup/dropoff
767
+ if (!$waypoint) {
768
+ $waypoint = collect([$this->pickup, $this->dropoff])->firstWhere('uuid', $destinationKey);
769
+ }
770
+
771
+ if ($waypoint) {
772
+ return $waypoint;
773
+ }
774
+ }
775
+
776
+ // confirm destination_uuid is indeed a place record
777
+ if (isset($attributes['destination_uuid']) && Place::where('uuid', $attributes['destination_uuid'])->doesntExist()) {
778
+ // search waypoints for search_uuid if any
779
+ $destination = Place::where('meta->search_uuid', $attributes['destination_uuid'])->first();
780
+
781
+ if ($destination instanceof Place) {
782
+ return $destination;
783
+ }
784
+ }
785
+
786
+ return null;
787
+ }
717
788
  }
@@ -4,6 +4,7 @@ namespace Fleetbase\FleetOps\Models;
4
4
 
5
5
  use Fleetbase\Casts\Json;
6
6
  use Fleetbase\FleetOps\Casts\Point;
7
+ use Fleetbase\FleetOps\Support\Geocoding;
7
8
  use Fleetbase\FleetOps\Support\Utils;
8
9
  use Fleetbase\Models\Model;
9
10
  use Fleetbase\Traits\HasApiModelBehavior;
@@ -251,8 +252,10 @@ class Place extends Model
251
252
 
252
253
  /**
253
254
  * Create a new Place instance from a Google Address instance and optionally save it to the database.
255
+ *
256
+ * @return \Fleetbase\Models\Place|null
254
257
  */
255
- public static function createFromGoogleAddress(\Geocoder\Provider\GoogleMaps\Model\GoogleAddress $address, bool $saveInstance = false): Place
258
+ public static function createFromGoogleAddress(\Geocoder\Provider\GoogleMaps\Model\GoogleAddress $address, bool $saveInstance = false): ?Place
256
259
  {
257
260
  $instance = (new static())->fillWithGoogleAddress($address);
258
261
 
@@ -279,8 +282,10 @@ class Place extends Model
279
282
  * Create a new Place instance from a geocoding lookup.
280
283
  *
281
284
  * @param bool $saveInstance
285
+ *
286
+ * @return \Fleetbase\Models\Place|null
282
287
  */
283
- public static function createFromGeocodingLookup(string $address, $saveInstance = false): Place
288
+ public static function createFromGeocodingLookup(string $address, $saveInstance = false): ?Place
284
289
  {
285
290
  $results = \Geocoder\Laravel\Facades\Geocoder::geocode($address)->get();
286
291
 
@@ -291,20 +296,49 @@ class Place extends Model
291
296
  return static::createFromGoogleAddress($results->first(), $saveInstance);
292
297
  }
293
298
 
299
+ /**
300
+ * Create a new Place instance from a geocoding lookup.
301
+ *
302
+ * @param bool $saveInstance
303
+ *
304
+ * @return \Fleetbase\Models\Place|null
305
+ */
306
+ public static function createFromReverseGeocodingLookup(\Grimzy\LaravelMysqlSpatial\Types\Point $point, $saveInstance = false): ?Place
307
+ {
308
+ $results = Geocoding::reverseFromCoordinates($point->getLat(), $point->getLng());
309
+ $place = $results->first();
310
+
311
+ if (!$place) {
312
+ $place = (new static())->newInstance(['location' => $point]);
313
+ }
314
+
315
+ if ($saveInstance) {
316
+ $place->save();
317
+ }
318
+
319
+ return $place;
320
+ }
321
+
294
322
  /**
295
323
  * Creates a new Place instance from given coordinates.
296
324
  *
297
- * @param array $attributes
298
- * @param bool $saveInstance
325
+ * @param \Grimzy\LaravelMysqlSpatial\Types\Point|array $coordinates
326
+ * @param bool $saveInstance
299
327
  *
300
- * @return Place|false
328
+ * @return \Fleetbase\Models\Place|null
301
329
  */
302
- public static function createFromCoordinates($coordinates, $attributes = [], $saveInstance = false)
330
+ public static function createFromCoordinates($coordinates, array $attributes = [], $saveInstance = false): ?Place
303
331
  {
304
332
  $instance = new Place();
333
+ $point = Utils::getPointFromMixed($coordinates);
305
334
 
306
- $latitude = Utils::getLatitudeFromCoordinates($coordinates);
307
- $longitude = Utils::getLongitudeFromCoordinates($coordinates);
335
+ if ($coordinates instanceof \Grimzy\LaravelMysqlSpatial\Types\Point) {
336
+ $latitude = $coordinates->getLat();
337
+ $longitude = $coordinates->getLng();
338
+ } elseif ($point instanceof \Grimzy\LaravelMysqlSpatial\Types\Point) {
339
+ $latitude = $point->getLat();
340
+ $longitude = $point->getLng();
341
+ }
308
342
 
309
343
  $instance->setAttribute('location', new \Grimzy\LaravelMysqlSpatial\Types\Point($latitude, $longitude));
310
344
  $instance->fill($attributes);
@@ -312,7 +346,7 @@ class Place extends Model
312
346
  $results = \Geocoder\Laravel\Facades\Geocoder::reverse($latitude, $longitude)->get();
313
347
 
314
348
  if ($results->isEmpty()) {
315
- return false;
349
+ return null;
316
350
  }
317
351
 
318
352
  $instance->fillWithGoogleAddress($results->first());
@@ -327,15 +361,15 @@ class Place extends Model
327
361
  /**
328
362
  * Inserts a new place into the database using latitude and longitude coordinates.
329
363
  *
364
+ * @param \Grimzy\LaravelMysqlSpatial\Types\Point|array $coordinates
330
365
  * @param \Grimzy\LaravelMysqlSpatial\Types\Point|string|array $coordinates the coordinates to use for the new place
331
366
  *
332
367
  * @return mixed returns the UUID of the new place on success or false on failure
333
368
  */
334
- public static function insertFromCoordinates($coordinates)
369
+ public static function insertFromCoordinates($coordinates, array $attributes = [])
335
370
  {
336
- $attributes = [];
337
-
338
- $point = Utils::getPointFromMixed($coordinates);
371
+ $attributes = array_merge([], $attributes);
372
+ $point = Utils::getPointFromMixed($coordinates);
339
373
 
340
374
  if ($coordinates instanceof \Grimzy\LaravelMysqlSpatial\Types\Point) {
341
375
  $attributes['location'] = $coordinates;
@@ -365,10 +399,15 @@ class Place extends Model
365
399
  * @param array $attributes
366
400
  * @param bool $saveInstance
367
401
  *
368
- * @return \App\Models\Place|false
402
+ * @return \Fleetbase\Models\Place|null
369
403
  */
370
- public static function createFromMixed($place, $attributes = [], $saveInstance = true)
404
+ public static function createFromMixed($place, $attributes = [], $saveInstance = true): ?Place
371
405
  {
406
+ // If place is already an instance
407
+ if ($place instanceof Place) {
408
+ return $place;
409
+ }
410
+
372
411
  // If $place is a string
373
412
  if (is_string($place)) {
374
413
  // Check if $place is a valid public_id, return matching Place object if found
@@ -399,7 +438,7 @@ class Place extends Model
399
438
  }
400
439
  // If $place is an array of coordinates
401
440
  elseif (Utils::isCoordinatesStrict($place)) {
402
- return static::insertFromCoordinates($place, true);
441
+ return static::createFromCoordinates($place, $attributes, $saveInstance);
403
442
  }
404
443
  // If $place is an array
405
444
  elseif (is_array($place)) {
@@ -421,7 +460,7 @@ class Place extends Model
421
460
  return static::createFromGoogleAddress($place, $saveInstance);
422
461
  }
423
462
 
424
- return false;
463
+ return null;
425
464
  }
426
465
 
427
466
  /**