@fleetbase/fleetops-engine 0.6.49 → 0.6.51

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 (271) hide show
  1. package/README.md +185 -67
  2. package/addon/components/contact/panel-header.hbs +11 -48
  3. package/addon/components/customer/create-order-form.hbs +2 -2
  4. package/addon/components/customer/details.hbs +1 -2
  5. package/addon/components/customer/form.hbs +62 -50
  6. package/addon/components/customer/form.js +27 -1
  7. package/addon/components/customer/order-form.hbs +2 -2
  8. package/addon/components/customer/orders.hbs +50 -2
  9. package/addon/components/customer/orders.js +67 -5
  10. package/addon/components/display-place.hbs +2 -2
  11. package/addon/components/driver/form.hbs +1 -1
  12. package/addon/components/home/getting-started-guidance.hbs +113 -0
  13. package/addon/components/home/getting-started-guidance.js +107 -0
  14. package/addon/components/issue/details/comments.hbs +3 -0
  15. package/addon/components/issue/details/comments.js +3 -0
  16. package/addon/components/issue/details/correspondence.hbs +9 -0
  17. package/addon/components/issue/details/correspondence.js +83 -0
  18. package/addon/components/issue/details/documents.hbs +69 -0
  19. package/addon/components/issue/details/documents.js +85 -0
  20. package/addon/components/issue/details.hbs +220 -59
  21. package/addon/components/issue/details.js +245 -0
  22. package/addon/components/issue/form.hbs +19 -1
  23. package/addon/components/issue/panel-header.hbs +43 -0
  24. package/addon/components/issue/panel-header.js +22 -0
  25. package/addon/components/issue/timeline.hbs +40 -0
  26. package/addon/components/issue/timeline.js +45 -0
  27. package/addon/components/leaflet-tracking-marker.js +3 -0
  28. package/addon/components/map/drawer/position-listing.js +3 -0
  29. package/addon/components/map/google-live-map.js +6 -2
  30. package/addon/components/map/leaflet-live-map.hbs +48 -14
  31. package/addon/components/map/leaflet-live-map.js +201 -20
  32. package/addon/components/map/order-list-overlay.hbs +4 -4
  33. package/addon/components/modals/convert-customer-to-vendor.hbs +30 -0
  34. package/addon/components/modals/convert-customer-to-vendor.js +55 -0
  35. package/addon/components/modals/issue-assign.hbs +20 -0
  36. package/addon/components/modals/issue-assign.js +49 -0
  37. package/addon/components/modals/issue-close.hbs +30 -0
  38. package/addon/components/modals/issue-close.js +73 -0
  39. package/addon/components/modals/issue-status.hbs +20 -0
  40. package/addon/components/modals/issue-status.js +43 -0
  41. package/addon/components/modals/order-change-destination.hbs +46 -0
  42. package/addon/components/modals/order-change-destination.js +106 -0
  43. package/addon/components/modals/reset-customer-credentials.js +12 -6
  44. package/addon/components/modals/stop-activity.hbs +28 -0
  45. package/addon/components/modals/stop-activity.js +52 -0
  46. package/addon/components/modals/update-order-activity.hbs +78 -2
  47. package/addon/components/modals/update-order-activity.js +197 -5
  48. package/addon/components/orchestrator/resource-panel.hbs +0 -10
  49. package/addon/components/orchestrator/resource-panel.js +2 -4
  50. package/addon/components/order/activity-list.hbs +2 -2
  51. package/addon/components/order/activity-timeline.hbs +31 -29
  52. package/addon/components/order/details/activity.hbs +3 -3
  53. package/addon/components/order/details/activity.js +13 -2
  54. package/addon/components/order/details/documents.js +2 -0
  55. package/addon/components/order/details/proof.hbs +40 -38
  56. package/addon/components/order/details/proof.js +31 -4
  57. package/addon/components/order/details/purchase-rate.hbs +2 -2
  58. package/addon/components/order/details/route.hbs +11 -3
  59. package/addon/components/order/details/route.js +91 -14
  60. package/addon/components/order/details/tracking.hbs +101 -72
  61. package/addon/components/order/details/tracking.js +149 -2
  62. package/addon/components/order/details.hbs +5 -5
  63. package/addon/components/order/details.js +19 -1
  64. package/addon/components/order/form/details.hbs +3 -3
  65. package/addon/components/order/form/documents.js +11 -4
  66. package/addon/components/order/form/route.hbs +108 -104
  67. package/addon/components/order/form/route.js +37 -1
  68. package/addon/components/order/form/service-rate.hbs +2 -2
  69. package/addon/components/order/header.hbs +1 -1
  70. package/addon/components/order-config-manager/activity-flow.hbs +4 -1
  71. package/addon/components/order-config-manager/activity-flow.js +178 -12
  72. package/addon/components/place/address.js +1 -1
  73. package/addon/components/route-list.hbs +17 -29
  74. package/addon/components/route-list.js +42 -10
  75. package/addon/components/service-rate/details.hbs +42 -1
  76. package/addon/components/service-rate/form.hbs +119 -1
  77. package/addon/components/service-rate/form.js +59 -0
  78. package/addon/components/vehicle/form.js +1 -1
  79. package/addon/components/vehicle/pill.hbs +1 -1
  80. package/addon/components/vendor/personnel-manager.hbs +166 -0
  81. package/addon/components/vendor/personnel-manager.js +143 -0
  82. package/addon/components/widget/live-fleet.hbs +1 -0
  83. package/addon/components/widget/live-fleet.js +2 -7
  84. package/addon/components/widget/revenue-trend.hbs +1 -1
  85. package/addon/components/widget/revenue-trend.js +75 -2
  86. package/addon/controllers/management/contacts/customers/details.js +31 -13
  87. package/addon/controllers/management/contacts/customers.js +16 -5
  88. package/addon/controllers/management/contacts/index/details.js +31 -13
  89. package/addon/controllers/management/contacts/index.js +7 -0
  90. package/addon/controllers/management/issues/index/details.js +52 -6
  91. package/addon/controllers/management/vehicles/index/new.js +1 -1
  92. package/addon/controllers/management/vendors/index/details.js +4 -0
  93. package/addon/controllers/operations/orders/index/details.js +15 -7
  94. package/addon/controllers/operations/orders/index.js +15 -1
  95. package/addon/extension.js +19 -12
  96. package/addon/helpers/format-duration.js +1 -38
  97. package/addon/helpers/place-address-html.js +2 -2
  98. package/addon/initializers/load-leaflet-assets.js +5 -6
  99. package/addon/initializers/patch-ember-leaflet-tooltip-layer.js +51 -0
  100. package/addon/routes/management/issues/index/details.js +1 -1
  101. package/addon/routes/operations/service-rates/index.js +1 -1
  102. package/addon/routes.js +1 -0
  103. package/addon/services/contact-actions.js +231 -1
  104. package/addon/services/geofence.js +163 -19
  105. package/addon/services/getting-started.js +44 -0
  106. package/addon/services/issue-actions.js +71 -0
  107. package/addon/services/leaflet-contextmenu-manager.js +27 -0
  108. package/addon/services/leaflet-map-manager.js +2 -0
  109. package/addon/services/map-adapter/leaflet.js +19 -0
  110. package/addon/services/service-areas.js +3 -0
  111. package/addon/services/vehicle-actions.js +1 -1
  112. package/addon/styles/fleetops-engine.css +1127 -1
  113. package/addon/templates/management/contacts/customers/details.hbs +1 -1
  114. package/addon/templates/management/contacts/index/details.hbs +1 -1
  115. package/addon/templates/management/contacts.hbs +2 -2
  116. package/addon/templates/management/issues/index/details/index.hbs +3 -1
  117. package/addon/templates/management/issues/index/details.hbs +3 -2
  118. package/addon/templates/management/vendors/index/details/personnel.hbs +1 -2
  119. package/addon/templates/operations/orders/index/details/index.hbs +2 -2
  120. package/addon/templates/operations/orders/index.hbs +1 -1
  121. package/addon/templates/operations/service-rates/index/edit.hbs +1 -0
  122. package/addon/templates/operations/service-rates/index/new.hbs +1 -0
  123. package/addon/templates/settings/payments/onboard.hbs +8 -8
  124. package/addon/utils/fleet-ops-options.js +2 -1
  125. package/addon/utils/leaflet-draw-namespace-guard.js +22 -0
  126. package/addon/utils/leaflet-plugin-loader.js +219 -0
  127. package/addon/utils/normalize-order-config-flow.js +41 -0
  128. package/addon/utils/place-address-html.js +3 -2
  129. package/addon/utils/route-visualization.js +54 -7
  130. package/addon/utils/setup-customer-portal.js +4 -64
  131. package/app/components/home/getting-started-guidance.js +1 -0
  132. package/app/components/issue/details/comments.js +1 -0
  133. package/app/components/issue/details/correspondence.js +1 -0
  134. package/app/components/issue/details/documents.js +1 -0
  135. package/app/components/issue/panel-header.js +1 -0
  136. package/app/components/modals/convert-customer-to-vendor.js +1 -0
  137. package/app/components/modals/issue-assign.js +1 -0
  138. package/app/components/modals/issue-close.js +1 -0
  139. package/app/components/modals/issue-status.js +1 -0
  140. package/app/components/modals/order-change-destination.js +1 -0
  141. package/app/components/modals/stop-activity.js +1 -0
  142. package/app/components/vendor/personnel-manager.js +1 -0
  143. package/app/helpers/format-duration.js +1 -1
  144. package/app/services/getting-started.js +1 -0
  145. package/app/utils/leaflet-draw-namespace-guard.js +1 -0
  146. package/app/utils/leaflet-plugin-loader.js +1 -0
  147. package/composer.json +1 -1
  148. package/extension.json +1 -1
  149. package/package.json +5 -5
  150. package/server/migrations/2026_05_21_000001_add_geographic_rules_to_service_rate_fees_table.php +37 -0
  151. package/server/migrations/2026_05_25_000001_add_endpoint_tracking_refs_to_payloads_table.php +50 -0
  152. package/server/migrations/2026_05_27_000001_default_driver_vehicle_statuses_to_available.php +48 -0
  153. package/server/migrations/2026_05_31_000001_add_portal_fields_to_vendor_personnels_table.php +30 -0
  154. package/server/migrations/2026_06_03_000000_ensure_tags_column_on_issues_table.php +31 -0
  155. package/server/migrations/2026_06_03_000001_add_order_uuid_to_issues_table.php +25 -0
  156. package/server/migrations/2026_06_04_000001_backfill_order_transaction_subjects.php +39 -0
  157. package/server/migrations/2026_06_04_000002_backfill_order_transaction_directions.php +24 -0
  158. package/server/resources/views/labels/default.php +57 -49
  159. package/server/resources/views/labels/waypoint-label.php +27 -20
  160. package/server/resources/views/mail/customer-credentials.blade.php +16 -13
  161. package/server/seeders/Testing/ConnectivitySeeder.php +1 -0
  162. package/server/seeders/Testing/FleetSeeder.php +22 -22
  163. package/server/seeders/Testing/OrdersSeeder.php +6 -22
  164. package/server/seeders/Testing/VroomOrchestrationSeeder.php +21 -21
  165. package/server/src/Console/Commands/AuditCustomerUserConflicts.php +75 -0
  166. package/server/src/Exceptions/CustomerUserConflictException.php +13 -0
  167. package/server/src/Expansions/UserFilterExpansion.php +28 -0
  168. package/server/src/Http/Controllers/Api/v1/ContactController.php +17 -2
  169. package/server/src/Http/Controllers/Api/v1/CustomerController.php +876 -0
  170. package/server/src/Http/Controllers/Api/v1/DriverController.php +1 -1
  171. package/server/src/Http/Controllers/Api/v1/IssueController.php +2 -0
  172. package/server/src/Http/Controllers/Api/v1/OrderConfigController.php +54 -0
  173. package/server/src/Http/Controllers/Api/v1/OrderController.php +109 -80
  174. package/server/src/Http/Controllers/Api/v1/PlaceController.php +10 -58
  175. package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +2 -2
  176. package/server/src/Http/Controllers/Api/v1/VehicleController.php +20 -3
  177. package/server/src/Http/Controllers/Internal/v1/ContactController.php +154 -0
  178. package/server/src/Http/Controllers/Internal/v1/CustomerController.php +116 -6
  179. package/server/src/Http/Controllers/Internal/v1/GettingStartedController.php +17 -0
  180. package/server/src/Http/Controllers/Internal/v1/IssueController.php +251 -0
  181. package/server/src/Http/Controllers/Internal/v1/LiveController.php +101 -66
  182. package/server/src/Http/Controllers/Internal/v1/OrderController.php +530 -52
  183. package/server/src/Http/Controllers/Internal/v1/PlaceController.php +10 -68
  184. package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +1 -1
  185. package/server/src/Http/Controllers/Internal/v1/SettingController.php +2 -2
  186. package/server/src/Http/Controllers/Internal/v1/VehicleController.php +54 -1
  187. package/server/src/Http/Controllers/Internal/v1/VendorController.php +89 -0
  188. package/server/src/Http/Middleware/AuthenticateCustomerToken.php +34 -0
  189. package/server/src/Http/Requests/CreateCustomerOrderRequest.php +63 -0
  190. package/server/src/Http/Requests/CreateCustomerRequest.php +48 -0
  191. package/server/src/Http/Requests/CreateDriverRequest.php +1 -1
  192. package/server/src/Http/Requests/CreateIssueRequest.php +4 -0
  193. package/server/src/Http/Requests/CreateVehicleRequest.php +25 -1
  194. package/server/src/Http/Requests/Internal/CreateDriverRequest.php +1 -1
  195. package/server/src/Http/Requests/UpdateIssueRequest.php +4 -0
  196. package/server/src/Http/Requests/VerifyCreateCustomerRequest.php +29 -0
  197. package/server/src/Http/Resources/Internal/v1/OrderConfig.php +41 -0
  198. package/server/src/Http/Resources/v1/Customer.php +79 -0
  199. package/server/src/Http/Resources/v1/Index/Order.php +12 -9
  200. package/server/src/Http/Resources/v1/Issue.php +25 -0
  201. package/server/src/Http/Resources/v1/Order.php +20 -18
  202. package/server/src/Http/Resources/v1/OrderConfig.php +74 -0
  203. package/server/src/Http/Resources/v1/Payload.php +23 -20
  204. package/server/src/Http/Resources/v1/ServiceArea.php +33 -19
  205. package/server/src/Http/Resources/v1/ServiceRateFee.php +7 -0
  206. package/server/src/Listeners/HandleOrderDispatched.php +2 -2
  207. package/server/src/Mail/CustomerCredentialsMail.php +5 -6
  208. package/server/src/Models/Contact.php +122 -66
  209. package/server/src/Models/Customer.php +64 -0
  210. package/server/src/Models/Driver.php +12 -3
  211. package/server/src/Models/Entity.php +2 -2
  212. package/server/src/Models/Issue.php +47 -6
  213. package/server/src/Models/Order.php +62 -10
  214. package/server/src/Models/Payload.php +17 -1
  215. package/server/src/Models/ServiceArea.php +1 -1
  216. package/server/src/Models/ServiceRate.php +273 -1
  217. package/server/src/Models/ServiceRateFee.php +39 -9
  218. package/server/src/Models/TrackingNumber.php +8 -2
  219. package/server/src/Models/Vehicle.php +18 -2
  220. package/server/src/Models/VendorPersonnel.php +10 -1
  221. package/server/src/Models/Waypoint.php +2 -2
  222. package/server/src/Models/Zone.php +1 -1
  223. package/server/src/Notifications/LateDeparture.php +2 -2
  224. package/server/src/Notifications/ProlongedStoppage.php +2 -2
  225. package/server/src/Notifications/RouteDeviation.php +2 -2
  226. package/server/src/Observers/ContactObserver.php +2 -0
  227. package/server/src/Observers/PurchaseRateObserver.php +20 -0
  228. package/server/src/Observers/ServiceRateObserver.php +6 -6
  229. package/server/src/Observers/ZoneObserver.php +56 -0
  230. package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +1 -1
  231. package/server/src/Providers/FleetOpsServiceProvider.php +2 -0
  232. package/server/src/Support/Analytics/AbstractAnalytics.php +6 -6
  233. package/server/src/Support/Analytics/FuelEfficiency.php +2 -2
  234. package/server/src/Support/Analytics/OrdersByStatus.php +1 -1
  235. package/server/src/Support/Analytics/RevenueTrend.php +0 -1
  236. package/server/src/Support/Analytics/TopDrivers.php +10 -2
  237. package/server/src/Support/CustomerAuth.php +98 -0
  238. package/server/src/Support/GettingStarted.php +144 -0
  239. package/server/src/Support/LabelPdf.php +52 -0
  240. package/server/src/Support/Metrics/AbstractMetric.php +4 -4
  241. package/server/src/Support/PlaceSearch.php +282 -0
  242. package/server/src/Support/ResolvesOrderServiceStops.php +522 -0
  243. package/server/src/Tracking/TrackingContextBuilder.php +41 -38
  244. package/server/src/Tracking/TrackingIntelligenceService.php +109 -9
  245. package/server/src/Tracking/TrackingStop.php +13 -11
  246. package/server/src/routes.php +76 -10
  247. package/server/tests/AnalyticsRoutesTest.php +8 -0
  248. package/server/tests/CapacityAllocationEngineTest.php +10 -10
  249. package/server/tests/CustomerContactIdentitySafetyTest.php +95 -0
  250. package/server/tests/CustomerEndpointTest.php +199 -0
  251. package/server/tests/DriverVehicleStatusDefaultTest.php +39 -0
  252. package/server/tests/GettingStartedStatusTest.php +21 -0
  253. package/server/tests/LabelPdfRenderingTest.php +23 -0
  254. package/server/tests/LiveControllerViewportTest.php +60 -0
  255. package/server/tests/MetricsRegistryTest.php +4 -8
  256. package/server/tests/OrchestrationPayloadBuilderTest.php +2 -2
  257. package/server/tests/OrderActivityFlowRegressionTest.php +116 -0
  258. package/server/tests/OrderConfigEndpointTest.php +86 -0
  259. package/server/tests/OrderFileAttachmentTest.php +20 -0
  260. package/server/tests/ServiceAreaZoneApiShapeTest.php +78 -0
  261. package/server/tests/VehicleDriverAssignmentTest.php +18 -0
  262. package/translations/ar-ae.yml +9 -0
  263. package/translations/bg-bg.yaml +9 -0
  264. package/translations/en-us.yaml +12 -0
  265. package/translations/es-pa.yaml +9 -0
  266. package/translations/fr-fr.yaml +9 -0
  267. package/translations/mn-mn.yaml +9 -0
  268. package/translations/pt-br.yaml +9 -0
  269. package/translations/ru-ru.yaml +9 -0
  270. package/translations/vi-vn.yaml +9 -0
  271. package/server/migrations/2026_05_13_000001_repair_customer_contact_user_types.php +0 -86
