@fleetbase/fleetops-engine 0.3.6 → 0.3.8

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 (74) hide show
  1. package/addon/components/admin/navigator-app.hbs +6 -3
  2. package/addon/components/layout/fleet-ops-sidebar/fleet-listing.hbs +5 -1
  3. package/addon/components/layout/fleet-ops-sidebar/fleet-listing.js +98 -1
  4. package/addon/components/layout/fleet-ops-sidebar.hbs +5 -1
  5. package/addon/components/layout/fleet-ops-sidebar.js +1 -0
  6. package/addon/controllers/management/drivers/index/edit.js +0 -26
  7. package/addon/engine.js +4 -4
  8. package/addon/styles/fleetops-engine.css +17 -0
  9. package/addon/templates/operations/service-rates/index/new.hbs +1 -1
  10. package/composer.json +2 -2
  11. package/extension.json +1 -1
  12. package/package.json +1 -1
  13. package/server/config/fleetops.php +4 -1
  14. package/server/src/Casts/MultiPolygon.php +14 -3
  15. package/server/src/Casts/Point.php +12 -2
  16. package/server/src/Casts/Polygon.php +19 -4
  17. package/server/src/Http/Controllers/Api/v1/DriverController.php +34 -18
  18. package/server/src/Http/Controllers/Api/v1/EntityController.php +36 -1
  19. package/server/src/Http/Controllers/Api/v1/LabelController.php +2 -2
  20. package/server/src/Http/Controllers/Api/v1/OrderController.php +139 -59
  21. package/server/src/Http/Controllers/Api/v1/PayloadController.php +20 -12
  22. package/server/src/Http/Controllers/Api/v1/PlaceController.php +25 -3
  23. package/server/src/Http/Controllers/Api/v1/PurchaseRateController.php +1 -1
  24. package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +71 -3
  25. package/server/src/Http/Controllers/Api/v1/ServiceQuoteController.php +1 -1
  26. package/server/src/Http/Controllers/Api/v1/ServiceRateController.php +3 -2
  27. package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +2 -2
  28. package/server/src/Http/Controllers/Api/v1/TrackingStatusController.php +2 -2
  29. package/server/src/Http/Controllers/Api/v1/VehicleController.php +22 -2
  30. package/server/src/Http/Controllers/Api/v1/ZoneController.php +59 -3
  31. package/server/src/Http/Controllers/Internal/v1/DriverController.php +148 -0
  32. package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +38 -0
  33. package/server/src/Http/Controllers/Internal/v1/OrderController.php +11 -1
  34. package/server/src/Http/Filter/TrackingStatusFilter.php +10 -0
  35. package/server/src/Http/Requests/CancelOrderRequest.php +1 -2
  36. package/server/src/Http/Requests/CreateContactRequest.php +5 -4
  37. package/server/src/Http/Requests/CreateDriverRequest.php +13 -11
  38. package/server/src/Http/Requests/CreateEntityRequest.php +7 -4
  39. package/server/src/Http/Requests/CreateOrderRequest.php +2 -2
  40. package/server/src/Http/Requests/CreatePayloadRequest.php +1 -1
  41. package/server/src/Http/Requests/CreatePlaceRequest.php +46 -4
  42. package/server/src/Http/Requests/CreatePurchaseRateRequest.php +3 -2
  43. package/server/src/Http/Requests/CreateServiceAreaRequest.php +24 -4
  44. package/server/src/Http/Requests/CreateServiceRateRequest.php +22 -21
  45. package/server/src/Http/Requests/CreateTrackingStatusRequest.php +9 -8
  46. package/server/src/Http/Requests/CreateVehicleRequest.php +6 -4
  47. package/server/src/Http/Requests/CreateZoneRequest.php +24 -5
  48. package/server/src/Http/Requests/QueryServiceQuotesRequest.php +11 -10
  49. package/server/src/Http/Requests/ScheduleOrderRequest.php +32 -0
  50. package/server/src/Http/Requests/UpdateContactRequest.php +0 -13
  51. package/server/src/Http/Requests/UpdateServiceAreaRequest.php +1 -23
  52. package/server/src/Http/Requests/UpdateServiceQuoteRequest.php +1 -23
  53. package/server/src/Http/Requests/UpdateServiceRateRequest.php +1 -23
  54. package/server/src/Http/Requests/UpdateTrackingStatusRequest.php +1 -26
  55. package/server/src/Http/Resources/v1/DeletedResource.php +2 -9
  56. package/server/src/Http/Resources/v1/Entity.php +47 -44
  57. package/server/src/Http/Resources/v1/Order.php +1 -1
  58. package/server/src/Http/Resources/v1/ServiceArea.php +2 -2
  59. package/server/src/Http/Resources/v1/Vehicle.php +1 -3
  60. package/server/src/Http/Resources/v1/Zone.php +2 -4
  61. package/server/src/Models/Entity.php +99 -3
  62. package/server/src/Models/Order.php +75 -7
  63. package/server/src/Models/Payload.php +104 -33
  64. package/server/src/Models/Place.php +56 -17
  65. package/server/src/Models/ServiceArea.php +285 -18
  66. package/server/src/Models/ServiceRate.php +10 -6
  67. package/server/src/Models/TrackingNumber.php +18 -24
  68. package/server/src/Models/TrackingStatus.php +2 -6
  69. package/server/src/Models/Vehicle.php +2 -2
  70. package/server/src/Models/Waypoint.php +0 -10
  71. package/server/src/Models/Zone.php +132 -5
  72. package/server/src/Support/Flow.php +17 -3
  73. package/server/src/Support/Utils.php +143 -9
  74. package/server/src/routes.php +58 -3
