@fleetbase/fleetops-engine 0.3.8 → 0.4.0

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 (58) hide show
  1. package/addon/components/contact-form-panel.hbs +4 -1
  2. package/addon/components/contact-panel.hbs +1 -1
  3. package/addon/components/driver-form-panel.hbs +5 -12
  4. package/addon/components/driver-panel.hbs +4 -1
  5. package/addon/components/fleet-form-panel.hbs +4 -1
  6. package/addon/components/fleet-listing-panel.hbs +2 -2
  7. package/addon/components/fleet-panel.hbs +1 -1
  8. package/addon/components/fuel-report-form-panel.hbs +4 -1
  9. package/addon/components/fuel-report-panel.hbs +4 -1
  10. package/addon/components/issue-form-panel.hbs +4 -1
  11. package/addon/components/issue-panel.hbs +4 -1
  12. package/addon/components/layout/fleet-ops-sidebar/driver-listing.hbs +5 -0
  13. package/addon/components/layout/fleet-ops-sidebar/driver-listing.js +122 -0
  14. package/addon/components/layout/fleet-ops-sidebar/fleet-listing.hbs +2 -2
  15. package/addon/components/layout/fleet-ops-sidebar/fleet-listing.js +69 -49
  16. package/addon/components/layout/fleet-ops-sidebar.hbs +1 -1
  17. package/addon/components/layout/fleet-ops-sidebar.js +4 -3
  18. package/addon/components/live-map.hbs +90 -9
  19. package/addon/components/live-map.js +28 -11
  20. package/addon/components/map-container/toolbar/zones-panel.js +16 -13
  21. package/addon/components/place-form-panel.hbs +4 -1
  22. package/addon/components/place-panel.hbs +4 -1
  23. package/addon/components/settings-window.hbs +1 -1
  24. package/addon/components/vehicle-form-panel.hbs +4 -1
  25. package/addon/components/vehicle-panel.hbs +4 -1
  26. package/addon/components/vendor-form-panel.hbs +4 -1
  27. package/addon/components/vendor-panel.hbs +4 -1
  28. package/addon/controllers/management/drivers/index.js +10 -90
  29. package/addon/controllers/management/vehicles/index.js +11 -21
  30. package/addon/controllers/operations/orders/index/new.js +5 -5
  31. package/addon/controllers/operations/orders/index/view.js +9 -13
  32. package/addon/helpers/format-point.js +5 -2
  33. package/addon/helpers/point-to-coordinates.js +6 -2
  34. package/addon/services/context-panel.js +23 -18
  35. package/addon/services/driver-actions.js +107 -0
  36. package/addon/services/vehicle-actions.js +42 -0
  37. package/addon/styles/fleetops-engine.css +12 -2
  38. package/addon/templates/operations/orders/index/new.hbs +3 -3
  39. package/addon/utils/fly-to-leaflet-layer.js +7 -0
  40. package/app/components/layout/fleet-ops-sidebar/driver-listing.js +1 -0
  41. package/app/services/driver-actions.js +1 -0
  42. package/app/services/vehicle-actions.js +1 -0
  43. package/composer.json +2 -2
  44. package/extension.json +1 -1
  45. package/package.json +4 -4
  46. package/server/src/Console/Commands/FixDriverCompanies.php +65 -0
  47. package/server/src/Exceptions/IntegratedVendorException.php +44 -1
  48. package/server/src/Http/Controllers/Api/v1/DriverController.php +43 -34
  49. package/server/src/Http/Controllers/Internal/v1/DriverController.php +42 -5
  50. package/server/src/Http/Controllers/Internal/v1/LiveController.php +3 -10
  51. package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +1 -1
  52. package/server/src/Http/Resources/v1/Driver.php +1 -1
  53. package/server/src/Providers/FleetOpsServiceProvider.php +1 -0
  54. package/server/src/Support/Flow.php +19 -2
  55. package/addon/helpers/extract-coordinates.js +0 -6
  56. package/addon/utils/extract-coordinates.js +0 -1
  57. package/app/helpers/extract-coordinates.js +0 -1
  58. package/app/utils/extract-coordinates.js +0 -1
@@ -3,16 +3,59 @@
3
3
  namespace Fleetbase\FleetOps\Exceptions;
4
4
 
5
5
  use Fleetbase\FleetOps\Models\IntegratedVendor;
6
+ use Illuminate\Contracts\Support\Responsable;
7
+ use Illuminate\Http\JsonResponse;
6
8
 
