@fleetbase/fleetops-engine 0.3.5 → 0.3.7

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 (124) hide show
  1. package/README.md +4 -4
  2. package/addon/components/admin/navigator-app.hbs +8 -0
  3. package/addon/components/admin/navigator-app.js +27 -0
  4. package/addon/components/driver-form-panel.js +13 -19
  5. package/addon/components/leaflet-draw-control.js +2 -3
  6. package/addon/components/live-map.js +7 -4
  7. package/addon/components/modals/driver-assign-order.hbs +2 -2
  8. package/addon/components/modals/order-import.hbs +5 -5
  9. package/addon/components/modals/order-new-activity.hbs +1 -1
  10. package/addon/components/order-config/entities-editor.js +3 -5
  11. package/addon/components/route-list.hbs +2 -2
  12. package/addon/components/vendor-form-panel.js +1 -1
  13. package/addon/controllers/application.js +2 -2
  14. package/addon/controllers/base-controller.js +31 -0
  15. package/addon/controllers/management/contacts/index/details.js +2 -2
  16. package/addon/controllers/management/contacts/index/edit.js +2 -2
  17. package/addon/controllers/management/contacts/index/new.js +2 -2
  18. package/addon/controllers/management/contacts/index.js +2 -2
  19. package/addon/controllers/management/drivers/index/details.js +2 -2
  20. package/addon/controllers/management/drivers/index/edit.js +2 -2
  21. package/addon/controllers/management/drivers/index/new.js +2 -2
  22. package/addon/controllers/management/drivers/index.js +11 -24
  23. package/addon/controllers/management/fleets/index/details.js +2 -2
  24. package/addon/controllers/management/fleets/index/edit.js +2 -2
  25. package/addon/controllers/management/fleets/index/new.js +2 -2
  26. package/addon/controllers/management/fleets/index.js +9 -9
  27. package/addon/controllers/management/fuel-reports/index/details.js +2 -2
  28. package/addon/controllers/management/fuel-reports/index/edit.js +2 -2
  29. package/addon/controllers/management/fuel-reports/index/new.js +2 -2
  30. package/addon/controllers/management/fuel-reports/index.js +2 -2
  31. package/addon/controllers/management/issues/index/details.js +2 -2
  32. package/addon/controllers/management/issues/index/edit.js +2 -2
  33. package/addon/controllers/management/issues/index/new.js +2 -2
  34. package/addon/controllers/management/issues/index.js +2 -9
  35. package/addon/controllers/management/places/index/details.js +2 -2
  36. package/addon/controllers/management/places/index/edit.js +2 -2
  37. package/addon/controllers/management/places/index/new.js +2 -2
  38. package/addon/controllers/management/places/index.js +2 -2
  39. package/addon/controllers/management/vehicles/index/details.js +2 -2
  40. package/addon/controllers/management/vehicles/index/edit.js +2 -2
  41. package/addon/controllers/management/vehicles/index/new.js +2 -2
  42. package/addon/controllers/management/vehicles/index.js +11 -12
  43. package/addon/controllers/management/vendors/index/details.js +2 -2
  44. package/addon/controllers/management/vendors/index/edit.js +2 -2
  45. package/addon/controllers/management/vendors/index/new.js +2 -2
  46. package/addon/controllers/management/vendors/index.js +2 -8
  47. package/addon/controllers/management.js +2 -2
  48. package/addon/controllers/operations/orders/index/config/types.js +2 -2
  49. package/addon/controllers/operations/orders/index/config.js +2 -2
  50. package/addon/controllers/operations/orders/index/new.js +64 -44
  51. package/addon/controllers/operations/orders/index/view.js +11 -4
  52. package/addon/controllers/operations/orders/index.js +2 -2
  53. package/addon/controllers/operations/scheduler/index.js +2 -2
  54. package/addon/controllers/operations/service-rates/index/edit.js +12 -18
  55. package/addon/controllers/operations/service-rates/index/new.js +16 -22
  56. package/addon/controllers/operations/service-rates/index.js +2 -2
  57. package/addon/engine.js +6 -0
  58. package/addon/helpers/waypoint-label.js +6 -1
  59. package/addon/routes/application.js +4 -15
  60. package/addon/routes/management/contacts/index.js +9 -5
  61. package/addon/routes/management/drivers/index.js +7 -3
  62. package/addon/routes/management/fleets/index.js +9 -5
  63. package/addon/routes/management/fuel-reports/index.js +9 -5
  64. package/addon/routes/management/issues/index.js +9 -5
  65. package/addon/routes/management/places/index.js +9 -5
  66. package/addon/routes/management/vehicles/index/details.js +2 -2
  67. package/addon/routes/management/vehicles/index.js +9 -0
  68. package/addon/routes/management/vendors/index.js +9 -6
  69. package/addon/routes/operations/orders/index/view.js +6 -2
  70. package/addon/routes/operations/orders/index.js +7 -1
  71. package/addon/routes/operations/orders.js +0 -1
  72. package/addon/routes/operations/service-rates/index.js +9 -27
  73. package/addon/routes/operations/service-rates.js +1 -8
  74. package/addon/styles/fleetops-engine.css +14 -7
  75. package/addon/templates/operations/orders/index/new.hbs +7 -7
  76. package/addon/templates/operations/orders/index/view.hbs +17 -16
  77. package/addon/utils/waypoint-label.js +3 -0
  78. package/app/controllers/{operations/zones/index.js → base-controller.js} +1 -1
  79. package/app/utils/waypoint-label.js +1 -0
  80. package/composer.json +2 -2
  81. package/config/environment.js +11 -1
  82. package/extension.json +1 -1
  83. package/index.js +1 -0
  84. package/package.json +47 -41
  85. package/server/config/fleetops.php +4 -1
  86. package/server/migrations/2023_11_28_074244_add_supplier_uuid_column_to_entities_table.php +33 -0
  87. package/server/migrations/2023_12_14_100209_add_meta_column_on_driver_table.php +30 -0
  88. package/server/src/Http/Controllers/Api/v1/DriverController.php +14 -10
  89. package/server/src/Http/Controllers/Api/v1/OrderController.php +118 -42
  90. package/server/src/Http/Controllers/Api/v1/PayloadController.php +41 -43
  91. package/server/src/Http/Controllers/Api/v1/TrackingStatusController.php +43 -2
  92. package/server/src/Http/Controllers/Internal/v1/DriverController.php +148 -0
  93. package/server/src/Http/Controllers/Internal/v1/MorphController.php +48 -16
  94. package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +79 -0
  95. package/server/src/Http/Controllers/Internal/v1/OrderController.php +3 -2
  96. package/server/src/Http/Controllers/Internal/v1/PlaceController.php +2 -2
  97. package/server/src/Http/Requests/CreateDriverRequest.php +2 -0
  98. package/server/src/Http/Requests/CreateOrderRequest.php +18 -4
  99. package/server/src/Http/Requests/CreatePayloadRequest.php +23 -7
  100. package/server/src/Http/Requests/CreatePlaceRequest.php +9 -5
  101. package/server/src/Http/Requests/CreateTrackingStatusRequest.php +69 -12
  102. package/server/src/Http/Requests/CreateVehicleRequest.php +5 -3
  103. package/server/src/Http/Resources/v1/Entity.php +3 -0
  104. package/server/src/Http/Resources/v1/Order.php +3 -2
  105. package/server/src/Models/Driver.php +5 -2
  106. package/server/src/Models/Entity.php +1 -1
  107. package/server/src/Models/Order.php +2 -2
  108. package/server/src/Models/Payload.php +27 -9
  109. package/server/src/Models/Place.php +28 -5
  110. package/server/src/Models/TrackingStatus.php +9 -3
  111. package/server/src/Models/VehicleDevice.php +28 -0
  112. package/server/src/Models/Vendor.php +16 -0
  113. package/server/src/Observers/DriverObserver.php +1 -1
  114. package/server/src/routes.php +62 -0
  115. package/tsconfig.declarations.json +10 -0
  116. package/addon/components/file-icon.js +0 -1
  117. package/addon/controllers/operations/zones/index.js +0 -475
  118. package/addon/routes/operations/dispatch.js +0 -3
  119. package/addon/routes/operations/zones/index.js +0 -25
  120. package/addon/routes/operations/zones.js +0 -7
  121. package/addon/templates/operations/dispatch.hbs +0 -1
  122. package/addon/templates/operations/zones/index.hbs +0 -72
  123. package/addon/templates/operations/zones.hbs +0 -1
  124. package/app/components/file-icon.js +0 -1
