@fleetbase/fleetops-engine 0.6.44 → 0.6.46

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 (172) hide show
  1. package/addon/components/admin/map-settings.hbs +26 -0
  2. package/addon/components/admin/map-settings.js +46 -0
  3. package/addon/components/admin/routing-settings.hbs +11 -0
  4. package/addon/components/cell/order-route-type.hbs +46 -0
  5. package/addon/components/cell/order-route-type.js +90 -0
  6. package/addon/components/cell/place-address.hbs +1 -0
  7. package/addon/components/display-place.hbs +45 -56
  8. package/addon/components/display-place.js +21 -0
  9. package/addon/components/entity/form.hbs +24 -0
  10. package/addon/components/entity/form.js +30 -0
  11. package/addon/components/layout/fleet-ops-sidebar/driver-listing.js +5 -5
  12. package/addon/components/layout/fleet-ops-sidebar/fleet-listing.js +5 -5
  13. package/addon/components/layout/fleet-ops-sidebar.js +8 -0
  14. package/addon/components/leaflet-draw-control.js +1 -1
  15. package/addon/components/maintenance-schedule/form.js +2 -1
  16. package/addon/components/map/drawer/driver-listing.js +5 -5
  17. package/addon/components/map/drawer/geofence-event-listing.js +5 -2
  18. package/addon/components/map/drawer/place-listing.js +5 -5
  19. package/addon/components/map/drawer/position-listing.js +102 -21
  20. package/addon/components/map/drawer/vehicle-listing.js +5 -5
  21. package/addon/components/map/google-live-map.hbs +9 -0
  22. package/addon/components/map/google-live-map.js +445 -0
  23. package/addon/components/map/leaflet-live-map.hbs +186 -142
  24. package/addon/components/map/leaflet-live-map.js +121 -41
  25. package/addon/components/map/toolbar/visibility-control-panel.js +2 -2
  26. package/addon/components/map/toolbar/zones-panel.hbs +9 -9
  27. package/addon/components/map/toolbar.hbs +3 -3
  28. package/addon/components/map/toolbar.js +9 -1
  29. package/addon/components/modals/map-layer-form.hbs +132 -63
  30. package/addon/components/modals/orchestrator-import.hbs +4 -11
  31. package/addon/components/modals/orchestrator-import.js +17 -1
  32. package/addon/components/modals/update-order-activity.hbs +1 -1
  33. package/addon/components/orchestrator/order-pool.js +3 -2
  34. package/addon/components/orchestrator-workbench.js +29 -41
  35. package/addon/components/order/details/detail.js +2 -2
  36. package/addon/components/order/details/payload.hbs +5 -5
  37. package/addon/components/order/details/payload.js +18 -1
  38. package/addon/components/order/details/route.hbs +2 -2
  39. package/addon/components/order/details/route.js +76 -3
  40. package/addon/components/order/form/payload.hbs +33 -0
  41. package/addon/components/order/form/payload.js +1 -0
  42. package/addon/components/order/form/route.hbs +8 -8
  43. package/addon/components/order/form/route.js +78 -18
  44. package/addon/components/order/form/service-rate.hbs +1 -1
  45. package/addon/components/order/form.js +2 -2
  46. package/addon/components/order/route-editor.hbs +209 -147
  47. package/addon/components/order/route-editor.js +143 -102
  48. package/addon/components/place/address.hbs +1 -0
  49. package/addon/components/place/address.js +12 -0
  50. package/addon/components/route-list.hbs +43 -55
  51. package/addon/components/route-list.js +47 -0
  52. package/addon/components/route-optimization-wizard-panel.js +3 -4
  53. package/addon/components/service-rate/details.hbs +6 -6
  54. package/addon/components/service-rate/form.hbs +28 -15
  55. package/addon/components/vehicle/card.hbs +4 -4
  56. package/addon/controllers/maintenance/schedules/index.js +2 -1
  57. package/addon/controllers/operations/orders/index/details/virtual.js +5 -0
  58. package/addon/controllers/operations/orders/index/details.js +113 -15
  59. package/addon/controllers/operations/orders/index/new.js +1 -1
  60. package/addon/controllers/operations/orders/index.js +8 -1
  61. package/addon/controllers/operations/service-rates/index/edit.js +1 -0
  62. package/addon/controllers/operations/service-rates/index/new.js +1 -0
  63. package/addon/controllers/settings/map.js +97 -0
  64. package/addon/controllers/settings/routing.js +47 -12
  65. package/addon/extension.js +11 -0
  66. package/addon/helpers/f-to-int.js +6 -0
  67. package/addon/helpers/place-address-html.js +6 -0
  68. package/addon/instance-initializers/register-google-routes.js +17 -0
  69. package/addon/instance-initializers/register-osrm.js +5 -0
  70. package/addon/routes/application.js +9 -3
  71. package/addon/routes/operations/orchestrator.js +13 -0
  72. package/addon/routes/operations/orders/index/details/virtual.js +1 -0
  73. package/addon/routes/operations/orders/index/details.js +47 -24
  74. package/addon/routes/operations/orders/index/new.js +9 -0
  75. package/addon/routes/operations/orders/index.js +0 -1
  76. package/addon/routes/settings/map.js +3 -0
  77. package/addon/routes.js +1 -0
  78. package/addon/services/entity-actions.js +1 -1
  79. package/addon/services/equipment-actions.js +4 -6
  80. package/addon/services/geofence-event-bus.js +2 -1
  81. package/addon/services/geofence.js +204 -168
  82. package/addon/services/google-routes.js +300 -0
  83. package/addon/services/leaflet-draw-restriction.js +2 -1
  84. package/addon/services/leaflet-map-manager.js +21 -0
  85. package/addon/services/maintenance-actions.js +4 -6
  86. package/addon/services/map-adapter/google.js +2205 -0
  87. package/addon/services/map-adapter/leaflet.js +1042 -0
  88. package/addon/services/map-adapter-interface.js +551 -0
  89. package/addon/services/map-manager.js +768 -0
  90. package/addon/services/map-settings.js +75 -0
  91. package/addon/services/movement-tracker.js +83 -32
  92. package/addon/services/order-actions.js +11 -1
  93. package/addon/services/osrm.js +79 -6
  94. package/addon/services/part-actions.js +4 -6
  95. package/addon/services/position-playback.js +135 -62
  96. package/addon/services/route-engine.js +83 -0
  97. package/addon/services/service-areas.js +8 -1
  98. package/addon/services/service-rate-actions.js +8 -3
  99. package/addon/styles/fleetops-engine.css +555 -0
  100. package/addon/templates/management/vehicles/index.hbs +0 -1
  101. package/addon/templates/operations/orders/index/details/virtual.hbs +7 -1
  102. package/addon/templates/operations/orders/index/details.hbs +0 -1
  103. package/addon/templates/settings/map.hbs +53 -0
  104. package/addon/templates/settings/routing.hbs +15 -4
  105. package/addon/utils/fleet-ops-options.js +34 -0
  106. package/addon/utils/has-valid-coordinates.js +6 -0
  107. package/addon/utils/map-provider-options.js +6 -0
  108. package/addon/utils/order-route-editing.js +86 -0
  109. package/addon/utils/order-route-summary.js +20 -0
  110. package/addon/utils/place-address-html.js +41 -0
  111. package/addon/utils/route-colors.js +43 -12
  112. package/addon/utils/route-visualization.js +93 -0
  113. package/addon/utils/serialize-payload.js +1 -1
  114. package/addon/utils/vendor-integration.js +2 -1
  115. package/app/components/admin/map-settings.js +1 -0
  116. package/app/components/admin/routing-settings.js +1 -0
  117. package/app/components/cell/order-route-type.js +1 -0
  118. package/app/components/cell/place-address.js +1 -0
  119. package/app/components/map/google-live-map.js +1 -0
  120. package/app/components/place/address.js +1 -0
  121. package/app/controllers/operations/orders/index/details/virtual.js +1 -0
  122. package/app/controllers/settings/map.js +1 -0
  123. package/app/helpers/f-to-int.js +1 -0
  124. package/app/helpers/place-address-html.js +1 -0
  125. package/app/routes/settings/map.js +1 -0
  126. package/app/services/map-adapter/google.js +1 -0
  127. package/app/services/map-adapter/leaflet.js +1 -0
  128. package/app/services/map-adapter-interface.js +1 -0
  129. package/app/services/map-manager.js +1 -0
  130. package/app/services/map-settings.js +1 -0
  131. package/app/templates/settings/map.js +1 -0
  132. package/app/utils/has-valid-coordinates.js +1 -0
  133. package/app/utils/order-route-editing.js +2 -0
  134. package/app/utils/order-route-summary.js +1 -0
  135. package/app/utils/place-address-html.js +1 -0
  136. package/app/utils/route-colors.js +1 -1
  137. package/app/utils/route-visualization.js +1 -0
  138. package/assets/images/drawing-controls-spritesheet.svg +156 -0
  139. package/composer.json +1 -1
  140. package/extension.json +1 -1
  141. package/package.json +3 -3
  142. package/server/src/Auth/Schemas/FleetOps.php +5 -0
  143. package/server/src/Http/Controllers/Api/v1/OrderController.php +36 -8
  144. package/server/src/Http/Controllers/Api/v1/PayloadController.php +14 -1
  145. package/server/src/Http/Controllers/Api/v1/PurchaseRateController.php +11 -3
  146. package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +2 -0
  147. package/server/src/Http/Controllers/Api/v1/ServiceQuoteController.php +7 -2
  148. package/server/src/Http/Controllers/Api/v1/ServiceRateController.php +6 -1
  149. package/server/src/Http/Controllers/Api/v1/ZoneController.php +2 -0
  150. package/server/src/Http/Controllers/Internal/v1/LiveController.php +2 -1
  151. package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +7 -4
  152. package/server/src/Http/Controllers/Internal/v1/OrderController.php +61 -34
  153. package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +3 -2
  154. package/server/src/Http/Controllers/Internal/v1/SettingController.php +106 -3
  155. package/server/src/Http/Filter/OrderFilter.php +2 -1
  156. package/server/src/Http/Requests/CreateServiceRateRequest.php +2 -2
  157. package/server/src/Http/Resources/v1/Index/Payload.php +9 -7
  158. package/server/src/Http/Resources/v1/Order.php +20 -2
  159. package/server/src/Http/Resources/v1/ServiceQuote.php +2 -2
  160. package/server/src/Models/Entity.php +7 -0
  161. package/server/src/Models/Order.php +81 -8
  162. package/server/src/Models/OrderConfig.php +15 -0
  163. package/server/src/Models/Payload.php +131 -27
  164. package/server/src/Models/Place.php +182 -48
  165. package/server/src/Models/ServiceRate.php +125 -32
  166. package/server/src/Observers/PurchaseRateObserver.php +3 -5
  167. package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +59 -23
  168. package/server/src/Rules/ComputableAlgo.php +1 -3
  169. package/server/src/Support/Algo.php +87 -1
  170. package/server/src/Support/Utils.php +69 -0
  171. package/server/src/routes.php +4 -0
  172. package/translations/en-us.yaml +1937 -1916