7
- class IntegratedVendorException extends \Exception
9
+ /**
10
+ * Class IntegratedVendorException.
11
+ *
12
+ * Custom exception class for IntegratedVendor-related exceptions.
13
+ */
14
+ class IntegratedVendorException extends \Exception implements Responsable
8
15
  {
16
+ /**
17
+ * @var IntegratedVendor|null the IntegratedVendor instance associated with the exception
18
+ */
9
19
  public ?IntegratedVendor $integratedVendor;
20
+
21
+ /**
22
+ * @var string the trigger method that caused the exception
23
+ */
10
24
  public string $triggerMethod;
11
25
 
26
+ /**
27
+ * IntegratedVendorException constructor.
28
+ *
29
+ * @param string $message the exception message
30
+ * @param IntegratedVendor|null $integratedVendor the IntegratedVendor instance associated with the exception
31
+ * @param string|null $triggerMethod the trigger method that caused the exception
32
+ * @param int $code the exception code
33
+ * @param \Throwable|null $previous the previous throwable used for the exception chaining
34
+ */
12
35
  public function __construct(string $message = '', IntegratedVendor $integratedVendor = null, string $triggerMethod = null, int $code = 400, \Throwable $previous = null)
13
36
  {
14
37
  parent::__construct($message, $code, $previous);
15
38
  $this->integratedVendor = $integratedVendor;
16
39
  $this->triggerMethod = $triggerMethod;
17
40
  }
41
+
42
+ /**
43
+ * Get the response representing the exception.
44
+ *
45
+ * @param \Illuminate\Http\Request $request
46
+ *
47
+ * @return \Illuminate\Http\JsonResponse
48
+ */
49
+ public function toResponse($request)
50
+ {
51
+ $errorMessage = $this->getMessage();
52
+
53
+ return new JsonResponse(
54
+ [
55
+ 'errors' => [$errorMessage],
56
+ 'integratedVendorId' => data_get($this->integratedVendor, 'uuid'),
57
+ ],
58
+ 400
59
+ );
60
+ }
18
61
  }