@@ -0,0 +1,79 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Http\Resources\v1;
4
+
5
+ use Fleetbase\FleetOps\Models\Order;
6
+ use Fleetbase\FleetOps\Support\Utils;
7
+ use Fleetbase\Http\Resources\FleetbaseResource;
8
+ use Fleetbase\Models\Company;
9
+ use Fleetbase\Support\Http;
10
+ use Illuminate\Http\Request;
11
+ use Illuminate\Support\Str;
12
+
13
+ /**
14
+ * Public API resource for FleetOps customers.
15
+ *
16
+ * Wraps a {@see \Fleetbase\FleetOps\Models\Contact} of `type='customer'` and
17
+ * exposes the auth `token` field that login/signup endpoints attach.
18
+ */
19
+ class Customer extends FleetbaseResource
20
+ {
21
+ public function toArray($request): array
22
+ {
23
+ $this->loadMissing(['place', 'places']);
24
+
25
+ return [
26
+ 'id' => $this->when(Http::isInternalRequest(), $this->id, Str::replaceFirst('contact', 'customer', $this->public_id)),
27
+ 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
28
+ 'user_uuid' => $this->when(Http::isInternalRequest(), $this->user_uuid),
29
+ 'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid),
30
+ 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
31
+ 'internal_id' => $this->internal_id,
32
+ 'name' => $this->name,
33
+ 'title' => $this->title,
34
+ 'photo_url' => $this->photo_url,
35
+ 'email' => $this->email,
36
+ 'phone' => $this->phone,
37
+ 'address' => data_get($this, 'place.address'),
38
+ 'addresses' => $this->whenLoaded('places', fn () => Place::collection($this->places)),
39
+ 'token' => $this->when($this->token, $this->token),
40
+ 'orders_count' => $this->getOrdersCount($request),
41
+ 'company' => $this->when($this->company_uuid, fn () => $this->buildCompanyPayload()),
42
+ 'meta' => data_get($this, 'meta', Utils::createObject()),
43
+ 'slug' => $this->slug,
44
+ 'created_at' => $this->created_at,
45
+ 'updated_at' => $this->updated_at,
46
+ ];
47
+ }
48
+
49
+ private function getOrdersCount(Request $request): int
50
+ {
51
+ return Order::where('customer_uuid', $this->uuid)
52
+ ->whereNull('deleted_at')
53
+ ->withoutGlobalScopes()
54
+ ->count();
55
+ }
56
+
57
+ /**
58
+ * Public-safe projection of the customer's company. Returns the same
59
+ * fields any caller could fetch through other public endpoints — name,
60
+ * resolved currency, country, phone — plus the company's public id.
61
+ * Currency falls back through company.currency → ledger base_currency
62
+ * → "USD" via {@see Utils::getCompanyTransactionCurrency}.
63
+ */
64
+ private function buildCompanyPayload(): ?array
65
+ {
66
+ $company = Company::find($this->company_uuid);
67
+ if (!$company) {
68
+ return null;
69
+ }
70
+
71
+ return [
72
+ 'id' => $company->public_id,
73
+ 'name' => $company->name,
74
+ 'currency' => Utils::getCompanyTransactionCurrency($company),
75
+ 'country' => $company->country,
76
+ 'phone' => $company->phone,
77
+ ];
78
+ }
79
+ }
@@ -44,9 +44,10 @@ class Order extends FleetbaseResource
44
44
  $isInternal,