@@ -1,5 +1,8 @@
1
1
  <ContentPanel @title="Navigator App" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
2
- <InputGroup @name="URL">
3
- <ClickToCopy>{{this.url}}</ClickToCopy>
2
+ <InputGroup @name="Instance Linking URL">
3
+ <ClickToCopy class="px-4 py-2 border rounded-md bg-gray-100 shadow-sm dark:bg-gray-700 border-gray-200 dark:border-gray-800" @value={{this.url}}>{{this.url}}</ClickToCopy>
4
+ <Attach::Tooltip @class="clean" @animation="scale" @placement="top">
5
+ <InputInfo>Use this URL to link the official Navigator app to this {{t "app.name"}} instance. Opening this URL on a mobile device will open the Navigator app and update it's configuration and branding.</InputInfo>
6
+ </Attach::Tooltip>
4
7
  </InputGroup>
5
- </ContentPanel>
8
+ </ContentPanel>
@@ -1 +1,5 @@
1
- <FleetListingPanel ...attributes />
1
+ <Layout::Sidebar::Panel @open={{true}} @titleIcon={{@icon}} @title="Fleets" @wrapperClass="next-fleet-summary">
2
+ {{#each this.fleets as |fleet|}}
3
+ <FleetListingPanel @fleet={{fleet}} @onVehicleClicked={{this.onFocusVehicle}} @depth={{1}} @open={{true}} />
4
+ {{/each}}
5
+ </Layout::Sidebar::Panel>
@@ -1,3 +1,100 @@
1
1
  import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { action } from '@ember/object';
5
+ import { isArray } from '@ember/array';
6
+ import { later } from '@ember/runloop';
2
7
 
3
- export default class LayoutFleetOpsSidebarFleetListingComponent extends Component {}
8
+ export default class LayoutFleetOpsSidebarFleetListingComponent extends Component {
9
+ @service store;
10
+ @service notifications;
11
+ @service universe;
12
+ @service hostRouter;
13
+ @tracked fleets = [];
14
+ @tracked isLoading = false;
15
+
16
+ constructor() {
17
+ super(...arguments);
18
+ this.loadFleetsWithVehicles();
19
+ this.listenForFleetChanges();
20
+ }
21
+
22
+ @action transitionHome() {
23
+ return this.hostRouter.transitionTo('console.fleet-ops.operations.orders.index', { queryParams: { layout: 'map' } });
24
+ }
25
+
26
+ @action async onFocusVehicle(vehicle) {
27
+ const { onFocusVehicle } = this.args;
28
+ // const { currentRouteName } = this.hostRouter;
29
+ // const isOperationsRouteActive = typeof currentRouteName === 'string' && currentRouteName.includes('fleet-ops.operations.orders');
30
+
31
+ // transition to dashboard/map display
32
+ try {
33
+ await this.hostRouter.transitionTo('console.fleet-ops.operations.orders.index', { queryParams: { layout: 'map' } });
34
+ } catch (error) {
35
+ // silent
36
+ }
37
+
38
+ // focus vehicle on live map
39
+ this.focusVehicleOnLiveMap(vehicle);
40
+
41
+ if (typeof onFocusVehicle === 'function') {
42
+ onFocusVehicle(vehicle);
43
+ }
44
+ }
45
+
46
+ @action focusVehicleOnLiveMap(vehicle) {
47
+ const FleetOpsLiveMap = this.universe.get('FleetOpsLiveMap');
48
+
49
+ if (FleetOpsLiveMap) {
50
+ if (FleetOpsLiveMap.contextPanel) {
51
+ FleetOpsLiveMap.contextPanel.clear();
52
+ }
53
+
54
+ FleetOpsLiveMap.showAll();
55
+ FleetOpsLiveMap.focusLayerByRecord(vehicle, 16, {
56
+ onAfterFocusWithRecord: function () {
57
+ later(
58
+ this,
59
+ () => {
60
+ FleetOpsLiveMap.onVehicleClicked(vehicle);
61
+ },
62
+ 600 * 2
63
+ );
64
+ },
65
+ });
66
+ }
67
+ }
68
+
69
+ listenForFleetChanges() {
70
+ // when a vehicle is assigned/ or unassigned reload
71
+ this.universe.on('fleet.vehicle.assigned', () => {
72
+ this.loadFleetsWithVehicles();
73
+ });
74
+
75
+ // when a vehicle is assigned/ or unassigned reload
76
+ this.universe.on('fleet.vehicle.unassigned', () => {
77
+ this.loadFleetsWithVehicles();
78
+ });
79
+ }
80
+
81
+ loadFleetsWithVehicles() {
82
+ this.isLoading = true;
83
+ this.store
84
+ .query('fleet', { with: ['vehicles', 'subfleets'], parents_only: true })
85
+ .then((fleets) => {
86
+ this.fleets = fleets.toArray().map(this.resolveFleetVehicles);
87
+ })
88
+ .catch((error) => {
89
+ this.notifications.serverError(error);
90
+ })
91
+ .finally(() => {
92
+ this.isLoading = false;
93
+ });
94
+ }
95
+
96
+ @action resolveFleetVehicles(fleet) {
97
+ fleet.vehicles = isArray(fleet.vehicles) ? fleet.vehicles.toArray() : [];
98
+ return fleet;
99
+ }
100
+ }
@@ -11,7 +11,11 @@
11
11
  {{#each this.menuPanels as |menuPanel|}}
12
12
  <Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}}>
13
13
  {{#each menuPanel.items as |menuItem|}}
14
- <Layout::Sidebar::Item @route={{concat this.routePrefix menuItem.route}} @icon={{menuItem.icon}} @rightSideComponent={{menuItem.rightSideComponent}} @rightSideComponentContext={{menuItem.rightSideComponentContext}} @rightSideStatus={{menuItem.rightSideStatus}} @rightSideStatusText={{menuItem.rightSideStatusText}} @hideRightSideStatusDot={{menuItem.hideRightSideStatusDot}} @rightSideStatusClass={{menuItem.rightSideStatusClass}} @disableRightSideStatusHumanize={{menuItem.disableRightSideStatusHumanize}} @dropdownButton={{menuItem.dropdownButton}} @dropdownButtonActions={{menuItem.dropdownButtonActions}} @dropdownButtonIcon={{menuItem.dropdownButtonIcon}} @dropdownButtonIconPrefix={{menuItem.dropdownButtonIconPrefix}} @dropdownButtonText={{menuItem.dropdownButtonText}} @dropdownButtonCalculatePosition={{menuItem.dropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{menuItem.dropdownButtonRenderInPlace}} @dropdownButtonMenuLabel={{menuItem.dropdownButtonMenuLabel}} @dropdownButtonWrapperClass={{menuItem.dropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{menuItem.dropdownButtonTriggerClass}} @registerDropdownButtonAPI={{menuItem.registerDropdownButtonAPI}}>{{menuItem.title}}</Layout::Sidebar::Item>
14
+ {{#if menuItem.renderComponentInPlace}}
15
+ {{component menuItem.component menuItem=menuItem title=@menuItem.title route=(concat this.routePrefix menuItem.route) icon=menuItem.icon rightSideComponent=menuItem.rightSideComponent rightSideComponentContext=menuItem.rightSideComponentContext rightSideStatus=menuItem.rightSideStatus rightSideStatusText=menuItem.rightSideStatusText hideRightSideStatusDot=menuItem.hideRightSideStatusDot rightSideStatusClass=menuItem.rightSideStatusClass disableRightSideStatusHumanize=menuItem.disableRightSideStatusHumanize dropdownButton=menuItem.dropdownButton dropdownButtonActions=menuItem.dropdownButtonActions dropdownButtonIcon=menuItem.dropdownButtonIcon dropdownButtonIconPrefix=menuItem.dropdownButtonIconPrefix dropdownButtonText=menuItem.dropdownButtonText dropdownButtonCalculatePosition=menuItem.dropdownButtonCalculatePosition dropdownButtonRenderInPlace=menuItem.dropdownButtonRenderInPlace dropdownButtonMenuLabel=menuItem.dropdownButtonMenuLabel dropdownButtonWrapperClass=menuItem.dropdownButtonWrapperClass dropdownButtonTriggerClass=menuItem.dropdownButtonTriggerClass registerDropdownButtonAPI=menuItem.registerDropdownButtonAPI}}
16
+ {{else}}
17
+ <Layout::Sidebar::Item @route={{concat this.routePrefix menuItem.route}} @icon={{menuItem.icon}} @rightSideComponent={{menuItem.rightSideComponent}} @rightSideComponentContext={{menuItem.rightSideComponentContext}} @rightSideStatus={{menuItem.rightSideStatus}} @rightSideStatusText={{menuItem.rightSideStatusText}} @hideRightSideStatusDot={{menuItem.hideRightSideStatusDot}} @rightSideStatusClass={{menuItem.rightSideStatusClass}} @disableRightSideStatusHumanize={{menuItem.disableRightSideStatusHumanize}} @dropdownButton={{menuItem.dropdownButton}} @dropdownButtonActions={{menuItem.dropdownButtonActions}} @dropdownButtonIcon={{menuItem.dropdownButtonIcon}} @dropdownButtonIconPrefix={{menuItem.dropdownButtonIconPrefix}} @dropdownButtonText={{menuItem.dropdownButtonText}} @dropdownButtonCalculatePosition={{menuItem.dropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{menuItem.dropdownButtonRenderInPlace}} @dropdownButtonMenuLabel={{menuItem.dropdownButtonMenuLabel}} @dropdownButtonWrapperClass={{menuItem.dropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{menuItem.dropdownButtonTriggerClass}} @registerDropdownButtonAPI={{menuItem.registerDropdownButtonAPI}}>{{menuItem.title}}</Layout::Sidebar::Item>
18
+ {{/if}}
15
19
  {{/each}}
16
20
  </Layout::Sidebar::Panel>
17
21
  {{/each}}
@@ -3,6 +3,7 @@ import { tracked } from '@glimmer/tracking';
3
3
  import { inject as service } from '@ember/service';
4
4
  import { action } from '@ember/object';
5
5
  import { isArray } from '@ember/array';
6
+ // import FleetListingComponent from './fleet-ops-sidebar/fleet-listing';
6
7
 
7
8
  /**
8
9
  * LayoutFleetOpsSidebarComponent
@@ -25,13 +25,6 @@ export default class ManagementDriversIndexEditController extends BaseController
25
25
  */
26
26
  @tracked overlay;
27
27
 
28
- /**
29
- * The universe service.
30
- *
31
- * @memberof ManagementDriversIndexEditController
32
- */
33
- @tracked universe;
34
-
35
28
  /**
36
29
  * When exiting the overlay.
37
30
  *
@@ -115,23 +108,4 @@ export default class ManagementDriversIndexEditController extends BaseController
115
108
  ...options,
116
109
  });
117
110
  }
118
-
119
- /**
120
- * Transitions to a specified route within the '@fleetbase/fleetops-engine' engine.
121
- *
122
- * This action is a wrapper around the `transitionToEngineRoute` method of the `universe` service (or object),
123
- * specifically targeting the '@fleetbase/fleetops-engine'. It allows for easy transitioning to routes
124
- * within this engine, abstracting away the need to repeatedly specify the engine name.
125
- *
126
- * @param {string} route - The route within the '@fleetbase/fleetops-engine' to transition to.
127
- * @param {...any} args - Additional arguments to pass to the transitionToEngineRoute method.
128
- * @returns {Promise} A Promise that resolves with the result of the transitionToEngineRoute method.
129
- *
130
- * @example
131
- * // To transition to the 'management.fleets.index.new' route within the '@fleetbase/fleetops-engine'
132
- * this.transitionToRoute('management.fleets.index.new');
133
- */
134
- @action _transitionToRoute(route, ...args) {
135
- return this.universe.transitionToEngineRoute('@fleetbase/fleetops-engine', route, ...args);
136
- }
137
111
  }
package/addon/engine.js CHANGED
@@ -4,7 +4,7 @@ import Resolver from 'ember-resolver';
4
4
  import config from './config/environment';
5
5
  import services from '@fleetbase/ember-core/exports/services';
6
6
  import AdminVisibilityControlsComponent from './components/admin/visibility-controls';
7
- import NavigatorAppControlsComponent from './components/admin/navigator-app';
7
+ import NavigatorAppConfigComponent from './components/admin/navigator-app';
8
8
 
9
9
  const { modulePrefix } = config;
10
10
  const externalRoutes = ['console', 'extensions'];
@@ -30,9 +30,9 @@ export default class FleetOpsEngine extends Engine {
30
30
  component: AdminVisibilityControlsComponent,
31
31
  },
32
32
  {
33
- title: 'Navigator Apps',
34
- icon: 'key',
35
- component: NavigatorAppControlsComponent,
33
+ title: 'Navigator App',
34
+ icon: 'location-arrow',
35
+ component: NavigatorAppConfigComponent,
36
36
  },
37
37
  ],
38
38
  {
@@ -33,3 +33,20 @@ body[data-theme='dark'] .scheduler-left-sidebar {
33
33
  .fleetbase-console .dragSortList {
34
34
  overflow: visible !important;
35
35
  }
36
+
37
+ .next-fleet-summary-fleet .next-content-panel-body > .next-content-panel-body-inner > a.next-nav-item > .next-nav-item-icon-container > svg.text-green-500 {
38
+ color: rgb(34 197 94) !important;
39
+ }
40
+
41
+ .next-fleet-summary-fleet .next-content-panel-body > .next-content-panel-body-inner > a.next-nav-item > .next-nav-item-icon-container > svg.text-yellow-200 {
42
+ color: rgb(254 240 138) !important;
43
+ }
44
+
45
+ .next-fleet-summary {
46
+ --fleet-summary-toggle-base-padding: 2rem;
47
+ --fleet-summary-nav-item-base-padding: 1.25rem;
48
+ }
49
+
50
+ .next-sidebar .next-sidebar-panel-container.next-fleet-summary > .next-sidebar-panel > .next-content-panel > .next-sidebar-panel-toggle {
51
+ padding-left: 2rem;
52
+ }
@@ -1,4 +1,4 @@
1
- <Overlay @position="right" @noBackdrop={{true}} @isResizable={{true}} @fullHeight={{true}} @width="800px">
1
+ <Overlay @position="right" @noBackdrop={{true}} @isResizable={{true}} @fullHeight={{true}} @width="570px">
2
2
  <Overlay::Header @title={{if this.serviceRate.id this.serviceRate.service_name "New service rate"}} @status={{this.serviceRate.public_id}} @hideStatusDot={{true}} @createdAt={{this.serviceRate.createdAt}} @onPressCancel={{this.transitionBack}}>
3
3
  {{#if this.serviceRate.id}}
4
4
  <Button @icon="save" @type="primary" @text="Save Service Rate" @onClick={{this.updateServiceRate}} @isLoading={{this.isUpdatingServiceRate}} />
package/composer.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbase/fleetops-api",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "keywords": [
6
6
  "fleetbase-extension",
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "require": {
24
24
  "php": "^7.4|^8.0",
25
- "fleetbase/core-api": "^1.3.2",
25
+ "fleetbase/core-api": "^1.3.6",
26
26
  "barryvdh/laravel-dompdf": "^2.0",
27
27
  "brick/geo": "0.7.2",
28
28
  "cknow/laravel-money": "^7.1",
package/extension.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "Fleet-Ops",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "repository": "https://github.com/fleetbase/fleetops",
6
6
  "license": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleetbase/fleetops-engine",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "fleetbase": {
6
6
  "route": "fleet-ops",
@@ -12,7 +12,10 @@ return [
12
12
  'prefix' => null,
13
13
  'internal_prefix' => 'int'
14
14
  ]
15
- ],
15
+ ],
16
+ 'navigator' => [
17
+ 'bypass_verification_code' => env('NAVIGATOR_BYPASS_VERIFICATION_CODE', '999000')
18
+ ],
16
19
  'connection' => [
17
20
  'db' => env('DB_CONNECTION', 'mysql')
18
21
  ]
@@ -5,7 +5,7 @@ namespace Fleetbase\FleetOps\Casts;
5
5
  use Fleetbase\FleetOps\Support\Utils;
6
6
  use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialExpression;
7
7
  use Grimzy\LaravelMysqlSpatial\Types\GeometryInterface;
8
- use Grimzy\LaravelMysqlSpatial\Types\MultiPolygon as MultiPolygonType;
8
+ use Grimzy\LaravelMysqlSpatial\Types\MultiPolygon as SpatialMultiPolygon;
9
9
  use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
10
10
 
11
11
  class MultiPolygon implements CastsAttributes
@@ -37,14 +37,25 @@ class MultiPolygon implements CastsAttributes
37
37
  return new SpatialExpression($value);
38
38
  }
39
39
 
40
+ if ($value instanceof SpatialMultiPolygon) {
41
+ $model->geometries[$key] = $value;
42
+
43
+ return $value;
44
+ }
45
+
40
46
  if (Utils::isGeoJson($value)) {
41
- return Utils::createSpatialExpressionFromGeoJson($value);
47
+ $value = Utils::createGeometryObjectFromGeoJson($value);
48
+ $model->geometries[$key] = $value;
49
+
50
+ return $value;
42
51
  }
43
52
 
44
53
  if ($value instanceof SpatialExpression) {
54
+ $model->geometries[$key] = $value;
55
+
45
56
  return $value;
46
57
  }
47
58
 
48
- return new SpatialExpression(new MultiPolygonType([]));
59
+ throw new \Exception('Invalid MultiPolygon provided for ' . $key);
49
60
  }
50
61
  }
@@ -50,15 +50,25 @@ class Point implements CastsAttributes
50
50
  }
51
51
 
52
52
  if (Utils::isGeoJson($value)) {
53
- return Utils::createSpatialExpressionFromGeoJson($value);
53
+ $value = Utils::createSpatialExpressionFromGeoJson($value);
54
+ $model->geometries[$key] = $value;
55
+
56
+ return $value;
54
57
  }
55
58
 
56
59
  if (Utils::isCoordinates($value)) {
57
- $point = Utils::getPointFromCoordinates($value);
60
+ $point = Utils::getPointFromCoordinates($value);
61
+ $model->geometries[$key] = $point;
58
62
 
59
63
  return $point;
60
64
  }
61
65
 
66
+ if ($value instanceof SpatialExpression) {
67
+ $model->geometries[$key] = $value;
68
+
69
+ return $value;
70
+ }
71
+
62
72
  return static::createEmptySpatialExpression();
63
73
  }
64
74
 
@@ -5,7 +5,7 @@ namespace Fleetbase\FleetOps\Casts;
5
5
  use Fleetbase\FleetOps\Support\Utils;
6
6
  use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialExpression;
7
7
  use Grimzy\LaravelMysqlSpatial\Types\GeometryInterface;
8
- use Grimzy\LaravelMysqlSpatial\Types\Polygon as PolygonType;
8
+ use Grimzy\LaravelMysqlSpatial\Types\Polygon as SpatialPolygon;
9
9
  use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
10
10
 
11
11
  class Polygon implements CastsAttributes
@@ -34,13 +34,28 @@ class Polygon implements CastsAttributes
34
34
  if ($value instanceof GeometryInterface) {
35
35
  $model->geometries[$key] = $value;
36
36
 
37
- return new SpatialExpression($value);
37
+ return $value;
38
+ }
39
+
40
+ if ($value instanceof SpatialPolygon) {
41
+ $model->geometries[$key] = $value;
42
+
43
+ return $value;
38
44
  }
39
45
 
40
46
  if (Utils::isGeoJson($value)) {
41
- return Utils::createSpatialExpressionFromGeoJson($value);
47
+ $value = Utils::createGeometryObjectFromGeoJson($value);
48
+ $model->geometries[$key] = $value;
49
+
50
+ return $value;
51
+ }
52
+
53
+ if ($value instanceof SpatialExpression) {
54
+ $model->geometries[$key] = $value;
55
+
56
+ return $value;
42
57
  }
43
58
 
44
- return new SpatialExpression(new PolygonType([]));
59
+ throw new \Exception('Invalid Polygon provided for ' . $key);
45
60
  }
46
61
  }
@@ -80,9 +80,14 @@ class DriverController extends Controller
80
80
  ]);
81
81
  }
82
82
 
83
- // default location
84
- if ($request->missing('location')) {
85
- $input['location'] = new Point(0, 0);
83
+ // set default online
84
+ if (!isset($input['online'])) {
85
+ $input['online'] = 0;
86
+ }
87
+
88
+ // latitude / longitude
89
+ if ($request->has(['latitude', 'longitude'])) {
90
+ $input['location'] = Utils::getPointFromCoordinates($request->only(['latitude', 'longitude']));
86
91
  }
87
92
 
88
93
  // create the driver
@@ -150,6 +155,16 @@ class DriverController extends Controller
150
155
  ]);
