@fleetbase/fleetops-engine 0.6.13 → 0.6.15

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 (58) hide show
  1. package/addon/components/customer/orders.js +2 -2
  2. package/addon/components/live-map.hbs +1 -1
  3. package/addon/components/live-map.js +2 -2
  4. package/addon/components/route-optimization-engine-select-button.hbs +2 -1
  5. package/addon/components/route-optimization-wizard-panel.hbs +24 -0
  6. package/addon/components/route-optimization-wizard-panel.js +46 -0
  7. package/addon/controllers/operations/orders/index/new.js +6 -5
  8. package/addon/controllers/operations/orders/index/view.js +2 -2
  9. package/addon/controllers/operations/orders/index.js +26 -1
  10. package/addon/controllers/operations/routes/index/new.js +36 -0
  11. package/addon/controllers/operations/routes/index/view.js +3 -0
  12. package/addon/controllers/operations/routes/index.js +13 -0
  13. package/addon/controllers/settings/routing.js +25 -3
  14. package/addon/engine.js +6 -5
  15. package/addon/routes/operations/routes/index/new.js +9 -0
  16. package/addon/routes/operations/routes/index/view.js +3 -0
  17. package/addon/routes/operations/routes/index.js +3 -0
  18. package/addon/routes/operations/routes.js +3 -0
  19. package/addon/routes.js +6 -0
  20. package/addon/services/leaflet-routing-control.js +64 -0
  21. package/addon/services/osrm.js +1 -1
  22. package/addon/templates/operations/routes/index/new.hbs +2 -0
  23. package/addon/templates/operations/routes/index/view.hbs +1 -0
  24. package/addon/templates/operations/routes/index.hbs +13 -0
  25. package/addon/templates/operations/routes.hbs +1 -0
  26. package/addon/templates/settings/routing.hbs +15 -1
  27. package/app/components/route-optimization-wizard-panel.js +1 -0
  28. package/app/controllers/operations/routes/index/new.js +1 -0
  29. package/app/controllers/operations/routes/index/view.js +1 -0
  30. package/app/routes/operations/routes/index/new.js +1 -0
  31. package/app/routes/operations/routes/index/view.js +1 -0
  32. package/app/routes/operations/routes/index.js +1 -0
  33. package/app/routes/operations/routes.js +1 -0
  34. package/app/services/leaflet-routing-control.js +1 -0
  35. package/app/templates/operations/routes/index/new.js +1 -0
  36. package/app/templates/operations/routes/index/view.js +1 -0
  37. package/app/templates/operations/routes/index.js +1 -0
  38. package/app/templates/operations/routes.js +1 -0
  39. package/composer.json +1 -1
  40. package/extension.json +1 -1
  41. package/package.json +1 -1
  42. package/server/src/Events/EntityActivityChanged.php +2 -2
  43. package/server/src/Events/EntityCompleted.php +2 -2
  44. package/server/src/Events/OrderCanceled.php +2 -2
  45. package/server/src/Events/OrderCompleted.php +2 -2
  46. package/server/src/Events/OrderDispatched.php +2 -2
  47. package/server/src/Events/OrderDriverAssigned.php +1 -1
  48. package/server/src/Events/OrderFailed.php +2 -2
  49. package/server/src/Events/OrderReady.php +1 -1
  50. package/server/src/Events/OrderStarted.php +1 -1
  51. package/server/src/Events/WaypointActivityChanged.php +2 -2
  52. package/server/src/Events/WaypointCompleted.php +2 -2
  53. package/server/src/Http/Controllers/Internal/v1/SettingController.php +8 -2
  54. package/server/src/Http/Filter/OrderFilter.php +5 -0
  55. package/server/src/Http/Requests/CreateDriverRequest.php +1 -1
  56. package/server/src/Listeners/NotifyOrderEvent.php +1 -0
  57. package/server/src/Models/Order.php +1 -1
  58. package/translations/en-us.yaml +1 -0