45
45
  $this->whenLoaded('orderConfig', function () {
46
46
  return [
47
- 'id' => $this->orderConfig->public_id,
48
- 'name' => $this->orderConfig->name,
49
- 'key' => $this->orderConfig->key,
47
+ 'uuid' => $this->orderConfig->uuid,
48
+ 'public_id' => $this->orderConfig->public_id,
49
+ 'name' => $this->orderConfig->name,
50
+ 'key' => $this->orderConfig->key,
50
51
  ];
51
52
  })
52
53
  ),
@@ -104,12 +105,14 @@ class Order extends FleetbaseResource
104
105
  }),
105
106
 
106
107
  // Essential scalar fields
107
- 'type' => $this->type,
108
- 'status' => $this->status,
109
- 'adhoc' => (bool) data_get($this, 'adhoc', false),
110
- 'dispatched' => (bool) data_get($this, 'dispatched', false),
111
- 'has_driver_assigned' => $this->when($isInternal, $this->has_driver_assigned),
112
- 'is_scheduled' => $this->when($isInternal, $this->is_scheduled),
108
+ 'type' => $this->type,
109
+ 'status' => $this->status,
110
+ 'adhoc' => (bool) data_get($this, 'adhoc', false),
111
+ 'dispatched' => (bool) data_get($this, 'dispatched', false),
112
+ 'has_driver_assigned' => $this->when($isInternal, $this->has_driver_assigned),
113
+ 'is_scheduled' => $this->when($isInternal, $this->is_scheduled),
114
+ 'transaction_amount' => $this->transaction_amount,
115
+ 'currency' => $this->transaction_currency,
113
116
 
