validated(); // Tenant gate. New residents always belong to one LGU; the // ResolveTenant middleware sets it from the X-Tenant-Code header. $tenant = Tenancy::current(); if (! $tenant) { return $this->fail('Pick your LGU first.', ['tenant' => ['LGU code required']], 400); } $user = DB::transaction(function () use ($data, $tenant, $dopFinder) { $user = User::create([ 'tenant_id' => $tenant->id, 'first_name' => $data['first_name'], 'middle_name' => $data['middle_name'] ?? null, 'last_name' => $data['last_name'], 'email' => $data['email'], 'phone' => $data['phone'], 'password' => Hash::make($data['password']), 'role' => $data['role'], 'status' => User::STATUS_PENDING, 'preferred_language' => $data['preferred_language'] ?? 'en', ]); $user->assignRole($data['role']); $profileClass = User::profileModelForRole($data['role']); if ($profileClass) { $profileClass::create(['user_id' => $user->id]); } NotificationPreference::create([ 'user_id' => $user->id, 'language' => $data['preferred_language'] ?? 'en', ]); if ($data['role'] === User::ROLE_RESIDENT) { $point = new Point((float) $data['lat'], (float) $data['lng'], 4326); $nearestDop = $dopFinder->nearest((float) $data['lat'], (float) $data['lng']); $household = Household::create([ 'tenant_id' => $tenant->id, 'head_user_id' => $user->id, 'barangay_id' => $data['barangay_id'] ?? null, 'address_line' => $data['address_line'], 'coordinates' => $point, 'household_size' => $data['household_size'] ?? 1, 'assigned_drop_off_point_id' => $nearestDop?->id, 'verification_status' => Household::VERIFICATION_PENDING, ]); HouseholdMember::create([ 'household_id' => $household->id, 'user_id' => $user->id, 'relationship' => HouseholdMember::RELATIONSHIP_HEAD, 'full_name' => $user->full_name, ]); app(\App\Services\Qr\QrAllocator::class)->allocateFreeToHousehold($household); } return $user; }); $issue = $otp->issue( destination: $user->phone, purpose: OtpCode::PURPOSE_REGISTER, user: $user, ); // Fire-and-forget email verification link. If the mail backend is // misconfigured we don't block registration. try { $user->sendEmailVerificationNotification(); } catch (\Throwable $e) { \Log::warning('Failed to send verification email', [ 'user_id' => $user->id, 'error' => $e->getMessage(), ]); } return $this->created([ 'user' => new UserResource($user), 'otp_sent' => $issue->issued, 'otp_destination' => $user->phone, 'debug_code' => app()->environment('local', 'testing') ? $issue->plainCode : null, ], 'Registration successful. Verify the OTP sent to your phone.'); } }