HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/ai.naniguide.com/database/seeders/Demo/Stage03_CustomersSeeder.php
<?php

namespace Database\Seeders\Demo;

use App\Model\Customer;
use App\Model\Language;
use App\Model\Role;
use App\Model\User;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;

/**
 * Creates demo customer accounts via AccountProvisioningService::createCustomer
 * (the same flow `/admin/customers/create` uses).
 *
 * Special-case: when a customer entry has `reuse_admin` set, we skip user
 * creation and instead link the existing admin user to a freshly-created
 * Customer record.  This is how the primary customer shares the user account
 * with the default admin so the same login works for both /admin and /rui routes.
 */
class Stage03_CustomersSeeder extends AbstractDemoSeeder
{
    protected int $fakerOffset = 3;

    /** key → Customer */
    public static array $created = [];

    /** customer key → list of additional User team-member rows (besides primary owner). */
    public static array $teamUsers = [];

    public function run(): void
    {
        $language = Language::getFirstLanguageByCode('en') ?? Language::first();

        // Use the super admin as the "creator" admin for all customers
        $superAdminEntry = Stage01_AdminsSeeder::$created['super'] ?? null;
        if (!$superAdminEntry) {
            throw new \RuntimeException('Stage03 needs Stage01 to have run first.');
        }
        $creatorAdmin = $superAdminEntry['admin'];
        $defaultRole  = Role::getDefaultAdminRole();

        foreach (DemoConfig::customers() as $cfg) {
            $this->time("create customer {$cfg['email']}", function () use ($cfg, $creatorAdmin, $language, $defaultRole) {
                if (!empty($cfg['reuse_admin'])) {
                    $this->createCustomerReusingAdminUser($cfg, $creatorAdmin, $language);
                } else {
                    $this->createCustomerWithNewUser($cfg, $creatorAdmin, $language, $defaultRole);
                }

                if (!empty($cfg['team_users'])) {
                    $this->createTeamUsers($cfg, $defaultRole);
                }
            });
        }

        $this->log('seeded ' . count(self::$created) . ' customers');
        $teamCount = array_sum(array_map('count', self::$teamUsers));
        if ($teamCount > 0) {
            $this->log("seeded {$teamCount} additional team users");
        }
    }

    /**
     * Create a Customer row + link it to the existing admin's user.
     * This is for the "primary" customer that shares the admin user account.
     */
    protected function createCustomerReusingAdminUser(array $cfg, $creatorAdmin, $language): void
    {
        $adminEntry = Stage01_AdminsSeeder::$created[$cfg['reuse_admin']] ?? null;
        if (!$adminEntry) {
            throw new \RuntimeException("reuse_admin=[{$cfg['reuse_admin']}] not found");
        }
        [$validator, $customer] = Customer::createCustomer(
            $cfg['company'],
            $cfg['timezone'],
            $language ? $language->id : null,
            $creatorAdmin
        );
        if ($validator->fails()) {
            throw new \RuntimeException('createCustomer failed: ' . $validator->errors()->first());
        }
        $customer->addUser($adminEntry['user']);
        self::$created[$cfg['key']] = $customer;
    }

    /**
     * Standard flow — same steps as the admin "create customer" form path, but
     * inlined so we can detect success by exception (the wrapper service
     * re-evaluates a stale unique-email validator after the transaction commits
     * which produces a false-positive failure).
     */
    protected function createCustomerWithNewUser(array $cfg, $creatorAdmin, $language, $defaultRole): void
    {
        if (!$defaultRole) {
            throw new \RuntimeException('No default admin role exists.');
        }
        DB::transaction(function () use ($cfg, $creatorAdmin, $language, $defaultRole) {
            // 1. user
            $user = User::newDefault();
            [$ok, $errors] = $user->saveUser(
                $cfg['email'],
                $cfg['password'],
                $cfg['password'],
                $cfg['first_name'],
                $cfg['last_name'],
                null,
                $defaultRole->uid
            );
            if (!$ok) {
                throw new \RuntimeException("saveUser failed for {$cfg['email']}: " . implode(', ', $errors->all()));
            }

            // 2. customer
            [$validator, $customer] = Customer::createCustomer(
                $cfg['company'],
                $cfg['timezone'],
                $language ? $language->id : null,
                $creatorAdmin
            );
            if ($validator->fails()) {
                throw new \RuntimeException("createCustomer failed for {$cfg['email']}: " . $validator->errors()->first());
            }
            $customer->addUser($user);
            self::$created[$cfg['key']] = $customer;

            // 3. avatar
            if (!empty($cfg['avatar'])) {
                Stage01_AdminsSeeder::copyAvatar($user, $cfg['avatar']);
            }

            // 4. backdate created_at for Customer Growth chart
            if (!empty($cfg['created_months_ago'])) {
                $date = Carbon::now()->subMonths($cfg['created_months_ago'])
                    ->startOfMonth()->addDays(rand(0, 27));
                $customer->created_at = $date;
                $customer->save();
                $user->created_at = $date;
                $user->save();
            }
        });
    }

    /**
     * Add additional team-member User rows to a customer that already exists.
     * Same flow as `/rui/account/users/create` (AccountController::userStore):
     * Customer::newUser() → User::saveUser() → Customer::addUser() to wire FK.
     * All members receive the global organization_admin role for demo simplicity.
     */
    protected function createTeamUsers(array $cfg, $defaultRole): void
    {
        $customer = self::$created[$cfg['key']] ?? null;
        if (!$customer) {
            throw new \RuntimeException("createTeamUsers: customer [{$cfg['key']}] not in \$created map.");
        }
        if (!$defaultRole) {
            throw new \RuntimeException('No default admin role exists — cannot seed team users.');
        }

        foreach ($cfg['team_users'] as $member) {
            DB::transaction(function () use ($customer, $member, $defaultRole, $cfg) {
                $user = $customer->newUser();
                [$ok, $errors] = $user->saveUser(
                    $member['email'],
                    $member['password'],
                    $member['password'],
                    $member['first_name'],
                    $member['last_name'],
                    null,
                    $defaultRole->uid
                );
                if (!$ok) {
                    throw new \RuntimeException("team-user saveUser failed for {$member['email']}: " . implode(', ', $errors->all()));
                }
                $customer->addUser($user);

                if (!empty($member['avatar'])) {
                    Stage01_AdminsSeeder::copyAvatar($user, $member['avatar']);
                }

                self::$teamUsers[$cfg['key']][] = $user;
            });
        }
    }
}