@@ -360,32 +360,31 @@ class DriverController extends Controller
360
360
  {
361
361
  $identity = $request->input('identity');
362
362
  $password = $request->input('password');
363
- $attrs = $request->input(['name', 'phone', 'email']);
363
+ // $attrs = $request->input(['name', 'phone', 'email']);
364
364
 
365
- $user = User::where('email', $identity)->orWhere('phone', static::phone($identity))->first();
365
+ // Get driver attempting to authenticate via phone
366
+ $user = User::where(
367
+ function ($query) use ($identity) {
368
+ $query->where('phone', static::phone($identity));
369
+ $query->owWhere('email', $identity);
370
+ }
371
+ )->whereHas('driver')->first();
366
372
 
373
+ // Check password to authenticate driver
367
374
  if (!Hash::check($password, $user->password)) {
368
375
  return response()->apiError('Authentication failed using password provided.', 401);
369
376
  }
370
377
 
371
- // Get the company session for the user
372
- $company = Flow::getCompanySessionForUser($user);
378
+ // Get the user's company for this driver profile
379
+ $company = $this->_getDriverCompanyFromUser($user);
373
380
 
374
381
  // Get driver record
375
- $driver = Driver::firstOrCreate(
376
- [
377
- 'user_uuid' => $user->uuid,
378
- 'company_uuid' => $company->uuid,
379
- ],
382
+ $driver = Driver::where(
380
383
  [
381
384
  'user_uuid' => $user->uuid,
382
385
  'company_uuid' => $company->uuid,
383
- 'name' => data_get($attrs, 'name', $user->name),
384
- 'phone' => data_get($attrs, 'phone', $user->phone),
385
- 'email' => data_get($attrs, 'email', $user->email),
386
- 'location' => new Point(0, 0),
387
386
  ]
388
- );
387
+ )->first();
389
388
 
390
389
  // generate auth token
391
390
  try {
@@ -409,19 +408,18 @@ class DriverController extends Controller
409
408
  $phone = static::phone();
410
409
 
411
410
  // check if user exists
412
- $user = User::where('phone', $phone)->whereNull('deleted_at')->withoutGlobalScopes()->first();
413
-
411
+ $user = User::where('phone', $phone)->whereHas('driver')->whereNull('deleted_at')->withoutGlobalScopes()->first();
414
412
  if (!$user) {
415
413
  return response()->apiError('No driver with this phone # found.');
416
414
  }
417
415
 
418
- // get the current company session
419
- $company = Flow::getCompanySessionForUser($user);
416
+ // Get the user's company for this driver profile
417
+ $company = $this->_getDriverCompanyFromUser($user);
420
418
 
421
419
  // generate verification token
422
420
  try {
423
421
  VerificationCode::generateSmsVerificationFor($user, 'driver_login', function ($verification) use ($company) {
424
- return "Your {$company->name} verification code is {$verification->code}";
422
+ return 'Your ' . data_get($company, 'name', config('app.name')) . ' verification code is ' . $verification->code;
425
423
  });
426
424
  } catch (\Throwable $e) {
427
425
  return response()->apiError($e->getMessage());
@@ -447,9 +445,9 @@ class DriverController extends Controller
447
445
  }
448
446
 
449
447
  // check if user exists
450
- $user = User::where('type', 'driver')->where(function ($query) use ($identity) {
448
+ $user = User::whereHas('driver')->where(function ($query) use ($identity) {
451
449
  $query->where('phone', $identity);
452
- $query->orWhere('phone', $identity);
450
+ $query->orWhere('email', $identity);
453
451
  })->first();
454
452
 
455
453
  if (!$user) {
@@ -458,29 +456,20 @@ class DriverController extends Controller
458
456
 
459
457
  // find and verify code
460
458
  $verificationCode = VerificationCode::where(['subject_uuid' => $user->uuid, 'code' => $code, 'for' => $for])->exists();
461
-
462
459
  if (!$verificationCode && $code !== config('fleetops.navigator.bypass_verification_code')) {
463
460
  return response()->apiError('Invalid verification code!');
464
461
  }
465
462
 
466
- // get the current company session
467
- $company = Flow::getCompanySessionForUser($user);
463
+ // Get the user's company for this driver profile
464
+ $company = $this->_getDriverCompanyFromUser($user);
468
465
 
469
466
  // get driver record
470
- $driver = Driver::firstOrCreate(
471
- [
472
- 'user_uuid' => $user->uuid,
473
- 'company_uuid' => $company->uuid,
474
- ],
467
+ $driver = Driver::where(
475
468
  [
476
469
  'user_uuid' => $user->uuid,
477
470
  'company_uuid' => $company->uuid,
478
- 'name' => data_get($attrs, 'name', $user->name),
479
- 'phone' => data_get($attrs, 'phone', $user->phone),
480
- 'email' => data_get($attrs, 'email', $user->email),
481
- 'location' => new Point(0, 0),
482
471
  ]
483
- );
472
+ )->first();
484
473
 
485
474
  // generate auth token
486
475
  try {
@@ -707,4 +696,24 @@ class DriverController extends Controller
707
696
 
708
697
  return response()->json($route);
709
698
  }
699
+
700
+ private function _getDriverCompanyFromUser(User $user): ?Company
701
+ {
702
+ // company defaults to null
703
+ $company = null;
704
+
705
+ // Load the driver profile to get the company
706
+ $driverProfile = Driver::where('user_uuid', $user->uuid)->first();
707
+ if ($driverProfile) {
708
+ // get company from driver profile
709
+ $company = Company::where('uuid', $driverProfile->company_uuid)->first();
710
+ }
711
+
712
+ // If unable to find company from driver profile, fallback to session flow
713
+ if (!$company) {
714
+ $company = Flow::getCompanySessionForUser($user);
715
+ }
716
+
717
+ return $company;
718
+ }
710
719
  }
@@ -13,10 +13,13 @@ use Fleetbase\FleetOps\Models\Driver;
13
13
  use Fleetbase\FleetOps\Models\Order;
14
14
  use Fleetbase\FleetOps\Support\Utils;
15
15
  use Fleetbase\Http\Requests\ExportRequest;
16
+ use Fleetbase\Models\CompanyUser;
16
17
  use Fleetbase\Models\Invite;
17
18
  use Fleetbase\Models\User;
18
19
  use Fleetbase\Models\VerificationCode;
19
20
  use Fleetbase\Notifications\UserInvited;
21
+ use Fleetbase\Support\Auth;
22
+ use Grimzy\LaravelMysqlSpatial\Types\Point;
20
23
  use Illuminate\Http\Request;
21
24
  use Illuminate\Support\Facades\DB;
22
25
  use Illuminate\Support\Facades\Validator;
@@ -79,6 +82,12 @@ class DriverController extends FleetOpsController
79
82
  // if exists in organization create driver profile for user
80
83
  $isOrganizationMember = $existingUser->companies()->where('company_uuid', session('company'))->exists();
81
84
 
85
+ // Check if driver profile also already exists
86
+ $existingDriverProfile = Driver::where(['company_uuid' => session('company'), 'user_uuid' => $existingUser->uuid])->first();
87
+ if ($existingDriverProfile) {
88
+ return ['driver' => new $this->resource($existingDriverProfile)];
89
+ }
90
+
82
91
  // create driver profile for user
83
92
  $input = collect($input)
84
93
  ->except(['name', 'password', 'email', 'phone', 'meta', 'avatar_uuid', 'photo_uuid'])
@@ -90,6 +99,11 @@ class DriverController extends FleetOpsController
90
99
  $input['user_uuid'] = $existingUser->uuid;
91
100
  $input['slug'] = $existingUser->slug;
92
101
 
102
+ // If no location provided set
103
+ if (empty($input['location'])) {
104
+ $input['location'] = new Point(0, 0);
105
+ }
106
+
93
107
  // create the profile
94
108
  $driverProfile = Driver::create($input);
95
109
 
@@ -109,7 +123,7 @@ class DriverController extends FleetOpsController
109
123
  $existingUser->notify(new UserInvited($invitation));
110
124
  }
111
125
 
112
- return response()->json(['driver' => $driverProfile]);
126
+ return ['driver' => new $this->resource($driverProfile)];
113
127
  }
114
128
  }
115
129
 
@@ -138,15 +152,33 @@ class DriverController extends FleetOpsController
138
152
  ->filter()
139
153
  ->toArray();
140
154
 
141
- if (!isset($input['password'])) {
142
- $input['password'] = data_get($userInput, 'phone', Str::random(14));
155
+ // Make sure password is set
156
+ if (empty($userInput['password'])) {
157
+ $userInput['password'] = Str::random(14);
143
158
  }
144
159
 
145
- $userInput['company_uuid'] = session('company');
146
- $userInput['type'] = 'driver';
160
+ // Get current session company
161
+ $company = Auth::getCompany();
162
+ $userInput['company_uuid'] = $company ? $company->uuid : session('company');
147
163
 
164
+ // Create user account
148
165
  $user = User::create($userInput);
149
166
 
167
+ // Assign user to company
168
+ if ($company) {
169
+ $user->assignCompany($company);
170
+
171
+ // create company user
172
+ CompanyUser::create([
173
+ 'user_uuid' => $user->uuid,
174
+ 'company_uuid' => $company->uuid,
175
+ 'status' => 'active',
176
+ ]);
177
+ }
178
+
179
+ // Set user type as driver
180
+ $user->setUserType('driver');
181
+
150
182
  // send invitation to user
151
183
  $invitation = Invite::create([
152
184
  'company_uuid' => session('company'),
@@ -163,6 +195,11 @@ class DriverController extends FleetOpsController
163
195
 
164
196
  $input['user_uuid'] = $user->uuid;
165
197
  $input['slug'] = $user->slug;
198
+
199
+ // If no location provided set
200
+ if (empty($input['location'])) {
201
+ $input['location'] = new Point(0, 0);
202
+ }
166
203
  },
167
204
  function ($request, &$driver) {
168
205
  $driver->load(['user']);
@@ -82,26 +82,19 @@ class LiveController extends Controller
82
82
  }
83
83
 
84
84
  /**
85
- * Get online drivers with active jobs for the current company.
85
+ * Get drivers for the current company.
86
86
  *
87
87
  * @return \Illuminate\Http\JsonResponse
88
88
  */
89
89
  public function drivers()
90
90
  {
91
- $drivers = Driver::where(['company_uuid' => session('company'), 'online' => 1])
92
- ->whereHas(
93
- 'currentJob',
94
- function ($q) {
95
- $q->whereNotIn('status', ['canceled', 'completed']);
96
- }
97
- )
98
- ->get();
91
+ $drivers = Driver::where(['company_uuid' => session('company')])->get();
99
92
 
100
93
  return DriverResource::collection($drivers);
101
94
  }
102
95
 
103
96
  /**
104
- * Get online vehicles for the current company.
97
+ * Get vehicles for the current company.
105
98
  *
106
99
  * @return \Illuminate\Http\JsonResponse
107
100
  */
@@ -30,7 +30,7 @@ class NavigatorController extends Controller
30
30
  ]
31
31
  );
32
32
 
33
- return redirect()->away('flbnavigator://configure?key=' . $apiCredential->key . '&host=' . url()->secure('/'));
33
+ return redirect()->away('flbnavigator://configure?key=' . $apiCredential->key . '&host=' . url()->secure('/') . '&socketcluster_host=' . env('SOCKETCLUSTER_HOST', 'socket') . '&socketcluster_port=' . env('SOCKETCLUSTER_PORT', 8000));
34
34
  }