@@ -7,10 +7,9 @@ use Fleetbase\FleetOps\Http\Requests\UpdatePayloadRequest;
7
7
  use Fleetbase\FleetOps\Http\Resources\v1\DeletedResource;
8
8
  use Fleetbase\FleetOps\Http\Resources\v1\Payload as PayloadResource;
9
9
  use Fleetbase\FleetOps\Models\Payload;
10
- use Fleetbase\FleetOps\Models\Place;
11
- use Fleetbase\FleetOps\Models\Waypoint;
12
10
  use Fleetbase\Http\Controllers\Controller;
13
11
  use Illuminate\Http\Request;
12
+ use Illuminate\Support\Arr;
14
13
 
15
14
  // use Fleetbase\FleetOps\Support\Utils;
16
15
 
@@ -25,41 +24,42 @@ class PayloadController extends Controller
25
24
  */
26
25
  public function create(CreatePayloadRequest $request)
27
26
  {
28
- // get request input
29
- $input = $request->only(['pickup', 'dropoff', 'type', 'return', 'waypoints', 'customer', 'meta', 'cod_amount', 'cod_currency', 'cod_payment_method']);
27
+ $input = $request->all();
28
+ $entities = data_get($input, 'entities', []);
29
+ $waypoints = data_get($input, 'waypoints', []);
30
+ $pickup = data_get($input, 'pickup');
31
+ $dropoff = data_get($input, 'dropoff');
32
+ $return = data_get($input, 'return');
30
33
 
31
34
  // make sure company is set
32
35
  $input['company_uuid'] = session('company');
33
36
 
34
37
  // create the payload
35
- $payload = new Payload($input);
38
+ $payload = new Payload(Arr::only($input, ['type', 'provider', 'meta', 'cod_amount', 'cod_currency', 'cod_payment_method']));
39
+
40
+ // if no pickup and dropoff extract from waypoints
41
+ if (empty($pickup) && empty($dropoff) && count($waypoints)) {
42
+ $pickup = array_shift($waypoints);
43
+ $dropoff = array_pop($waypoints);
44
+ }
36
45
 
37
46
  // set pickup point
38
- $payload->setPickup($request->input('pickup'));
47
+ $payload->setPickup($pickup);
39
48
 
40
49
  // set dropoff point
41
- $payload->setDropoff($request->input('dropoff'));
50
+ $payload->setDropoff($dropoff);
42
51
 
43
52
  // set return point
44
- $payload->setReturn($request->input('return'));
53
+ $payload->setReturn($return);
45
54
 
46
55
  // save payload
47
56
  $payload->save();
48
57
 
49
58
  // set waypoints
50
- if ($request->has('waypoints') && is_array($request->input('waypoints'))) {
51
- foreach ($request->input('waypoints') as $index => $place) {
52
- // get place
53
- $id = Place::createFromMixed($place);
54
-
55
- // create waypoint
56
- Waypoint::create([
57
- 'place_uuid' => $id,
58
- 'payload_uuid' => $payload->uuid,
59
- 'order' => $index,
60
- ]);
61
- }
62
- }
59
+ $payload->setWaypoints($waypoints);
60
+
61
+ // set entities
62
+ $payload->setEntities($entities);
63
63
 
64
64
  // response the driver resource
65
65
  return new PayloadResource($payload);
@@ -88,42 +88,40 @@ class PayloadController extends Controller
88
88
  }
