@fleetbase/fleetops-engine 0.4.2 → 0.4.4

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 (30) hide show
  1. package/addon/components/edit-order-route-panel.hbs +182 -0
  2. package/addon/components/edit-order-route-panel.js +265 -0
  3. package/addon/components/fleet-panel.js +3 -3
  4. package/addon/components/map-container/toolbar.hbs +2 -2
  5. package/addon/components/modals/order-route-form.hbs +1 -1
  6. package/addon/controllers/operations/orders/index/new.js +73 -36
  7. package/addon/controllers/operations/orders/index/view.js +131 -126
  8. package/addon/routes/operations/orders/index/view.js +1 -1
  9. package/addon/services/context-panel.js +6 -0
  10. package/addon/styles/fleetops-engine.css +5 -0
  11. package/addon/templates/operations/orders/index/new.hbs +390 -58
  12. package/addon/templates/operations/orders/index/view.hbs +135 -105
  13. package/addon/templates/operations/service-rates/index/new.hbs +3 -1
  14. package/composer.json +2 -2
  15. package/extension.json +1 -1
  16. package/package.json +3 -3
  17. package/server/src/Http/Controllers/Api/v1/DriverController.php +59 -20
  18. package/server/src/Http/Controllers/Api/v1/OrderController.php +2 -0
  19. package/server/src/Http/Controllers/Internal/v1/DriverController.php +16 -3
  20. package/server/src/Http/Controllers/Internal/v1/OrderController.php +11 -0
  21. package/server/src/Http/Resources/v1/Order.php +3 -0
  22. package/server/src/Http/Resources/v1/PurchaseRate.php +2 -1
  23. package/server/src/Http/Resources/v1/ServiceQuote.php +1 -0
  24. package/server/src/Http/Resources/v1/ServiceQuoteItem.php +29 -0
  25. package/server/src/Models/Driver.php +1 -1
  26. package/server/src/Models/Order.php +16 -0
  27. package/server/src/Models/Place.php +2 -2
  28. package/server/src/Observers/DriverObserver.php +6 -1
  29. package/server/src/routes.php +1 -0
  30. package/translations/en-us.yaml +9 -2