114
117
  // Timestamps
115
118
  'scheduled_at' => $this->scheduled_at,
@@ -3,6 +3,7 @@
3
3
  namespace Fleetbase\FleetOps\Http\Resources\v1;
4
4
 
5
5
  use Fleetbase\FleetOps\Support\Utils;
6
+ use Fleetbase\Http\Resources\File;
6
7
  use Fleetbase\Http\Resources\FleetbaseResource;
7
8
  use Fleetbase\Http\Resources\User;
8
9
  use Fleetbase\LaravelMysqlSpatial\Types\Point;
@@ -26,12 +27,15 @@ class Issue extends FleetbaseResource
26
27
  'driver_uuid' => $this->when(Http::isInternalRequest(), $this->driver_uuid),
27
28
  'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid),
28
29
  'vehicle_uuid' => $this->when(Http::isInternalRequest(), $this->vehicle_uuid),
30
+ 'order_uuid' => $this->when(Http::isInternalRequest(), $this->order_uuid ?? data_get($this, 'meta.order_uuid')),
29
31
  'assigned_to_uuid' => $this->when(Http::isInternalRequest(), $this->assigned_to_uuid),
30
32
  'reported_by_uuid' => $this->when(Http::isInternalRequest(), $this->reported_by_uuid),
31
33
  'assignee' => $this->whenLoaded('assignee', fn () => new User($this->assignee)),