89
89
 
90
90
  // get request input
91
- $input = $request->only(['pickup', 'dropoff', 'type', 'return', 'waypoints', 'customer', 'meta', 'cod_amount', 'cod_currency', 'cod_payment_method']);
91
+ $input = $request->all();
92
+ $entities = data_get($input, 'entities', []);
93
+ $waypoints = data_get($input, 'waypoints', []);
94
+ $pickup = data_get($input, 'pickup');
95
+ $dropoff = data_get($input, 'dropoff');
96
+ $return = data_get($input, 'return');
92
97
 
93
98
  // pickup assignment
94
- if ($request->has('pickup')) {
95
- $payload->setPickup($request->input('pickup'));
99
+ if ($pickup) {
100
+ $payload->setPickup($pickup);
96
101
  }
97
102
 
98
103
  // dropoff assignment
99
- if ($request->has('dropoff')) {
100
- $payload->setDropoff($request->input('dropoff'));
104
+ if ($dropoff) {
105
+ $payload->setDropoff($dropoff);
101
106
  }
102
107
 
103
108
  // return assignment
104
- if ($request->has('return')) {
105
- $payload->setReturn($request->input('return'));
109
+ if ($return) {
110
+ $payload->setReturn($return);
106
111
  }
107
112
 
108
113
  // set waypoints
109
- if ($request->has('waypoints') && is_array($request->input('waypoints'))) {
110
- $waypointCount = $payload->waypoints->count() ?? 0;
111
-
112
- foreach ($request->input('waypoints') as $index => $place) {
113
- // get place
114
- $id = Place::createFromMixed($place);
115
-
116
- // create waypoint
117
- Waypoint::create([
118
- 'place_uuid' => $id,
119
- 'payload_uuid' => $payload->uuid,
120
- 'order' => $index + $waypointCount,
121
- ]);
122
- }
114
+ if ($waypoints) {
115
+ $payload->setWaypoints($waypoints);
116
+ }
117
+
118
+ // set entities
119
+ if ($entities) {
120
+ $payload->setEntities($entities);
123
121
  }
124
122
 
125
123
  // update the payload
126
- $payload->fill($input);
124
+ $payload->fill(array_filter(Arr::only($input, ['type', 'provider', 'meta', 'cod_amount', 'cod_currency', 'cod_payment_method'])));
127
125
 
128
126
  // save the payload
129
127
  $payload->save();
@@ -6,9 +6,11 @@ use Fleetbase\FleetOps\Http\Requests\CreateTrackingStatusRequest;
6
6
  use Fleetbase\FleetOps\Http\Requests\UpdateTrackingStatusRequest;
7
7
  use Fleetbase\FleetOps\Http\Resources\v1\DeletedResource;
8
8
  use Fleetbase\FleetOps\Http\Resources\v1\TrackingStatus as TrackingStatusResource;
9
+ use Fleetbase\FleetOps\Models\Order;
9
10
  use Fleetbase\FleetOps\Models\TrackingStatus;
10
11
  use Fleetbase\FleetOps\Support\Utils;
11
12
  use Fleetbase\Http\Controllers\Controller;
13
+ use Grimzy\LaravelMysqlSpatial\Types\Point;
12
14
  use Illuminate\Http\Request;
13
15
 
14
16
  class TrackingStatusController extends Controller
@@ -23,7 +25,24 @@ class TrackingStatusController extends Controller
23
25
  public function create(CreateTrackingStatusRequest $request)
24
26
  {
25
27
  // get request input
26
- $input = $request->only(['status', 'details', 'code', 'city', 'province', 'postal_code', 'country', 'latitude', 'longitude']);
28
+ $input = $request->only(['status', 'details', 'code', 'city', 'province', 'postal_code', 'country', 'location', 'latitude', 'longitude']);
29
+
30
+ // if no location provided but latitude/longitude
31
+ if (empty($input['location']) && isset($input['latitude']) && isset($input['longitude'])) {
32
+ $latitude = data_get($input, 'latitude');
33
+ $longitude = data_get($input, 'longitude');
34
+
35
+ // unset latitude and longitude
36
+ unset($input['latitude'], $input['longitude']);
37
+
38
+ // create location
39
+ $input['location'] = new Point($latitude, $longitude);
40
+ }
41
+
42
+ // if no code set create a code from the status
43
+ if (empty($input['code'])) {
44
+ $input['code'] = TrackingStatus::prepareCode($input['status']);
45
+ }
27
46
 
28
47
  // make sure company is set
29
48
  $input['company_uuid'] = session('company');
@@ -36,6 +55,11 @@ class TrackingStatusController extends Controller
36
55
  ]);
37
56
  }
38
57
 
58
+ // tracking number assignment
59
+ if ($request->has('order')) {
60
+ $input['tracking_number_uuid'] = Order::where('public_id', $request->input('order'))->value('tracking_number_uuid');
61
+ }
62
+
39
63
  // create the trackingStatus
40
64
  $trackingStatus = TrackingStatus::create($input);
41
65
 
@@ -66,7 +90,24 @@ class TrackingStatusController extends Controller
66
90
  }
67
91
 
68
92
  // get request input
69
- $input = $request->only(['status', 'details', 'code', 'city', 'province', 'postal_code', 'country', 'latitude', 'longitude']);
93
+ $input = $request->only(['status', 'details', 'code', 'city', 'province', 'postal_code', 'country', 'location', 'latitude', 'longitude']);
94
+
95
+ // if no location provided but latitude/longitude
96
+ if (empty($input['location']) && isset($input['latitude']) && isset($input['longitude'])) {
97
+ $latitude = data_get($input, 'latitude');
98
+ $longitude = data_get($input, 'longitude');
99
+
100
+ // unset latitude and longitude
101
+ unset($input['latitude'], $input['longitude']);
102
+
103
+ // create location
104
+ $input['location'] = new Point($latitude, $longitude);
105
+ }
106
+
107
+ // if no code set create a code from the status
108
+ if (empty($input['code'])) {
109
+ $input['code'] = TrackingStatus::prepareCode($input['status']);
110
+ }
70
111
 
71
112
  // update the trackingStatus
72
113
  $trackingStatus->update($input);
@@ -4,14 +4,18 @@ namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
4
4
 
5
5
  use Fleetbase\Exceptions\FleetbaseRequestValidationException;
6
6
  use Fleetbase\FleetOps\Exports\DriverExport;
7
+ use Fleetbase\FleetOps\Http\Controllers\Api\v1\DriverController as ApiDriverController;
7
8
  use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
9
+ use Fleetbase\FleetOps\Http\Requests\Internal\AssignOrderRequest;
8
10
  use Fleetbase\FleetOps\Http\Requests\Internal\CreateDriverRequest;
9
11
  use Fleetbase\FleetOps\Http\Requests\Internal\UpdateDriverRequest;
10
12
  use Fleetbase\FleetOps\Models\Driver;
13
+ use Fleetbase\FleetOps\Models\Order;
11
14
  use Fleetbase\FleetOps\Support\Utils;
12
15
  use Fleetbase\Http\Requests\ExportRequest;
13
16
  use Fleetbase\Models\Invite;
14
17
  use Fleetbase\Models\User;
18
+ use Fleetbase\Models\VerificationCode;
15
19
  use Fleetbase\Notifications\UserInvited;
16
20
  use Illuminate\Http\Request;
17
21
  use Illuminate\Support\Facades\DB;
@@ -267,4 +271,148 @@ class DriverController extends FleetOpsController
267
271
 
268
272
  return Excel::download(new DriverExport(), $fileName);
269
273
  }
