@fleetbase/fleetops-engine 0.4.16 → 0.4.17

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 (218) hide show
  1. package/.php-cs-fixer.php +2 -0
  2. package/addon/components/activity-event-selector.hbs +35 -0
  3. package/addon/components/activity-event-selector.js +85 -0
  4. package/addon/components/activity-form-panel.hbs +23 -0
  5. package/addon/components/activity-form-panel.js +90 -0
  6. package/addon/components/activity-logic-builder.hbs +80 -0
  7. package/addon/components/activity-logic-builder.js +260 -0
  8. package/addon/components/contact-form-panel.hbs +1 -1
  9. package/addon/components/contact-panel.hbs +1 -1
  10. package/addon/components/custom-entity-form-panel.hbs +43 -0
  11. package/addon/components/custom-entity-form-panel.js +129 -0
  12. package/addon/components/custom-field-form-panel/options-input.hbs +12 -0
  13. package/addon/components/custom-field-form-panel/options-input.js +139 -0
  14. package/addon/components/custom-field-form-panel.hbs +77 -0
  15. package/addon/components/custom-field-form-panel.js +144 -0
  16. package/addon/components/custom-field.hbs +63 -41
  17. package/addon/components/custom-field.js +123 -25
  18. package/addon/components/driver-form-panel.hbs +1 -1
  19. package/addon/components/driver-panel.hbs +1 -1
  20. package/addon/components/edit-order-route-panel.hbs +1 -1
  21. package/addon/components/fleet-form-panel.hbs +1 -1
  22. package/addon/components/fleet-panel.hbs +1 -1
  23. package/addon/components/fuel-report-form-panel.hbs +1 -1
  24. package/addon/components/fuel-report-panel.hbs +1 -1
  25. package/addon/components/issue-form-panel.hbs +1 -1
  26. package/addon/components/issue-panel.hbs +1 -1
  27. package/addon/components/joint-graph.hbs +1 -0
  28. package/addon/components/joint-graph.js +103 -0
  29. package/addon/components/layout/fleet-ops-sidebar.hbs +3 -3
  30. package/addon/components/layout/fleet-ops-sidebar.js +1 -0
  31. package/addon/components/live-map.js +71 -28
  32. package/addon/components/modals/new-custom-field-group.hbs +5 -0
  33. package/addon/components/modals/new-order-config.hbs +3 -3
  34. package/addon/components/modals/order-new-activity.hbs +1 -1
  35. package/addon/components/order-config-manager/activity-flow.hbs +11 -0
  36. package/addon/components/order-config-manager/activity-flow.js +964 -0
  37. package/addon/components/order-config-manager/custom-fields.hbs +50 -0
  38. package/addon/components/order-config-manager/custom-fields.js +276 -0
  39. package/addon/components/order-config-manager/details.hbs +23 -0
  40. package/addon/components/order-config-manager/details.js +97 -0
  41. package/addon/components/order-config-manager/entities.hbs +54 -0
  42. package/addon/components/order-config-manager/entities.js +227 -0
  43. package/addon/components/order-config-manager-overlay.hbs +26 -0
  44. package/addon/components/order-config-manager-overlay.js +60 -0
  45. package/addon/components/order-config-manager.hbs +15 -0
  46. package/addon/components/order-config-manager.js +285 -0
  47. package/addon/components/order-flow.hbs +1 -0
  48. package/addon/components/order-flow.js +3 -0
  49. package/addon/components/place-form-panel.hbs +1 -1
  50. package/addon/components/place-panel.hbs +1 -1
  51. package/addon/components/vehicle-form-panel.hbs +1 -1
  52. package/addon/components/vehicle-panel.hbs +1 -1
  53. package/addon/components/vendor-form-panel.hbs +1 -1
  54. package/addon/components/vendor-panel.hbs +1 -1
  55. package/addon/controllers/application.js +5 -1
  56. package/addon/controllers/operations/order-config.js +42 -0
  57. package/addon/controllers/operations/orders/index/new.js +125 -21
  58. package/addon/controllers/operations/orders/index/view.js +87 -4
  59. package/addon/controllers/operations/orders/index.js +2 -2
  60. package/addon/engine.js +10 -1
  61. package/addon/initializers/load-jointjs.js +16 -0
  62. package/addon/routes/application.js +1 -1
  63. package/addon/routes/operations/order-config.js +28 -0
  64. package/addon/routes/operations/orders/index/new.js +2 -3
  65. package/addon/routes/operations/orders/index/view.js +1 -1
  66. package/addon/routes.js +1 -0
  67. package/addon/services/context-panel.js +65 -3
  68. package/addon/styles/fleetops-engine.css +268 -0
  69. package/addon/templates/application.hbs +1 -1
  70. package/addon/templates/operations/order-config.hbs +55 -0
  71. package/addon/templates/operations/orders/index/new.hbs +98 -339
  72. package/addon/templates/operations/orders/index/view.hbs +36 -96
  73. package/addon/templates/operations/orders/index.hbs +0 -1
  74. package/addon/utils/apply-context-component-arguments.js +4 -2
  75. package/addon/utils/create-custom-entity.js +22 -0
  76. package/addon/utils/create-flow-activity.js +31 -0
  77. package/addon/utils/get-custom-field-type-map.js +34 -0
  78. package/app/components/activity-event-selector.js +1 -0
  79. package/app/components/activity-form-panel.js +1 -0
  80. package/app/components/activity-logic-builder.js +1 -0
  81. package/app/components/custom-entity-form-panel.js +1 -0
  82. package/app/components/custom-field-form-panel/options-input.js +1 -0
  83. package/app/components/custom-field-form-panel.js +1 -0
  84. package/app/components/joint-graph.js +1 -0
  85. package/app/components/modals/new-custom-field-group.js +1 -0
  86. package/app/components/order-config-manager/activity-flow.js +1 -0
  87. package/app/components/order-config-manager/custom-fields.js +1 -0
  88. package/app/components/order-config-manager/details.js +1 -0
  89. package/app/components/order-config-manager/entities.js +1 -0
  90. package/app/components/order-config-manager-overlay.js +1 -0
  91. package/app/components/order-config-manager.js +1 -0
  92. package/app/components/order-flow.js +1 -0
  93. package/app/controllers/operations/order-config.js +1 -0
  94. package/app/routes/operations/order-config.js +1 -0
  95. package/app/templates/operations/order-config.js +1 -0
  96. package/app/utils/create-custom-entity.js +1 -0
  97. package/app/utils/create-flow-activity.js +1 -0
  98. package/app/utils/get-custom-field-type-map.js +1 -0
  99. package/composer.json +4 -3
  100. package/config/environment.js +1 -0
  101. package/extension.json +1 -1
  102. package/index.js +20 -0
  103. package/package.json +7 -5
  104. package/server/migrations/2023_04_27_053456_create_contacts_table.php +1 -2
  105. package/server/migrations/2023_04_27_053456_create_drivers_table.php +1 -2
  106. package/server/migrations/2023_04_27_053456_create_entities_table.php +1 -2
  107. package/server/migrations/2023_04_27_053456_create_fleet_drivers_table.php +1 -2
  108. package/server/migrations/2023_04_27_053456_create_fleets_table.php +1 -2
  109. package/server/migrations/2023_04_27_053456_create_fuel_reports_table.php +1 -2
  110. package/server/migrations/2023_04_27_053456_create_integrated_vendors_table.php +1 -2
  111. package/server/migrations/2023_04_27_053456_create_issues_table.php +1 -2
  112. package/server/migrations/2023_04_27_053456_create_orders_table.php +1 -2
  113. package/server/migrations/2023_04_27_053456_create_payloads_table.php +1 -2
  114. package/server/migrations/2023_04_27_053456_create_places_table.php +1 -2
  115. package/server/migrations/2023_04_27_053456_create_positions_table.php +1 -2
  116. package/server/migrations/2023_04_27_053456_create_proofs_table.php +1 -2
  117. package/server/migrations/2023_04_27_053456_create_purchase_rates_table.php +1 -2
  118. package/server/migrations/2023_04_27_053456_create_routes_table.php +1 -2
  119. package/server/migrations/2023_04_27_053456_create_service_areas_table.php +1 -2
  120. package/server/migrations/2023_04_27_053456_create_service_quote_items_table.php +1 -2
  121. package/server/migrations/2023_04_27_053456_create_service_quotes_table.php +1 -2
  122. package/server/migrations/2023_04_27_053456_create_service_rate_fees_table.php +1 -2
  123. package/server/migrations/2023_04_27_053456_create_service_rate_parcel_fees_table.php +1 -2
  124. package/server/migrations/2023_04_27_053456_create_service_rates_table.php +1 -2
  125. package/server/migrations/2023_04_27_053456_create_tracking_numbers_table.php +1 -2
  126. package/server/migrations/2023_04_27_053456_create_tracking_statuses_table.php +1 -2
  127. package/server/migrations/2023_04_27_053456_create_vehicles_table.php +1 -2
  128. package/server/migrations/2023_04_27_053456_create_vendors_table.php +1 -2
  129. package/server/migrations/2023_04_27_053456_create_waypoints_table.php +1 -2
  130. package/server/migrations/2023_04_27_053456_create_zones_table.php +1 -2
  131. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_companies_table.php +1 -2
  132. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_contacts_table.php +1 -2
  133. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_drivers_table.php +1 -2
  134. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_entities_table.php +1 -2
  135. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_fleet_drivers_table.php +1 -2
  136. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_fleets_table.php +1 -2
  137. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_fuel_reports_table.php +1 -2
  138. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_integrated_vendors_table.php +1 -2
  139. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_issues_table.php +1 -2
  140. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_orders_table.php +1 -2
  141. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_payloads_table.php +1 -2
  142. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_places_table.php +1 -2
  143. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_positions_table.php +1 -2
  144. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_proofs_table.php +1 -2
  145. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_purchase_rates_table.php +1 -2
  146. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_routes_table.php +1 -2
  147. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_areas_table.php +1 -2
  148. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_quote_items_table.php +1 -2
  149. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_quotes_table.php +1 -2
  150. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_rate_fees_table.php +1 -2
  151. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_rate_parcel_fees_table.php +1 -2
  152. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_rates_table.php +1 -2
  153. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_tracking_numbers_table.php +1 -2
  154. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_tracking_statuses_table.php +1 -2
  155. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_vehicles_table.php +1 -2
  156. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_vendors_table.php +1 -2
  157. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_waypoints_table.php +1 -2
  158. package/server/migrations/2023_04_27_053459_add_foreign_keys_to_zones_table.php +1 -2
  159. package/server/migrations/2023_09_14_074512_update_vehicles_table.php +1 -2
  160. package/server/migrations/2023_09_14_074619_create_vehicle_devices_table.php +35 -36
  161. package/server/migrations/2023_09_26_071205_add_online_column_to_vehicles_table.php +1 -2
  162. package/server/migrations/2023_09_26_083957_create_fleet_vehicles_table.php +1 -2
  163. package/server/migrations/2023_09_27_023757_add_column_to_fleets_table.php +1 -2
  164. package/server/migrations/2023_10_05_074811_update_vehicle.php +1 -2
  165. package/server/migrations/2023_10_25_093014_create_vehicle_device_events_table.php +1 -2
  166. package/server/migrations/2023_11_03_072503_refactor_issues_table_columns.php +1 -2
  167. package/server/migrations/2023_11_06_040645_refactor_fuel_reports_table.php +1 -2
  168. package/server/migrations/2023_11_09_041807_add_status_column_to_fuel_reports_table.php +1 -2
  169. package/server/migrations/2023_11_15_062814_add_comments_column_and_resolved_at_column_to_vehicle_device_events_table.php +1 -2
  170. package/server/migrations/2023_11_17_053001_add_category_uuid_to_entities_table.php +1 -2
  171. package/server/migrations/2023_11_28_074244_add_supplier_uuid_column_to_entities_table.php +1 -2
  172. package/server/migrations/2023_12_14_100209_add_meta_column_on_driver_table copy.php +1 -2
  173. package/server/migrations/2024_02_18_100209_add_avatar_url_columns_table.php +3 -4
  174. package/server/migrations/2024_02_27_093648_create_order_configs_table.php +43 -0
  175. package/server/migrations/2024_03_07_075508_add_order_config_uuid_column_to_orders_table.php +28 -0
  176. package/server/seeders/OrderConfigSeeder.php +151 -0
  177. package/server/src/Casts/OrderConfigEntities.php +53 -0
  178. package/server/src/Console/Commands/FixLegacyOrderConfigs.php +66 -0
  179. package/server/src/Events/DriverLocationChanged.php +1 -1
  180. package/server/src/Events/DriverSimulatedLocationChanged.php +1 -1
  181. package/server/src/Flow/Activity.php +232 -6
  182. package/server/src/Flow/Condition.php +84 -0
  183. package/server/src/Flow/Event.php +88 -0
  184. package/server/src/Flow/Flow.php +50 -0
  185. package/server/src/Flow/FlowResource.php +143 -0
  186. package/server/src/Flow/Logic.php +57 -1
  187. package/server/src/Http/Controllers/Api/v1/DriverController.php +2 -2
  188. package/server/src/Http/Controllers/Api/v1/IssueController.php +132 -0
  189. package/server/src/Http/Controllers/Api/v1/OrderController.php +130 -57
  190. package/server/src/Http/Controllers/Api/v1/OrganizationController.php +27 -0
  191. package/server/src/Http/Controllers/Api/v1/PlaceController.php +2 -3
  192. package/server/src/Http/Controllers/Controller.php +9 -0
  193. package/server/src/Http/Controllers/FleetOpsController.php +7 -0
  194. package/server/src/Http/Controllers/Internal/v1/OrderConfigController.php +5 -259
  195. package/server/src/Http/Controllers/Internal/v1/OrderController.php +46 -26
  196. package/server/src/Http/Controllers/Internal/v1/SettingController.php +20 -0
  197. package/server/src/Http/Filter/OrderConfigFilter.php +13 -0
  198. package/server/src/Http/Requests/CreateIssueRequest.php +19 -0
  199. package/server/src/Http/Requests/UpdateIssueRequest.php +7 -0
  200. package/server/src/Http/Resources/v1/Order.php +3 -0
  201. package/server/src/Listeners/HandleOrderCanceled.php +8 -4
  202. package/server/src/Listeners/HandleOrderDispatched.php +14 -12
  203. package/server/src/Models/Order.php +527 -31
  204. package/server/src/Models/OrderConfig.php +419 -0
  205. package/server/src/Models/Payload.php +6 -7
  206. package/server/src/Notifications/OrderAssigned.php +1 -1
  207. package/server/src/Notifications/OrderCanceled.php +1 -1
  208. package/server/src/Notifications/OrderDispatchFailed.php +1 -1
  209. package/server/src/Notifications/OrderDispatched.php +1 -1
  210. package/server/src/Notifications/OrderPing.php +1 -1
  211. package/server/src/Providers/FleetOpsServiceProvider.php +3 -1
  212. package/server/src/Providers/NotificationServiceProvider.php +2 -1
  213. package/server/src/Support/Utils.php +17 -0
  214. package/server/src/Traits/HasTrackingNumber.php +9 -9
  215. package/server/src/routes.php +19 -11
  216. package/translations/en-us.yaml +137 -0
  217. package/server/src/Flow/Config.php +0 -7
  218. package/server/src/Support/Flow.php +0 -653