@@ -25,7 +25,7 @@ export default class CustomerOrdersComponent extends Component {
25
25
  @service modalsManager;
26
26
  @service customerSession;
27
27
  @service hostRouter;
28
- @service leafletRouterControl;
28
+ @service leafletRoutingControl;
29
29
  @engineService('@fleetbase/fleetops-engine') movementTracker;
30
30
  @engineService('@fleetbase/fleetops-engine') location;
31
31
  @tracked orders = [];
@@ -240,7 +240,7 @@ export default class CustomerOrdersComponent extends Component {
240
240
  }
241
241
 
242
242
  const routingService = this.currentUser.getOption('routing', { router: 'osrm' }).router;
243
- const { router, formatter } = this.leafletRouterControl.get(routingService);
243
+ const { router, formatter } = this.leafletRoutingControl.get(routingService);
244
244
 
245
245
  this.routeControl = new RoutingControl({
246
246
  router,
@@ -243,7 +243,7 @@
243
243
  {{/if}}
244
244
  </div>
245
245
 
246
- {{#if this.isDataLoaded}}
246
+ {{#if (and this.isDataLoaded (not-eq @drawerTab false))}}
247
247
  <LiveMapDrawer
248
248
  @tab={{@drawerTab}}
249
249
  @onTabChanged={{@onDrawerTabChanged}}
@@ -36,7 +36,7 @@ export default class LiveMapComponent extends Component {
36
36
  @service contextPanel;
37
37
  @service leafletMapManager;
38
38
  @service leafletContextmenuManager;
39
- @service leafletRouterControl;
39
+ @service leafletRoutingControl;
40
40
  @service theme;
41
41
 
42
42
  /**
@@ -1140,7 +1140,7 @@ export default class LiveMapComponent extends Component {
1140
1140
  }
1141
1141
 
1142
1142
  const routingService = this.currentUser.getOption('routing', { router: 'osrm' }).router;
1143
- const { router, formatter } = this.leafletRouterControl.get(routingService);
1143
+ const { router, formatter } = this.leafletRoutingControl.get(routingService);
1144
1144
 
1145
1145
  this.routeControl = new RoutingControl({
1146
1146
  router,
@@ -15,7 +15,8 @@
15
15
  <div class="px-1">
16
16
  {{#each this.routeOptimization.availableServices as |service|}}
17
17
  <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.handleClick service)}}>
18
- <div >
18
+ <div class="flex flex-row items-center">
19
+ <div class="mr-2"><FaIcon @icon="arrow-right" /></div>
19
20
  <div class="text-sm">{{service.name}}</div>
20
21
  </div>
21
22
  </a>
@@ -0,0 +1,24 @@
1
+ <Overlay
2
+ @isOpen={{true}}
3
+ @onLoad={{this.setOverlayContext}}
4
+ @position="right"
5
+ @noBackdrop={{true}}
6
+ @fullHeight={{true}}
7
+ @isResizeble={{true}}
8
+ @width="450px"
9
+ @overlayClass="route-optimization-wizard-panel"
10
+ >
11
+ <Overlay::Header @title="New Route Optimization">
12
+ <div class="flex flex-1 justify-end">
13
+ <Button @icon="play" @type="primary" @text="Run" @wrapperClass="mr-2" />
14
+ <Button @type="default" @icon="times" />
15
+ </div>
16
+ </Overlay::Header>
17
+
18
+ <Overlay::Body @wrapperClass="px-4 space-y-4 pt-4">
19
+ {{#each @waypoints as |waypoint|}}
20
+ <div class="border rounded p-4 flex items-center mb-3">{{waypoint.address}}</div>
21
+ {{/each}}
22
+ <Spacer @height="300px" />
23
+ </Overlay::Body>
24
+ </Overlay>
@@ -0,0 +1,46 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { action } from '@ember/object';
4
+ import { inject as service } from '@ember/service';
5
+ import contextComponentCallback from '@fleetbase/ember-core/utils/context-component-callback';
6
+ import applyContextComponentArguments from '@fleetbase/ember-core/utils/apply-context-component-arguments';
7
+
8
+ export default class RouteOptimizationWizardPanelComponent extends Component {
9
+ @service universe;
10
+ @tracked context;
11
+
12
+ /**
13
+ * Constructs the component and applies initial state.
14
+ */
15
+ constructor(owner, { controller }) {
16
+ super(...arguments);
17
+ this.controller = controller;
18
+ applyContextComponentArguments(this);
19
+ }
20
+
21
+ /**
22
+ * Sets the overlay context.
23
+ *
24
+ * @action
25
+ * @param {OverlayContextObject} overlayContext
26
+ */
27
+ @action setOverlayContext(overlayContext) {
28
+ this.context = overlayContext;
29
+ // hide sidebar
30
+ if (this.universe.sidebarContext) {
31
+ this.universe.sidebarContext.hide();
32
+ }
33
+ contextComponentCallback(this, 'onLoad', ...arguments);
34
+ }
35
+
36
+ /**
37
+ * Handles the cancel action.
38
+ *
39
+ * @method
40
+ * @action
41
+ * @returns {Boolean} Indicates whether the cancel action was overridden.
42
+ */
43
+ @action onPressCancel() {
44
+ return contextComponentCallback(this, 'onPressCancel');
45
+ }
46
+ }
@@ -41,7 +41,7 @@ export default class OperationsOrdersIndexNewController extends BaseController {
41
41
  @service contextPanel;
42
42
  @service universe;
43
43
  @service routeOptimization;
44
- @service leafletRouterControl;
44
+ @service leafletRoutingControl;
45
45
  @service osrm;
46
46
 
47
47
  @tracked order = this.store.createRecord('order', { meta: [] });
@@ -613,7 +613,7 @@ export default class OperationsOrdersIndexNewController extends BaseController {
613
613
  return route;
614
614
  }
615
615
 
616
- @action setOptimizedRoute(route, trip, waypoints) {
616
+ @action setOptimizedRoute(route, trip, waypoints, engine = 'osrm') {
617
617
  let summary = { totalDistance: trip.distance, totalTime: trip.duration };
618
618
  let payload = {
619
619
  optimized: true,
@@ -621,6 +621,7 @@ export default class OperationsOrdersIndexNewController extends BaseController {
621
621
  waypoints,
622
622
  trip,
623
623
  summary,
624
+ engine,
624
625
  };
625
626
 
626
627
  this.leafletOptimizedRoute = payload;
@@ -792,7 +793,7 @@ export default class OperationsOrdersIndexNewController extends BaseController {
792
793
 
793
794
  if (canPreviewRoute) {
794
795
  const routingService = this.currentUser.getOption('routing', { router: 'osrm' }).router;
795
- const { router, formatter } = this.leafletRouterControl.get(routingService);
796
+ const { router, formatter } = this.leafletRoutingControl.get(routingService);
796
797
 
797
798
  this.previewRouteControl = new RoutingControl({
798
799
  router,
@@ -886,7 +887,7 @@ export default class OperationsOrdersIndexNewController extends BaseController {
886
887
  }
887
888
  }
888
889
 
889
- handleRouteOptimization({ sortedWaypoints, route, trip, result }) {
890
+ handleRouteOptimization({ sortedWaypoints, route, trip, result, engine = 'osrm' }) {
890
891
  // Update map layers & UI
891
892
  this.removeRoutingControlPreview();
892
893
  this.removeOptimizedRoute(this.leafletMap);
@@ -895,7 +896,7 @@ export default class OperationsOrdersIndexNewController extends BaseController {
895
896
  // Update controller state
896
897
  this.waypoints = sortedWaypoints;
897
898
  if (route) {
898
- this.setOptimizedRoute(route, trip, result.waypoints);
899
+ this.setOptimizedRoute(route, trip, result.waypoints, engine);
899
900
  }
900
901
  this.previewDraftOrderRoute(this.payload, this.waypoints, this.isMultipleDropoffOrder);
901
902
  this.updatePayloadCoordinates();
@@ -23,7 +23,7 @@ export default class OperationsOrdersIndexViewController extends BaseController
23
23
  @service socket;
24
24
  @service universe;
25
25
  @service contextPanel;
26
- @service leafletRouterControl;
26
+ @service leafletRoutingControl;
27
27
 
28
28
  @tracked isLoadingAdditionalData = false;
29
29
  @tracked isWaypointsCollapsed;
@@ -383,7 +383,7 @@ export default class OperationsOrdersIndexViewController extends BaseController
383
383
  leafletMap.flyTo(waypoints.firstObject);
384
384
 
385
385
  const routingService = this.currentUser.getOption('routing', { router: 'osrm' }).router;
386
- const { router, formatter } = this.leafletRouterControl.get(routingService);
386
+ const { router, formatter } = this.leafletRoutingControl.get(routingService);
387
387
 
388
388
  this.routeControl = new RoutingControl({
389
389
  router,
@@ -22,6 +22,7 @@ export default class OperationsOrdersIndexController extends BaseController {
22
22
  @service socket;
23
23
  @service abilities;
24
24
  @service theme;
25
+ @service routeOptimization;
25
26
 
26
27
  /**
27
28
  * Queryable parameters for this controller's model
@@ -1130,7 +1131,6 @@ export default class OperationsOrdersIndexController extends BaseController {
1130
1131
  */
1131
1132
  @action bulkAssignDriver(selected = []) {
1132
1133
  selected = selected.length > 0 ? selected : this.table.selectedRows;
1133
-
1134
1134
  if (!isArray(selected) || selected.length === 0) {
1135
1135
  return;
1136
1136
  }
@@ -1199,12 +1199,37 @@ export default class OperationsOrdersIndexController extends BaseController {
1199
1199
  });
1200
1200
  }
1201
1201
 
1202
+ /**
1203
+ * Commits the bulk query to the server for results.
1204
+ * @action
1205
+ * @memberof OperationsOrdersIndexController
1206
+ */
1202
1207
  @action commitBulkQuery() {
1203
1208
  this.bulk_query = this.bulkSearchValue;
1204
1209
  }
1205
1210
 
1211
+ /**
1212
+ * Resets/clear the bulk query search.
1213
+ * @action
1214
+ * @memberof OperationsOrdersIndexController
1215
+ */
1206
1216
  @action removeBulkQuery() {
1207
1217
  this.bulkSearchValue = '';
1208
1218
  this.bulk_query = null;
1209
1219
  }
1220
+
1221
+ /**
1222
+ * Run route optimization wizard.
1223
+ * @action
1224
+ * @memberof OperationsOrdersIndexController
1225
+ */
1226
+ @action optimizeOrderRoutes(selected = []) {
1227
+ selected = selected.length > 0 ? selected : this.table.selectedRows;
1228
+
1229
+ return this.hostRouter.transitionTo('console.fleet-ops.operations.routes.index.new', {
1230
+ queryParams: {
1231
+ selectedOrders: selected.map((_) => _.public_id).join(','),
1232
+ },
1233
+ });
1234
+ }
1210
1235
  }
@@ -0,0 +1,36 @@
1
+ import Controller from '@ember/controller';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { action } from '@ember/object';
5
+ import { task } from 'ember-concurrency';
6
+
7
+ export default class OperationsRoutesIndexNewController extends Controller {
8
+ @service store;
9
+ @tracked panel;
10
+ @tracked selectedOrders = '';
11
+ @tracked waypoints = [];
12
+
13
+ @action setOverlayPanelContext(overlayPanelContext) {
14
+ this.panel = overlayPanelContext;
15
+ this.loadSelectedOrders.perform(this.selectedOrders.split(','));
16
+ }
17
+
18
+ @task *loadSelectedOrders(selectedOrders) {
19
+ const orders = yield this.store.query('order', { only: selectedOrders });
20
+ console.log('[orders]', orders);
21
+ this.extractWaypoints(orders);
22
+ }
23
+
24
+ extractWaypoints(orders = []) {
25
+ const extracted = [];
26
+
27
+ orders.forEach((order) => {
28
+ const pickup = order.get('payload.pickup');
29
+ const dropoff = order.get('payload.dropoff');
30
+ const waypoints = order.get('payload.waypoints')?.toArray() ?? [];
31
+ extracted.push(pickup, dropoff, ...waypoints);
32
+ });
33
+
34
+ this.waypoints = extracted.filter(Boolean);
35
+ }
36
+ }
@@ -0,0 +1,3 @@
1
+ import Controller from '@ember/controller';
2
+
3
+ export default class OperationsRoutesIndexViewController extends Controller {}
@@ -0,0 +1,13 @@
1
+ import Controller from '@ember/controller';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { action } from '@ember/object';
4
+
5
+ export default class OperationsRoutesIndexController extends Controller {
6
+ @tracked leafletMap;
7
+ @tracked liveMap;
8
+
9
+ @action setMapReference({ target }) {
10
+ this.leafletMap = target;
11
+ this.liveMap = target.liveMap;
12
+ }
13
+ }
@@ -7,8 +7,14 @@ export default class SettingsRoutingController extends Controller {
7
7
  @service fetch;
8
8
  @service notifications;
9
9
  @service currentUser;
10
- @service leafletRouterControl;
10
+ @service leafletRoutingControl;
11
11
  @tracked routerService = 'osrm';
12
+ @tracked routingUnit = 'km';
13
+ @tracked routingUnitOptions = [
14
+ { label: 'Kilometers', value: 'km' },
15
+ { label: 'Miles', value: 'mi' },
16
+ ];
17
+ @tracked saveTasks = [];
12
18
 
13
19
  constructor() {
14
20
  super(...arguments);
@@ -23,8 +29,9 @@ export default class SettingsRoutingController extends Controller {
23
29
  @task *saveSettings() {
24
30
  try {
25
31
  yield this.fetch.post('fleet-ops/settings/routing-settings', { router: this.routerService });
32
+ yield this.performAdditionalSaveTasks();
26
33
  // Save in local memory too
27
- this.currentUser.setOption('routing', { router: this.routerService });
34
+ this.currentUser.setOption('routing', { router: this.routerService, unit: this.routingUnit });
28
35
  this.notifications.success('Routing setting saved.');
29
36
  } catch (error) {
30
37
  this.notifications.serverError(error);
@@ -38,10 +45,25 @@ export default class SettingsRoutingController extends Controller {
38
45
  */
39
46
  @task *getSettings() {
40
47
  try {
41
- const { router } = yield this.fetch.get('fleet-ops/settings/routing-settings');
48
+ const { router, unit } = yield this.fetch.get('fleet-ops/settings/routing-settings');
42
49
  this.routerService = router;
50
+ this.routingUnit = unit;
43
51
  } catch (error) {
44
52
  this.notifications.serverError(error);
45
53
  }
46
54
  }
55
+
56
+ registerSaveTask(task) {
57
+ this.saveTasks.push(task);
58
+ }
59
+
60
+ async performAdditionalSaveTasks() {
61
+ for (let i = 0; i < this.saveTasks.length; i++) {
62
+ const task = this.saveTasks[i];
63
+ if (typeof task.perform === 'function') {
64
+ await task.perform();
65
+ }
66
+ }
67
+ return true;
68
+ }
47
69
  }
package/addon/engine.js CHANGED
@@ -9,7 +9,7 @@ import AdminAvatarManagementComponent from './components/admin/avatar-management
9
9
  import CustomerOrdersComponent from './components/customer/orders';
10
10
  import CustomerAdminSettingsComponent from './components/customer/admin-settings';
11
11
  import OrderTrackingLookupComponent from './components/order-tracking-lookup';
12
- import { RouterControl } from './services/leaflet-router-control';
12
+ import { RoutingControl } from './services/leaflet-routing-control';
13
13
  import { OSRMv1 } from '@fleetbase/leaflet-routing-machine';
14
14
  import getRoutingHost from '@fleetbase/ember-core/utils/get-routing-host';
15
15
 
@@ -68,12 +68,12 @@ export default class FleetOpsEngine extends Engine {
68
68
  }
69
69
 
70
70
  // Register OSRM as Routing Controler
71
- const leafletRouterControl = app.lookup('service:leaflet-router-control');
72
- if (leafletRouterControl) {
71
+ const leafletRoutingControl = app.lookup('service:leaflet-routing-control');
72
+ if (leafletRoutingControl) {
73
73
  const routingHost = getRoutingHost();
74
- leafletRouterControl.register(
74
+ leafletRoutingControl.register(
75
75
  'osrm',
76
- new RouterControl({
76
+ new RoutingControl({
77
77
  name: 'OSRM',
78
78
  router: new OSRMv1({
79
79
  serviceUrl: `${routingHost}/route/v1`,
@@ -133,6 +133,7 @@ export default class FleetOpsEngine extends Engine {
133
133
  'fleet-ops:template:operations:orders:new',
134
134
  'fleet-ops:template:operations:orders:new:entities-input',
135
135
  'fleet-ops:template:operations:orders:new:entities-input:entity',
136
+ 'fleet-ops:template:settings:routing',
136
137
  ]);
137
138
 
138
139
  universe.afterBoot(function (universe) {
@@ -0,0 +1,9 @@
1
+ import Route from '@ember/routing/route';
2
+
3
+ export default class OperationsRoutesIndexNewRoute extends Route {
4
+ queryParams = {
5
+ selectedOrders: {
6
+ refreshModel: false,
7
+ },
8
+ };
9
+ }
@@ -0,0 +1,3 @@
1
+ import Route from '@ember/routing/route';
2
+
3
+ export default class OperationsRoutesIndexViewRoute extends Route {}
@@ -0,0 +1,3 @@
1
+ import Route from '@ember/routing/route';
2
+
3
+ export default class OperationsRoutesIndexRoute extends Route {}
@@ -0,0 +1,3 @@
1
+ import Route from '@ember/routing/route';
2
+
3
+ export default class OperationsRoutesRoute extends Route {}
package/addon/routes.js CHANGED
@@ -31,6 +31,12 @@ export default buildRoutes(function () {
31
31
  });
32
32
  });
33
33
  });
34
+ this.route('routes', function () {
35
+ this.route('index', { path: '/' }, function () {
36
+ this.route('new');
37
+ this.route('view', { path: '/:public_id' });
38
+ });
39
+ });
34
40
  });
35
41
  this.route('management', { path: '/manage' }, function () {
36
42
  this.route('fleets', function () {
@@ -0,0 +1,64 @@
1
+ import Service, { inject as service } from '@ember/service';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { underscore } from '@ember/string';
4
+
5
+ export class RoutingControlRegistry {
6
+ @tracked routers = {};
7
+ }
8
+
9
+ export class RoutingControl {
10
+ @tracked name;
11
+ @tracked router;
12
+ @tracked formatter;
13
+
14
+ constructor(init) {
15
+ const { name, router, formatter } = typeof init === 'function' ? init() : init;
16
+ this.name = name;
17
+ this.router = router;
18
+ this.formatter = formatter;
19
+ }
20
+ }
21
+
22
+ export default class LeafletRoutingControlService extends Service {
23
+ @service universe;
24
+ registry = this.#initializeRegistry();
25
+
26
+ get availableEngines() {
27
+ return Object.keys(this.registry.routers).map(underscore);
28
+ }
29
+
30
+ get availableServices() {
31
+ return Object.entries(this.registry.routers).map(([key, control]) => ({
32
+ key,
33
+ name: control.name ?? key,
34
+ }));
35
+ }
36
+
37
+ register(name, getter) {
38
+ this.registry.routers = {
39
+ ...this.registry.routers,
40
+ [underscore(name)]: getter,
41
+ };
42
+ }
43
+
44
+ /* eslint-disable no-unused-vars */
45
+ unregister(name) {
46
+ let key = underscore(name);
47
+ let { [key]: _, ...rest } = this.registry.routers;
48
+ this.registry.routers = rest;
49
+ }
50
+
51
+ get(name) {
52
+ return this.registry.routers[underscore(name)];
53
+ }
54
+
55
+ #initializeRegistry() {
56
+ const registry = 'registry:routing-controls';
57
+ const application = this.universe.getApplicationInstance();
58
+ if (!application.hasRegistration(registry)) {
59
+ application.register(registry, new RoutingControlRegistry(), { instantiate: false });
60
+ }
61
+
62
+ return application.resolveRegistration(registry);
63
+ }
64
+ }
@@ -37,7 +37,7 @@ export default class OsrmService extends RouteOptimizationInterfaceService {
37
37
  const trip = result.trips?.[0];
38
38
  const route = polyline.decode(trip.geometry);
39
39
 
40
- return { sortedWaypoints, trip, route, result };
40
+ return { sortedWaypoints, trip, route, result, engine: 'osrm' };
41
41
  } catch (err) {
42
42
  debug(`[OSRM] Error routing trip : ${err.message}`);
43
43
  throw err;
@@ -0,0 +1,2 @@
1
+ <RouteOptimizationWizardPanel @waypoints={{this.waypoints}} @controller={{this}} @onLoad={{this.setOverlayPanelContext}} />
2
+ {{outlet}}
@@ -0,0 +1 @@
1
+ {{outlet}}
@@ -0,0 +1,13 @@
1
+ <LiveMap
2
+ id="leafletMap"
3
+ class="next-leaflet-container-map"
4
+ @lat={{1.3521}}
5
+ @lng={{103.8198}}
6
+ @zoom={{12}}
7
+ @zoomControl={{false}}
8
+ @drawerTab={{false}}
9
+ @onLoad={{this.setMapReference}}
10
+ @darkMode={{eq this.theme.activeTheme "dark"}}
11
+ {{set-container-dimensions}}
12
+ />
13
+ {{outlet}}
@@ -0,0 +1 @@
1
+ {{outlet}}
@@ -17,7 +17,7 @@
17
17
  <InputGroup @name="Routing Service" @helpText="Select the service which is responsible for calculating and plotting routes on the map.">
18
18
  <Select
19
19
  @value={{this.routerService}}
20
- @options={{this.leafletRouterControl.availableServices}}
20
+ @options={{this.leafletRoutingControl.availableServices}}
21
21
  @optionLabel="name"
22
22
  @optionValue="key"
23
23
  @onSelect={{fn (mut this.routerService)}}
@@ -25,7 +25,21 @@
25
25
  class="w-full"
26
26
  />
27
27
  </InputGroup>
28
+ <InputGroup @name="Routing Distance Unit" @helpText="The unit used for calculating distance and routes.">
29
+ <Select
30
+ @value={{this.routingUnit}}
31
+ @options={{this.routingUnitOptions}}
32
+ @optionLabel="label"
33
+ @optionValue="value"
34
+ @onSelect={{fn (mut this.routingUnit)}}
35
+ @placeholder="Select routing unit..."
36
+ class="w-full"
37
+ />
38
+ </InputGroup>
28
39
  </ContentPanel>
40
+ <RegistryYield @registry="fleet-ops:template:settings:routing" as |RegistryComponent|>
41
+ <RegistryComponent @controller={{this}} />
42
+ </RegistryYield>
29
43
  </div>
30
44
  </div>
31
45
  <Spacer @height="600px" />
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/route-optimization-wizard-panel';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/controllers/operations/routes/index/new';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/controllers/operations/routes/index/view';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/operations/routes/index/new';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/operations/routes/index/view';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/operations/routes/index';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/operations/routes';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/services/leaflet-routing-control';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/operations/routes/index/new';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/operations/routes/index/view';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/operations/routes/index';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/operations/routes';
package/composer.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbase/fleetops-api",
3
- "version": "0.6.13",
3
+ "version": "0.6.15",
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.13",
3
+ "version": "0.6.15",
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.13",
3
+ "version": "0.6.15",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "fleetbase": {
6
6
  "route": "fleet-ops"
@@ -21,12 +21,12 @@ class EntityActivityChanged implements ShouldBroadcast
21
21
  /**
22
22
  * The entity which has new activity.
23
23
  */
24
- public Entity $entity;
24
+ public ?Entity $entity = null;
25
25
 
26
26
  /**
27
27
  * The activity which triggered the waypoint completed.
28
28
  */
29
- public Activity $activity;
29
+ public ?Activity $activity = null;
30
30
 
31
31
  /**
32
32
  * The event id.
@@ -21,12 +21,12 @@ class EntityCompleted implements ShouldBroadcast
21
21
  /**
22
22
  * The entity which is completed.
23
23
  */
24
- public Entity $entity;
24
+ public ?Entity $entity = null;
25
25
 
26
26
  /**
27
27
  * The activity which triggered the waypoint completed.
28
28
  */
29
- public Activity $activity;
29
+ public ?Activity $activity = null;
30
30
 
31
31
  /**
32
32
  * The event id.
@@ -18,10 +18,10 @@ class OrderCanceled extends ResourceLifecycleEvent
18
18
  /**
19
19
  * Assosciated activity which triggered the event.
20
20
  */
21
- public ?Activity $activity;
21
+ public ?Activity $activity = null;
22
22
 
23
23
  /**
24
24
  * Assosciated order waypoint which event is for.
25
25
  */
26
- public ?Waypoint $waypoint;
26
+ public ?Waypoint $waypoint = null;
27
27
  }
@@ -18,10 +18,10 @@ class OrderCompleted extends ResourceLifecycleEvent
18
18
  /**
19
19
  * Assosciated activity which triggered the event.
20
20
  */
21
- public ?Activity $activity;
21
+ public ?Activity $activity = null;
22
22
 
23
23
  /**
24
24
  * Assosciated order waypoint which event is for.
25
25
  */
26
- public ?Waypoint $waypoint;
26
+ public ?Waypoint $waypoint = null;
27
27
  }
@@ -18,10 +18,10 @@ class OrderDispatched extends ResourceLifecycleEvent
18
18
  /**
19
19
  * Assosciated activity which triggered the event.
20
20
  */
21
- public ?Activity $activity;
21
+ public ?Activity $activity = null;
22
22
 
23
23
  /**
24
24
  * Assosciated order waypoint which event is for.
25
25
  */
26
- public ?Waypoint $waypoint;
26
+ public ?Waypoint $waypoint = null;
27
27
  }
@@ -17,5 +17,5 @@ class OrderDriverAssigned extends ResourceLifecycleEvent
17
17
  /**
18
18
  * Assosciated activity which triggered the event.
19
19
  */
20
- public ?Activity $activity;
20
+ public ?Activity $activity = null;
21
21
  }
@@ -18,10 +18,10 @@ class OrderFailed extends ResourceLifecycleEvent
18
18
  /**
19
19
  * Assosciated activity which triggered the event.
20
20
  */
21
- public ?Activity $activity;
21
+ public ?Activity $activity = null;
22
22
 
23
23
  /**
24
24
  * Assosciated order waypoint which event is for.
25
25
  */
26
- public ?Waypoint $waypoint;
26
+ public ?Waypoint $waypoint = null;
27
27
  }
@@ -17,5 +17,5 @@ class OrderReady extends ResourceLifecycleEvent
17
17
  /**
18
18
  * Assosciated activity which triggered the event.
19
19
  */
20
- public ?Activity $activity;
20
+ public ?Activity $activity = null;
21
21
  }
@@ -17,5 +17,5 @@ class OrderStarted extends ResourceLifecycleEvent
17
17
  /**
18
18
  * Assosciated activity which triggered the event.
19
19
  */
20
- public ?Activity $activity;
20
+ public ?Activity $activity = null;
21
21
  }
@@ -21,12 +21,12 @@ class WaypointActivityChanged implements ShouldBroadcast
21
21
  /**
22
22
  * The waypoint which is completed.
23
23
  */
24
- public Waypoint $waypoint;
24
+ public ?Waypoint $waypoint = null;
25
25
 
26
26
  /**
27
27
  * The activity which triggered the waypoint completed.
28
28
  */
29
- public Activity $activity;
29
+ public ?Activity $activity = null;
30
30
 
31
31
  /**
32
32
  * The event id.
@@ -21,12 +21,12 @@ class WaypointCompleted implements ShouldBroadcast
21
21
  /**
22
22
  * The waypoint which is completed.
23
23
  */
24
- public Waypoint $waypoint;
24
+ public ?Waypoint $waypoint = null;
25
25
 
26
26
  /**
27
27
  * The activity which triggered the waypoint completed.
28
28
  */
29
- public Activity $activity;
29
+ public ?Activity $activity = null;
30
30
 
31
31
  /**
32
32
  * The event id.
@@ -185,7 +185,8 @@ class SettingController extends Controller
185
185
  public function saveRoutingSettings(Request $request)
186
186
  {
187
187
  $router = $request->input('router');
188
- Setting::configureCompany('routing', ['router' => $router]);
188
+ $unit = $request->input('unit', 'km');
189
+ Setting::configureCompany('routing', ['router' => $router, 'unit' => $unit]);
189
190
 
190
191
  return response()->json([
191
192
  'status' => 'ok',
@@ -200,7 +201,12 @@ class SettingController extends Controller
200
201
  */
201
202
  public function getRoutingSettings()
202
203
  {
203
- $routingSettings = Setting::lookupCompany('routing', ['router' => 'osrm']);
204
+ $routingSettings = Setting::lookupCompany('routing', ['router' => 'osrm', 'unit' => 'km']);
205
+
206
+ // always default to km if no unit is set
207
+ if (!isset($routingSettings['unit'])) {
208
+ $routingSettings['unit'] = 'km';
209
+ }
204
210
 
205
211
  return response()->json($routingSettings);
206
212
  }
@@ -173,6 +173,11 @@ class OrderFilter extends Filter
173
173
  }
174
174
  }
175
175
 
176
+ public function only($ids)
177
+ {
178
+ $this->builder->whereIn('public_id', $ids);
179
+ }
180
+
176
181
  public function pickup(string $pickup)
177
182
  {
178
183
  $this->builder->whereHas(
@@ -34,7 +34,7 @@ class CreateDriverRequest extends FleetbaseRequest
34
34
  'password' => 'nullable|string',
35
35
  'country' => 'nullable|size:2',
36
36
  'city' => 'nullable|string',
37
- 'vehicle' => 'nullable|string|starts_with:vehicle_|exists:drivers,public_id',
37
+ 'vehicle' => 'nullable|string|starts_with:vehicle_|exists:vehicles,public_id',
38
38
  'status' => 'nullable|string|in:active,inactive',
39
39
  'vendor' => 'nullable|exists:vendors,public_id',
40
40
  'job' => 'nullable|exists:orders,public_id',
@@ -34,6 +34,7 @@ class NotifyOrderEvent implements ShouldQueue
34
34
  $reason = $event->activity ? $event->activity->get('details') : '';
35
35
  NotificationRegistry::notify(OrderCanceled::class, $order, $reason, $event->waypoint);
36
36
  }
37
+
37
38
  if ($event instanceof \Fleetbase\FleetOps\Events\OrderCompleted) {
38
39
  NotificationRegistry::notify(OrderCompleted::class, $order, $event->waypoint);
39
40
  }
@@ -1187,7 +1187,7 @@ class Order extends Model
1187
1187
  }
1188
1188
  }
1189
1189
 
1190
- return event(new OrderCanceled($this));
1190
+ return dispatch(fn () => event(new OrderCanceled($this)))->afterCommit();
1191
1191
  }
1192
1192
 
1193
1193
  /**
@@ -1332,6 +1332,7 @@ fleet-ops:
1332
1332
  delete-orders: Delete Orders
1333
1333
  dispatch-orders: Dispatch Orders
1334
1334
  assign-driver: Assign Driver
1335
+ route-optimization: Route Optimization
1335
1336
  bulk-assign-driver-helptext: Select a driver to assign to multiple orders.
1336
1337
  new:
1337
1338
  create-new-customer: Create new customer