274
+
275
+ /**
276
+ * Assigns a driver to a specified order.
277
+ *
278
+ * @param Fleetbase\FleetOps\Http\Requests\Internal\AssignOrderRequest $request
279
+ *
280
+ * @return \Illuminate\Http\Response $response
281
+ */
282
+ public function assignOrder(AssignOrderRequest $request)
283
+ {
284
+ $driver = Driver::where('public_id', $request->driver)->first();
285
+ $order = Order::where('public_id', $request->order)->first();
286
+
287
+ if ($order->hasDriverAssigned) {
288
+ return response()->error('A driver is already assigned to this order.');
289
+ }
290
+
291
+ if ($order->isDriver($driver)) {
292
+ return response()->error('The driver is already assigned to this order.');
293
+ }
294
+
295
+ $order->assignDriver($driver);
296
+
297
+ return response()->json([
298
+ 'status' => 'ok',
299
+ 'message' => 'Driver assigned',
300
+ ]);
301
+ }
302
+
303
+ /**
304
+ * Update drivers geolocation data.
305
+ *
306
+ * @return \Illuminate\Http\Response
307
+ */
308
+ public function track(string $id, Request $request)
309
+ {
310
+ return app(ApiDriverController::class)->track($id, $request);
311
+ }
312
+
313
+ /**
314
+ * Query for Storefront Customer orders.
315
+ *
316
+ * @return \Fleetbase\Http\Resources\Storefront\Customer
317
+ */
318
+ public function registerDevice(Request $request)
319
+ {
320
+ return app(ApiDriverController::class)->registerDevice($request);
321
+ }
322
+
323
+ /**
324
+ * Authenticates customer using login credentials and returns with auth token.
325
+ *
326
+ * @return \Fleetbase\Http\Resources\Storefront\Customer
327
+ */
328
+ public function login(Request $request)
329
+ {
330
+ return app(ApiDriverController::class)->login($request);
331
+ }
332
+
333
+ /**
334
+ * Attempts authentication with phone number via SMS verification.
335
+ *
336
+ * @return \Illuminate\Http\Response
337
+ */
338
+ public function loginWithPhone()
339
+ {
340
+ $phone = static::phone();
341
+
342
+ // Check if user exists
343
+ $user = User::where('phone', $phone)->whereNull('deleted_at')->withoutGlobalScopes()->first();
344
+
345
+ if (!$user) {
346
+ return response()->error('No driver with this phone # found.');
347
+ }
348
+
349
+ // Generate verification token
350
+ VerificationCode::generateSmsVerificationFor($user, 'driver_login', function ($verification) {
351
+ return 'Your ' . config('app.name') . ' verification code is ' . $verification->code;
352
+ });
353
+
354
+ return response()->json(['status' => 'OK']);
355
+ }
356
+
357
+ /**
358
+ * Verifys SMS code and sends auth token with driver resource.
359
+ *
360
+ * @return \Fleetbase\Http\Resources\FleetOps\Driver
361
+ */
362
+ public function verifyCode(Request $request)
363
+ {
364
+ $identity = Utils::isEmail($request->identity) ? $request->identity : static::phone($request->identity);
365
+ $code = $request->input('code');
366
+ $for = $request->input('for', 'driver_login');
367
+ $attrs = $request->input(['name', 'phone', 'email']);
368
+
369
+ if ($for === 'create_driver') {
370
+ return app(ApiDriverController::class)->create($request);
371
+ }
372
+
373
+ // Check if user exists
374
+ $user = User::where('phone', $identity)->orWhere('email', $identity)->first();
375
+ if (!$user) {
376
+ return response()->error('Unable to verify code.');
377
+ }
378
+
379
+ // Find and verify code
380
+ $verificationCode = VerificationCode::where(['subject_uuid' => $user->uuid, 'code' => $code, 'for' => $for])->exists();
381
+ if (!$verificationCode && $code !== config('fleetops.navigator.bypass_verification_code')) {
382
+ return response()->error('Invalid verification code!');
383
+ }
384
+
385
+ // Get driver record
386
+ $driver = Driver::where('user_uuid', $user->uuid)->whereNull('deleted_at')->withoutGlobalScopes()->first();
387
+ if (!$driver) {
388
+ return response()->error('No driver/agent record found for login.');
389
+ }
390
+
391
+ // Generate auth token
392
+ try {
393
+ $token = $user->createToken($driver->uuid);
394
+ } catch (\Exception $e) {
395
+ return response()->error($e->getMessage());
396
+ }
397
+
398
+ $driver->token = $token->plainTextToken;
399
+
400
+ return new $this->resource($driver);
401
+ }
402
+
403
+ /**
404
+ * Patches phone number with international code.
405
+ */
406
+ public static function phone(string $phone = null): string
407
+ {
408
+ if ($phone === null) {
409
+ $phone = request()->input('phone');
410
+ }
411
+
412
+ if (!Str::startsWith($phone, '+')) {
413
+ $phone = '+' . $phone;
414
+ }
415
+
416
+ return $phone;
417
+ }
270
418
  }