151
156
  }
152
157
 
158
+ // set default online
159
+ if (!isset($input['online'])) {
160
+ $input['online'] = 0;
161
+ }
162
+
163
+ // latitude / longitude
164
+ if ($request->has(['latitude', 'longitude'])) {
165
+ $input['location'] = Utils::getPointFromCoordinates($request->only(['latitude', 'longitude']));
166
+ }
167
+
153
168
  // create the driver
154
169
  $driver->update($input);
155
170
  $driver->flushAttributesCache();
@@ -311,11 +326,11 @@ class DriverController extends Controller
311
326
  $platform = $request->or(['platform', 'os']);
312
327
 
313
328
  if (!$token) {
314
- return response()->error('Token is required to register device.');
329
+ return response()->apiError('Token is required to register device.');
315
330
  }
316
331
 
317
332
  if (!$platform) {
318
- return response()->error('Platform is required to register device.');
333
+ return response()->apiError('Platform is required to register device.');
319
334
  }
320
335
 
321
336
  $device = UserDevice::firstOrCreate(
@@ -350,13 +365,13 @@ class DriverController extends Controller
350
365
  $user = User::where('email', $identity)->orWhere('phone', static::phone($identity))->first();
351
366
 
352
367
  if (!Hash::check($password, $user->password)) {
353
- return response()->error('Authentication failed using password provided.', 401);
368
+ return response()->apiError('Authentication failed using password provided.', 401);
354
369
  }
355
370
 
356
- // get the current company session
371
+ // Get the company session for the user
357
372
  $company = Flow::getCompanySessionForUser($user);
358
373
 
359
- // get driver record
374
+ // Get driver record
360
375
  $driver = Driver::firstOrCreate(
361
376
  [
362
377
  'user_uuid' => $user->uuid,
@@ -365,9 +380,10 @@ class DriverController extends Controller
365
380
  [
366
381
  'user_uuid' => $user->uuid,
367
382
  'company_uuid' => $company->uuid,
368
- 'name' => $attrs['name'] ?? $user->name,
369
- 'phone' => $attrs['phone'] ?? $user->phone,
370
- 'email' => $attrs['email'] ?? $user->email,
383
+ 'name' => data_get($attrs, 'name', $user->name),
384
+ 'phone' => data_get($attrs, 'phone', $user->phone),
385
+ 'email' => data_get($attrs, 'email', $user->email),
386
+ 'location' => new Point(0, 0),
371
387
  ]
372
388
  );
373
389
 
@@ -375,7 +391,7 @@ class DriverController extends Controller
375
391
  try {
376
392
  $token = $user->createToken($driver->uuid);
377
393
  } catch (\Exception $e) {
378
- return response()->error($e->getMessage());
394
+ return response()->apiError($e->getMessage());
379
395
  }
380
396
 
381
397
  $driver->token = $token->plainTextToken;
@@ -396,7 +412,7 @@ class DriverController extends Controller
396
412
  $user = User::where('phone', $phone)->whereNull('deleted_at')->withoutGlobalScopes()->first();
397
413
 
398
414
  if (!$user) {
399
- return response()->error('No driver with this phone # found.');
415
+ return response()->apiError('No driver with this phone # found.');
400
416
  }
401
417
 
402
418
  // get the current company session
@@ -408,7 +424,7 @@ class DriverController extends Controller
408
424
  return "Your {$company->name} verification code is {$verification->code}";
409
425
  });
