@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.
- package/addon/components/admin/navigator-app.hbs +6 -3
- package/addon/components/layout/fleet-ops-sidebar/fleet-listing.hbs +5 -1
- package/addon/components/layout/fleet-ops-sidebar/fleet-listing.js +98 -1
- package/addon/components/layout/fleet-ops-sidebar.hbs +5 -1
- package/addon/components/layout/fleet-ops-sidebar.js +1 -0
- package/addon/controllers/management/drivers/index/edit.js +0 -26
- package/addon/engine.js +4 -4
- package/addon/styles/fleetops-engine.css +17 -0
- package/addon/templates/operations/service-rates/index/new.hbs +1 -1
- package/composer.json +2 -2
- package/extension.json +1 -1
- package/package.json +1 -1
- package/server/config/fleetops.php +4 -1
- package/server/src/Casts/MultiPolygon.php +14 -3
- package/server/src/Casts/Point.php +12 -2
- package/server/src/Casts/Polygon.php +19 -4
- package/server/src/Http/Controllers/Api/v1/DriverController.php +34 -18
- package/server/src/Http/Controllers/Api/v1/EntityController.php +36 -1
- package/server/src/Http/Controllers/Api/v1/LabelController.php +2 -2
- package/server/src/Http/Controllers/Api/v1/OrderController.php +139 -59
- package/server/src/Http/Controllers/Api/v1/PayloadController.php +20 -12
- package/server/src/Http/Controllers/Api/v1/PlaceController.php +25 -3
- package/server/src/Http/Controllers/Api/v1/PurchaseRateController.php +1 -1
- package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +71 -3
- package/server/src/Http/Controllers/Api/v1/ServiceQuoteController.php +1 -1
- package/server/src/Http/Controllers/Api/v1/ServiceRateController.php +3 -2
- package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +2 -2
- package/server/src/Http/Controllers/Api/v1/TrackingStatusController.php +2 -2
- package/server/src/Http/Controllers/Api/v1/VehicleController.php +22 -2
- package/server/src/Http/Controllers/Api/v1/ZoneController.php +59 -3
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +148 -0
- package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +38 -0
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +11 -1
- package/server/src/Http/Filter/TrackingStatusFilter.php +10 -0
- package/server/src/Http/Requests/CancelOrderRequest.php +1 -2
- package/server/src/Http/Requests/CreateContactRequest.php +5 -4
- package/server/src/Http/Requests/CreateDriverRequest.php +13 -11
- package/server/src/Http/Requests/CreateEntityRequest.php +7 -4
- package/server/src/Http/Requests/CreateOrderRequest.php +2 -2
- package/server/src/Http/Requests/CreatePayloadRequest.php +1 -1
- package/server/src/Http/Requests/CreatePlaceRequest.php +46 -4
- package/server/src/Http/Requests/CreatePurchaseRateRequest.php +3 -2
- package/server/src/Http/Requests/CreateServiceAreaRequest.php +24 -4
- package/server/src/Http/Requests/CreateServiceRateRequest.php +22 -21
- package/server/src/Http/Requests/CreateTrackingStatusRequest.php +9 -8
- package/server/src/Http/Requests/CreateVehicleRequest.php +6 -4
- package/server/src/Http/Requests/CreateZoneRequest.php +24 -5
- package/server/src/Http/Requests/QueryServiceQuotesRequest.php +11 -10
- package/server/src/Http/Requests/ScheduleOrderRequest.php +32 -0
- package/server/src/Http/Requests/UpdateContactRequest.php +0 -13
- package/server/src/Http/Requests/UpdateServiceAreaRequest.php +1 -23
- package/server/src/Http/Requests/UpdateServiceQuoteRequest.php +1 -23
- package/server/src/Http/Requests/UpdateServiceRateRequest.php +1 -23
- package/server/src/Http/Requests/UpdateTrackingStatusRequest.php +1 -26
- package/server/src/Http/Resources/v1/DeletedResource.php +2 -9
- package/server/src/Http/Resources/v1/Entity.php +47 -44
- package/server/src/Http/Resources/v1/Order.php +1 -1
- package/server/src/Http/Resources/v1/ServiceArea.php +2 -2
- package/server/src/Http/Resources/v1/Vehicle.php +1 -3
- package/server/src/Http/Resources/v1/Zone.php +2 -4
- package/server/src/Models/Entity.php +99 -3
- package/server/src/Models/Order.php +75 -7
- package/server/src/Models/Payload.php +104 -33
- package/server/src/Models/Place.php +56 -17
- package/server/src/Models/ServiceArea.php +285 -18
- package/server/src/Models/ServiceRate.php +10 -6
- package/server/src/Models/TrackingNumber.php +18 -24
- package/server/src/Models/TrackingStatus.php +2 -6
- package/server/src/Models/Vehicle.php +2 -2
- package/server/src/Models/Waypoint.php +0 -10
- package/server/src/Models/Zone.php +132 -5
- package/server/src/Support/Flow.php +17 -3
- package/server/src/Support/Utils.php +143 -9
- 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
|
-
<
|
|
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
|
-
|
|
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
|
|
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
|
|
34
|
-
icon: '
|
|
35
|
-
component:
|
|
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="
|
|
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.
|
|
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.
|
|
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
package/package.json
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
84
|
-
if ($
|
|
85
|
-
$input['
|
|
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()->
|
|
329
|
+
return response()->apiError('Token is required to register device.');
|
|
315
330
|
}
|
|
316
331
|
|
|
317
332
|
if (!$platform) {
|
|
318
|
-
return response()->
|
|
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()->
|
|
368
|
+
return response()->apiError('Authentication failed using password provided.', 401);
|
|
354
369
|
}
|
|
355
370
|
|
|
356
|
-
//
|
|
371
|
+
// Get the company session for the user
|
|
357
372
|
$company = Flow::getCompanySessionForUser($user);
|
|
358
373
|
|
|
359
|
-
//
|
|
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
|
|
369
|
-
'phone' => $attrs
|
|
370
|
-
'email' => $attrs
|
|
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()->
|
|
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()->
|
|
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()->
|
|
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()->
|
|
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 !== '
|
|
447
|
-
return response()->
|
|
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()->
|
|
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()->
|
|
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()->
|
|
61
|
+
return response()->apiError('Unable to render label.');
|
|
62
62
|
}
|
|
63
63
|
}
|