32
34
  'reporter' => $this->whenLoaded('reporter', fn () => new User($this->reporter)),
33
35
  'vehicle' => $this->whenLoaded('vehicle', fn () => new Vehicle($this->vehicle)),
34
36
  'driver' => $this->whenLoaded('driver', fn () => new Driver($this->driver)),
37
+ 'order' => $this->when(Http::isInternalRequest(), fn () => $this->resolveLinkedOrder()),
38
+ 'files' => $this->whenLoaded('files', fn () => File::collection($this->files)),
35
39
  'driver_name' => $this->driver_name,
36
40
  'vehicle_name' => $this->vehicle_name,
37
41
  'vehicle_id' => $this->vehicle_id,
@@ -55,6 +59,27 @@ class Issue extends FleetbaseResource
55
59
  ]);
56
60
  }
57
61
 
62
+ protected function resolveLinkedOrder()
63
+ {
64
+ if ($this->relationLoaded('order') && $this->order) {
65
+ $this->order->loadMissing(['payload.pickup', 'payload.dropoff', 'trackingNumber', 'customer']);
66
+
67
+ return new Order($this->order);
68
+ }
69
+
70
+ $orderUuid = $this->order_uuid ?? data_get($this, 'meta.order_uuid');
71
+ if (!$orderUuid) {
72
+ return null;
73
+ }
74
+
75
+ $order = \Fleetbase\FleetOps\Models\Order::with(['payload.pickup', 'payload.dropoff', 'trackingNumber', 'customer'])
76
+ ->where('uuid', $orderUuid)
77
+ ->where('company_uuid', $this->company_uuid)
78
+ ->first();
79
+
80
+ return $order ? new Order($order) : null;
81
+ }
82
+
58
83
  /**
59
84
  * Transform the resource into an webhook payload.
60
85
  *
@@ -73,24 +73,26 @@ class Order extends FleetbaseResource
73
73
  'tracking_statuses' => $this->whenLoaded('trackingStatuses', function () {
74
74
  return TrackingStatus::collection($this->trackingStatuses);
75
75
  }),
76
- 'tracking' => $this->when($isInternal, $this->trackingNumber ? $this->trackingNumber->tracking_number : null),
77
- 'barcode' => $this->when($isInternal, $this->trackingNumber ? $this->trackingNumber->barcode : null),
78
- 'qr_code' => $this->when($isInternal, $this->trackingNumber ? $this->trackingNumber->qr_code : null),
79
- 'comments' => $this->when($isInternal, Comment::collection($this->comments)),
80
- 'files' => $this->when($isInternal, $this->files, File::collection($this->files)),
81
- 'purchase_rate' => new PurchaseRate($this->purchaseRate),
82
- 'notes' => $this->notes,
83
- 'type' => $this->type,
84
- 'status' => $this->status,
85
- 'pod_method' => $this->pod_method,
86
- 'pod_required' => (bool) data_get($this, 'pod_required', false),
87
- 'dispatched' => (bool) data_get($this, 'dispatched', false),
88
- 'started' => (bool) data_get($this, 'started', false),
89
- 'adhoc' => (bool) data_get($this, 'adhoc', false),
90
- 'adhoc_distance' => (int) $this->getAdhocDistance(),
91
- 'distance' => (int) $this->distance,
92
- 'time' => (int) $this->time,
93
- 'tracker_data' => $this->when($withTrackerData, function () use ($tracker) {
76
+ 'tracking' => $this->when($isInternal, $this->trackingNumber ? $this->trackingNumber->tracking_number : null),
77
+ 'barcode' => $this->when($isInternal, $this->trackingNumber ? $this->trackingNumber->barcode : null),
78
+ 'qr_code' => $this->when($isInternal, $this->trackingNumber ? $this->trackingNumber->qr_code : null),
79
+ 'comments' => $this->when($isInternal, Comment::collection($this->comments)),
80
+ 'files' => $this->when($isInternal, $this->files, File::collection($this->files)),
81
+ 'purchase_rate' => new PurchaseRate($this->purchaseRate),
82
+ 'notes' => $this->notes,
83
+ 'type' => $this->type,
84
+ 'status' => $this->status,
85
+ 'pod_method' => $this->pod_method,
86
+ 'pod_required' => (bool) data_get($this, 'pod_required', false),
87
+ 'dispatched' => (bool) data_get($this, 'dispatched', false),
88
+ 'started' => (bool) data_get($this, 'started', false),
89
+ 'adhoc' => (bool) data_get($this, 'adhoc', false),
90
+ 'adhoc_distance' => (int) $this->getAdhocDistance(),
91
+ 'distance' => (int) $this->distance,
92
+ 'time' => (int) $this->time,
93
+ 'transaction_amount' => $this->transaction_amount,
94
+ 'currency' => $this->transaction_currency,
95
+ 'tracker_data' => $this->when($withTrackerData, function () use ($tracker) {
94
96
  return $this->resource->tracker_data ?? ($tracker ? $tracker->toArray() : null);
95
97
  }),
96
98
  'eta' => $this->when($withEta, function () use ($tracker) {
@@ -0,0 +1,74 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Http\Resources\v1;
4
+
5
+ use Fleetbase\Http\Resources\FleetbaseResource;
6
+ use Fleetbase\Support\Http;
7
+
8
+ /**
9
+ * Public, read-only projection of an OrderConfig.
10
+ *
11
+ * Exposes the activity `flow` so consumers can render status filter chips,
12
+ * activity labels, and progress UI without learning the internal config
13
+ * schema. Internal-only fields (entities JSON, version, namespace columns
14
+ * that aren't part of the public contract) are filtered out.
15
+ */
16
+ class OrderConfig extends FleetbaseResource
17
+ {
18
+ /**
19
+ * Transform the resource into an array.
20
+ *
21
+ * @param \Illuminate\Http\Request $request
22
+ */
23
+ public function toArray($request): array
24
+ {
25
+ return [
26
+ 'id' => $this->when(Http::isInternalRequest(), $this->id, $this->public_id),
27
+ 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
28
+ 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
29
+ 'company_uuid' => $this->when(Http::isInternalRequest(), $this->company_uuid),
30
+ 'key' => $this->key,
31
+ 'name' => $this->name,
32
+ 'namespace' => $this->namespace,
33
+ 'description' => $this->description,
34
+ 'tags' => $this->tags,
35
+ 'status' => $this->status,
36
+ 'version' => $this->version,
37
+ 'flow' => $this->projectFlow(),
38
+ 'created_at' => $this->created_at,
39
+ 'updated_at' => $this->updated_at,
40
+ ];
41
+ }
42
+
43
+ /**
44
+ * Project the flow JSON into an ordered list of activities, keeping only
45
+ * the public-safe per-activity fields. `code` and `status` (the label)
46
+ * are the contract; `complete`, `color`, `details`, `pod_method`, and
47
+ * `require_pod` are useful UI hints that can ride along.
48
+ */
49
+ protected function projectFlow(): array
50
+ {
51
+ $flow = $this->flow;
52
+ if (!is_array($flow) || empty($flow)) {
53
+ return [];
54
+ }
55
+
56
+ $activities = [];
57
+ foreach ($flow as $activity) {
58
+ if (!is_array($activity)) {
59
+ continue;
60
+ }
61
+ $activities[] = [
62
+ 'code' => $activity['code'] ?? ($activity['key'] ?? null),
63
+ 'status' => $activity['status'] ?? null,
64
+ 'details' => $activity['details'] ?? null,
65
+ 'color' => $activity['color'] ?? null,
66
+ 'complete' => (bool) ($activity['complete'] ?? false),
67
+ 'pod_method' => $activity['pod_method'] ?? null,
68
+ 'require_pod' => (bool) ($activity['require_pod'] ?? false),
69
+ ];
70
+ }
71
+
72
+ return $activities;
73
+ }
74
+ }
@@ -22,26 +22,29 @@ class Payload extends FleetbaseResource
22
22
  $withRouteETA = $request->has('with_route_eta');