410
426
  } catch (\Throwable $e) {
411
- return response()->error($e->getMessage());
427
+ return response()->apiError($e->getMessage());
412
428
  }
413
429
 
414
430
  return response()->json(['status' => 'OK']);
@@ -437,14 +453,14 @@ class DriverController extends Controller
437
453
  })->first();
438
454
 
439
455
  if (!$user) {
440
- return response()->error('Unable to verify code.');
456
+ return response()->apiError('Unable to verify code.');
441
457
  }
442
458
 
443
459
  // find and verify code
444
460
  $verificationCode = VerificationCode::where(['subject_uuid' => $user->uuid, 'code' => $code, 'for' => $for])->exists();
445
461
 
446
- if (!$verificationCode && $code !== '999000') {
447
- return response()->error('Invalid verification code!');
462
+ if (!$verificationCode && $code !== config('fleetops.navigator.bypass_verification_code')) {
463
+ return response()->apiError('Invalid verification code!');
448
464
  }
449
465
 
450
466
  // get the current company session
@@ -470,7 +486,7 @@ class DriverController extends Controller
470
486
  try {
471
487
  $token = $user->createToken($driver->uuid);
472
488
  } catch (\Exception $e) {
473
- return response()->error($e->getMessage());
489
+ return response()->apiError($e->getMessage());
474
490
  }
475
491
 
476
492
  // $driver->update(['auth_token' => $token->plainTextToken]);
@@ -7,6 +7,8 @@ use Fleetbase\FleetOps\Http\Requests\UpdateEntityRequest;
7
7
  use Fleetbase\FleetOps\Http\Resources\v1\DeletedResource;
8
8
  use Fleetbase\FleetOps\Http\Resources\v1\Entity as EntityResource;
9
9
  use Fleetbase\FleetOps\Models\Entity;
10
+ use Fleetbase\FleetOps\Models\Payload;
11
+ use Fleetbase\FleetOps\Models\Place;
10
12
  use Fleetbase\FleetOps\Support\Utils;
11
13
  use Fleetbase\Http\Controllers\Controller;
12
14
  use Illuminate\Http\Request;
@@ -76,6 +78,23 @@ class EntityController extends Controller
76
78
  ]);