@@ -20,13 +20,16 @@ use Illuminate\Support\Facades\Log;
20
20
  *
21
21
  * Resolution order for configuration:
22
22
  *
23
- * 1. Company-level setting — `Setting::lookupCompany('vroom', 'api_key')`
24
- * (written by the fleetbase/vroom extension settings page, if installed)
25
- * 2. Environment variable — `VROOM_API_KEY`
26
- * 3. No key — requests are sent without an api_key parameter
23
+ * 1. Company-level setting — organization override
24
+ * 2. System-level setting — admin default
25
+ * 3. Environment/config fallback
26
+ * 4. No key — requests are sent without an api_key parameter
27
27
  * (works for self-hosted VROOM instances that do not require auth)
28
28
  *
29
- * Base URI: `config('vroom.base_uri')` → `VROOM_HOST` env → default production URL
29
+ * Base URI and endpoint mode follow the same precedence, with endpoint mode
30
+ * controlling whether requests are posted to `/solve` or directly to the
31
+ * configured binary host.
32
+ *
30
33
  * Timeout: `VROOM_TIMEOUT` env (default 30 s)
31
34
  *
32
35
  * The VROOM HTTP API endpoint used is `POST {base_uri}/solve`, matching the
@@ -101,27 +104,17 @@ class VroomOrchestrationEngine implements OrchestrationEngineInterface
101
104
  unset($job);