23
23
 
24
24
  return [
25
- 'id' => $this->when(Http::isInternalRequest(), $this->id, $this->public_id),
26
- 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
27
- 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
28
- 'current_waypoint_uuid' => $this->when(Http::isInternalRequest(), $this->current_waypoint_uuid),
29
- 'pickup_uuid' => $this->when(Http::isInternalRequest(), $this->pickup_uuid),
30
- 'dropoff_uuid' => $this->when(Http::isInternalRequest(), $this->dropoff_uuid),
31
- 'return_uuid' => $this->when(Http::isInternalRequest(), $this->return_uuid),
32
- 'current_waypoint' => $this->when(Http::isPublicRequest() && $this->currentWaypoint, data_get($this, 'currentWaypoint.public_id')),
33
- 'pickup' => $this->getPlace($this->pickup),
34
- 'dropoff' => $this->getPlace($this->dropoff),
35
- 'return' => new Place($this->return),
36
- 'waypoints' => Waypoint::collection($this->getWaypoints($withRouteETA)),
37
- 'entities' => Entity::collection($this->entities),
38
- 'cod_amount' => $this->cod_amount ?? null,
39
- 'cod_currency' => $this->cod_currency ?? null,
40
- 'cod_payment_method' => $this->cod_payment_method ?? null,
41
- 'payment_method' => $this->payment_method ?? null,
42
- 'meta' => data_get($this, 'meta', Utils::createObject()),
43
- 'updated_at' => $this->updated_at,
44
- 'created_at' => $this->created_at,
25
+ 'id' => $this->when(Http::isInternalRequest(), $this->id, $this->public_id),
26
+ 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
27
+ 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
28
+ 'current_waypoint_uuid' => $this->when(Http::isInternalRequest(), $this->current_waypoint_uuid),
29
+ 'pickup_uuid' => $this->when(Http::isInternalRequest(), $this->pickup_uuid),
30
+ 'pickup_tracking_number_uuid' => $this->when(Http::isInternalRequest(), $this->pickup_tracking_number_uuid),
31
+ 'dropoff_uuid' => $this->when(Http::isInternalRequest(), $this->dropoff_uuid),
32
+ 'dropoff_tracking_number_uuid' => $this->when(Http::isInternalRequest(), $this->dropoff_tracking_number_uuid),
33
+ 'return_uuid' => $this->when(Http::isInternalRequest(), $this->return_uuid),
34
+ 'return_tracking_number_uuid' => $this->when(Http::isInternalRequest(), $this->return_tracking_number_uuid),
35
+ 'current_waypoint' => $this->when(Http::isPublicRequest() && $this->currentWaypoint, data_get($this, 'currentWaypoint.public_id')),
36
+ 'pickup' => $this->getPlace($this->pickup),
37
+ 'dropoff' => $this->getPlace($this->dropoff),
38
+ 'return' => new Place($this->return),
39
+ 'waypoints' => Waypoint::collection($this->getWaypoints($withRouteETA)),
40
+ 'entities' => Entity::collection($this->entities),
41
+ 'cod_amount' => $this->cod_amount ?? null,
42
+ 'cod_currency' => $this->cod_currency ?? null,
43
+ 'cod_payment_method' => $this->cod_payment_method ?? null,
44
+ 'payment_method' => $this->payment_method ?? null,
45
+ 'meta' => data_get($this, 'meta', Utils::createObject()),
46
+ 'updated_at' => $this->updated_at,
47
+ 'created_at' => $this->created_at,
45
48
  ];