@@ -2,12 +2,16 @@
2
2
 
3
3
  namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
4
4
 
5
+ use Fleetbase\FleetOps\Http\Filter\ContactFilter;
6
+ use Fleetbase\FleetOps\Http\Filter\VendorFilter;
5
7
  use Fleetbase\FleetOps\Models\Contact;
6
8
  use Fleetbase\FleetOps\Models\IntegratedVendor;
7
9
  use Fleetbase\FleetOps\Models\Vendor;
8
10
  use Fleetbase\FleetOps\Support\Utils;
9
11
  use Fleetbase\Http\Controllers\Controller;
10
12
  use Illuminate\Http\Request;
13
+ use Illuminate\Pagination\LengthAwarePaginator;
14
+ use Illuminate\Support\Facades\URL;
11
15
  use Illuminate\Support\Str;
12
16
 
13
17
  class MorphController extends Controller
@@ -21,18 +25,26 @@ class MorphController extends Controller
21
25
  {
22
26
  $query = $request->input('query');
23
27
  $limit = $request->input('limit', 12);
28
+ $page = $request->input('page', 1);
24
29
  $type = Str::lower($request->segment(4));
25
30
  $resourceType = Str::lower(Utils::singularize($type));
26
31
 
27
- $contacts = Contact::searchWhere('name', $query)
32
+ $contactsQuery = Contact::searchWhere('name', $query)
28
33
  ->where('company_uuid', session('company'))
29
- ->limit($limit)
30
- ->get();
34
+ ->filter(new ContactFilter($request));
31
35
 
32
- $vendors = Vendor::searchWhere('name', $query)
36
+ $vendorsQuery = Vendor::searchWhere('name', $query)
33
37
  ->where('company_uuid', session('company'))
34
- ->limit($limit)
35
- ->get();
38
+ ->filter(new VendorFilter($request));
39
+
40
+ // Get total count for pagination
41
+ $totalContacts = $contactsQuery->count();
42
+ $totalVendors = $vendorsQuery->count();
43
+ $total = $totalContacts + $totalVendors;
44
+
45
+ // Get paginated items
46
+ $contacts = $contactsQuery->limit($limit)->get();
47
+ $vendors = $vendorsQuery->limit($limit)->get();
36
48
 
37
49
  $results = collect([...$contacts, ...$vendors])
38
50
  ->sortBy('name')
@@ -59,19 +71,39 @@ class MorphController extends Controller
59
71
  }