35
35
 
36
36
  return response()->error('Organization for linking not found.');
@@ -42,7 +42,7 @@ class Driver extends FleetbaseResource
42
42
  'jobs' => $this->whenLoaded('jobs', CurrentJob::collection($this->jobs()->without(['driverAssigned'])->get())),
43
43
  'vendor' => $this->whenLoaded('vendor', new Vendor($this->vendor)),
44
44
  'fleets' => $this->whenLoaded('fleets', Fleet::collection($this->fleets()->without('drivers')->get())),
45
- 'location' => data_get($this, 'location', new Point(0, 0)),
45
+ 'location' => $this->wasRecentlyCreated ? new Point(0, 0) : data_get($this, 'location', new Point(0, 0)),
46
46
  'heading' => (int) data_get($this, 'heading', 0),
47
47
  'altitude' => (int) data_get($this, 'altitude', 0),
48
48
  'speed' => (int) data_get($this, 'speed', 0),
@@ -44,6 +44,7 @@ class FleetOpsServiceProvider extends CoreServiceProvider
44
44
  \Fleetbase\FleetOps\Console\Commands\DispatchAdhocOrders::class,
45
45
  \Fleetbase\FleetOps\Console\Commands\DispatchOrders::class,
46
46
  \Fleetbase\FleetOps\Console\Commands\TrackOrderDistanceAndTime::class,
