@fleetbase/fleetops-engine 0.6.28 → 0.6.30

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 (92) hide show
  1. package/addon/components/customer/create-order-form.hbs +1 -1
  2. package/addon/components/customer/order-form.hbs +34 -34
  3. package/addon/components/customer/orders.hbs +2 -2
  4. package/addon/components/display-place.hbs +1 -1
  5. package/addon/components/driver/pill.hbs +16 -17
  6. package/addon/components/driver/pill.js +5 -1
  7. package/addon/components/map/leaflet-live-map.js +35 -3
  8. package/addon/components/map/order-list-overlay/order.hbs +1 -0
  9. package/addon/components/map/order-list-overlay/order.js +42 -0
  10. package/addon/components/modals/bulk-assign-driver.hbs +2 -2
  11. package/addon/components/order/details/detail.hbs +6 -6
  12. package/addon/components/order/details/notes.js +1 -1
  13. package/addon/components/order/route-editor.hbs +3 -3
  14. package/addon/components/order-tracking-lookup.hbs +1 -1
  15. package/addon/components/service-rate/details.hbs +117 -75
  16. package/addon/components/service-rate/form.hbs +7 -4
  17. package/addon/components/service-rate/form.js +6 -0
  18. package/addon/components/vehicle/pill.hbs +32 -33
  19. package/addon/components/vehicle/pill.js +5 -1
  20. package/addon/controllers/operations/orders/index.js +1 -1
  21. package/addon/controllers/operations/scheduler/index.js +17 -2
  22. package/addon/controllers/operations/service-rates/index/edit.js +1 -7
  23. package/addon/controllers/operations/service-rates/index/new.js +0 -7
  24. package/addon/controllers/operations/service-rates/index.js +10 -2
  25. package/addon/routes/operations/orders/index/details.js +7 -0
  26. package/addon/routes/operations/scheduler/index.js +3 -3
  27. package/addon/services/driver-actions.js +20 -4
  28. package/addon/services/leaflet-routing-control.js +7 -1
  29. package/addon/services/order-list-overlay.js +0 -1
  30. package/addon/services/place-actions.js +20 -4
  31. package/addon/services/service-rate-actions.js +31 -0
  32. package/addon/services/vehicle-actions.js +20 -4
  33. package/addon/templates/operations/scheduler/index.hbs +2 -2
  34. package/addon/utils/create-full-calendar-event-from-order.js +6 -0
  35. package/composer.json +1 -1
  36. package/extension.json +1 -1
  37. package/index.js +0 -11
  38. package/package.json +4 -4
  39. package/server/migrations/2025_12_16_000001_add_subject_created_at_index_to_positions.php +40 -0
  40. package/server/migrations/2025_12_16_000003_add_performance_indexes_to_fleetops_core_tables.php +442 -0
  41. package/server/src/Console/Commands/DispatchAdhocOrders.php +7 -2
  42. package/server/src/Http/Controllers/Api/v1/DriverController.php +2 -0
  43. package/server/src/Http/Controllers/Api/v1/OrderController.php +30 -0
  44. package/server/src/Http/Controllers/Internal/v1/LiveController.php +184 -86
  45. package/server/src/Http/Controllers/Internal/v1/OrderController.php +14 -1
  46. package/server/src/Http/Controllers/Internal/v1/PlaceController.php +5 -0
  47. package/server/src/Http/Filter/DriverFilter.php +10 -0
  48. package/server/src/Http/Filter/OrderFilter.php +8 -1
  49. package/server/src/Http/Resources/v1/Contact.php +2 -2
  50. package/server/src/Http/Resources/v1/Entity.php +1 -1
  51. package/server/src/Http/Resources/v1/Index/Customer.php +33 -0
  52. package/server/src/Http/Resources/v1/Index/Driver.php +45 -0
  53. package/server/src/Http/Resources/v1/Index/Facilitator.php +33 -0
  54. package/server/src/Http/Resources/v1/Index/Order.php +127 -0
  55. package/server/src/Http/Resources/v1/Index/Payload.php +57 -0
  56. package/server/src/Http/Resources/v1/Index/Place.php +45 -0
  57. package/server/src/Http/Resources/v1/Index/TrackingNumber.php +25 -0
  58. package/server/src/Http/Resources/v1/Index/Vehicle.php +50 -0
  59. package/server/src/Http/Resources/v1/Order.php +41 -14
  60. package/server/src/Http/Resources/v1/Place.php +1 -1
  61. package/server/src/Http/Resources/v1/Position.php +2 -1
  62. package/server/src/Http/Resources/v1/ServiceRate.php +4 -4
  63. package/server/src/Http/Resources/v1/ServiceRateFee.php +12 -12
  64. package/server/src/Http/Resources/v1/ServiceRateParcelFee.php +14 -7
  65. package/server/src/Http/Resources/v1/TrackingNumber.php +1 -1
  66. package/server/src/Http/Resources/v1/Waypoint.php +1 -1
  67. package/server/src/Listeners/HandleOrderDispatched.php +5 -0
  68. package/server/src/Models/Contact.php +2 -0
  69. package/server/src/Models/Device.php +2 -0
  70. package/server/src/Models/DeviceEvent.php +2 -0
  71. package/server/src/Models/Driver.php +2 -0
  72. package/server/src/Models/FuelReport.php +2 -0
  73. package/server/src/Models/Issue.php +2 -0
  74. package/server/src/Models/Order.php +12 -5
  75. package/server/src/Models/Place.php +2 -0
  76. package/server/src/Models/Position.php +2 -0
  77. package/server/src/Models/ServiceArea.php +2 -0
  78. package/server/src/Models/ServiceRate.php +5 -1
  79. package/server/src/Models/ServiceRateFee.php +3 -17
  80. package/server/src/Models/ServiceRateParcelFee.php +1 -12
  81. package/server/src/Models/Vehicle.php +2 -0
  82. package/server/src/Models/Vendor.php +2 -0
  83. package/server/src/Models/Zone.php +2 -0
  84. package/server/src/Observers/DriverObserver.php +23 -0
  85. package/server/src/Observers/OrderObserver.php +31 -0
  86. package/server/src/Observers/PlaceObserver.php +31 -0
  87. package/server/src/Observers/ServiceRateObserver.php +0 -18
  88. package/server/src/Observers/VehicleObserver.php +7 -0
  89. package/server/src/Support/LiveCacheService.php +165 -0
  90. package/server/src/Support/OSRM.php +49 -22
  91. package/server/src/Support/OrderTracker.php +100 -28
  92. package/translations/en-us.yaml +3 -1
