From 8364f61e45658ee9772abee88e6a37d59c5fc9de Mon Sep 17 00:00:00 2001 From: roncodes <816371+roncodes@users.noreply.github.com> Date: Fri, 9 Jan 2026 02:13:26 -0500 Subject: [PATCH 1/9] fix: add complete validation rules for internal driver creation - Add required validation for name, email, and phone fields - Add validation for drivers_license_number and internal_id - Add validation for photo_uuid and avatar_uuid - Add validation for location fields (latitude, longitude) - Add custom error messages for better UX - Add custom attribute names for clearer validation errors - Ensure email and phone uniqueness checks - Add password minimum length validation (8 characters) This fixes the issue where drivers could be created without required fields through the internal API, and improves the validation error messages shown to users. Resolves issue where onboarding driver creation was failing silently due to incomplete validation rules. --- .../Requests/Internal/CreateDriverRequest.php | 72 +++++++++++++++++-- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/server/src/Http/Requests/Internal/CreateDriverRequest.php b/server/src/Http/Requests/Internal/CreateDriverRequest.php index eac5a18c..3ceed900 100644 --- a/server/src/Http/Requests/Internal/CreateDriverRequest.php +++ b/server/src/Http/Requests/Internal/CreateDriverRequest.php @@ -3,7 +3,9 @@ namespace Fleetbase\FleetOps\Http\Requests\Internal; use Fleetbase\FleetOps\Http\Requests\CreateDriverRequest as CreateDriverApiRequest; +use Fleetbase\FleetOps\Rules\ResolvablePoint; use Fleetbase\Support\Auth; +use Illuminate\Validation\Rule; class CreateDriverRequest extends CreateDriverApiRequest { @@ -27,11 +29,71 @@ public function rules() $isCreating = $this->isMethod('POST'); return [ - 'password' => 'nullable|string', - 'country' => 'nullable|size:2', - 'city' => 'nullable|string', - 'status' => 'nullable|string|in:active,inactive', - 'job' => 'nullable|exists:orders,public_id', + // Required fields for driver creation + 'name' => [Rule::requiredIf($isCreating), 'string', 'max:255'], + 'email' => [ + Rule::requiredIf($isCreating), + Rule::when($this->filled('email'), ['email']), + Rule::when($isCreating, [Rule::unique('users')->whereNull('deleted_at')]) + ], + 'phone' => [ + Rule::requiredIf($isCreating), + Rule::when($isCreating, [Rule::unique('users')->whereNull('deleted_at')]) + ], + + // Optional fields + 'password' => 'nullable|string|min:8', + 'drivers_license_number' => 'nullable|string|max:255', + 'internal_id' => 'nullable|string|max:255', + 'country' => 'nullable|string|size:2', + 'city' => 'nullable|string|max:255', + 'vehicle' => 'nullable|string|starts_with:vehicle_|exists:vehicles,public_id', + 'status' => 'nullable|string|in:active,inactive', + 'vendor' => 'nullable|exists:vendors,public_id', + 'job' => 'nullable|exists:orders,public_id', + 'location' => ['nullable', new ResolvablePoint()], + 'latitude' => ['nullable', 'required_with:longitude', 'numeric'], + 'longitude' => ['nullable', 'required_with:latitude', 'numeric'], + + // Photo/avatar + 'photo_uuid' => 'nullable|exists:files,uuid', + 'avatar_uuid' => 'nullable|exists:files,uuid', + ]; + } + + /** + * Get custom attributes for validator errors. + * + * @return array + */ + public function attributes() + { + return [ + 'name' => 'driver name', + 'email' => 'email address', + 'phone' => 'phone number', + 'drivers_license_number' => 'driver\'s license number', + 'internal_id' => 'internal ID', + 'photo_uuid' => 'photo', + 'avatar_uuid' => 'avatar', + ]; + } + + /** + * Get custom messages for validator errors. + * + * @return array + */ + public function messages() + { + return [ + 'name.required' => 'Driver name is required.', + 'email.required' => 'Email address is required.', + 'email.email' => 'Please provide a valid email address.', + 'email.unique' => 'This email address is already registered.', + 'phone.required' => 'Phone number is required.', + 'phone.unique' => 'This phone number is already registered.', + 'password.min' => 'Password must be at least 8 characters.', ]; } } From 854b87924ca0380f1c44a24b314a2b1793d6d746 Mon Sep 17 00:00:00 2001 From: roncodes <816371+roncodes@users.noreply.github.com> Date: Fri, 9 Jan 2026 02:16:16 -0500 Subject: [PATCH 2/9] fix: handle null user when user_uuid provided but user doesn't exist - Check if user exists before calling methods on it - Create new user if user_uuid is provided but user doesn't exist - Prevents 'Call to a member function companies() on null' error - Fixes driver creation failure when invalid user_uuid is provided This resolves the error: Error: Call to a member function companies() on null in DriverController.php on line 172 --- .../Internal/v1/DriverController.php | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/server/src/Http/Controllers/Internal/v1/DriverController.php b/server/src/Http/Controllers/Internal/v1/DriverController.php index fccdab12..1daa9768 100644 --- a/server/src/Http/Controllers/Internal/v1/DriverController.php +++ b/server/src/Http/Controllers/Internal/v1/DriverController.php @@ -136,7 +136,37 @@ function (&$request, &$input) { if ($input->has('user_uuid')) { $user = User::where('uuid', $input->get('user_uuid'))->first(); - if ($user && $input->has('photo_uuid')) { + + // If user doesn't exist with provided UUID, create new user + if (!$user) { + $userInput = $input + ->only(['name', 'password', 'email', 'phone', 'status', 'avatar_uuid']) + ->filter() + ->toArray(); + + // handle `photo_uuid` + if (isset($input['photo_uuid']) && Str::isUuid($input['photo_uuid'])) { + $userInput['avatar_uuid'] = $input['photo_uuid']; + } + + // Make sure password is set + if (empty($userInput['password'])) { + $userInput['password'] = Str::random(14); + } + + // Set user company + $userInput['company_uuid'] = session('company', $company->uuid); + + // Apply user infos + $userInput = User::applyUserInfoFromRequest($request, $userInput); + + // Create user account + $user = User::create($userInput); + + // Set the user type to driver + $user->setType('driver'); + } elseif ($input->has('photo_uuid')) { + // Update existing user's avatar if photo provided $user->update(['avatar_uuid' => $input->get('photo_uuid')]); } } else { From 64ea5eb0f0e5601fe9404130bfe21c0a10fbce7c Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Tue, 13 Jan 2026 18:49:47 +0800 Subject: [PATCH 3/9] no duplicate places from google reverse queries --- .../Internal/v1/OrderController.php | 32 ------------------ .../Internal/v1/PlaceController.php | 33 ------------------- .../Internal/v1/VendorController.php | 31 ----------------- .../Requests/Internal/CreateDriverRequest.php | 12 ++++--- server/src/Models/Place.php | 22 +++++++++++++ 5 files changed, 29 insertions(+), 101 deletions(-) diff --git a/server/src/Http/Controllers/Internal/v1/OrderController.php b/server/src/Http/Controllers/Internal/v1/OrderController.php index 628611b0..63b4d214 100644 --- a/server/src/Http/Controllers/Internal/v1/OrderController.php +++ b/server/src/Http/Controllers/Internal/v1/OrderController.php @@ -29,14 +29,12 @@ use Fleetbase\FleetOps\Support\Utils; use Fleetbase\Http\Requests\ExportRequest; use Fleetbase\Http\Requests\Internal\BulkActionRequest; -use Fleetbase\Http\Requests\Internal\BulkDeleteRequest; use Fleetbase\Models\File; use Fleetbase\Models\Type; use Fleetbase\Support\TemplateString; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\QueryException; use Illuminate\Http\Request; -use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Validator; @@ -330,36 +328,6 @@ public function importFromFiles(Request $request) ); } - /** - * Updates a order to canceled and updates order activity. - * - * @return \Illuminate\Http\Response - */ - public function bulkDelete(BulkDeleteRequest $request) - { - $ids = $request->input('ids', []); - - if (!$ids) { - return response()->error('Nothing to delete.'); - } - - /** @var Order */ - $count = Order::whereIn('uuid', $ids)->count(); - $deleted = Order::whereIn('uuid', $ids)->delete(); - - if (!$deleted) { - return response()->error('Failed to bulk delete orders.'); - } - - return response()->json( - [ - 'status' => 'OK', - 'message' => 'Deleted ' . $count . ' orders', - 'count' => $count, - ] - ); - } - /** * Updates a order to canceled and updates order activity. * diff --git a/server/src/Http/Controllers/Internal/v1/PlaceController.php b/server/src/Http/Controllers/Internal/v1/PlaceController.php index f52c0f01..4636eaae 100644 --- a/server/src/Http/Controllers/Internal/v1/PlaceController.php +++ b/server/src/Http/Controllers/Internal/v1/PlaceController.php @@ -10,7 +10,6 @@ use Fleetbase\FleetOps\Support\Geocoding; use Fleetbase\Http\Requests\ExportRequest; use Fleetbase\Http\Requests\ImportRequest; -use Fleetbase\Http\Requests\Internal\BulkDeleteRequest; use Fleetbase\LaravelMysqlSpatial\Types\Point; use Illuminate\Http\Request; use Illuminate\Support\Str; @@ -150,38 +149,6 @@ public function export(ExportRequest $request) return Excel::download(new PlaceExport($selections), $fileName); } - /** - * Bulk deletes resources. - * - * @return \Illuminate\Http\Response - */ - public function bulkDelete(BulkDeleteRequest $request) - { - $ids = $request->input('ids', []); - - if (!$ids) { - return response()->error('Nothing to delete.'); - } - - /** - * @var \Fleetbase\Models\Place - */ - $count = Place::whereIn('uuid', $ids)->applyDirectivesForPermissions('fleet-ops list place')->count(); - $deleted = Place::whereIn('uuid', $ids)->applyDirectivesForPermissions('fleet-ops list place')->delete(); - - if (!$deleted) { - return response()->error('Failed to bulk delete places.'); - } - - return response()->json( - [ - 'status' => 'OK', - 'message' => 'Deleted ' . $count . ' places', - ], - 200 - ); - } - /** * Get all avatar options for an vehicle. * diff --git a/server/src/Http/Controllers/Internal/v1/VendorController.php b/server/src/Http/Controllers/Internal/v1/VendorController.php index 56d64def..57d1e9e1 100644 --- a/server/src/Http/Controllers/Internal/v1/VendorController.php +++ b/server/src/Http/Controllers/Internal/v1/VendorController.php @@ -9,7 +9,6 @@ use Fleetbase\FleetOps\Models\Vendor; use Fleetbase\Http\Requests\ExportRequest; use Fleetbase\Http\Requests\ImportRequest; -use Fleetbase\Http\Requests\Internal\BulkDeleteRequest; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; @@ -85,36 +84,6 @@ public static function export(ExportRequest $request) return Excel::download(new VendorExport($selections), $fileName); } - /** - * Bulk delete resources. - * - * @return \Illuminate\Http\Response - */ - public function bulkDelete(BulkDeleteRequest $request) - { - $ids = $request->input('ids', []); - - if (!$ids) { - return response()->error('Nothing to delete.'); - } - - /** @var \Fleetbase\Models\Vendor */ - $count = Vendor::whereIn('uuid', $ids)->count(); - $deleted = Vendor::whereIn('uuid', $ids)->delete(); - - if (!$deleted) { - return response()->error('Failed to bulk delete vendors.'); - } - - return response()->json( - [ - 'status' => 'OK', - 'message' => 'Deleted ' . $count . ' vendors', - ], - 200 - ); - } - /** * Get all status options for an vehicle. * diff --git a/server/src/Http/Requests/Internal/CreateDriverRequest.php b/server/src/Http/Requests/Internal/CreateDriverRequest.php index 3ceed900..08c4a48d 100644 --- a/server/src/Http/Requests/Internal/CreateDriverRequest.php +++ b/server/src/Http/Requests/Internal/CreateDriverRequest.php @@ -27,18 +27,20 @@ public function authorize() public function rules() { $isCreating = $this->isMethod('POST'); + $isCreatingWithUser = $this->filled('driver.user_uuid'); + $shouldValidateUserAttributes = $isCreating && !$isCreatingWithUser; return [ // Required fields for driver creation - 'name' => [Rule::requiredIf($isCreating), 'string', 'max:255'], + 'name' => [Rule::requiredIf($shouldValidateUserAttributes), 'nullable', 'string', 'max:255'], 'email' => [ - Rule::requiredIf($isCreating), + Rule::requiredIf($shouldValidateUserAttributes), Rule::when($this->filled('email'), ['email']), - Rule::when($isCreating, [Rule::unique('users')->whereNull('deleted_at')]) + Rule::when($shouldValidateUserAttributes, [Rule::unique('users')->whereNull('deleted_at')]) ], 'phone' => [ - Rule::requiredIf($isCreating), - Rule::when($isCreating, [Rule::unique('users')->whereNull('deleted_at')]) + Rule::requiredIf($shouldValidateUserAttributes), + Rule::when($shouldValidateUserAttributes, [Rule::unique('users')->whereNull('deleted_at')]) ], // Optional fields diff --git a/server/src/Models/Place.php b/server/src/Models/Place.php index 8c4c01c4..a3f24d2c 100644 --- a/server/src/Models/Place.php +++ b/server/src/Models/Place.php @@ -333,6 +333,28 @@ public static function createFromGoogleAddress(\Geocoder\Provider\GoogleMaps\Mod { $instance = (new static())->fillWithGoogleAddress($address); + // Before saving or returning this instance check the database for a duplicate address + // it cannot have any owner, and must belong to this session + if ($companyUuid = session('company')) { + $duplicate = static::where([ + 'company_uuid' => $companyUuid, + 'street1' => $instance->street1, + 'city' => $instance->city, + 'country' => $instance->country, + ]) + ->when( + $instance->postal_code !== null, + fn ($q) => $q->where('postal_code', $instance->postal_code), + fn ($q) => $q->whereNull('postal_code') + ) + ->whereNull('owner_uuid') + ->first(); + + if ($duplicate) { + return $duplicate; + } + } + if ($saveInstance) { $instance->save(); } From 211bc256d1d8832daa68bb7f5b83dc548c701b03 Mon Sep 17 00:00:00 2001 From: roncodes <816371+roncodes@users.noreply.github.com> Date: Tue, 13 Jan 2026 05:51:16 -0500 Subject: [PATCH 4/9] Fix CreateServiceRateRequest: closure should not expect input parameter - Changed closure from function($input) to function() - Use $this->input() to access request data instead - Fixes ArgumentCountError when Rule::requiredIf evaluates closure --- server/src/Http/Requests/CreateServiceRateRequest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/Http/Requests/CreateServiceRateRequest.php b/server/src/Http/Requests/CreateServiceRateRequest.php index b7b9d2b0..9f5a28b0 100644 --- a/server/src/Http/Requests/CreateServiceRateRequest.php +++ b/server/src/Http/Requests/CreateServiceRateRequest.php @@ -36,8 +36,8 @@ public function rules() 'base_fee' => ['numeric'], 'per_meter_unit' => ['required_if:rate_calculation_method,per_meter', 'string', 'in:km,m'], 'per_meter_flat_rate_fee' => ['required_if:rate_calculation_method,per_meter', 'numeric'], - 'meter_fees' => [Rule::requiredIf(function ($input) { - return in_array($input->rate_calculation_method, ['fixed_meter', 'fixed_rate']); + 'meter_fees' => [Rule::requiredIf(function () { + return in_array($this->input('rate_calculation_method'), ['fixed_meter', 'fixed_rate']); }), 'array'], 'meter_fees.*.distance' => ['numeric'], 'meter_fees.*.fee' => ['numeric'], From 7670963c3a48b62c5b483e56b0f8d02bcfcba13d Mon Sep 17 00:00:00 2001 From: roncodes <816371+roncodes@users.noreply.github.com> Date: Tue, 13 Jan 2026 21:26:45 -0500 Subject: [PATCH 5/9] Fix user resource tracking - set company_uuid before user creation Issue: Users created via driver API were not being tracked in billing system Root cause: company_uuid was set AFTER user creation via assignCompany() Solution: Set company_uuid in userDetails BEFORE User::create() This ensures ResourceCreatedListener can properly track the resource creation since it requires company_uuid to log usage to billing_resource_usage table. Without company_uuid at creation time, the listener logs a warning and exits: 'Could not determine company UUID for resource' Now the flow is: 1. Set company_uuid in userDetails 2. User::create() fires eloquent.created event 3. ResourceCreatedListener receives event with company_uuid 4. Resource usage tracked successfully --- server/src/Http/Controllers/Api/v1/DriverController.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/src/Http/Controllers/Api/v1/DriverController.php b/server/src/Http/Controllers/Api/v1/DriverController.php index fe1654e5..f4f294b0 100644 --- a/server/src/Http/Controllers/Api/v1/DriverController.php +++ b/server/src/Http/Controllers/Api/v1/DriverController.php @@ -62,6 +62,9 @@ public function create(CreateDriverRequest $request) // Apply user infos $userDetails = User::applyUserInfoFromRequest($request, $userDetails); + // Set company_uuid before creating user (required for billing resource tracking) + $userDetails['company_uuid'] = $company->uuid; + // create user account for driver $user = User::create($userDetails); From bf27347b0bc4b1ae9b1aa5ddac6a9cd47df0621a Mon Sep 17 00:00:00 2001 From: roncodes <816371+roncodes@users.noreply.github.com> Date: Tue, 13 Jan 2026 23:00:44 -0500 Subject: [PATCH 6/9] Fix vehicle resource tracking - use Vehicle::create() instead of new + fill + save Issue: Vehicles created via API were not being tracked in billing system Root cause: Using new Vehicle() + fill() + save() doesn't fire 'created' event Solution: Replace with Vehicle::create() which properly fires the event The problem: - new Vehicle() creates instance - fill() populates attributes - save() fires 'updated' event, NOT 'created' event - ResourceCreatedListener only listens for 'created' event The fix: - Vehicle::create($input) fires 'created' event properly - ResourceCreatedListener receives event with company_uuid - Resource usage tracked successfully This is cleaner and more idiomatic Laravel code, and ensures billing resource tracking works correctly. --- .../src/Http/Controllers/Api/v1/VehicleController.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/server/src/Http/Controllers/Api/v1/VehicleController.php b/server/src/Http/Controllers/Api/v1/VehicleController.php index 87d52b48..24db4810 100644 --- a/server/src/Http/Controllers/Api/v1/VehicleController.php +++ b/server/src/Http/Controllers/Api/v1/VehicleController.php @@ -30,9 +30,6 @@ public function create(CreateVehicleRequest $request) // make sure company is set $input['company_uuid'] = session('company'); - // create instance of vehicle model - $vehicle = new Vehicle(); - // set default online if (!isset($input['online'])) { $input['online'] = 0; @@ -51,11 +48,8 @@ public function create(CreateVehicleRequest $request) $input['location'] = Utils::getPointFromCoordinates($request->only(['latitude', 'longitude'])); } - // apply user input to vehicle - $vehicle = $vehicle->fill($input); - - // save the vehicle - $vehicle->save(); + // create the vehicle (fires 'created' event for billing resource tracking) + $vehicle = Vehicle::create($input); // driver assignment if ($request->has('driver')) { From 0c2239460fd9299a73e7a18a742fcf4320329943 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Wed, 14 Jan 2026 12:02:55 +0800 Subject: [PATCH 7/9] little tweaks --- server/src/Http/Controllers/Api/v1/DriverController.php | 2 +- server/src/Http/Controllers/Api/v1/VehicleController.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/Http/Controllers/Api/v1/DriverController.php b/server/src/Http/Controllers/Api/v1/DriverController.php index f4f294b0..c7c358e3 100644 --- a/server/src/Http/Controllers/Api/v1/DriverController.php +++ b/server/src/Http/Controllers/Api/v1/DriverController.php @@ -62,7 +62,7 @@ public function create(CreateDriverRequest $request) // Apply user infos $userDetails = User::applyUserInfoFromRequest($request, $userDetails); - // Set company_uuid before creating user (required for billing resource tracking) + // Set company_uuid before creating user $userDetails['company_uuid'] = $company->uuid; // create user account for driver diff --git a/server/src/Http/Controllers/Api/v1/VehicleController.php b/server/src/Http/Controllers/Api/v1/VehicleController.php index 24db4810..2a1c244f 100644 --- a/server/src/Http/Controllers/Api/v1/VehicleController.php +++ b/server/src/Http/Controllers/Api/v1/VehicleController.php @@ -27,6 +27,7 @@ public function create(CreateVehicleRequest $request) { // get request input $input = $request->only(['status', 'make', 'model', 'year', 'trim', 'type', 'plate_number', 'vin', 'meta', 'online', 'location', 'altitude', 'heading', 'speed']); + // make sure company is set $input['company_uuid'] = session('company'); From 3398dafdaffb2787e458f533b854498a05d35d38 Mon Sep 17 00:00:00 2001 From: roncodes <816371+roncodes@users.noreply.github.com> Date: Thu, 15 Jan 2026 20:04:29 -0500 Subject: [PATCH 8/9] Add TestEmail command to test CustomerCredentialsMail with mail-layout component --- server/src/Console/Commands/TestEmail.php | 92 +++++++++++++++++++ .../src/Providers/FleetOpsServiceProvider.php | 1 + 2 files changed, 93 insertions(+) create mode 100644 server/src/Console/Commands/TestEmail.php diff --git a/server/src/Console/Commands/TestEmail.php b/server/src/Console/Commands/TestEmail.php new file mode 100644 index 00000000..00be0e08 --- /dev/null +++ b/server/src/Console/Commands/TestEmail.php @@ -0,0 +1,92 @@ +argument('email'); + $type = $this->option('type'); + + $this->info('Sending test email...'); + $this->info("Type: {$type}"); + $this->info("To: {$email}"); + + try { + switch ($type) { + case 'customer_credentials': + $this->sendCustomerCredentialsEmail($email); + break; + + default: + $this->error("Unknown email type: {$type}"); + return Command::FAILURE; + } + + $this->info('✓ Test email sent successfully!'); + return Command::SUCCESS; + } catch (\Exception $e) { + $this->error('Failed to send test email: ' . $e->getMessage()); + return Command::FAILURE; + } + } + + /** + * Send a test customer credentials email. + * + * @param string $email + * @return void + */ + private function sendCustomerCredentialsEmail(string $email): void + { + // Create a mock customer + $customer = new Contact([ + 'name' => 'Test Customer', + 'email' => $email, + 'phone' => '+1234567890', + ]); + + // Set company relation with mock data + $customer->setRelation('company', (object)[ + 'name' => 'Test Company', + 'public_id' => 'test_company_123', + ]); + + // Set user relation with mock data + $customer->setRelation('user', (object)[ + 'email' => $email, + 'name' => 'Test Customer', + ]); + + // Mock password + $plaintextPassword = 'TestPassword123!'; + + // Send the email + Mail::to($email)->send(new CustomerCredentialsMail($plaintextPassword, $customer)); + } +} diff --git a/server/src/Providers/FleetOpsServiceProvider.php b/server/src/Providers/FleetOpsServiceProvider.php index 67a858a6..452ab51e 100644 --- a/server/src/Providers/FleetOpsServiceProvider.php +++ b/server/src/Providers/FleetOpsServiceProvider.php @@ -60,6 +60,7 @@ class FleetOpsServiceProvider extends CoreServiceProvider \Fleetbase\FleetOps\Console\Commands\PurgeUnpurchasedServiceQuotes::class, \Fleetbase\FleetOps\Console\Commands\SendDriverNotification::class, \Fleetbase\FleetOps\Console\Commands\ReplayVehicleLocations::class, + \Fleetbase\FleetOps\Console\Commands\TestEmail::class, ]; /** From 9aca8cae175974c9a1db47fee4fcd92082cd7605 Mon Sep 17 00:00:00 2001 From: roncodes <816371+roncodes@users.noreply.github.com> Date: Thu, 15 Jan 2026 20:20:02 -0500 Subject: [PATCH 9/9] Fix TestEmail command to use proper User and Company instances instead of stdClass --- server/src/Console/Commands/TestEmail.php | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/server/src/Console/Commands/TestEmail.php b/server/src/Console/Commands/TestEmail.php index 00be0e08..afe820ce 100644 --- a/server/src/Console/Commands/TestEmail.php +++ b/server/src/Console/Commands/TestEmail.php @@ -4,6 +4,8 @@ use Fleetbase\FleetOps\Mail\CustomerCredentialsMail; use Fleetbase\FleetOps\Models\Contact; +use Fleetbase\Models\Company; +use Fleetbase\Models\User; use Illuminate\Console\Command; use Illuminate\Support\Facades\Mail; @@ -64,25 +66,29 @@ public function handle() */ private function sendCustomerCredentialsEmail(string $email): void { - // Create a mock customer - $customer = new Contact([ + // Create a mock user + $user = new User([ 'name' => 'Test Customer', 'email' => $email, - 'phone' => '+1234567890', ]); - // Set company relation with mock data - $customer->setRelation('company', (object)[ + // Create a mock company + $company = new Company([ 'name' => 'Test Company', 'public_id' => 'test_company_123', ]); - // Set user relation with mock data - $customer->setRelation('user', (object)[ - 'email' => $email, + // Create a mock customer + $customer = new Contact([ 'name' => 'Test Customer', + 'email' => $email, + 'phone' => '+1234567890', ]); + // Set relations + $customer->setRelation('company', $company); + $customer->setRelation('user', $user); + // Mock password $plaintextPassword = 'TestPassword123!';