@@ -0,0 +1,182 @@
1
+ <Overlay
2
+ @onLoad={{this.setOverlayContext}}
3
+ @onOpen={{this.onOpen}}
4
+ @onClose={{this.onClose}}
5
+ @onToggle={{this.onToggle}}
6
+ @position="right"
7
+ @noBackdrop={{true}}
8
+ @fullHeight={{true}}
9
+ @isResizeble={{or this.isResizable @isResizable}}
10
+ @width={{or this.width @width "570px"}}
11
+ >
12
+ <Overlay::Header @title={{concat "Edit order " this.order.public_id " route"}}>
13
+ <Button @type="primary" @icon="check" @text="Save" @helpText="Save order route changes" @onClick={{this.onSave}} @wrapperClass="mr-2" />
14
+ <Button @type="default" @icon="times" @helpText={{t "fleet-ops.common.cancel"}} @onClick={{this.onPressCancel}} />
15
+ </Overlay::Header>
16
+
17
+ <Overlay::Body @increaseInnerBodyHeightBy={{1000}}>
18
+ <div class="p-4">
19
+ <div class="flex flex-row justify-between mb-6">
20
+ <div class="flex">
21
+ <Toggle @isToggled={{this.order.payload.isMultiDrop}} @onToggle={{this.toggleMultiDropOrder}} @label={{t "fleet-ops.component.modals.order-route-form.toggle"}} />
22
+ </div>
23
+ <div class="flex flex-1 justify-end space-x-2">
24
+ {{#if this.order.payload.isMultiDrop}}
25
+ {{!-- <Button @type="magic" @icon="magic" @text={{t "fleet-ops.component.modals.order-route-form.optimize"}} @size="sm" @onClick={{fn this.optimizeRoute}} @helpText={{t "fleet-ops.component.modals.order-route-form.optimize-text"}} @disabled={{lt this.order.payload.waypoints.length 3}} @isLoading={{this.isOptimizingRoute}} /> --}}
26
+ <Button
27
+ @icon="map-marked-alt"
28
+ @text={{t "fleet-ops.component.modals.order-route-form.add"}}
29
+ @size="sm"
30
+ @onClick={{this.addWaypoint}}
31
+ @helpText={{t "fleet-ops.component.modals.order-route-form.add-text"}}
32
+ />
33
+ {{/if}}
34
+ </div>
35
+ </div>
36
+
37
+ {{#if this.order.payload.isMultiDrop}}
38
+ <DragSortList class="overflow-visible" @items={{this.order.payload.waypoints}} @dragEndAction={{this.sortWaypoints}} as |waypoint index|>
39
+ <div id={{concat "waypoint_" (add index 1)}} class="py-1 mb-3">
40
+ <div class="flex items-center justify-between">
41
+ <div class="flex items-center justify-between cursor-move">
42
+ <FaIcon @icon="grip-lines" @prefix="fas" class="mr-3 text-gray-100" />
43
+ <label class="waypoint-label dark:text-gray-100 text-sm">
44
+ {{waypoint-label (add index 1)}}
45
+ </label>
46
+ </div>
47
+
48
+ <div class="flex-1 px-4">
49
+ <ModelSelect
50
+ @modelName="place"
51
+ @selectedModel={{waypoint}}
52
+ @placeholder={{concat (t "fleet-ops.operations.orders.index.new.select-waypoint-placeholder") " " (add index 1)}}
53
+ @triggerClass="form-select form-input truncate max-w-300px"
54
+ @infiniteScroll={{false}}
55
+ @customSearchEndpoint="places/search"
56
+ @query={{hash geo=true latitude=this.latitude longitude=this.longitude}}
57
+ @renderInPlace={{true}}
58
+ @onChange={{fn this.setWaypointPlace index}}
59
+ as |model|
60
+ >
61
+ {{model.address}}
62
+ </ModelSelect>
63
+
64
+ {{#unless waypoint.isNew}}
65
+ {{#if waypoint.hasInvalidCoordinates}}
66
+ <div class="leading-5 text-sm text-red-400 mt-2">
67
+ <FaIcon @icon="exclamation-triangle" class="mr-1" />
68
+ {{t "fleet-ops.component.modals.order-route-form.invalid"}}
69
+ </div>
70
+ {{/if}}
71
+ {{/unless}}
72
+ </div>
73
+
74
+ <div class="flex items-center">
75
+ <Button class="mr-2" @icon="edit" @size="sm" @onClick={{fn this.editPlace waypoint}} />
76
+ <Button @type="danger" @icon="trash" @iconPrefix="fas" @size="sm" @onClick={{fn this.removeWaypoint waypoint}} />
77
+ </div>
78
+ </div>
79
+ </div>
80
+ </DragSortList>
81
+ {{else}}
82
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-3 text-xs dark:text-gray-100">
83
+ <div class="input-group">
84
+ <div class="flex items-center justify-between">
85
+ <label>{{t "fleet-ops.component.modals.order-route-form.pickup"}}</label>
86
+
87
+ {{#if this.order.payload.pickup}}
88
+ <a href="javascript:;" {{on "click" (fn this.editPlace this.order.payload.pickup)}}>{{t "fleet-ops.component.modals.order-route-form.edit-address"}}</a>
89
+ {{/if}}
90
+ </div>
91
+
92
+ <ModelSelect
93
+ @modelName="place"
94
+ @selectedModel={{this.order.payload.pickup}}
95
+ @placeholder={{t "fleet-ops.component.modals.order-route-form.select-pickup"}}
96
+ @triggerClass="form-select form-input"
97
+ @infiniteScroll={{false}}
98
+ @customSearchEndpoint="places/search"
99
+ @query={{hash geo=true latitude=this.latitude longitude=this.longitude}}
100
+ @renderInPlace={{true}}
101
+ @onChange={{fn this.setPayloadPlace "pickup"}}
102
+ as |model|
103
+ >
104
+ {{model.address}}
105
+ </ModelSelect>
106
+
107
+ {{#if this.order.payload.pickup.hasInvalidCoordinates}}
108
+ <div class="leading-5 text-sm text-red-400 mt-2">
109
+ <FaIcon @icon="exclamation-triangle" class="mr-1" />
110
+ {{t "fleet-ops.component.modals.order-route-form.invalid"}}
111
+ </div>
112
+ {{/if}}
113
+ </div>
114
+
115
+ <div class="input-group">
116
+ <div class="flex items-center justify-between">
117
+ <label>{{t "fleet-ops.component.modals.order-route-form.dropoff"}}</label>
118
+
119
+ {{#if this.order.payload.dropoff}}
120
+ <a href="javascript:;" {{on "click" (fn this.editPlace this.order.payload.dropoff)}}>{{t "fleet-ops.component.modals.order-route-form.edit-address"}}</a>
121
+ {{/if}}
122
+ </div>
123
+
124
+ <ModelSelect
125
+ @modelName="place"
126
+ @selectedModel={{this.order.payload.dropoff}}
127
+ @placeholder={{t "fleet-ops.component.modals.order-route-form.select-dropoff"}}
128
+ @triggerClass="form-select form-input"
129
+ @infiniteScroll={{false}}
130
+ @customSearchEndpoint="places/search"
131
+ @query={{hash geo=true latitude=this.latitude longitude=this.longitude}}
132
+ @renderInPlace={{true}}
133
+ @onChange={{fn this.setPayloadPlace "dropoff"}}
134
+ as |model|
135
+ >
136
+ {{model.address}}
137
+ </ModelSelect>
138
+
139
+ {{#if this.order.payload.dropoff.hasInvalidCoordinates}}
140
+ <div class="leading-5 text-sm text-red-400 mt-2">
141
+ <FaIcon @icon="exclamation-triangle" class="mr-1" />
142
+ {{t "fleet-ops.component.modals.order-route-form.invalid"}}
143
+ </div>
144
+ {{/if}}
145
+ </div>
146
+
147
+ <div class="input-group">
148
+ <div class="flex items-center justify-between">
149
+ <label>{{t "fleet-ops.component.modals.order-route-form.return"}}</label>
150
+
151
+ {{#if this.order.payload.return}}
152
+ <a href="javascript:;" {{on "click" (fn this.editPlace this.order.payload.return)}}>{{t "fleet-ops.component.modals.order-route-form.edit-address"}}</a>
153
+ {{/if}}
154
+ </div>
155
+
156
+ <ModelSelect
157
+ @modelName="place"
158
+ @selectedModel={{this.order.payload.return}}
159
+ @placeholder={{t "fleet-ops.component.modals.order-route-form.select-return"}}
160
+ @triggerClass="form-select form-input"
161
+ @infiniteScroll={{false}}
162
+ @customSearchEndpoint="places/search"
163
+ @query={{hash geo=true latitude=this.latitude longitude=this.longitude}}
164
+ @renderInPlace={{true}}
165
+ @onChange={{fn this.setPayloadPlace "return"}}
166
+ as |model|
167
+ >
168
+ {{model.address}}
169
+ </ModelSelect>
170
+
171
+ {{#if this.order.payload.return.hasInvalidCoordinates}}
172
+ <div class="leading-5 text-sm text-red-400 mt-2">
173
+ <FaIcon @icon="exclamation-triangle" class="mr-1" />
174
+ {{t "fleet-ops.component.modals.order-route-form.invalid"}}
175
+ </div>
176
+ {{/if}}
177
+ </div>
178
+ </div>
179
+ {{/if}}
180
+ </div>
181
+ </Overlay::Body>
182
+ </Overlay>
@@ -0,0 +1,265 @@
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 { isArray } from '@ember/array';
6
+ import contextComponentCallback from '../utils/context-component-callback';
7
+ import applyContextComponentArguments from '../utils/apply-context-component-arguments';
8
+ import getRoutingHost from '@fleetbase/ember-core/utils/get-routing-host';
9
+ import Point from '@fleetbase/fleetops-data/utils/geojson/point';
10
+ import findClosestWaypoint from '@fleetbase/ember-core/utils/find-closest-waypoint';
11
+
12
+ export default class EditOrderRoutePanelComponent extends Component {
13
+ /**
14
+ * Fetch service.
15
+ *
16
+ * @type {Service}
17
+ */
18
+ @service fetch;
19
+
20
+ /**
21
+ * Ember data store service.
22
+ *
23
+ * @type {Service}
24
+ */
25
+ @service store;
26
+
27
+ /**
28
+ * Service for managing routing within the host app.
29
+ *
30
+ * @type {Service}
31
+ */
32
+ @service hostRouter;
33
+
34
+ /**
35
+ * Service for managing the modals.
36
+ *
37
+ * @type {Service}
38
+ */
39
+ @service modalsManager;
40
+
41
+ /**
42
+ * Service for managing the context panel.
43
+ *
44
+ * @type {Service}
45
+ */
46
+ @service contextPanel;
47
+
48
+ /**
49
+ * Service for internationalization.
50
+ *
51
+ * @type {Service}
52
+ */
53
+ @service intl;
54
+
55
+ /**
56
+ * Service for notifications
57
+ *
58
+ * @type {Service}
59
+ */
60
+ @service notifications;
61
+
62
+ /**
63
+ * The orderwhich route is being edited.
64
+ *
65
+ * @type {OrderModel}
66
+ * @tracked
67
+ */
68
+ @tracked order;
69
+
70
+ /**
71
+ * Initializes the vehicle panel component.
72
+ */
73
+ constructor() {
74
+ super(...arguments);
75
+ this.order = this.args.order;
76
+ applyContextComponentArguments(this);
77
+ }
78
+
79
+ /**
80
+ * Sets the overlay context.
81
+ *
82
+ * @action
83
+ * @param {OverlayContextObject} overlayContext
84
+ */
85
+ @action setOverlayContext(overlayContext) {
86
+ this.context = overlayContext;
87
+ contextComponentCallback(this, 'onLoad', ...arguments);
88
+ }
89
+
90
+ /**
91
+ * Handles save action for the order route.
92
+ *
93
+ * @method
94
+ * @action
95
+ */
96
+ @action onSave() {
97
+ const isActionOverrided = contextComponentCallback(this, 'onSave', this.order);
98
+
99
+ if (!isActionOverrided) {
100
+ return this.order
101
+ .save()
102
+ .then((order) => {
103
+ this.notifications.success(this.intl.t('fleet-ops.operations.orders.index.view.update-success', { orderId: order.public_id }));
104
+ contextComponentCallback(this, 'onAfterSave', order);
105
+ })
106
+ .catch((error) => {
107
+ this.notifications.serverError(error);
108
+ });
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Handles the cancel action.
114
+ *
115
+ * @method
116
+ * @action
117
+ * @returns {Boolean} Indicates whether the cancel action was overridden.
118
+ */
119
+ @action onPressCancel() {
120
+ return contextComponentCallback(this, 'onPressCancel', this.order);
121
+ }
122
+
123
+ @action async editPlace(place) {
124
+ await this.modalsManager.done();
125
+
126
+ this.contextPanel.focus(place, 'editing', {
127
+ args: {
128
+ onClose: () => {
129
+ this.editOrderRoute(this.order);
130
+ },
131
+ },
132
+ });
133
+ }
134
+
135
+ @action toggleMultiDropOrder(isMultiDrop) {
136
+ const { pickup, dropoff } = this.order.payload;
137
+
138
+ if (isMultiDrop) {
139
+ // if pickup move it to multipdrop
140
+ if (pickup) {
141
+ this.addWaypointFromExistingPlace(pickup);
142
+ }
143
+
144
+ // if pickup move it to multipdrop
145
+ if (dropoff) {
146
+ this.addWaypointFromExistingPlace(dropoff);
147
+ }
148
+
149
+ this.order.payload.setProperties({
150
+ pickup_uuid: null,
151
+ dropoff_uuid: null,
152
+ });
153
+ } else {
154
+ const waypoint = this.store.createRecord('waypoint');
155
+ this.order.payload.waypoints.pushObject(waypoint);
156
+
157
+ this.order.payload.setProperties({
158
+ pickup_uuid: null,
159
+ dropoff_uuid: null,
160
+ pickup: null,
161
+ dropoff: null,
162
+ });
163
+ }
164
+
165
+ contextComponentCallback(this, 'onRouteChanged');
166
+ }
167
+
168
+ addWaypointFromExistingPlace(place) {
169
+ const waypoint = this.store.createRecord('waypoint', { place, location: place.location });
170
+ this.order.payload.waypoints.pushObject(waypoint);
171
+
172
+ // fire callback
173
+ contextComponentCallback(this, 'onWaypointAdded', waypoint);
174
+ }
175
+
176
+ @action removeWaypoint(waypoint) {
177
+ this.order.payload.waypoints.removeObject(waypoint);
178
+
179
+ // fire callback
180
+ contextComponentCallback(this, 'onWaypointRemoved', waypoint);
181
+ contextComponentCallback(this, 'onRouteChanged');
182
+ }
183
+
184
+ @action addWaypoint() {
185
+ const location = new Point(0, 0);
186
+ const place = this.store.createRecord('place', { location });
187
+ const waypoint = this.store.createRecord('waypoint', { place, location });
188
+
189
+ this.order.payload.waypoints.pushObject(waypoint);
190
+ // fire callback
191
+ contextComponentCallback(this, 'onWaypointAdded', waypoint);
192
+ }
193
+
194
+ @action setWaypointPlace(index, place) {
195
+ if (isArray(this.order.payload.waypoints) && !this.order.payload.waypoints.objectAt(index)) {
196
+ return;
197
+ }
198
+
199
+ this.order.payload.waypoints.objectAt(index).setProperties({
200
+ name: place.name,
201
+ place_uuid: place.id,
202
+ location: place.location,
203
+ place,
204
+ });
205
+
206
+ // fire callback waypoint place selected
207
+ contextComponentCallback(this, 'onWaypointPlaceSelected', place);
208
+ contextComponentCallback(this, 'onRouteChanged');
209
+ }
210
+
211
+ @action setPayloadPlace(prop, place) {
212
+ this.order.payload.set(prop, place);
213
+
214
+ // fire callback
215
+ contextComponentCallback(this, 'onPlaceSelected', place);
216
+ contextComponentCallback(this, 'onRouteChanged');
217
+ }
218
+
219
+ @action async optimizeRoute() {
220
+ this.isOptimizingRoute = true;
221
+
222
+ const coordinates = this.order.payload.payloadCoordinates;
223
+ const routingHost = getRoutingHost(this.order.payload, this.order.payload.waypoints);
224
+ let sortedWaypoints = [];
225
+
226
+ const response = await this.fetch.routing(coordinates, { source: 'any', destination: 'any', annotations: true }, { host: routingHost }).catch(() => {
227
+ this.notifications.error(this.intl.t('fleet-ops.operations.orders.index.view.route-error'));
228
+ this.isOptimizingRoute = false;
229
+ });
230
+
231
+ if (response && response.code === 'Ok') {
232
+ if (response.waypoints && isArray(response.waypoints)) {
233
+ const responseWaypoints = response.waypoints.sortBy('waypoint_index');
234
+
235
+ for (let i = 0; i < responseWaypoints.length; i++) {
236
+ const optimizedWaypoint = responseWaypoints.objectAt(i);
237
+ const optimizedWaypointLongitude = optimizedWaypoint.location.firstObject;
238
+ const optimizedWaypointLatitude = optimizedWaypoint.location.lastObject;
239
+ const waypointModel = findClosestWaypoint(optimizedWaypointLatitude, optimizedWaypointLongitude, this.order.payload.waypoints);
240
+
241
+ sortedWaypoints.pushObject(waypointModel);
242
+ }
243
+
244
+ this.order.payload.waypoints = sortedWaypoints;
245
+ }
246
+ } else {
247
+ this.notifications.error(this.intl.t('fleet-ops.operations.orders.index.view.route-error'));
248
+ }
249
+
250
+ this.isOptimizingRoute = false;
251
+ }
252
+
253
+ @action sortWaypoints({ sourceList, sourceIndex, targetList, targetIndex }) {
254
+ if (sourceList === targetList && sourceIndex === targetIndex) {
255
+ return;
256
+ }
257
+
258
+ const item = sourceList.objectAt(sourceIndex);
259
+
260
+ sourceList.removeAt(sourceIndex);
261
+ targetList.insertAt(targetIndex, item);
262
+
263
+ contextComponentCallback(this, 'onRouteChanged');
264
+ }
265
+ }
@@ -61,12 +61,12 @@ export default class FleetPanelComponent extends Component {
61
61
  @tracked tab;
62
62
 
63
63
  /**
64
- * The vehicle being displayed or edited.
64
+ * The fleet being displayed or edited.
65
65
  *
66
- * @type {VehicleModel}
66
+ * @type {FleetModel}
67
67
  * @tracked
68
68
  */
69
- @tracked vehicle;
69
+ @tracked fleet;
70
70
 
71
71
  /**
72
72
  * Returns the array of tabs available for the panel.
@@ -33,14 +33,14 @@
33
33
  </div>
34
34
  <FaIcon @icon="layer-group" />
35
35
  <Attach::Tooltip @class="clean" @animation="scale" @placement="right">
36
- <InputInfo @text={{t "fleet-ops.component.map-container.toolbar.view"}} @iconClass="hidden" class="py-1 px-2 bg-gray-900 -mt-1" />
36
+ <InputInfo @text={{t "fleet-ops.component.map-container.toolbar.view-order"}} @iconClass="hidden" class="py-1 px-2 bg-gray-900 -mt-1" />
37
37
  </Attach::Tooltip>
38
38
  </button>
39
39
  <BasicDropdown id="map-toolbar-service-areas-button" @horizontalPosition="right" @calculatePosition={{this.calculatePosition}} @renderInPlace={{true}} as |dd|>
40
40
  <dd.Trigger class="toolbar-button">
41
41
  <FaIcon @icon="map-marked-alt" />
42
42
  <Attach::Tooltip @class="clean" @animation="scale" @placement="right">
43
- <InputInfo @text={{t "fleet-ops.component.map-container.toolbar.view"}} @iconClass="hidden" class="{{if dd.isOpen 'hidden'}} py-1 px-2 bg-gray-900 -mt-1" />
43
+ <InputInfo @text={{t "fleet-ops.component.map-container.toolbar.view-service-area"}} @iconClass="hidden" class="{{if dd.isOpen 'hidden'}} py-1 px-2 bg-gray-900 -mt-1" />
44
44
  </Attach::Tooltip>
45
45
  </dd.Trigger>
46
46
  <dd.Content>
@@ -2,7 +2,7 @@
2
2
  <div class="modal-body-container">
3
3
  <div class="flex flex-row justify-between mb-6">
4
4
  <div class="flex">
5
- <ShortToggle @isToggled={{@options.order.payload.isMultiDrop}} @onToggle={{@options.toggleMultiDropOrder}} @label={{t "fleet-ops.component.modals.order-route-form.toggle"}} />
5
+ <Toggle @isToggled={{@options.order.payload.isMultiDrop}} @onToggle={{@options.toggleMultiDropOrder}} @label={{t "fleet-ops.component.modals.order-route-form.toggle"}} />
6
6
  </div>
7
7
  <div class="flex flex-1 justify-end space-x-2">
8
8
  {{#if @options.order.payload.isMultiDrop}}
@@ -161,6 +161,28 @@ export default class OperationsOrdersIndexNewController extends BaseController {
161
161
  onClick: this.editMetaData,
162
162
  },
163
163
  ];
164
+ @tracked uploadQueue = [];
165
+ acceptedFileTypes = [
166
+ 'application/vnd.ms-excel',
167
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
168
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
169
+ 'application/msword',
170
+ 'application/pdf',
171
+ 'application/x-pdf',
172
+ 'image/jpeg',
173
+ 'image/png',
174
+ 'image/gif',
175
+ 'image/webp',
176
+ 'video/mp4',
177
+ 'video/quicktime',
178
+ 'video/x-msvideo',
179
+ 'video/x-flv',
180
+ 'video/x-ms-wmv',
181
+ 'audio/mpeg',
182
+ 'video/x-msvideo',
183
+ 'application/zip',
184
+ 'application/x-tar',
185
+ ];
164
186
 
165
187
  @not('isServicable') isNotServicable;
166
188
  @alias('currentUser.latitude') userLatitude;
@@ -211,27 +233,6 @@ export default class OperationsOrdersIndexNewController extends BaseController {
211
233
  this.payloadCoordinates = coordinates;
212
234
  }
213
235
 
214
- // @computed('payload.{dropoff,pickup,waypoints}', 'waypoints.[]')
215
- // get payloadCoordinates() {
216
- // let waypoints = [];
217
- // let coordinates = [];
218
-
219
- // console.log('[this.waypoints]', this.waypoints);
220
-
221
- // waypoints.pushObjects([this.payload.pickup, ...this.waypoints.map((waypoint) => waypoint.place), this.payload.dropoff]);
222
- // waypoints.forEach((place) => {
223
- // if (place && place.get('longitude') && place.get('latitude')) {
224
- // if (place.hasInvalidCoordinates) {
225
- // return;
226
- // }
227
-
228
- // coordinates.pushObject([place.get('longitude'), place.get('latitude')]);
229
- // }
230
- // });
231
-
232
- // return coordinates;
233
- // }
234
-
235
236
  @computed('payloadCoordinates.length', 'waypoints.[]') get isServicable() {
236
237
  return this.payloadCoordinates.length >= 2;
237
238
  }
@@ -571,7 +572,6 @@ export default class OperationsOrdersIndexNewController extends BaseController {
571
572
  is_route_optimized,
572
573
  })
573
574
  .then((serviceQuotes) => {
574
- console.log('[serviceQuotes]', serviceQuotes);
575
575
  set(this, 'serviceQuotes', isArray(serviceQuotes) ? serviceQuotes : []);
576
576
 
577
577
  if (this.serviceQuotes.length && this.isUsingIntegratedVendor) {
@@ -588,27 +588,31 @@ export default class OperationsOrdersIndexNewController extends BaseController {
588
588
 
589
589
  _getSerializedPayload(payload) {
590
590
  const serialized = {
591
- pickup: payload.pickup,
592
- dropoff: payload.dropoff,
591
+ pickup: this._seriailizeModel(payload.pickup),
592
+ dropoff: this._seriailizeModel(payload.dropoff),
593
+ entitities: this._serializeArray(payload.entities),
594
+ waypoints: this._serializeArray(payload.waypoint),
593
595
  };
594
596
 
595
- if (isModel(payload.pickup)) {
596
- serialized.pickup = payload.pickup.toJSON();
597
- }
597
+ return serialized;
598
+ }
598
599
 
599
- if (isModel(payload.dropoff)) {
600
- serialized.dropoff = payload.dropoff.toJSON();
601
- }
600
+ _seriailizeModel(model) {
601
+ if (isModel(model)) {
602
+ if (typeof model.toJSON === 'function') {
603
+ return model.toJSON();
604
+ }
602
605
 
603
- if (isArray(payload.entities)) {
604
- serialized.entities = payload.entities.toArray();
606
+ if (typeof model.serialize === 'function') {
607
+ return model.serialize();
608
+ }
605
609
  }
606
610
 
607
- if (isArray(payload.waypoints)) {
608
- serialized.waypoints = payload.waypoints.toArray();
609
- }
611
+ return model;
612
+ }
610
613
 
611
- return serialized;
614
+ _serializeArray(array) {
615
+ return isArray(array) ? array.map((item) => this._seriailizeModel(item)) : array;
612
616
  }
613
617
 
614
618
  @action scheduleOrder(dateInstance) {
@@ -1448,4 +1452,37 @@ export default class OperationsOrdersIndexNewController extends BaseController {
1448
1452
  }
1449
1453
  }
1450
1454
  }
1455
+
1456
+ @action queueFile(file) {
1457
+ // since we have dropzone and upload button within dropzone validate the file state first
1458
+ // as this method can be called twice from both functions
1459
+ if (['queued', 'failed', 'timed_out', 'aborted'].indexOf(file.state) === -1) {
1460
+ return;
1461
+ }
1462
+
1463
+ // Queue and upload immediatley
1464
+ this.uploadQueue.pushObject(file);
1465
+ this.fetch.uploadFile.perform(
1466
+ file,
1467
+ {
1468
+ path: 'uploads/fleet-ops/order-files',
1469
+ type: 'order_file',
1470
+ },
1471
+ (uploadedFile) => {
1472
+ this.order.files.pushObject(uploadedFile);
1473
+ this.uploadQueue.removeObject(file);
1474
+ },
1475
+ () => {
1476
+ this.uploadQueue.removeObject(file);
1477
+ // remove file from queue
1478
+ if (file.queue && typeof file.queue.remove === 'function') {
1479
+ file.queue.remove(file);
1480
+ }
1481
+ }
1482
+ );
1483
+ }
1484
+
1485
+ @action removeFile(file) {
1486
+ return file.destroyRecord();
1487
+ }
1451
1488
  }