60
72
  }
61
73
 
62
- // convert to array
63
- $results = $results->toArray();
64
-
65
74
  // set resource type
66
- $results = array_map(
67
- function ($attributes) use ($resourceType) {
68
- $attributes['type'] = $resourceType;
75
+ $results = $results->map(
76
+ function ($item) use ($resourceType) {
77
+ $item['type'] = $resourceType;
69
78
 
70
- return $attributes;
71
- },
72
- $results
79
+ return $item;
80
+ }
73
81
  );
74
82
 
75
- return response()->json([$type => $results]);
83
+ // Create a LengthAwarePaginator instance
84
+ $results = new LengthAwarePaginator(
85
+ $results->forPage($page, $limit),
86
+ $total,
87
+ $limit,
88
+ $page,
89
+ ['path' => URL::current()]
90
+ );
91
+
92
+ // Manually structure the response
93
+ $response = [
94
+ $type => $results->items(),
95
+ 'meta' => [
96
+ 'total' => $results->total(),
97
+ 'per_page' => $results->perPage(),
98
+ 'current_page' => $results->currentPage(),
99
+ 'last_page' => $results->lastPage(),
100
+ 'next_page_url' => $results->nextPageUrl(),
101
+ 'prev_page_url' => $results->previousPageUrl(),
102
+ 'from' => $results->firstItem(),
103
+ 'to' => $results->lastItem(),
104
+ ],
105
+ ];
106
+
107
+ return response()->json($response);
76
108
  }