102
105
 
103
106
  // ── Resolve connection config ─────────────────────────────────────────
104
- // Base URI: prefer the vroom extension config, then VROOM_HOST env, then
105
- // the production verso-optim.com hosted service.
106
- $baseUri = config('vroom.base_uri', env('VROOM_HOST', 'https://api.verso-optim.com/vrp/v1'));
107
+ $baseUri = $this->resolveVroomBaseUri();
108
+ $endpointMode = $this->resolveVroomEndpointMode();
107
109
  $timeout = (int) env('VROOM_TIMEOUT', 30);
108
110
 
109
- // ── Resolve API key ───────────────────────────────────────────────────
110
- // 1. Company-level setting (written by fleetbase/vroom extension UI)
111
- // 2. VROOM_API_KEY env var
112
- // 3. null — no key appended (for self-hosted instances)
113
- $apiKey = null;
114
- try {
115
- $apiKey = Setting::lookupCompany('vroom', ['api_key' => null])['api_key'] ?? null;
116
- } catch (\Throwable) {
117
- // Setting table may not exist in minimal installs — ignore
118
- }
119
- if (!$apiKey) {
120
- $apiKey = env('VROOM_API_KEY');
121
- }
111
+ $apiKey = $this->resolveVroomApiKey();
122
112
 