47
+ \Fleetbase\FleetOps\Console\Commands\FixDriverCompanies::class,
47
48
  ];
48
49
 
49
50
  /**
@@ -6,6 +6,7 @@ use Fleetbase\FleetOps\Models\Driver;
6
6
  use Fleetbase\FleetOps\Models\Order;
7
7
  use Fleetbase\FleetOps\Models\Waypoint;
8
8
  use Fleetbase\Models\Company;
9
+ use Fleetbase\Models\CompanyUser;
9
10
  use Fleetbase\Models\Extension;
10
11
  use Fleetbase\Models\ExtensionInstall;
11
12
  use Fleetbase\Models\User;
@@ -550,9 +551,25 @@ class Flow
550
551
  return Company::currentSession();
551
552
  }
552
553
 
553
- public static function getCompanySessionForUser(User $user)
554
+ public static function getCompanySessionForUser(User $user): ?Company
554
555
  {
555
- return Company::where('uuid', $user->company_uuid)->first();
556
+ if (Str::isUuid($user->company_uuid)) {
557
+ $company = Company::where('uuid', $user->company_uuid)->first();
558
+ if ($company) {
559
+ return $company;
560
+ }
561
+ }
562
+
563
+ // fallback to get user's first company
564
+ $userCompany = CompanyUser::where('user_uuid', $user->uuid)->first();
565
+ if ($userCompany) {
566
+ $company = Company::where('uuid', $userCompany->company_uuid)->first();
567
+ if ($company) {
568
+ return $company;
569
+ }
570
+ }
571
+
572
+ return null;
556
573
  }
557
574
 
558
575
  public static function getDefaultOrderFlow()
@@ -1,6 +0,0 @@
1
- import { helper } from '@ember/component/helper';
2
- import extractCoordinatesUtil from '../utils/extract-coordinates';
3
-
4
- export default helper(function extractCoordinates([coordinates = [], format = 'latlng']) {
5
- return extractCoordinatesUtil(coordinates, format);
6
- });
@@ -1 +0,0 @@
1
- export { default } from '@fleetbase/ember-core/utils/extract-coordinates';
@@ -1 +0,0 @@
1
- export { default, extractCoordinates } from '@fleetbase/fleetops-engine/helpers/extract-coordinates';
@@ -1 +0,0 @@
1
- export { default } from '@fleetbase/fleetops-engine/utils/extract-coordinates';