77
109
  }
@@ -0,0 +1,79 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
4
+
5
+ use Fleetbase\Http\Controllers\Controller;
6
+ use Fleetbase\Http\Resources\Organization;
7
+ use Fleetbase\Models\ApiCredential;
8
+ use Fleetbase\Models\Company;
9
+ use Fleetbase\Models\User;
10
+ use Illuminate\Http\Request;
11
+ use Illuminate\Support\Str;
12
+
13
+ class NavigatorController extends Controller
14
+ {
15
+ public function linkApp()
16
+ {
17
+ $adminUser = User::where('type', 'admin')->first();
18
+
19
+ if ($adminUser->company) {
20
+ $apiCredential = ApiCredential::firstOrCreate(
21
+ [
22
+ 'user_uuid' => $adminUser->uuid,
23
+ 'company_uuid' => $adminUser->company_uuid,
24
+ 'name' => 'NavigationAppLinker',
25
+ ],
26
+ [
27
+ 'user_uuid' => $adminUser->uuid,
28
+ 'company_uuid' => $adminUser->company->uuid,
29
+ 'name' => 'NavigationAppLinker',
30
+ ]
31
+ );
32
+
33
+ return redirect()->away('flbnavigator://configure?key=' . $apiCredential->key . '&host=' . url()->secure('/'));
34
+ }
35
+
36
+ return response()->error('Organization for linking not found.');
37
+ }
38
+
39
+ public function getLinkAppUrl()
40
+ {
41
+ return response()->json([
42
+ 'linkUrl' => url('int/v1/fleet-ops/navigator/link-app'),
43
+ ]);
44
+ }
45
+
46
+ public function getCurrentOrganization(Request $request)
47
+ {
48
+ $token = $request->bearerToken();
49
+ $isSecretKey = Str::startsWith($token, '$');
50
+
51
+ // Depending on API key format set the connection to find credential on
52
+ $connection = Str::startsWith($token, 'flb_test_') ? 'sandbox' : 'mysql';
53
+
54
+ // Find the API Credential record
55
+ $findApKey = ApiCredential::on($connection)
56
+ ->where(function ($query) use ($isSecretKey, $token) {
57
+ if ($isSecretKey) {
58
+ $query->where('secret', $token);
59
+ } else {
60
+ $query->where('key', $token);
61
+ }
62
+ })
63
+ ->with(['company.owner'])
64
+ ->withoutGlobalScopes();
65
+
66
+ // Get the api credential model record
67
+ $apiCredential = $findApKey->first();
68
+
69
+ // Handle no api credential found
70
+ if (!$apiCredential) {
71
+ return response()->error('No API key found to fetch company details with.');
72
+ }
73
+
74
+ // Get the organization owning the API key
75
+ $organization = Company::where('uuid', $apiCredential->company_uuid)->first();
76
+
77
+ return new Organization($organization);
78
+ }
79
+ }
@@ -129,6 +129,7 @@ class OrderController extends FleetOpsController
129
129
  public function importFromFiles(Request $request)