46
49
  }
47
50
 
@@ -17,17 +17,24 @@ class ServiceArea extends FleetbaseResource
17
17
  public function toArray($request)
18
18
  {
19
19
  return $this->withCustomFields([
20
- 'id' => $this->when(Http::isInternalRequest(), $this->id, $this->public_id),
21
- 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
22
- 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
23
- 'name' => $this->name,
24
- 'type' => $this->type,
25
- 'center' => $this->location,
26
- 'border' => $this->border,
27
- 'zones' => $this->whenLoaded('zones', fn () => Zone::collection($this->zones)),
28
- 'status' => $this->status,
29
- 'updated_at' => $this->updated_at,
30
- 'created_at' => $this->created_at,
20
+ 'id' => $this->when(Http::isInternalRequest(), $this->id, $this->public_id),
21
+ 'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
22
+ 'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
23
+ 'name' => $this->name,
24
+ 'type' => $this->type,
25
+ 'center' => $this->location,
26
+ 'border' => $this->border,
27
+ 'zones' => $this->whenLoaded('zones', fn () => Zone::collection($this->zones)),
28
+ 'color' => $this->color,
29
+ 'stroke_color' => $this->stroke_color,
30
+ 'trigger_on_entry' => $this->trigger_on_entry,
31
+ 'trigger_on_exit' => $this->trigger_on_exit,
32
+ 'dwell_threshold_minutes' => $this->dwell_threshold_minutes,
33
+ 'speed_limit_kmh' => $this->speed_limit_kmh,
34
+ 'country' => $this->country,
35
+ 'status' => $this->status,
36
+ 'updated_at' => $this->updated_at,
37
+ 'created_at' => $this->created_at,
31
38
  ]);
32
39
  }