@@ -5,7 +5,7 @@ import { computed, action } from '@ember/object';
5
5
 
6
6
  export default class ApplicationController extends BaseController {
7
7
  @service hostRouter;
8
-
8
+ @service contextPanel;
9
9
  @tracked routes = ['console.fleet-ops.operations', 'console.fleet-ops.management', 'console.fleet-ops.comms'];
10
10
  @tracked settingsContext;
11
11
 
@@ -21,6 +21,10 @@ export default class ApplicationController extends BaseController {
21
21
  this.settingsContext?.close();
22
22
  }
23
23
 
24
+ @action openOrderConfigManager() {
25
+ this.contextPanel.focus('orderConfigManager');
26
+ }
27
+
24
28
  @action isRouteActive(route) {
25
29
  const currentRouteName = this.hostRouter.currentRouteName;
26
30
  const contains = (haystack, needle) => haystack.includes(needle);
@@ -0,0 +1,42 @@
1
+ import Controller from '@ember/controller';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { action } from '@ember/object';
4
+
5
+ export default class OperationsOrderConfigController extends Controller {
6
+ @tracked tab = 'details';
7
+ @tracked config;
8
+ @tracked context;
9
+ @tracked contextModel;
10
+ queryParams = ['tab', 'config', 'context', 'contextModel'];
11
+
12
+ /**
13
+ * Handle tab change.
14
+ *
15
+ * @param {string} tab
16
+ * @memberof OperationsOrderConfigController
17
+ */
18
+ @action onTabChanged(tab) {
19
+ this.tab = tab;
20
+ }
21
+
22
+ /**
23
+ * Handle order config change.
24
+ *
25
+ * @param {*} config
26
+ * @memberof OperationsOrderConfigController
27
+ */
28
+ @action onConfigChanged(config) {
29
+ this.config = config.id;
30
+ }
31
+
32
+ /**
33
+ * Handle order config change.
34
+ *
35
+ * @param {*} config
36
+ * @memberof OperationsOrderConfigController
37
+ */
38
+ @action onContextChanged(context, contextModel) {
39
+ this.context = context;
40
+ this.contextModel = contextModel;
41
+ }
42
+ }
@@ -5,14 +5,15 @@ import { tracked } from '@glimmer/tracking';
5
5
  import { action, computed, setProperties, set, get } from '@ember/object';
6
6
  import { not, equal, alias } from '@ember/object/computed';
7
7
  import { isArray } from '@ember/array';
8
+ import { isBlank } from '@ember/utils';
8
9
  import { dasherize } from '@ember/string';
9
10
  import { later, next } from '@ember/runloop';
11
+ import { task } from 'ember-concurrency-decorators';
10
12
  import { OSRMv1, Control as RoutingControl } from '@fleetbase/leaflet-routing-machine';
11
13
  import polyline from '@fleetbase/ember-core/utils/polyline';
12
14
  import findClosestWaypoint from '@fleetbase/ember-core/utils/find-closest-waypoint';
13
15
  import isNotEmpty from '@fleetbase/ember-core/utils/is-not-empty';
14
16
  import getRoutingHost from '@fleetbase/ember-core/utils/get-routing-host';
15
- import groupBy from '@fleetbase/ember-core/utils/macros/group-by';
16
17
  import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
17
18
  import isModel from '@fleetbase/ember-core/utils/is-model';
18
19
 
@@ -125,10 +126,15 @@ export default class OperationsOrdersIndexNewController extends BaseController {
125
126
  @tracked entities = [];
126
127
  @tracked waypoints = [];
127
128
  @tracked payloadCoordinates = [];
128
- @tracked types = [];
129
+ @tracked orderConfig;
130
+ @tracked orderConfigs = [];
131
+ @tracked customFieldGroups = [];
132
+ @tracked customFields = [];
133
+ @tracked customFieldValues = {};
129
134
  @tracked serviceRates = [];
130
135
  @tracked selectedServiceRate;
131
136
  @tracked selectedServiceQuote;
137
+ @tracked isCustomFieldsValid = true;
132
138
  @tracked isCreatingOrder = false;
133
139
  @tracked isMultipleDropoffOrder = false;
134
140
  @tracked isViewingRoutePreview = false;
@@ -145,7 +151,7 @@ export default class OperationsOrdersIndexNewController extends BaseController {
145
151
  @tracked leafletLayers = [];
146
152
  @tracked routeProfile = 'driving';
147
153
  @tracked routeProfileOptions = ['driving', 'bycicle', 'walking'];
148
- @tracked podOptions = ['scan', 'signature'];
154
+ @tracked podOptions = ['scan', 'signature', 'photo'];
149
155
  @tracked isCsvImportedOrder = false;
150
156
  @tracked routePreviewArray = [];
151
157
  @tracked previewRouteControl;
@@ -184,14 +190,18 @@ export default class OperationsOrdersIndexNewController extends BaseController {
184
190
  'application/x-tar',
185
191
  ];
186
192
 
193
+ get renderableComponents() {
194
+ const renderableComponents = this.universe.getRenderableComponentsFromRegistry('fleet-ops:template:operations:orders:new');
195
+ return renderableComponents;
196
+ }
197
+
187
198
  @not('isServicable') isNotServicable;
188
199
  @alias('currentUser.latitude') userLatitude;
189
200
  @alias('currentUser.longitude') userLongitude;
190
201
  @alias('ordersController.leafletMap') leafletMap;
191
202
  @equal('isCsvImportedOrder', false) isNotCsvImportedOrder;
192
- @groupBy('typeConfig.meta.fields', 'group') groupedMetaFields;
193
203
 
194
- @computed('entities.length', 'isMultipleDropoffOrder', 'isFetchingQuotes', 'isSubscriptionValid', 'order.type', 'payload.{dropoff,pickup}', 'waypoints.length')
204
+ @computed('isCustomFieldsValid', 'entities.length', 'isMultipleDropoffOrder', 'isFetchingQuotes', 'isSubscriptionValid', 'order.type', 'payload.{dropoff,pickup}', 'waypoints.length')
195
205
  get isValid() {
196
206
  const { isMultipleDropoffOrder, isSubscriptionValid, isFetchingQuotes } = this;
197
207
  const isOrderTypeSet = isNotEmpty(this.order?.type);
@@ -212,7 +222,7 @@ export default class OperationsOrdersIndexNewController extends BaseController {
212
222
  return isOrderTypeSet && isWaypointsSet;
213
223
  }
214
224
 
215
- return isOrderTypeSet && isPickupSet && isDropoffSet;
225
+ return isOrderTypeSet && isPickupSet && isDropoffSet && this.isCustomFieldsValid;
216
226
  }
217
227
 
218
228
  updatePayloadCoordinates() {
@@ -246,14 +256,6 @@ export default class OperationsOrdersIndexNewController extends BaseController {
246
256
  );
247
257
  }
248
258
 
249
- @computed('order.type', 'types') get typeConfig() {
250
- return this.types.find((type) => type.key === this.order.type);
251
- }
252
-
253
- @computed('order.type', 'types') get typeConfigIndex() {
254
- return this.types.findIndex((type) => type.key === this.order.type);
255
- }
256
-
257
259
  @computed('entities.[]', 'waypoints.[]') get entitiesByImportId() {
258
260
  const groups = [];
259
261
 
@@ -276,6 +278,16 @@ export default class OperationsOrdersIndexNewController extends BaseController {
276
278
  return groups;
277
279
  }
278
280
 
281
+ checkIfCustomFieldsValid() {
282
+ this.isCustomFieldsValid = this.customFields.every((customField) => {
283
+ if (!customField.required) {
284
+ return true;
285
+ }
286
+ const customFieldValue = this.customFieldValues[customField.id];
287
+ return customFieldValue && !isBlank(customFieldValue.value);
288
+ });
289
+ }
290
+
279
291
  @action createOrder() {
280
292
  if (!this.isValid) {
281
293
  return;
@@ -307,6 +319,29 @@ export default class OperationsOrdersIndexNewController extends BaseController {
307
319
  return;
308
320
  }
309
321
 
322
+ // valiadate custom field inputs
323
+ for (let i = 0; i < this.customFields.length; i++) {
324
+ const customField = this.customFields[i];
325
+ if (customField.required) {
326
+ const customFieldValue = this.customFieldValues[customField.id];
327
+ if (!customFieldValue || isBlank(customFieldValue.value)) {
328
+ this.loader.removeLoader();
329
+ return this.notifications.error(this.intl.t('fleet-ops.operations.orders.index.new.input-field-required', { inputFieldName: customField.label }));
330
+ }
331
+ }
332
+ }
333
+
334
+ // create custom field values
335
+ for (let customFieldId in this.customFieldValues) {
336
+ const { value, value_type } = this.customFieldValues[customFieldId];
337
+ const customFieldValue = this.store.createRecord('custom-field-value', {
338
+ custom_field_uuid: customFieldId,
339
+ value,
340
+ value_type,
341
+ });
342
+ this.order.custom_field_values.push(customFieldValue);
343
+ }
344
+
310
345
  // send event that fleetops is `creating` an order
311
346
  this.universe.trigger('fleet-ops.order.creating', order);
312
347
  this.isCreatingOrder = true;
@@ -1033,7 +1068,8 @@ export default class OperationsOrdersIndexNewController extends BaseController {
1033
1068
  const meta = [];
1034
1069
  const entities = [];
1035
1070
  const waypoints = [];
1036
- const types = [];
1071
+ const orderConfigs = [];
1072
+ const orderConfig = undefined;
1037
1073
  const isCreatingOrder = false;
1038
1074
  const isMultipleDropoffOrder = false;
1039
1075
  const leafletRoute = undefined;
@@ -1051,7 +1087,8 @@ export default class OperationsOrdersIndexNewController extends BaseController {
1051
1087
  meta,
1052
1088
  entities,
1053
1089
  waypoints,
1054
- types,
1090
+ orderConfigs,
1091
+ orderConfig,
1055
1092
  isCreatingOrder,
1056
1093
  isMultipleDropoffOrder,
1057
1094
  leafletRoute,
@@ -1063,14 +1100,72 @@ export default class OperationsOrdersIndexNewController extends BaseController {
1063
1100
  this.resetInterface();
1064
1101
  }
1065
1102
 
1066
- @action setConfig(type) {
1067
- if (!type) {
1103
+ @action setConfig(event) {
1104
+ const orderConfigId = event.target.value;
1105
+ if (!orderConfigId) {
1068
1106
  return;
1069
1107
  }
1070
1108
 
1071
- set(this, 'order.type', type);
1072
- this.meta = [];
1073
- this.applyCustomMetaFields(type);
1109
+ const orderConfig = this.store.peekRecord('order-config', orderConfigId);
1110
+ this.orderConfig = orderConfig;
1111
+ this.order.set('order_config_uuid', orderConfig.id);
1112
+ this.order.set('type', orderConfig.key);
1113
+
1114
+ // load custom fields
1115
+ this.loadCustomFields.perform(orderConfig);
1116
+ }
1117
+
1118
+ /**
1119
+ * A task method to load custom fields from the store and group them.
1120
+ * @task
1121
+ */
1122
+ @task *loadCustomFields(orderConfig) {
1123
+ this.customFieldGroups = yield this.store.query('category', { owner_uuid: orderConfig.id, for: 'custom_field_group' });
1124
+ this.customFields = yield this.store.query('custom-field', { subject_uuid: orderConfig.id });
1125
+ this.groupCustomFields();
1126
+ this.checkIfCustomFieldsValid();
1127
+ }
1128
+
1129
+ /**
1130
+ * Organizes custom fields into their respective groups.
1131
+ */
1132
+ groupCustomFields() {
1133
+ for (let i = 0; i < this.customFieldGroups.length; i++) {
1134
+ const group = this.customFieldGroups[i];
1135
+ group.set(
1136
+ 'customFields',
1137
+ this.customFields.filter((customField) => {
1138
+ return customField.category_uuid === group.id;
1139
+ })
1140
+ );
1141
+ }
1142
+ }
1143
+
1144
+ @action setCustomFieldValue(value, customField) {
1145
+ this.customFieldValues = {
1146
+ ...this.customFieldValues,
1147
+ [customField.id]: {
1148
+ value,
1149
+ value_type: this._getCustomFieldValueType(customField),
1150
+ },
1151
+ };
1152
+ this.checkIfCustomFieldsValid();
1153
+ }
1154
+
1155
+ _getCustomFieldValueType(customField) {
1156
+ if (customField.type === 'file-upload') {
1157
+ return 'file';
1158
+ }
1159
+
1160
+ if (customField.type === 'date-time-input') {
1161
+ return 'date';
1162
+ }
1163
+
1164
+ if (customField.type === 'model-select') {
1165
+ return 'model';
1166
+ }
1167
+
1168
+ return 'text';
1074
1169
  }
1075
1170
 
1076
1171
  @action setOrderFacilitator(model) {
@@ -1302,6 +1397,15 @@ export default class OperationsOrdersIndexNewController extends BaseController {
1302
1397
  this.entities[index].destination_uuid = value;
1303
1398
  }
1304
1399
 
1400
+ @action addFromCustomEntity(customEntity) {
1401
+ const entity = this.store.createRecord('entity', {
1402
+ ...customEntity,
1403
+ id: undefined,
1404
+ });
1405
+
1406
+ this.entities.pushObject(entity);
1407
+ }
1408
+
1305
1409
  @action addEntity(importId = null) {
1306
1410
  const entity = this.store.createRecord('entity', {
1307
1411
  _import_id: importId,
@@ -7,7 +7,6 @@ import { later } from '@ember/runloop';
7
7
  import { not, notEmpty, alias } from '@ember/object/computed';
8
8
  import { task } from 'ember-concurrency-decorators';
9
9
  import { OSRMv1, Control as RoutingControl } from '@fleetbase/leaflet-routing-machine';
10
- import groupBy from '@fleetbase/ember-core/utils/macros/group-by';
11
10
  import getRoutingHost from '@fleetbase/ember-core/utils/get-routing-host';
12
11
 
13
12
  export default class OperationsOrdersIndexViewController extends BaseController {
@@ -111,9 +110,12 @@ export default class OperationsOrdersIndexViewController extends BaseController
111
110
 
112
111
  @tracked isLoadingAdditionalData = false;
113
112
  @tracked isWaypointsCollapsed;
113
+ @tracked isEditingOrderNotes = false;
114
114
  @tracked leafletRoute;
115
115
  @tracked routeControl;
116
116
  @tracked commentInput = '';
117
+ @tracked customFieldGroups = [];
118
+ @tracked customFields = [];
117
119
  @tracked uploadQueue = [];
118
120
  acceptedFileTypes = [
119
121
  'application/vnd.ms-excel',
@@ -166,10 +168,26 @@ export default class OperationsOrdersIndexViewController extends BaseController
166
168
  },
167
169
  ];
168
170
 
171
+ @tracked notesPanelButtons = [
172
+ {
173
+ type: 'default',
174
+ text: 'Edit',
175
+ icon: 'pencil',
176
+ iconPrefix: 'fas',
177
+ onClick: () => {
178
+ this.editOrderNotes();
179
+ },
180
+ },
181
+ ];
182
+
169
183
  @not('isWaypointsCollapsed') waypointsIsNotCollapsed;
170
184
  @notEmpty('model.payload.waypoints') isMultiDropOrder;
171
185
  @alias('ordersController.leafletMap') leafletMap;
172
- @groupBy('model.order_config.meta.fields', 'group') groupedMetaFields;
186
+
187
+ get renderableComponents() {
188
+ const renderableComponents = this.universe.getRenderableComponentsFromRegistry('fleet-ops:template:operations:orders:view');
189
+ return renderableComponents;
190
+ }
173
191
 
174
192
  /** @var entitiesByDestination */
175
193
  @computed('model.payload.{entities.[],waypoints.[]}')
@@ -220,14 +238,53 @@ export default class OperationsOrdersIndexViewController extends BaseController
220
238
  }
221
239
 
222
240
  @task *loadOrderRelations(order) {
241
+ yield order.loadOrderConfig();
223
242
  yield order.loadPayload();
224
243
  yield order.loadDriver();
225
244
  yield order.loadTrackingNumber();
226
245
  yield order.loadCustomer();
227
246
  yield order.loadTrackingActivity();
228
- yield order.loadOrderConfig();
229
247
  yield order.loadPurchaseRate();
230
248
  yield order.loadFiles();
249
+ this.loadCustomFields.perform(order);
250
+ }
251
+
252
+ /**
253
+ * A task method to load custom fields from the store and group them.
254
+ * @task
255
+ */
256
+ @task *loadCustomFields(order) {
257
+ const orderConfig = order.order_config;
258
+ if (orderConfig) {
259
+ this.customFieldGroups = yield this.store.query('category', { owner_uuid: orderConfig.id, for: 'custom_field_group' });
260
+ this.customFields = yield this.store.query('custom-field', { subject_uuid: orderConfig.id });
261
+ this.groupCustomFields(order);
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Organizes custom fields into their respective groups.
267
+ */
268
+ groupCustomFields(order) {
269
+ const customFields = Array.from(this.customFields);
270
+ const customFieldValues = Array.from(order.custom_field_values);
271
+ // map values to the custom fields
272
+ const customFieldsWithValues = customFields.map((customField) => {
273
+ customField.value = customFieldValues.find((customFieldValue) => customFieldValue.custom_field_uuid === customField.id);
274
+ return customField;
275
+ });
276
+ // update custom fields with values
277
+ this.customFields = customFieldsWithValues;
278
+ // group custom fields
279
+ for (let i = 0; i < this.customFieldGroups.length; i++) {
280
+ const group = this.customFieldGroups[i];
281
+ group.set(
282
+ 'customFields',
283
+ customFieldsWithValues.filter((customField) => {
284
+ return customField.category_uuid === group.id;
285
+ })
286
+ );
287
+ }
231
288
  }
232
289
 
233
290
  @action resetView() {
@@ -495,6 +552,25 @@ export default class OperationsOrdersIndexViewController extends BaseController
495
552
  });
496
553
  }
497
554
 
555
+ @action editOrderNotes() {
556
+ this.isEditingOrderNotes = true;
557
+ }
558
+
559
+ @task *saveOrderNotes() {
560
+ const { notes } = this.model;
561
+ yield this.model.persistProperty('notes', notes).then(() => {
562
+ this.notifications.success(this.intl.t('fleet-ops.operations.orders.index.view.order-notes-updated'));
563
+ });
564
+ this.isEditingOrderNotes = false;
565
+ }
566
+
567
+ /**
568
+ * Prompt to unassign driver from otder.
569
+ *
570
+ * @param {OrderModel} order
571
+ * @param {*} [options={}]
572
+ * @memberof OperationsOrdersIndexViewController
573
+ */
498
574
  @action unassignDriver(order, options = {}) {
499
575
  this.modalsManager.confirm({
500
576
  title: this.intl.t('fleet-ops.operations.orders.index.view.edit-order-title', { driverName: order.driver_assigned.name }),
@@ -593,7 +669,7 @@ export default class OperationsOrdersIndexViewController extends BaseController
593
669
  @action dispatchOrder(order) {
594
670
  this.ordersController.dispatchOrder(order, {
595
671
  onConfirm: () => {
596
- order.loadTrackingActivity();
672
+ this.loadOrderRelations.perform(order);
597
673
  },
598
674
  });
599
675
  }
@@ -916,4 +992,11 @@ export default class OperationsOrdersIndexViewController extends BaseController
916
992
  @action removeFile(file) {
917
993
  return file.destroyRecord();
918
994
  }
995
+
996
+ @action removeCustomFieldFile(customFieldValue, file) {
997
+ customFieldValue.set('value', null);
998
+ customFieldValue.save().then(() => {
999
+ return file.destroyRecord();
1000
+ });
1001
+ }
919
1002
  }
@@ -491,7 +491,7 @@ export default class OperationsOrdersIndexController extends BaseController {
491
491
  },
492
492
  {
493
493
  label: this.intl.t('fleet-ops.common.created-at'),
494
- valuePath: 'createdAt',
494
+ valuePath: 'createdAtShort',
495
495
  sortParam: 'created_at',
496
496
  filterParam: 'created_at',
497
497
  width: '140px',
@@ -502,7 +502,7 @@ export default class OperationsOrdersIndexController extends BaseController {
502
502
  },
503
503
  {
504
504
  label: this.intl.t('fleet-ops.common.updated-at'),
505
- valuePath: 'updatedAt',
505
+ valuePath: 'updatedAtShort',
506
506
  sortParam: 'updated_at',
507
507
  filterParam: 'updated_at',
508
508
  width: '125px',
package/addon/engine.js CHANGED
@@ -65,7 +65,16 @@ export default class FleetOpsEngine extends Engine {
65
65
  universe.registerDashboardWidgets([KeyMetricsWidgetDefinition]);
66
66
 
67
67
  // create all registries necessary
68
- universe.createRegistries(['engine:fleet-ops', 'component:vehicle-panel', 'component:driver-panel', 'contextmenu:vehicle', 'contextmenu:driver', 'view:order', 'view:create-order']);
68
+ universe.createRegistries([
69
+ 'engine:fleet-ops',
70
+ 'component:vehicle-panel',
71
+ 'component:driver-panel',
72
+ 'component:order-config-manager',
73
+ 'contextmenu:vehicle',
74
+ 'contextmenu:driver',
75
+ 'fleet-ops:template:operations:orders:view',
76
+ 'fleet-ops:template:operations:orders:new',
77
+ ]);
69
78
  };
70
79
  }
71
80
 
@@ -0,0 +1,16 @@
1
+ export function initialize() {
2
+ // Add jointjs script
3
+ const jointJsScript = document.createElement('script');
4
+ jointJsScript.src = '/engines-dist/joint.min.js';
5
+ document.body.appendChild(jointJsScript);
6
+
7
+ // Add jointjs directed graph lib
8
+ const jointJsDirectedGraphScript = document.createElement('script');
9
+ jointJsDirectedGraphScript.src = '/engines-dist/DirectedGraph.min.js';
10
+ document.body.appendChild(jointJsDirectedGraphScript);
11
+ }
12
+
13
+ export default {
14
+ initialize,
15
+ after: 'load-leaflet-assets',
16
+ };
@@ -17,7 +17,7 @@ export default class ApplicationRoute extends Route {
17
17
  }
18
18
 
19
19
  beforeModel() {
20
- return this.location.getUserLocation();
20
+ this.location.getUserLocation();
21
21
  }
22
22
 
23
23
  model() {
@@ -0,0 +1,28 @@
1
+ import Route from '@ember/routing/route';
2
+ import { inject as service } from '@ember/service';
3
+ import { action } from '@ember/object';
4
+
5
+ export default class OperationsOrderConfigRoute extends Route {
6
+ @service loader;
7
+
8
+ queryParams = {
9
+ config: {
10
+ refreshModel: true,
11
+ },
12
+ tab: {
13
+ refreshModel: false,
14
+ },
15
+ context: {
16
+ refreshModel: false,
17
+ },
18
+ contextModel: {
19
+ refreshModel: false,
20
+ },
21
+ };
22
+
23
+ @action loading(transition) {
24
+ this.loader.showOnInitialTransition(transition, 'section.next-view-section', {
25
+ loadingMessage: this.intl.t('fleet-ops.operations.order-config.route-loading-message'),
26
+ });
27
+ }
28
+ }
@@ -3,8 +3,7 @@ import { inject as service } from '@ember/service';
3
3
  import { action } from '@ember/object';
4
4
 
5
5
  export default class OperationsOrdersIndexNewRoute extends Route {
6
- @service currentUser;
7
- @service loader;
6
+ @service store;
8
7
 
9
8
  @action willTransition() {
10
9
  if (this.controller) {
@@ -13,6 +12,6 @@ export default class OperationsOrdersIndexNewRoute extends Route {
13
12
  }
14
13
 
15
14
  async setupController(controller) {
16
- controller.types = await this.currentUser.getInstalledOrderConfigs();
15
+ controller.orderConfigs = await this.store.findAll('order-config');
17
16
  }
18
17
  }
@@ -29,7 +29,7 @@ export default class OperationsOrdersIndexViewRoute extends Route {
29
29
  return this.store.queryRecord('order', {
30
30
  public_id,
31
31
  single: true,
32
- with: ['payload', 'driverAssigned', 'customer', 'facilitator', 'trackingStatuses', 'trackingNumber', 'purchaseRate', 'comments', 'files'],
32
+ with: ['payload', 'driverAssigned', 'orderConfig', 'customer', 'facilitator', 'trackingStatuses', 'trackingNumber', 'purchaseRate', 'comments', 'files'],
33
33
  });
34
34
  }
35
35
 
package/addon/routes.js CHANGED
@@ -5,6 +5,7 @@ export default buildRoutes(function () {
5
5
  this.route('operations', { path: '/' }, function () {
6
6
  this.route('dispatch');
7
7
  this.route('zones', function () {});
8
+ this.route('order-config', function () {});
8
9
  this.route('service-rates', function () {
9
10
  this.route('index', { path: '/' }, function () {
10
11
  this.route('new');