77
79
  }
78
80
 
81
+ // if destination is set
82
+ if ($request->has('destination') || $request->has('waypoint')) {
83
+ $destinationKey = $request->or(['destination', 'waypoint']);
84
+
85
+ if ($request->has('payload')) {
86
+ $payload = Payload::where('public_id', $request->input('payload'))->first();
87
+
88
+ if ($payload) {
89
+ // if a destination or waypoint is explicitly set
90
+ $destination = $payload->findDestinationFromKey($destinationKey);
91
+ if ($destination instanceof Place) {
92
+ $input['destination_uuid'] = $destination->uuid;
93
+ }
94
+ }
95
+ }
96
+ }
97
+
79
98
  // make sure company is set
80
99
  $input['company_uuid'] = session('company');
81
100
 
@@ -161,9 +180,25 @@ class EntityController extends Controller
161
180
  ]);
162
181
  }
163
182
 
183
+ // if destination is set
184
+ if ($request->has('destination') || $request->has('waypoint')) {
185
+ $destinationKey = $request->or(['destination', 'waypoint']);
186
+
187
+ if ($request->has('payload')) {
188
+ $payload = Payload::where('public_id', $request->input('payload'))->first();
189
+
190
+ if ($payload) {
191
+ // if a destination or waypoint is explicitly set
192
+ $destination = $payload->findDestinationFromKey($destinationKey);
193
+ if ($destination instanceof Place) {
194
+ $attributes['destination_uuid'] = $destination->uuid;
195
+ }
196
+ }
197
+ }
198
+ }
199
+
164
200
  // update the entity
165
201
  $entity->update($input);
166
- // $entity->flushAttributesCache();
167
202
 
168
203
  // response the entity resource
169
204
  return new EntityResource($entity);
@@ -36,7 +36,7 @@ class LabelController extends Controller
36
36
  }
37
37
 
38
38
  if (!$subject) {
39
- return response()->error('Unable to render label.');
39
+ return response()->apiError('Unable to render label.');
40
40
  }
41
41
 
42
42
  switch ($format) {
@@ -58,6 +58,6 @@ class LabelController extends Controller
58
58
  return response()->json(['data' => mb_convert_encoding($base64, 'UTF-8', 'UTF-8')]);
59
59
  }
60
60
 
61
- return response()->error('Unable to render label.');
61
+ return response()->apiError('Unable to render label.');
62
62
  }
63
63
  }