33
40
 
@@ -39,14 +46,21 @@ class ServiceArea extends FleetbaseResource
39
46
  public function toWebhookPayload()
40
47
  {
41
48
  return [
42
- 'id' => $this->public_id,
43
- 'name' => $this->name,
44
- 'type' => $this->type,
45
- 'center' => $this->location,
46
- 'border' => $this->border,
47
- 'status' => $this->status,
48
- 'updated_at' => $this->updated_at,
49
- 'created_at' => $this->created_at,
49
+ 'id' => $this->public_id,
50
+ 'name' => $this->name,
51
+ 'type' => $this->type,
52
+ 'center' => $this->location,
53
+ 'border' => $this->border,
54
+ 'color' => $this->color,
55
+ 'stroke_color' => $this->stroke_color,
56
+ 'trigger_on_entry' => $this->trigger_on_entry,
57
+ 'trigger_on_exit' => $this->trigger_on_exit,
58
+ 'dwell_threshold_minutes' => $this->dwell_threshold_minutes,
59
+ 'speed_limit_kmh' => $this->speed_limit_kmh,
60
+ 'country' => $this->country,
61
+ 'status' => $this->status,
62
+ 'updated_at' => $this->updated_at,
63
+ 'created_at' => $this->created_at,
50
64
  ];
51
65
  }
52
66
  }
@@ -20,6 +20,13 @@ class ServiceRateFee extends FleetbaseResource
20
20
  'id' => $this->when(Http::isInternalRequest(), $this->id),
21
21
  'uuid' => $this->when(Http::isInternalRequest(), $this->uuid),
22
22
  'service_rate_uuid' => $this->when(Http::isInternalRequest(), $this->service_rate_uuid),
23
+ 'service_area_uuid' => $this->when(Http::isInternalRequest(), $this->service_area_uuid),
24
+ 'zone_uuid' => $this->when(Http::isInternalRequest(), $this->zone_uuid),
25
+ 'service_area' => $this->whenLoaded('serviceArea', fn () => new ServiceArea($this->serviceArea)),
26
+ 'zone' => $this->whenLoaded('zone', fn () => new Zone($this->zone)),
27
+ 'label' => $this->label,
28
+ 'priority' => $this->priority,
29
+ 'is_fallback' => (bool) $this->is_fallback,
23
30
  'fee' => $this->fee,
24
31
  'currency' => $this->currency,
25
32
  'min' => $this->min,
@@ -69,11 +69,11 @@ class HandleOrderDispatched implements ShouldQueue
69
69
  return;
70
70
  }
71
71
 
72
- $drivers = Driver::where(['status' => 'active', 'online' => 1])
72
+ $drivers = Driver::where(['status' => 'available', 'online' => 1])
73
73
  ->whereHas('company', function ($q) {
74
74
  $q->whereHas('users', function ($q) {
75
75
  $q->whereHas('driver', function ($q) {
76
- $q->where(['status' => 'active', 'online' => 1]);
76
+ $q->where(['status' => 'available', 'online' => 1]);
77
77
  $q->whereNull('deleted_at');
78
78
  });
79
79
  });
@@ -45,7 +45,7 @@ class CustomerCredentialsMail extends Mailable
45
45
  $this->customer->loadMissing('company');
46
46
 
47
47
  return new Envelope(
48
- subject: 'Your login credentials for ' . $this->customer->company->name . ' on ' . config('app.name'),
48
+ subject: 'Your ' . $this->customer->company->name . ' customer portal access is ready',
49
49
  );
50
50
  }
51
51
 
@@ -63,19 +63,18 @@ class CustomerCredentialsMail extends Mailable
63
63
  'customer' => $this->customer,
64
64
  'plaintextPassword' => $this->plaintextPassword,
65
65
  'customerPortalUrl' => $this->getCustomerPortalAccessUrl(),
66
- 'currentHour' => now()->hour,
67
66
  ]
68
67
  );
69
68
  }
70
69
 
71
70
  /**
72
- * Get the customer portal URL if available.
71
+ * Get the customer portal URL.
73
72
  */
74
- private function getCustomerPortalAccessUrl(): ?string
73
+ private function getCustomerPortalAccessUrl(): string
75
74
  {
76
75
  $customerPortalConfig = Setting::lookupFromCompany('customer-portal-config');
77
- $accessUrlSlug = data_get($customerPortalConfig, 'accessUrlSlug');
76
+ $accessUrlSlug = data_get($customerPortalConfig, 'accessUrlSlug', 'customer-portal');
78
77
 
79
- return $accessUrlSlug ? Utils::consoleUrl($accessUrlSlug) : null;
78
+ return Utils::consoleUrl($accessUrlSlug ?: 'customer-portal');
80
79
  }
81
80
  }