130
130
  {
131
131
  $info = Utils::lookupIp();
132
+ $disk = $request->input('disk', config('filesystems.default'));
132
133
  $files = $request->input('files');
133
134
  $files = File::whereIn('uuid', $files)->get();
134
135
  $country = $request->input('country', Utils::or($info, ['country_name', 'region'], 'Singapore'));
@@ -143,7 +144,7 @@ class OrderController extends FleetOpsController
143
144
  }
144
145
 
145
146
  try {
146
- $data = Excel::toArray(new OrdersImport(), $file->path, 's3');
147
+ $data = Excel::toArray(new OrdersImport(), $file->path, $disk);
147
148
  } catch (\Exception $e) {
148
149
  return response()->error('Invalid file, unable to proccess.');
149
150
  }
@@ -177,7 +178,7 @@ class OrderController extends FleetOpsController
177
178
  $entity = new Entity(['name' => $itemName]);
178
179
  $entity->setAttribute('destination_uuid', $place->uuid);
179
180
  $entity->setAttribute('_import_id', $importId);
180
- $entity->setMetas($place->getMeta());
181
+ $entity->setMeta($place->getMeta());
181
182
  $entities[] = $entity;
182
183
  }
183
184
  }
@@ -76,7 +76,7 @@ class PlaceController extends FleetOpsController
76
76
  }
77
77
  }
78
78
 
79
- return response()->json($results);
79
+ return response()->json($results)->withHeaders(['Cache-Control' => 'no-cache']);
80
80
  }
81
81
 
82
82
  /**
@@ -113,7 +113,7 @@ class PlaceController extends FleetOpsController
113
113
  }
114
114
  }
115
115
 
116
- return response()->json($results);
116
+ return response()->json($results)->withHeaders(['Cache-Control' => 'no-cache']);
117
117
  }
118
118
 
119
119
  /**
@@ -2,6 +2,7 @@
2
2
 
3
3
  namespace Fleetbase\FleetOps\Http\Requests;
4
4
 
5
+ use Fleetbase\FleetOps\Rules\ResolvablePoint;
5
6
  use Fleetbase\Http\Requests\FleetbaseRequest;
6
7
  use Illuminate\Validation\Rule;
7
8
 
@@ -37,6 +38,7 @@ class CreateDriverRequest extends FleetbaseRequest
37
38
  'status' => 'nullable|string|in:active,inactive',
38
39
  'vendor' => 'nullable|exists:vendors,public_id',
39
40
  'job' => 'nullable|exists:orders,public_id',
41
+ 'location' => ['nullable', new ResolvablePoint()],
40
42
  ];
41
43
  }
42
44
 
@@ -46,8 +46,16 @@ class CreateOrderRequest extends FleetbaseRequest
46
46
 
47
47
  if ($this->isArray('payload')) {
48
48
  $validations['payload'] = 'required';
49
- $validations['payload.pickup'] = 'required';
50
- $validations['payload.dropoff'] = 'required';
49
+
50
+ if ($this->missing('payload.waypoints')) {
51
+ $validations['payload.pickup'] = 'required';
52
+ $validations['payload.dropoff'] = 'required';
53
+ }
54
+
55
+ if ($this->missing(['payload.pickup', 'payload.dropoff'])) {
56
+ $validations['payload.waypoints'] = 'required|array|min:2';
57
+ }
58
+
51
59
  $validations['payload.return'] = 'nullable';
52
60
  }
53
61
 
@@ -57,8 +65,14 @@ class CreateOrderRequest extends FleetbaseRequest
57
65
  }
58
66
 
59
67
  if ($this->missing('payload') && $this->isMethod('POST')) {
60
- $validations['pickup'] = 'required';
61
- $validations['dropoff'] = 'required';
68
+ if ($this->missing('waypoints')) {
69
+ $validations['pickup'] = 'required';
70
+ $validations['dropoff'] = 'required';
71
+ }
72
+
73
+ if ($this->missing(['pickup', 'dropoff'])) {
74
+ $validations['waypoints'] = 'required|array|min:2';
75
+ }
62
76
  }
63
77
 
64
78
  return $validations;