123
- // Build the solve URL — append api_key as query param when present
124
- $solveUrl = rtrim($baseUri, '/') . '/solve';
113
+ // Build the solve URL — append api_key as query param when present.
114
+ $solveUrl = rtrim($baseUri, '/');
115
+ if ($endpointMode !== 'binary') {
116
+ $solveUrl .= '/solve';
117
+ }
125
118
  if ($apiKey) {
126
119
  $solveUrl .= '?api_key=' . urlencode($apiKey);
127
120
  }
@@ -189,4 +182,47 @@ class VroomOrchestrationEngine implements OrchestrationEngineInterface
189
182
  'summary' => $vroomResult['summary'] ?? [],
190
183
  ];
191
184
  }
185
+
186
+ protected function resolveVroomBaseUri(): string
187
+ {
188
+ return $this->resolveVroomSetting('api_host', config('vroom.base_uri', env('VROOM_HOST', 'https://api.verso-optim.com/vrp/v1')));
189
+ }
190
+
191
+ protected function resolveVroomApiKey(): ?string
192
+ {
193
+ return $this->resolveVroomSetting('api_key', env('VROOM_API_KEY'));
194
+ }
195
+
196
+ protected function resolveVroomEndpointMode(): string
197
+ {
198
+ return $this->resolveVroomSetting('endpoint_mode', config('vroom.endpoint_mode', env('VROOM_ENDPOINT_MODE', 'saas')));
199
+ }
200
+
201
+ protected function resolveVroomSetting(string $key, $default = null)
202
+ {
203
+ try {
204
+ $organizationValue = data_get(Setting::lookupCompany('vroom', []), $key);
205
+ if ($this->hasConfiguredValue($organizationValue)) {
206
+ return $organizationValue;
207
+ }
208
+
209
+ $systemValue = data_get(Setting::lookup('vroom', []), $key);
210
+ if ($this->hasConfiguredValue($systemValue)) {
211
+ return $systemValue;
212
+ }
213
+ } catch (\Throwable) {
214
+ // Setting table may not exist in minimal installs — ignore
215
+ }
216
+
217
+ return $default;
218
+ }
219
+
220
+ protected function hasConfiguredValue($value): bool
221
+ {
222
+ if (is_string($value)) {
223
+ return trim($value) !== '';
224
+ }
225
+
226
+ return $value !== null;
227
+ }
192
228
  }
@@ -16,9 +16,7 @@ class ComputableAlgo implements Rule
16
16
  */
17
17
  public function passes($attribute, $value)
18
18
  {
19
- $distanceAndTime = Algo::calculateDrivingDistanceAndTime('1.3506853', '103.87199110000006', '1.3621663', '103.88450490000002');
20
-
21
- return Algo::exec($value, $distanceAndTime) > 0;
19
+ return Algo::isComputable($value);
22
20
  }
23
21
 