@@ -47,8 +47,8 @@
47
47
  </ContentPanel>
48
48
 
49
49
  {{#if @resource.isFixedRate}}
50
- <ContentPanel @title={{t "service-rate.fields.fixed-meter"}} @open={{true}} @wrapperClass="bordered-top">
51
- <div class="mb-3">
50
+ <ContentPanel @title={{t "service-rate.fields.fixed-meter"}} @open={{true}} @wrapperClass="bordered-top" @panelBodyWrapperClass="p-0i">
51
+ <div class="mb-3 px-3">
52
52
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-2">
53
53
  <div class="field-info-container">
54
54
  <div class="field-name">{{t "service-rate.fields.maximum-distance"}}</div>
@@ -70,31 +70,33 @@
70
70
  </div>
71
71
 
72
72
  <div class="overflow-x-auto">
73
- <table class="table table-fixed w-full">
74
- <thead>
75
- <tr>
76
- <th>{{t "service-rate.fields.distance"}}</th>
77
- <th>{{t "service-rate.fields.fee"}}</th>
78
- </tr>
79
- </thead>
80
- <tbody>
81
- {{#each @resource.rateFees as |rateFee|}}
73
+ <div class="next-table-wrapper h-auto table-fluid rounded-none overflow-x-auto">
74
+ <table class="table table-fixed w-full">
75
+ <thead>
82
76
  <tr>
83
- <td>{{rateFee.distance}}-{{add rateFee.distance 1}} {{@resource.max_distance_unit}}</td>
84
- <td>{{format-currency rateFee.fee @resource.currency}}</td>
77
+ <th>{{t "service-rate.fields.distance"}}</th>
78
+ <th>{{t "service-rate.fields.fee"}}</th>
85
79
  </tr>
86
- {{else}}
87
- <tr>
88
- <td colspan="2" class="text-center text-gray-500">No rate fees defined</td>
89
- </tr>
90
- {{/each}}
91
- </tbody>
92
- </table>
80
+ </thead>
81
+ <tbody>
82
+ {{#each @resource.rateFees as |rateFee|}}
83
+ <tr>
84
+ <td>{{rateFee.distance}}-{{add rateFee.distance 1}} {{@resource.max_distance_unit}}</td>
85
+ <td>{{format-currency rateFee.fee @resource.currency}}</td>
86
+ </tr>
87
+ {{else}}
88
+ <tr>
89
+ <td colspan="2" class="text-center text-gray-500 italic">No rate fees defined</td>
90
+ </tr>
91
+ {{/each}}
92
+ </tbody>
93
+ </table>
94
+ </div>
93
95
  </div>
94
96
  </ContentPanel>
95
97
  {{else if @resource.isPerDrop}}
96
- <ContentPanel @title={{t "service-rate.fields.per-drop-off-title"}} @open={{true}} @wrapperClass="bordered-top">
97
- <div class="overflow-x-auto">
98
+ <ContentPanel @title={{t "service-rate.fields.per-drop-off-title"}} @open={{true}} @wrapperClass="bordered-top" @panelBodyWrapperClass="p-0i">
99
+ <div class="next-table-wrapper h-auto table-fluid rounded-none overflow-x-auto">
98
100
  <table class="table table-fixed w-full">
99
101
  <thead>
100
102
  <tr>
@@ -104,7 +106,7 @@
104
106
  </tr>
105
107
  </thead>
106
108
  <tbody>
107
- {{#each @resource.perDropFees as |rateFee|}}
109
+ {{#each @resource.rate_fees as |rateFee|}}
108
110
  <tr>
109
111
  <td>{{n-a rateFee.min}}</td>
110
112
  <td>{{n-a rateFee.max}}</td>
@@ -112,7 +114,7 @@
112
114
  </tr>
113
115
  {{else}}
114
116
  <tr>
115
- <td colspan="3" class="text-center text-gray-500">No per drop fees defined</td>
117
+ <td colspan="3" class="text-center text-gray-500 italic">No per drop fees defined</td>
116
118
  </tr>
117
119
  {{/each}}
118
120
  </tbody>
@@ -162,59 +164,99 @@
162
164
  </ContentPanel>
163
165
  {{/if}}
164
166
 
165
- <ContentPanel @title={{t "service-rate.fields.percel-fee-title"}} @open={{true}} @wrapperClass="bordered-top">
166
- <div class="grid grid-cols-1 lg:grid-cols-2 gap-2">
167
- {{#if @resource.hasParcelFees}}
168
- <div class="field-info-container">
169
- <div class="field-name">{{t "service-rate.fields.cod-fee-label"}}</div>
170
- <div class="field-value">
171
- {{#if @resource.cod_calculation_method}}
172
- {{#let (find-by "value" @resource.cod_calculation_method (get-fleet-ops-options "serviceRateCodCalculationMethods")) as |method|}}
173
- {{#if method}}
174
- {{method.label}}:
175
- {{#if @resource.hasCodFlatFee}}
176
- {{format-currency @resource.cod_flat_fee @resource.currency}}
177
- {{else if @resource.hasCodPercentageFee}}
178
- {{@resource.cod_percent}}%
179
- {{/if}}
180
- {{else}}
181
- {{n-a @resource.cod_calculation_method}}
182
- {{/if}}
183
- {{/let}}
184
- {{else}}
185
- N/A
186
- {{/if}}
187
- </div>
188
- </div>
167
+ {{#if @resource.isParcelService}}
168
+ <ContentPanel @title={{t "service-rate.fields.percel-fee-title"}} @open={{true}} @wrapperClass="bordered-top">
169
+ <div class="space-y-2">
170
+ {{#each @resource.parcel_fees as |parcelFee|}}
171
+ <div class="dark:text-gray-100">
172
+ <div class="grid grid-cols-7">
173
+ <div class="flex flex-col items-start justify-start pt-3">
174
+ <img src="/engines-dist/images/boxes/{{parcelFee.size}}.png" alt="parcel size {{parcelFee.size}}" width="44" class="w-11" />
175
+ <div class="mt-2 text-sm font-medium">
176
+ {{humanize parcelFee.size}}
177
+ </div>
178
+ </div>
189
179
 
190
- <div class="field-info-container">
191
- <div class="field-name">{{t "service-rate.fields.peak-hours-fee-label"}}</div>
192
- <div class="field-value">
193
- {{#if @resource.peak_hours_calculation_method}}
194
- {{#let (find-by "value" @resource.peak_hours_calculation_method (get-fleet-ops-options "serviceRatePeakHourCalculationMethods")) as |method|}}
195
- {{#if method}}
196
- {{method.label}}:
197
- {{#if @resource.hasPeakHoursFlatFee}}
198
- {{format-currency @resource.peak_hours_flat_fee @resource.currency}}
199
- {{else if @resource.hasPeakHoursPercentageFee}}
200
- {{@resource.peak_hours_percent}}%
201
- {{/if}}
202
- {{else}}
203
- {{n-a @resource.peak_hours_calculation_method}}
204
- {{/if}}
205
- {{/let}}
206
- {{else}}
207
- N/A
208
- {{/if}}
180
+ <div class="col-span-6 dimensions-box space-x-2">
181
+ <div class="grid grid-cols-4 gap-2 px-2">
182
+ <div class="field-info-container">
183
+ <div class="field-name">
184
+ {{t "service-rate.fields.length-label"}}
185
+ </div>
186
+ <div class="field-value">
187
+ {{n-a parcelFee.length}}
188
+ {{parcelFee.dimensions_unit}}
189
+ </div>
190
+ </div>
191
+
192
+ <div class="field-info-container">
193
+ <div class="field-name">
194
+ {{t "service-rate.fields.width-label"}}
195
+ </div>
196
+ <div class="field-value">
197
+ {{n-a parcelFee.width}}
198
+ {{parcelFee.dimensions_unit}}
199
+ </div>
200
+ </div>
201
+
202
+ <div class="field-info-container">
203
+ <div class="field-name">
204
+ {{t "service-rate.fields.height-label"}}
205
+ </div>
206
+ <div class="field-value">
207
+ {{n-a parcelFee.height}}
208
+ {{parcelFee.dimensions_unit}}
209
+ </div>
210
+ </div>
211
+
212
+ <div class="field-info-container">
213
+ <div class="field-name">
214
+ {{t "service-rate.fields.weight-label"}}
215
+ </div>
216
+ <div class="field-value">
217
+ {{n-a parcelFee.weight}}
218
+ {{parcelFee.weight_unit}}
219
+ </div>
220
+ </div>
221
+
222
+ <div class="field-info-container">
223
+ <div class="field-name">
224
+ {{t "service-rate.fields.deminsions-unit"}}
225
+ </div>
226
+ <div class="field-value">
227
+ {{n-a (get-fleet-ops-option-label "dimensionUnits" parcelFee.dimensions_unit)}}
228
+ </div>
229
+ </div>
230
+
231
+ <div class="field-info-container">
232
+ <div class="field-name">
233
+ {{t "service-rate.fields.weight-unit"}}
234
+ </div>
235
+ <div class="field-value">
236
+ {{n-a (get-fleet-ops-option-label "weightUnits" parcelFee.weight_unit)}}
237
+ </div>
238
+ </div>
239
+
240
+ <div class="field-info-container col-span-2">
241
+ <div class="field-name">
242
+ {{t "service-rate.fields.additional-fee"}}
243
+ </div>
244
+ <div class="field-value">
245
+ {{n-a (format-currency parcelFee.fee @resource.currency)}}
246
+ </div>
247
+ </div>
248
+ </div>
249
+ </div>
250
+ </div>
209
251
  </div>
210
- </div>
211
- {{else}}
212
- <div class="field-info-container col-span-2">
213
- <div class="field-value text-gray-500">No parcel fees configured</div>
214
- </div>
215
- {{/if}}
216
- </div>
217
- </ContentPanel>
252
+ {{else}}
253
+ <div class="col-span-2">
254
+ <span class="text-gray-500 text-sm italic">No parcel fees configured</span>
255
+ </div>
256
+ {{/each}}
257
+ </div>
258
+ </ContentPanel>
259
+ {{/if}}
218
260
 
219
261
  <ContentPanel @title={{t "service-rate.fields.restrict-service-title"}} @open={{true}} @wrapperClass="bordered-top">
220
262
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-2">
@@ -16,7 +16,7 @@
16
16
  @options={{this.orderConfigActions.allOrderConfigs}}
17
17
  @selected={{@resource.order_config}}
18
18
  @onChange={{this.selectOrderConfig}}
19
- @placeholder={{t "fleet-ops.operations.orders.index.new.select-order-type"}}
19
+ @placeholder={{t "service-rate.fields.select-order-type"}}
20
20
  @triggerClass="form-select form-input"
21
21
  @disabled={{cannot-write @resource}}
22
22
  as |orderConfig|
@@ -112,6 +112,7 @@
112
112
  @helpText={{t "service-rate.fields.maximum-distance-help-text"}}
113
113
  @required={{true}}
114
114
  min={{1}}
115
+ {{on "change" this.onMaxDistanceChange}}
115
116
  />
116
117
  <InputGroup @name="Max Distance Unit" @helpText="Select the maximum distance this service rate supports" @required={{true}}>
117
118
  <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
@@ -191,7 +192,7 @@
191
192
  </tr>
192
193
  </thead>
193
194
  <tbody>
194
- {{#each @resource.perDropFees as |rateFee index|}}
195
+ {{#each @resource.rate_fees as |rateFee|}}
195
196
  <tr>
196
197
  <td>
197
198
  <Input
@@ -215,7 +216,7 @@
215
216
  <MoneyInput class="w-full" @currency={{@resource.currency}} @value={{rateFee.fee}} disabled={{cannot-write @resource}} />
216
217
  </td>
217
218
  <td>
218
- <Button @type="danger" @icon="trash" @onClick={{fn @resource.removePerDropFee index}} />
219
+ <Button @type="danger" @icon="trash" @onClick={{fn @resource.removePerDropFee rateFee}} />
219
220
  </td>
220
221
  </tr>
221
222
  {{/each}}
@@ -560,6 +561,7 @@
560
561
  @onChange={{fn (mut @resource.serviceArea)}}
561
562
  @onChangeId={{fn (mut @resource.service_area_uuid)}}
562
563
  @disabled={{cannot-write @resource}}
564
+ @allowClear={{true}}
563
565
  as |model|
564
566
  >
565
567
  {{model.name}}
@@ -567,7 +569,7 @@
567
569
  </InputGroup>
568
570
 
569
571
  {{#if @resource.serviceArea}}
570
- <InputGroup @name={{t "service-rate.fields.zone-label"}} @helpText={{t "service-rate.fields.zone-help-text"}}>
572
+ <InputGroup @name={{t "service-rate.fields.zone-label"}} @helpText={{t "service-rate.fields.zone-help-text"}} @wrapperClass="mt-2">
571
573
  <ModelSelect
572
574
  @modelName="zone"
573
575
  @selectedModel={{@resource.zone}}
@@ -579,6 +581,7 @@
579
581
  @onChange={{fn (mut @resource.zone)}}
580
582
  @onChangeId={{fn (mut @resource.zone_uuid)}}
581
583
  @disabled={{cannot-write @resource}}
584
+ @allowClear={{true}}
582
585
  as |model|
583
586
  >
584
587
  {{model.name}}
@@ -22,6 +22,12 @@ export default class ServiceRateFormComponent extends Component {
22
22
 
23
23
  if (rateCalculationMethod === 'per_drop') {
24
24
  this.args.resource.resetPerDropFees();
25
+ } else if (rateCalculationMethod === 'fixed_meter' || rateCalculationMethod === 'fixed_rate') {
26
+ this.serviceRateActions.generateFixedRateFees(this.args.resource);
25
27
  }
26
28
  }
29
+
30
+ @action onMaxDistanceChange() {
31
+ this.serviceRateActions.generateFixedRateFees(this.args.resource);
32
+ }
27
33
  }
@@ -1,34 +1,33 @@
1
- {{#let (or @vehicle @resource) as |resource|}}
2
- <Pill
3
- @resource={{resource}}
4
- @imageSrc={{resource.photo_url}}
5
- @fallbackImageType="vehicleImage"
6
- @showOnlineIndicator={{true}}
7
- @onClick={{@onClick}}
8
- @anchorClass={{@anchorClass}}
9
- @imageClass={{@imageClass}}
10
- @imageWrapperClass={{@imageWrapperClass}}
11
- @contentWrapperClass={{@contentWrapperClass}}
12
- @titleClass={{@titleClass}}
13
- @subtitleClass={{@subtitleClass}}
14
- ...attributes
15
- >
16
- <:default>
17
- <div class="text-sm">{{n-a resource.name resource.yearMakeModel}}</div>
18
- <div class="text-xs text-gray-400 dark:text-gray-500">{{or resource.plate_number resource.vin resource.serial_number resource.call_sign}}</div>
19
- </:default>
20
- <:tooltip>
21
- <div>
22
- <div class="text-xs font-semibold">{{resource.name resource.yearMakeModel}}</div>
23
- <div class="text-xs">{{t "resource.driver"}}: {{n-a resource.driver_name}}</div>
24
- <div class="text-xs">
25
- <span>{{t "common.status"}}:</span>
26
- <span class="{{if resource.online 'text-green-500' 'text-red-400'}}">
27
- {{if resource.online (t 'common.online') (t 'common.offline')}}
28
- </span>
29
- </div>
30
- <div class="text-xs truncate">Pos: {{point-coordinates resource.location}}</div>
1
+ <Pill
2
+ @this.resource={{this.resource}}
3
+ @imageSrc={{this.resource.photo_url}}
4
+ @fallbackImageType="vehicleImage"
5
+ @showOnlineIndicator={{if this.resource true false}}
6
+ @noTooltip={{not this.resource}}
7
+ @onClick={{@onClick}}
8
+ @anchorClass={{@anchorClass}}
9
+ @imageClass={{@imageClass}}
10
+ @imageWrapperClass={{@imageWrapperClass}}
11
+ @contentWrapperClass={{@contentWrapperClass}}
12
+ @titleClass={{@titleClass}}
13
+ @subtitleClass={{@subtitleClass}}
14
+ ...attributes
15
+ >
16
+ <:default>
17
+ <div class="text-sm">{{or this.resource.name this.resource.yearMakeModel @titleFallback "No vehicle"}}</div>
18
+ <div class="text-xs text-gray-400 dark:text-gray-500">{{or this.resource.plate_number this.resource.vin this.resource.serial_number this.resource.call_sign "-"}}</div>
19
+ </:default>
20
+ <:tooltip>
21
+ <div>
22
+ <div class="text-xs font-semibold">{{this.resource.name this.resource.yearMakeModel}}</div>
23
+ <div class="text-xs">{{t "this.resource.driver"}}: {{n-a this.resource.driver_name}}</div>
24
+ <div class="text-xs">
25
+ <span>{{t "common.status"}}:</span>
26
+ <span class="{{if this.resource.online 'text-green-500' 'text-red-400'}}">
27
+ {{if this.resource.online (t "common.online") (t "common.offline")}}
28
+ </span>
31
29
  </div>
32
- </:tooltip>
33
- </Pill>
34
- {{/let}}
30
+ <div class="text-xs truncate">Pos: {{point-coordinates this.resource.location}}</div>
31
+ </div>
32
+ </:tooltip>
33
+ </Pill>
@@ -1,3 +1,7 @@
1
1
  import Component from '@glimmer/component';
2
2
 
3
- export default class VehiclePillComponent extends Component {}
3
+ export default class VehiclePillComponent extends Component {
4
+ get resource() {
5
+ return this.args.vehicle ?? this.args.resource;
6
+ }
7
+ }
@@ -113,7 +113,7 @@ export default class OperationsOrdersIndexController extends Controller {
113
113
  fn: this.orderActions.bulkDispatch,
114
114
  },
115
115
  {
116
- label: this.intl.t('common.assign-driver'),
116
+ label: this.intl.t('common.assign-drivers'),
117
117
  icon: 'user-plus',
118
118
  fn: this.orderActions.bulkAssignDriver,
119
119
  },
@@ -5,9 +5,10 @@ import { action, computed } from '@ember/object';
5
5
  import { later } from '@ember/runloop';
6
6
  import { task } from 'ember-concurrency';
7
7
  import { format, isValid as isValidDate } from 'date-fns';
8
+ import { Tooltip } from '@fleetbase/ember-ui/utils/floating';
8
9
  import isObject from '@fleetbase/ember-core/utils/is-object';
9
10
  import isJson from '@fleetbase/ember-core/utils/is-json';
10
- import createFullCalendarEventFromOrder, { createOrderEventTitle } from '../../../utils/create-full-calendar-event-from-order';
11
+ import createFullCalendarEventFromOrder, { createOrderEventTitle, createOrderEventDescription } from '../../../utils/create-full-calendar-event-from-order';
11
12
 
12
13
  function createFullCalendarEventFromScheduleItem(item, driver) {
13
14
  return {
@@ -42,7 +43,7 @@ export default class OperationsSchedulerIndexController extends Controller {
42
43
  @service store;
43
44
  @service intl;
44
45
  @service hostRouter;
45
- @service scheduling;
46
+ // @service scheduling;
46
47
  @tracked scheduledOrders = [];
47
48
  @tracked unscheduledOrders = [];
48
49
  @tracked drivers = [];
@@ -105,6 +106,17 @@ export default class OperationsSchedulerIndexController extends Controller {
105
106
  this.calendar = calendar;
106
107
  // setup some custom post initialization stuff here
107
108
  // calendar.setOption('height', 800);
109
+ calendar.setOption('eventDidMount', (info) => {
110
+ if (!info.event.extendedProps.description) return;
111
+
112
+ info.tooltip = new Tooltip(info.el, {
113
+ text: info.event.extendedProps.description,
114
+ });
115
+ });
116
+
117
+ calendar.setOption('eventWillUnmount', (info) => {
118
+ info.tooltip?.destroy();
119
+ });
108
120
  }
109
121
 
110
122
  @action viewEvent(order) {
@@ -152,6 +164,7 @@ export default class OperationsSchedulerIndexController extends Controller {
152
164
 
153
165
  // update event props
154
166
  this.setEventProperty(event, 'title', createOrderEventTitle(order));
167
+ this.setEventProperty(event, 'description', createOrderEventDescription(order));
155
168
 
156
169
  // refresh route
157
170
  return this.hostRouter.refresh();
@@ -249,6 +262,7 @@ export default class OperationsSchedulerIndexController extends Controller {
249
262
  const order = this.store.peekRecord('order', event.id);
250
263
 
251
264
  this.setEventProperty(event, 'title', createOrderEventTitle(order));
265
+ this.setEventProperty(event, 'description', createOrderEventDescription(order));
252
266
  }
253
267
 
254
268
  @action async rescheduleEventFromDrag(eventDropInfo) {
@@ -282,6 +296,7 @@ export default class OperationsSchedulerIndexController extends Controller {
282
296
  order.set('scheduled_at', isValidDate(newDate) ? newDate : start);
283
297
  await order.save();
284
298
  this.setEventProperty(event, 'title', createOrderEventTitle(order));
299
+ this.setEventProperty(event, 'description', createOrderEventDescription(order));
285
300
  return this.hostRouter.refresh();
286
301
  } catch (error) {
287
302
  this.notifications.serverError(error);
@@ -5,6 +5,7 @@ import { action } from '@ember/object';
5
5
  import { task } from 'ember-concurrency';
6
6
 
7
7
  export default class OperationsServiceRatesIndexEditController extends Controller {
8
+ @service serviceRateActions;
8
9
  @service hostRouter;
9
10
  @service intl;
10
11
  @service notifications;
@@ -18,13 +19,6 @@ export default class OperationsServiceRatesIndexEditController extends Controlle
18
19
  ];
19
20
 
20
21
  @task *save(serviceRate) {
21
- if (typeof serviceRate.syncServiceRateFees === 'function') {
22
- serviceRate.syncServiceRateFees();
23
- }
24
- if (typeof serviceRate.syncPerDropFees === 'function') {
25
- serviceRate.syncPerDropFees();
26
- }
27
-
28
22
  try {
29
23
  yield serviceRate.save();
30
24
  this.overlay?.close();
@@ -13,13 +13,6 @@ export default class OperationsServiceRatesIndexNewController extends Controller
13
13
  @tracked serviceRate = this.serviceRateActions.createNewInstance();
14
14
 
15
15
  @task *save(serviceRate) {
16
- if (typeof serviceRate.syncServiceRateFees === 'function') {
17
- serviceRate.syncServiceRateFees();
18
- }
19
- if (typeof serviceRate.syncPerDropFees === 'function') {
20
- serviceRate.syncPerDropFees();
21
- }
22
-
23
16
  try {
24
17
  yield serviceRate.save();
25
18
  this.overlay?.close();
@@ -126,12 +126,20 @@ export default class OperationsServiceRatesIndexController extends Controller {
126
126
  width: 60,
127
127
  actions: [
128
128
  {
129
- label: this.intl.t('column.edit-service'),
129
+ label: this.intl.t('common.view-resource', { resource: this.intl.t('resource.service-rate') }),
130
+ icon: 'eye',
131
+ fn: this.serviceRateActions.transition.view,
132
+ permission: 'fleet-ops view service-rate',
133
+ },
134
+ {
135
+ label: this.intl.t('common.edit-resource', { resource: this.intl.t('resource.service-rate') }),
136
+ icon: 'pencil',
130
137
  fn: this.serviceRateActions.transition.edit,
131
138
  permission: 'fleet-ops view service-rate',
132
139
  },
133
140
  {
134
- label: this.intl.t('column.delete-service'),
141
+ label: this.intl.t('common.delete-resource', { resource: this.intl.t('resource.service-rate') }),
142
+ icon: 'trash',
135
143
  fn: this.serviceRateActions.delete,
136
144
  permission: 'fleet-ops delete service-rate',
137
145
  },
@@ -58,4 +58,11 @@ export default class OperationsOrdersIndexDetailsRoute extends Route {
58
58
  with: ['payload', 'driverAssigned', 'orderConfig', 'customer', 'facilitator', 'trackingStatuses', 'trackingNumber', 'purchaseRate', 'comments', 'files'],
59
59
  });
60
60
  }
61
+
62
+ async afterModel(order) {
63
+ await order.loadTrackingActivity();
64
+ if (order.meta?._index_resource) {
65
+ await order.reload();
66
+ }
67
+ }
61
68
  }
@@ -2,7 +2,7 @@ import Route from '@ember/routing/route';
2
2
  import { inject as service } from '@ember/service';
3
3
  import { isValid as isValidDate } from 'date-fns';
4
4
  import { isNone } from '@ember/utils';
5
- import createFullCalendarEventFromOrder from '../../../utils/create-full-calendar-event-from-order';
5
+ // import createFullCalendarEventFromOrder from '../../../utils/create-full-calendar-event-from-order';
6
6
 
7
7
  const getUnscheduledOrder = (order) => {
8
8
  return isNone(order.scheduled_at);
@@ -40,7 +40,7 @@ export default class OperationsSchedulerIndexRoute extends Route {
40
40
  // set scheduled orders
41
41
  controller.scheduledOrders = orders.filter(getScheduledOrder);
42
42
 
43
- // create events from scheduledOrders
44
- controller.events = controller.scheduledOrders.map(createFullCalendarEventFromOrder);
43
+ // // create events from scheduledOrders
44
+ // controller.events = controller.scheduledOrders.map(createFullCalendarEventFromOrder);
45
45
  }
46
46
  }
@@ -29,7 +29,11 @@ export default class DriverActionsService extends ResourceActionService {
29
29
  ...options,
30
30
  });
31
31
  },
32
- edit: (driver, options = {}) => {
32
+ edit: async (driver, options = {}) => {
33
+ if (driver?.meta?._index_resource) {
34
+ await driver.reload();
35
+ }
36
+
33
37
  return this.resourceContextPanel.open({
34
38
  content: 'driver/form',
35
39
  title: this.intl.t('common.edit-resource-name', { resourceName: driver.name }),
@@ -47,7 +51,11 @@ export default class DriverActionsService extends ResourceActionService {
47
51
  ...options,
48
52
  });
49
53
  },
50
- view: (driver, options = {}) => {
54
+ view: async (driver, options = {}) => {
55
+ if (driver?.meta?._index_resource) {
56
+ await driver.reload();
57
+ }
58
+
51
59
  return this.resourceContextPanel.open({
52
60
  driver,
53
61
  header: 'driver/panel-header',
@@ -83,7 +91,11 @@ export default class DriverActionsService extends ResourceActionService {
83
91
  ...options,
84
92
  });
85
93
  },
86
- edit: (driver, options = {}, saveOptions = {}) => {
94
+ edit: async (driver, options = {}, saveOptions = {}) => {
95
+ if (driver?.meta?._index_resource) {
96
+ await driver.reload();
97
+ }
98
+
87
99
  return this.modalsManager.show('modals/resource', {
88
100
  resource: driver,
89
101
  title: this.intl.t('common.edit-resource-name', { resourceName: driver.name }),
@@ -94,7 +106,11 @@ export default class DriverActionsService extends ResourceActionService {
94
106
  ...options,
95
107
  });
96
108
  },
97
- view: (driver, options = {}) => {
109
+ view: async (driver, options = {}) => {
110
+ if (driver?.meta?._index_resource) {
111
+ await driver.reload();
112
+ }
113
+
98
114
  return this.modalsManager.show('modals/resource', {
99
115
  resource: driver,
100
116
  title: driver.name,
@@ -51,7 +51,13 @@ export default class LeafletRoutingControlService extends Service {
51
51
 
52
52
  get(name) {
53
53
  name = name ?? this.getRouter();
54
- return this.registry.routers[underscore(name)];
54
+ let router = this.registry.routers[underscore(name)];
55
+ if (!router) {
56
+ // Fallback to OSRM default router
57
+ router = this.registry.routers.osrm;
58
+ }
59
+
60
+ return router;
55
61
  }
56
62
 
57
63
  getRouter(fallback = 'osrm') {
@@ -150,7 +150,6 @@ export default class OrderListOverlayService extends Service {
150
150
  'fleet-ops/live/orders',
151
151
  {
152
152
  active: 1,
153
- with_tracker_data: 1,
154
153
  exclude: excludeOrderIds,
155
154
  },
156
155
  {