24
22
  /**
@@ -6,6 +6,8 @@ use Webit\Util\EvalMath\EvalMath;
6
6
 
7
7
  class Algo
8
8
  {
9
+ protected const FUNCTION_PATTERN = '/\b(max|min|ceil|floor|round)\(([^()]*)\)/';
10
+
9
11
  /**
10
12
  * Execute an algorithm strig.
11
13
  *
@@ -16,11 +18,18 @@ class Algo
16
18
  $m = new EvalMath();
17
19
  $m->suppress_errors = true;
18
20
 
21
+ $variables = static::normalizeVariables($variables);
22
+
19
23
  foreach ($variables as $key => $value) {
20
24
  $algorithm = str_replace('{' . $key . '}', $value, $algorithm);
21
25
  }
22
26
 
23
- $result = $m->evaluate($algorithm);
27
+ $algorithm = static::evaluateFunctions($algorithm);
28
+ $result = $m->evaluate($algorithm);
29
+
30
+ if ($result === false || $result === null || !is_numeric($result)) {
31
+ return null;
32
+ }
24
33
 
25
34
  if ($round) {
26
35
  return round($result, 2); // precision 2 cuz most likely dealing with $
@@ -28,4 +37,81 @@ class Algo
28
37
 
29
38
  return $result;
30
39
  }
40
+
41
+ public static function isComputable($algorithm): bool
42
+ {
43
+ $result = static::exec($algorithm, static::validationFixture(), true);
44
+
45
+ return $result !== null && is_numeric($result);
46
+ }
47
+
48
+ public static function normalizeVariables($variables = []): array
49
+ {
50
+ $variables = collect($variables)->all();
51
+
52
+ $distanceM = (float) ($variables['distance_m'] ?? $variables['distance'] ?? 0);
53
+ $timeS = (float) ($variables['time_s'] ?? $variables['time'] ?? 0);
54
+
55
+ $normalized = [
56
+ 'distance_m' => $distanceM,
57
+ 'distance' => $distanceM,
58
+ 'distance_km'=> $distanceM / 1000,
59
+ 'distance_mi'=> $distanceM / 1609.344,
60
+ 'time_s' => $timeS,
61
+ 'time' => $timeS,
62
+ 'time_min' => $timeS / 60,
63
+ 'stops' => (int) ($variables['stops'] ?? 0),
64
+ 'waypoints' => (int) ($variables['waypoints'] ?? 0),
65
+ 'parcels' => (int) ($variables['parcels'] ?? 0),
66
+ 'entities' => (int) ($variables['entities'] ?? 0),
67
+ 'base_fee' => (float) ($variables['base_fee'] ?? 0),
68
+ ];
69
+
70
+ return array_merge($normalized, $variables);
71
+ }
72
+
73
+ protected static function validationFixture(): array
74
+ {
75
+ return static::normalizeVariables([
76
+ 'distance_m' => 25000,
77
+ 'time_s' => 5400,
78
+ 'stops' => 4,
79
+ 'waypoints' => 2,
80
+ 'parcels' => 3,
81
+ 'entities' => 5,
82
+ 'base_fee' => 100,
83
+ ]);
84
+ }
85
+
86
+ protected static function evaluateFunctions(string $algorithm): string
87
+ {
88
+ while (preg_match(static::FUNCTION_PATTERN, $algorithm)) {
89
+ $algorithm = preg_replace_callback(static::FUNCTION_PATTERN, function ($matches) {
90
+ $function = $matches[1];
91
+ $args = array_map('trim', explode(',', $matches[2]));
92
+ $m = new EvalMath();
93
+ $m->suppress_errors = true;
94
+ $numbers = array_map(function ($arg) use ($m) {
95
+ $result = $m->evaluate($arg);
96
+
97
+ if ($result === false || $result === null || !is_numeric($result)) {
98
+ return (float) $arg;
99
+ }
100
+
101
+ return (float) $result;
102
+ }, $args);
103
+
104
+ return match ($function) {
105
+ 'max' => (string) max($numbers[0] ?? 0, $numbers[1] ?? 0),
106
+ 'min' => (string) min($numbers[0] ?? 0, $numbers[1] ?? 0),
107
+ 'ceil' => (string) ceil($numbers[0] ?? 0),
108
+ 'floor' => (string) floor($numbers[0] ?? 0),
109
+ 'round' => (string) round($numbers[0] ?? 0, (int) ($numbers[1] ?? 0)),
110
+ default => $matches[0],
111
+ };
112
+ }, $algorithm);
113
+ }
114
+
115
+ return $algorithm;
116
+ }
31
117
  }
@@ -4,6 +4,8 @@ namespace Fleetbase\FleetOps\Support;
4
4
 
5
5
  use Fleetbase\FleetOps\Flow\Activity;
6
6
  use Fleetbase\LaravelMysqlSpatial\Types\Point;
7
+ use Fleetbase\Models\Company;
8
+ use Fleetbase\Models\Setting;
7
9
  use Fleetbase\Support\Utils as FleetbaseUtils;
8
10
  use Illuminate\Support\Arr;
9
11
  use Illuminate\Support\Facades\DB;
@@ -20,6 +22,39 @@ class Utils extends FleetbaseUtils
20
22
  */
21
23
  public const DRIVING_TIME_MULTIPLIER = 7.2;
22
24
 
25
+ /**
26
+ * Resolve the preferred transaction currency for a company.
27
+ *
28
+ * Resolution order:
29
+ * 1. Organization/company configured currency
30
+ * 2. Ledger accounting base currency
31
+ * 3. USD
32
+ */
33
+ public static function getCompanyTransactionCurrency(string|Company|null $company = null): string
34
+ {
35
+ $companyModel = $company instanceof Company
36
+ ? $company
37
+ : (filled($company) ? Company::where('uuid', $company)->first() : null);
38
+
39
+ $companyUuid = $companyModel?->uuid ?? (is_string($company) ? $company : null);
40
+
41
+ $companyCurrency = data_get($companyModel, 'currency');
42
+ if (filled($companyCurrency)) {
43
+ return strtoupper($companyCurrency);
44
+ }
45
+
46
+ if (filled($companyUuid)) {
47
+ $accountingSettings = Setting::lookup('company.' . $companyUuid . '.ledger.accounting-settings', []);
48
+ $baseCurrency = data_get($accountingSettings, 'base_currency');
49
+
50
+ if (filled($baseCurrency)) {
51
+ return strtoupper($baseCurrency);
52
+ }
53
+ }
54
+
55
+ return 'USD';
56
+ }
57
+
23
58
  /**
24
59
  * Get a formatted string representation of a place's address.
25
60
  *
@@ -209,6 +244,10 @@ class Utils extends FleetbaseUtils
209
244
  $coordinates = $coordinates->getSpatialValue();
210
245
  }
211
246
 
247
+ if ($coordinates instanceof \Illuminate\Database\Query\Expression) {
248
+ $coordinates = static::extractPointWktFromQueryExpression($coordinates) ?? $coordinates;
249
+ }
250
+
212
251
  if ($coordinates instanceof Point) {
213
252
  $latitude = $coordinates->getLat();
214
253
  $longitude = $coordinates->getLng();
@@ -334,6 +373,32 @@ class Utils extends FleetbaseUtils
334
373
  return new Point((float) $latitude, (float) $longitude);
335
374
  }
336
375
 
376
+ /**
377
+ * Attempts to extract a WKT POINT string from a query expression.
378
+ */
379
+ protected static function extractPointWktFromQueryExpression(\Illuminate\Database\Query\Expression $expression): ?string
380
+ {
381
+ $expressionValue = null;
382
+
383
+ if (method_exists($expression, 'getValue')) {
384
+ try {
385
+ $expressionValue = $expression->getValue(DB::connection()->getQueryGrammar());
386
+ } catch (\Throwable $e) {
387
+ $expressionValue = null;
388
+ }
389
+ }
390
+
391
+ if (!is_string($expressionValue) || blank($expressionValue)) {
392
+ return null;
393
+ }
394
+
395
+ if (preg_match("/POINT\\(\\s*([-+]?\\d*\\.?\\d+)\\s+([-+]?\\d*\\.?\\d+)\\s*\\)/i", $expressionValue, $matches)) {
396
+ return sprintf('POINT(%s %s)', $matches[1], $matches[2]);
397
+ }
398
+
399
+ return null;
400
+ }
401
+
337
402
  /**
338
403
  * Always return spatial point.
339
404
  *
@@ -379,6 +444,10 @@ class Utils extends FleetbaseUtils
379
444
  $coordinates = $coordinates->getSpatialValue();
380
445
  }
381
446
 
447
+ if ($coordinates instanceof \Illuminate\Database\Query\Expression) {
448
+ $coordinates = static::extractPointWktFromQueryExpression($coordinates) ?? $coordinates;
449
+ }
450
+
382
451
  if ($coordinates instanceof Point) {
383
452
  return $coordinates;
384
453
  }
@@ -546,6 +546,10 @@ Route::prefix(config('fleetops.api.routing.prefix', null))->namespace('Fleetbase
546
546
  $router->post('notification-settings', 'SettingController@saveNotificationSettings');
547
547
  $router->get('routing-settings', 'SettingController@getRoutingSettings');
548
548
  $router->post('routing-settings', 'SettingController@saveRoutingSettings');
549
+ $router->get('map', 'SettingController@getMapSettings');
550
+ $router->post('map', 'SettingController@saveMapSettings');
551
+ $router->get('admin-map', 'SettingController@getAdminMapSettings');
552
+ $router->post('admin-map', 'SettingController@saveAdminMapSettings');
549
553
  $router->get('scheduling-settings', 'SettingController@getSchedulingSettings');
550
554
  $router->post('scheduling-settings', 'SettingController@saveSchedulingSettings');
551
555
  $router->get('orchestrator-settings', 'SettingController@getOrchestratorSettings');