From 9744f0fe0126a976bde2ce9d8715493d575eec43 Mon Sep 17 00:00:00 2001 From: isaacclad Date: Fri, 17 Jul 2026 13:43:07 +0000 Subject: [PATCH] Seed DemoWorld business and customer continuity for Woo Manager demos Store site names now reference the DemoWorld business identity for the active plan, and order customers use DemoWorld people (name, email, phone) instead of generic "Demo Customer N" placeholders. Staff logins skip the login reseed. Co-authored-by: Cursor --- app/Console/Commands/DemoSeedCommand.php | 23 +- app/Services/Woo/DemoLoginReseeder.php | 8 + app/Support/DemoWorld.php | 553 +++++++++++++++++++++++ tests/Feature/DemoSeedCommandTest.php | 19 + 4 files changed, 594 insertions(+), 9 deletions(-) create mode 100644 app/Support/DemoWorld.php diff --git a/app/Console/Commands/DemoSeedCommand.php b/app/Console/Commands/DemoSeedCommand.php index 6fe51a2..205a2aa 100644 --- a/app/Console/Commands/DemoSeedCommand.php +++ b/app/Console/Commands/DemoSeedCommand.php @@ -9,6 +9,7 @@ use App\Models\WooOrder; use App\Models\WooProduct; use App\Models\WooStore; use App\Services\Woo\SubscriptionService; +use App\Support\DemoWorld; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; @@ -115,25 +116,26 @@ class DemoSeedCommand extends Command private function storeSpecs(string $plan): array { $baseCategories = ['Apparel', 'Accessories', 'Home']; + $businessName = DemoWorld::business($plan)['name']; return match ($plan) { 'enterprise' => [ [ - 'site_name' => 'Demo Accra Shop', + 'site_name' => $businessName.' Shop', 'site_url' => 'https://demo-accra.example.com', 'products' => 30, 'orders' => 12, 'categories' => $baseCategories, ], [ - 'site_name' => 'Demo Kumasi Shop', + 'site_name' => $businessName.' — Kumasi Branch Shop', 'site_url' => 'https://demo-kumasi.example.com', 'products' => 24, 'orders' => 8, 'categories' => ['Electronics', 'Gadgets'], ], [ - 'site_name' => 'Demo Wholesale', + 'site_name' => $businessName.' Wholesale', 'site_url' => 'https://demo-wholesale.example.com', 'products' => 20, 'orders' => 6, @@ -142,14 +144,14 @@ class DemoSeedCommand extends Command ], 'pro' => [ [ - 'site_name' => 'Demo Pro Shop', + 'site_name' => $businessName.' Shop', 'site_url' => 'https://demo-pro-shop.example.com', 'products' => 35, 'orders' => 10, 'categories' => $baseCategories, ], [ - 'site_name' => 'Demo Outlet', + 'site_name' => $businessName.' Outlet', 'site_url' => 'https://demo-outlet.example.com', 'products' => 15, 'orders' => 5, @@ -158,7 +160,7 @@ class DemoSeedCommand extends Command ], default => [ [ - 'site_name' => 'Demo Free Shop', + 'site_name' => $businessName.' Shop', 'site_url' => 'https://demo-free-shop.example.com', 'products' => 15, 'orders' => 4, @@ -225,10 +227,13 @@ class DemoSeedCommand extends Command } } + $people = DemoWorld::people(); + for ($i = 1; $i <= $spec['orders']; $i++) { $product = $products[($i - 1) % count($products)]; $qty = 1 + ($i % 3); $lineTotal = (int) $product->regular_price_minor * $qty; + $customer = $people[($i - 1) % count($people)]; WooOrder::query()->create([ 'woo_store_id' => $store->id, @@ -236,9 +241,9 @@ class DemoSeedCommand extends Command 'order_number' => (string) (1000 + $i), 'wc_status' => $i % 4 === 0 ? 'completed' : 'processing', 'payment_status' => 'paid', - 'customer_name' => 'Demo Customer '.$i, - 'customer_email' => 'customer'.$i.'@example.com', - 'customer_phone' => '+233200000'.str_pad((string) $i, 3, '0', STR_PAD_LEFT), + 'customer_name' => DemoWorld::fullName($customer), + 'customer_email' => $customer['email'], + 'customer_phone' => $customer['phone'], 'line_items' => [[ 'id' => $product->external_id, 'name' => $product->name, diff --git a/app/Services/Woo/DemoLoginReseeder.php b/app/Services/Woo/DemoLoginReseeder.php index 2f1b66e..9e7258d 100644 --- a/app/Services/Woo/DemoLoginReseeder.php +++ b/app/Services/Woo/DemoLoginReseeder.php @@ -3,12 +3,16 @@ namespace App\Services\Woo; use App\Models\User; +use App\Support\DemoWorld; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Log; /** * Reseed Woo Manager demo tenants after a fresh SSO login. + * + * Only owner demo accounts trigger a full reseed. Staff training logins + * share the owner tenant but never wipe mid-demo. */ class DemoLoginReseeder { @@ -19,6 +23,10 @@ class DemoLoginReseeder return; } + if (DemoWorld::isStaffDemoEmail($user->email)) { + return; + } + $plan = $this->planForEmail($user->email); if ($plan === null) { return; diff --git a/app/Support/DemoWorld.php b/app/Support/DemoWorld.php new file mode 100644 index 0000000..c2bc1b6 --- /dev/null +++ b/app/Support/DemoWorld.php @@ -0,0 +1,553 @@ + + */ + public const BUSINESS = [ + 'free' => [ + 'name' => 'Ridge Family Clinic', + 'legal_name' => 'Ridge Family Clinic Ltd', + 'phone' => '+233302400100', + 'email' => 'hello@ridgeclinic.demo.ladill.com', + 'address' => '12 Castle Road, Ridge, Accra', + 'city' => 'Accra', + 'region' => 'Greater Accra', + 'timezone' => self::TIMEZONE, + ], + 'pro' => [ + 'name' => 'Ridge Medical Centre', + 'legal_name' => 'Ridge Medical Centre Ltd', + 'phone' => '+233302400200', + 'email' => 'hello@ridgemedical.demo.ladill.com', + 'address' => '45 Independence Ave, Ridge, Accra', + 'city' => 'Accra', + 'region' => 'Greater Accra', + 'timezone' => self::TIMEZONE, + ], + 'enterprise' => [ + 'name' => 'Accra Healthcare Group', + 'legal_name' => 'Accra Healthcare Group Ltd', + 'phone' => '+233302400300', + 'email' => 'hello@accrahealth.demo.ladill.com', + 'address' => '1 Liberation Road, Airport Residential, Accra', + 'city' => 'Accra', + 'region' => 'Greater Accra', + 'timezone' => self::TIMEZONE, + ], + ]; + + /** + * Shared branch catalog. Plans take the first N (free=1, pro=3, enterprise=6). + * + * @var list + */ + public const BRANCHES = [ + ['code' => 'HQ', 'name' => 'Ridge Clinic', 'phone' => '+233302400101', 'address' => '12 Castle Road, Ridge, Accra'], + ['code' => 'EL', 'name' => 'East Legon Care', 'phone' => '+233302400102', 'address' => '18 Boundary Rd, East Legon, Accra'], + ['code' => 'TM', 'name' => 'Tema Harbour Clinic', 'phone' => '+233302400103', 'address' => 'Harbour Road, Community 1, Tema'], + ['code' => 'OS', 'name' => 'Osu Medical Centre', 'phone' => '+233302400104', 'address' => 'Oxford Street, Osu, Accra'], + ['code' => 'SX', 'name' => 'Spintex Wellness', 'phone' => '+233302400105', 'address' => 'Spintex Road, Accra'], + ['code' => 'AP', 'name' => 'Airport Residential Care', 'phone' => '+233302400106', 'address' => 'Liberation Rd, Airport Residential, Accra'], + ]; + + /** + * Canonical people reused as patients / visitors / ticket guests / CRM + * contacts / invoice clients / POS customers / event attendees. + * + * @var list + */ + public const PEOPLE = [ + ['key' => 'ama-mensah', 'first_name' => 'Ama', 'last_name' => 'Mensah', 'phone' => '+233241000001', 'email' => 'ama.mensah@demo.ladill.com', 'national_id' => 'GHA-729001001', 'gender' => 'female', 'dob' => '1990-03-12', 'company_key' => 'accra-retail', 'city' => 'Accra', 'address' => '14 Ring Road Central, Accra'], + ['key' => 'kofi-asante', 'first_name' => 'Kofi', 'last_name' => 'Asante', 'phone' => '+233241000002', 'email' => 'kofi.asante@demo.ladill.com', 'national_id' => 'GHA-729001002', 'gender' => 'male', 'dob' => '1985-07-21', 'company_key' => 'kumasi-foods', 'city' => 'Accra', 'address' => '3 Labone Crescent, Accra'], + ['key' => 'abena-osei', 'first_name' => 'Abena', 'last_name' => 'Osei', 'phone' => '+233241000003', 'email' => 'abena.osei@demo.ladill.com', 'national_id' => 'GHA-729001003', 'gender' => 'female', 'dob' => '1992-11-05', 'company_key' => 'tema-logistics', 'city' => 'Tema', 'address' => 'Community 4, Tema'], + ['key' => 'kwame-boateng', 'first_name' => 'Kwame', 'last_name' => 'Boateng', 'phone' => '+233241000004', 'email' => 'kwame.boateng@demo.ladill.com', 'national_id' => 'GHA-729001004', 'gender' => 'male', 'dob' => '1978-01-30', 'company_key' => 'cape-coast-tours', 'city' => 'Accra', 'address' => '8 Cantonments Road, Accra'], + ['key' => 'akosua-owusu', 'first_name' => 'Akosua', 'last_name' => 'Owusu', 'phone' => '+233241000005', 'email' => 'akosua.owusu@demo.ladill.com', 'national_id' => 'GHA-729001005', 'gender' => 'female', 'dob' => '1995-06-18', 'company_key' => 'tamale-agro', 'city' => 'Accra', 'address' => '22 Dansoman Estates, Accra'], + ['key' => 'yaw-adjei', 'first_name' => 'Yaw', 'last_name' => 'Adjei', 'phone' => '+233241000006', 'email' => 'yaw.adjei@demo.ladill.com', 'national_id' => 'GHA-729001006', 'gender' => 'male', 'dob' => '1988-09-09', 'company_key' => 'spintex-clinics', 'city' => 'Accra', 'address' => 'Spintex Junction, Accra'], + ['key' => 'efua-appiah', 'first_name' => 'Efua', 'last_name' => 'Appiah', 'phone' => '+233241000007', 'email' => 'efua.appiah@demo.ladill.com', 'national_id' => 'GHA-729001007', 'gender' => 'female', 'dob' => '1993-02-14', 'company_key' => 'osu-cafe', 'city' => 'Accra', 'address' => 'Oxford Street, Osu, Accra'], + ['key' => 'kojo-darko', 'first_name' => 'Kojo', 'last_name' => 'Darko', 'phone' => '+233241000008', 'email' => 'kojo.darko@demo.ladill.com', 'national_id' => 'GHA-729001008', 'gender' => 'male', 'dob' => '1982-12-01', 'company_key' => 'legon-tech', 'city' => 'Accra', 'address' => 'University Area, Legon'], + ['key' => 'adwoa-agyeman', 'first_name' => 'Adwoa', 'last_name' => 'Agyeman', 'phone' => '+233241000009', 'email' => 'adwoa.agyeman@demo.ladill.com', 'national_id' => 'GHA-729001009', 'gender' => 'female', 'dob' => '1991-04-22', 'company_key' => 'airport-hotels', 'city' => 'Accra', 'address' => 'Airport Residential, Accra'], + ['key' => 'kwesi-sarpong', 'first_name' => 'Kwesi', 'last_name' => 'Sarpong', 'phone' => '+233241000010', 'email' => 'kwesi.sarpong@demo.ladill.com', 'national_id' => 'GHA-729001010', 'gender' => 'male', 'dob' => '1987-08-16', 'company_key' => 'kaneshie-traders', 'city' => 'Accra', 'address' => 'Kaneshie Market, Accra'], + ['key' => 'afia-nyarko', 'first_name' => 'Afia', 'last_name' => 'Nyarko', 'phone' => '+233241000011', 'email' => 'afia.nyarko@demo.ladill.com', 'national_id' => 'GHA-729001011', 'gender' => 'female', 'dob' => '1994-10-03', 'company_key' => 'accra-retail', 'city' => 'Accra', 'address' => 'Adabraka, Accra'], + ['key' => 'kwadwo-ankrah', 'first_name' => 'Kwadwo', 'last_name' => 'Ankrah', 'phone' => '+233241000012', 'email' => 'kwadwo.ankrah@demo.ladill.com', 'national_id' => 'GHA-729001012', 'gender' => 'male', 'dob' => '1980-05-27', 'company_key' => 'kumasi-foods', 'city' => 'Accra', 'address' => 'Mamprobi, Accra'], + ['key' => 'esi-tetteh', 'first_name' => 'Esi', 'last_name' => 'Tetteh', 'phone' => '+233241000013', 'email' => 'esi.tetteh@demo.ladill.com', 'national_id' => 'GHA-729001013', 'gender' => 'female', 'dob' => '1996-01-19', 'company_key' => 'tema-logistics', 'city' => 'Tema', 'address' => 'Community 8, Tema'], + ['key' => 'fiifi-quaye', 'first_name' => 'Fiifi', 'last_name' => 'Quaye', 'phone' => '+233241000014', 'email' => 'fiifi.quaye@demo.ladill.com', 'national_id' => 'GHA-729001014', 'gender' => 'male', 'dob' => '1989-07-07', 'company_key' => 'cape-coast-tours', 'city' => 'Accra', 'address' => 'Tesano, Accra'], + ['key' => 'mansa-addo', 'first_name' => 'Mansa', 'last_name' => 'Addo', 'phone' => '+233241000015', 'email' => 'mansa.addo@demo.ladill.com', 'national_id' => 'GHA-729001015', 'gender' => 'female', 'dob' => '1993-09-25', 'company_key' => 'tamale-agro', 'city' => 'Accra', 'address' => 'Abelemkpe, Accra'], + ['key' => 'nana-frimpong', 'first_name' => 'Nana', 'last_name' => 'Frimpong', 'phone' => '+233241000016', 'email' => 'nana.frimpong@demo.ladill.com', 'national_id' => 'GHA-729001016', 'gender' => 'male', 'dob' => '1984-03-11', 'company_key' => 'spintex-clinics', 'city' => 'Accra', 'address' => 'Teshie, Accra'], + ['key' => 'ama-boateng', 'first_name' => 'Ama', 'last_name' => 'Boateng', 'phone' => '+233241000017', 'email' => 'ama.boateng@demo.ladill.com', 'national_id' => 'GHA-729001017', 'gender' => 'female', 'dob' => '1997-12-08', 'company_key' => 'osu-cafe', 'city' => 'Accra', 'address' => 'Kokomlemle, Accra'], + ['key' => 'kofi-owusu', 'first_name' => 'Kofi', 'last_name' => 'Owusu', 'phone' => '+233241000018', 'email' => 'kofi.owusu@demo.ladill.com', 'national_id' => 'GHA-729001018', 'gender' => 'male', 'dob' => '1986-06-02', 'company_key' => 'legon-tech', 'city' => 'Accra', 'address' => 'Haatso, Accra'], + ['key' => 'abena-darko', 'first_name' => 'Abena', 'last_name' => 'Darko', 'phone' => '+233241000019', 'email' => 'abena.darko@demo.ladill.com', 'national_id' => 'GHA-729001019', 'gender' => 'female', 'dob' => '1990-08-29', 'company_key' => 'airport-hotels', 'city' => 'Accra', 'address' => 'Dzorwulu, Accra'], + ['key' => 'kwame-mensah', 'first_name' => 'Kwame', 'last_name' => 'Mensah', 'phone' => '+233241000020', 'email' => 'kwame.mensah@demo.ladill.com', 'national_id' => 'GHA-729001020', 'gender' => 'male', 'dob' => '1979-11-13', 'company_key' => 'kaneshie-traders', 'city' => 'Accra', 'address' => 'Ablekuma, Accra'], + ['key' => 'akosua-asante', 'first_name' => 'Akosua', 'last_name' => 'Asante', 'phone' => '+233241000021', 'email' => 'akosua.asante@demo.ladill.com', 'national_id' => 'GHA-729001021', 'gender' => 'female', 'dob' => '1992-02-20', 'company_key' => 'accra-retail', 'city' => 'Accra', 'address' => 'Roman Ridge, Accra'], + ['key' => 'yaw-osei', 'first_name' => 'Yaw', 'last_name' => 'Osei', 'phone' => '+233241000022', 'email' => 'yaw.osei@demo.ladill.com', 'national_id' => 'GHA-729001022', 'gender' => 'male', 'dob' => '1983-04-15', 'company_key' => 'kumasi-foods', 'city' => 'Accra', 'address' => 'Nungua, Accra'], + ['key' => 'efua-boateng', 'first_name' => 'Efua', 'last_name' => 'Boateng', 'phone' => '+233241000023', 'email' => 'efua.boateng@demo.ladill.com', 'national_id' => 'GHA-729001023', 'gender' => 'female', 'dob' => '1995-07-01', 'company_key' => 'tema-logistics', 'city' => 'Tema', 'address' => 'Community 2, Tema'], + ['key' => 'kojo-owusu', 'first_name' => 'Kojo', 'last_name' => 'Owusu', 'phone' => '+233241000024', 'email' => 'kojo.owusu@demo.ladill.com', 'national_id' => 'GHA-729001024', 'gender' => 'male', 'dob' => '1981-10-28', 'company_key' => 'cape-coast-tours', 'city' => 'Accra', 'address' => 'Madina, Accra'], + ['key' => 'adwoa-adjei', 'first_name' => 'Adwoa', 'last_name' => 'Adjei', 'phone' => '+233241000025', 'email' => 'adwoa.adjei@demo.ladill.com', 'national_id' => 'GHA-729001025', 'gender' => 'female', 'dob' => '1994-05-06', 'company_key' => 'tamale-agro', 'city' => 'Accra', 'address' => 'Ashaiman, Accra'], + ['key' => 'kwesi-appiah', 'first_name' => 'Kwesi', 'last_name' => 'Appiah', 'phone' => '+233241000026', 'email' => 'kwesi.appiah@demo.ladill.com', 'national_id' => 'GHA-729001026', 'gender' => 'male', 'dob' => '1988-12-17', 'company_key' => 'spintex-clinics', 'city' => 'Accra', 'address' => 'Baatsona, Accra'], + ['key' => 'afia-darko', 'first_name' => 'Afia', 'last_name' => 'Darko', 'phone' => '+233241000027', 'email' => 'afia.darko@demo.ladill.com', 'national_id' => 'GHA-729001027', 'gender' => 'female', 'dob' => '1991-09-23', 'company_key' => 'osu-cafe', 'city' => 'Accra', 'address' => 'Labadi, Accra'], + ['key' => 'kwadwo-agyeman', 'first_name' => 'Kwadwo', 'last_name' => 'Agyeman', 'phone' => '+233241000028', 'email' => 'kwadwo.agyeman@demo.ladill.com', 'national_id' => 'GHA-729001028', 'gender' => 'male', 'dob' => '1985-01-04', 'company_key' => 'legon-tech', 'city' => 'Accra', 'address' => 'Kwabenya, Accra'], + ['key' => 'esi-sarpong', 'first_name' => 'Esi', 'last_name' => 'Sarpong', 'phone' => '+233241000029', 'email' => 'esi.sarpong@demo.ladill.com', 'national_id' => 'GHA-729001029', 'gender' => 'female', 'dob' => '1996-03-30', 'company_key' => 'airport-hotels', 'city' => 'Accra', 'address' => 'East Legon Hills, Accra'], + ['key' => 'fiifi-nyarko', 'first_name' => 'Fiifi', 'last_name' => 'Nyarko', 'phone' => '+233241000030', 'email' => 'fiifi.nyarko@demo.ladill.com', 'national_id' => 'GHA-729001030', 'gender' => 'male', 'dob' => '1987-06-14', 'company_key' => 'kaneshie-traders', 'city' => 'Accra', 'address' => 'Odorkor, Accra'], + ['key' => 'mansa-ankrah', 'first_name' => 'Mansa', 'last_name' => 'Ankrah', 'phone' => '+233241000031', 'email' => 'mansa.ankrah@demo.ladill.com', 'national_id' => 'GHA-729001031', 'gender' => 'female', 'dob' => '1993-11-11', 'company_key' => 'accra-retail', 'city' => 'Accra', 'address' => 'Korle Bu, Accra'], + ['key' => 'nana-tetteh', 'first_name' => 'Nana', 'last_name' => 'Tetteh', 'phone' => '+233241000032', 'email' => 'nana.tetteh@demo.ladill.com', 'national_id' => 'GHA-729001032', 'gender' => 'male', 'dob' => '1982-08-08', 'company_key' => 'kumasi-foods', 'city' => 'Accra', 'address' => 'Weija, Accra'], + ['key' => 'ama-quaye', 'first_name' => 'Ama', 'last_name' => 'Quaye', 'phone' => '+233241000033', 'email' => 'ama.quaye@demo.ladill.com', 'national_id' => 'GHA-729001033', 'gender' => 'female', 'dob' => '1990-04-04', 'company_key' => 'tema-logistics', 'city' => 'Tema', 'address' => 'Community 11, Tema'], + ['key' => 'kofi-addo', 'first_name' => 'Kofi', 'last_name' => 'Addo', 'phone' => '+233241000034', 'email' => 'kofi.addo@demo.ladill.com', 'national_id' => 'GHA-729001034', 'gender' => 'male', 'dob' => '1989-02-26', 'company_key' => 'cape-coast-tours', 'city' => 'Accra', 'address' => 'Kasoa Road, Accra'], + ['key' => 'abena-frimpong', 'first_name' => 'Abena', 'last_name' => 'Frimpong', 'phone' => '+233241000035', 'email' => 'abena.frimpong@demo.ladill.com', 'national_id' => 'GHA-729001035', 'gender' => 'female', 'dob' => '1994-07-19', 'company_key' => 'tamale-agro', 'city' => 'Accra', 'address' => 'Achimota, Accra'], + ['key' => 'kwame-agyeman', 'first_name' => 'Kwame', 'last_name' => 'Agyeman', 'phone' => '+233241000036', 'email' => 'kwame.agyeman@demo.ladill.com', 'national_id' => 'GHA-729001036', 'gender' => 'male', 'dob' => '1980-09-01', 'company_key' => 'spintex-clinics', 'city' => 'Accra', 'address' => 'Sakumono, Accra'], + ]; + + /** + * @var list + */ + public const COMPANIES = [ + ['key' => 'accra-retail', 'name' => 'Accra Retail Ltd', 'email' => 'accounts@accra-retail.demo.ladill.com', 'phone' => '+233302500001', 'address' => 'Oxford Street, Accra'], + ['key' => 'kumasi-foods', 'name' => 'Kumasi Foods', 'email' => 'billing@kumasi-foods.demo.ladill.com', 'phone' => '+233302500002', 'address' => 'Kejetia Road, Kumasi'], + ['key' => 'tema-logistics', 'name' => 'Tema Logistics', 'email' => 'finance@tema-logistics.demo.ladill.com', 'phone' => '+233302500003', 'address' => 'Harbour Road, Tema'], + ['key' => 'cape-coast-tours', 'name' => 'Cape Coast Tours', 'email' => 'pay@cape-coast-tours.demo.ladill.com', 'phone' => '+233302500004', 'address' => 'Castle Road, Cape Coast'], + ['key' => 'tamale-agro', 'name' => 'Tamale Agro', 'email' => 'accounts@tamale-agro.demo.ladill.com', 'phone' => '+233302500005', 'address' => 'Salaga Road, Tamale'], + ['key' => 'spintex-clinics', 'name' => 'Spintex Clinics', 'email' => 'billing@spintex-clinics.demo.ladill.com', 'phone' => '+233302500006', 'address' => 'Spintex Road, Accra'], + ['key' => 'osu-cafe', 'name' => 'Osu Café Co', 'email' => 'hello@osu-cafe.demo.ladill.com', 'phone' => '+233302500007', 'address' => 'Oxford Street, Osu'], + ['key' => 'legon-tech', 'name' => 'Legon Tech', 'email' => 'ap@legon-tech.demo.ladill.com', 'phone' => '+233302500008', 'address' => 'University Area, Legon'], + ['key' => 'airport-hotels', 'name' => 'Airport City Hotels', 'email' => 'finance@airport-hotels.demo.ladill.com', 'phone' => '+233302500009', 'address' => 'Airport City, Accra'], + ['key' => 'kaneshie-traders', 'name' => 'Kaneshie Market Traders', 'email' => 'pay@kaneshie-traders.demo.ladill.com', 'phone' => '+233302500010', 'address' => 'Kaneshie Market, Accra'], + ]; + + /** + * Plausible shared story amounts (GHS major units) for Accounting / Invoice / POS labels. + * + * @var array{care_consult: int, care_lab: int, invoice_typical: int, pos_typical: int, crm_deal: int} + */ + public const STORY_AMOUNTS_GHS = [ + 'care_consult' => 250, + 'care_lab' => 180, + 'invoice_typical' => 1500, + 'pos_typical' => 85, + 'crm_deal' => 12000, + ]; + + /** + * Staff roster keyed by tier. Free: owner + receptionist. Pro/Enterprise: full roster. + * + * @var array, + * roles: array, + * account_role?: string + * }>> + */ + public const STAFF = [ + 'free' => [ + [ + 'key' => 'receptionist', + 'email' => 'demo-free-receptionist@ladill.com', + 'name' => 'Abena Reception (Free)', + 'apps' => ['care', 'frontdesk', 'queue'], + 'roles' => [ + 'care' => 'receptionist', + 'frontdesk' => 'receptionist', + 'queue' => 'receptionist', + ], + ], + ], + 'pro' => [ + [ + 'key' => 'doctor', + 'email' => 'demo-pro-doctor@ladill.com', + 'name' => 'Dr. Kwame Mensah (Pro)', + 'apps' => ['care'], + 'roles' => ['care' => 'doctor'], + ], + [ + 'key' => 'nurse', + 'email' => 'demo-pro-nurse@ladill.com', + 'name' => 'Akosua Nurse (Pro)', + 'apps' => ['care'], + 'roles' => ['care' => 'nurse'], + ], + [ + 'key' => 'receptionist', + 'email' => 'demo-pro-receptionist@ladill.com', + 'name' => 'Abena Reception (Pro)', + 'apps' => ['care', 'frontdesk', 'queue'], + 'roles' => [ + 'care' => 'receptionist', + 'frontdesk' => 'receptionist', + 'queue' => 'receptionist', + ], + ], + [ + 'key' => 'pharmacist', + 'email' => 'demo-pro-pharmacist@ladill.com', + 'name' => 'Yaw Pharmacist (Pro)', + 'apps' => ['care'], + 'roles' => ['care' => 'pharmacist'], + ], + [ + 'key' => 'lab', + 'email' => 'demo-pro-lab@ladill.com', + 'name' => 'Efua Lab Tech (Pro)', + 'apps' => ['care'], + 'roles' => ['care' => 'lab_technician'], + ], + [ + 'key' => 'cashier', + 'email' => 'demo-pro-cashier@ladill.com', + 'name' => 'Kojo Cashier (Pro)', + 'apps' => ['care', 'pos'], + 'roles' => [ + 'care' => 'cashier', + 'pos' => 'cashier', + ], + ], + [ + 'key' => 'accountant', + 'email' => 'demo-pro-accountant@ladill.com', + 'name' => 'Adwoa Accountant (Pro)', + 'apps' => ['accounting', 'invoice'], + 'roles' => [ + 'accounting' => 'member', + 'invoice' => 'member', + 'care' => 'accountant', + ], + ], + [ + 'key' => 'sales', + 'email' => 'demo-pro-sales@ladill.com', + 'name' => 'Kofi Sales (Pro)', + 'apps' => ['crm', 'invoice', 'meet'], + 'roles' => [ + 'crm' => 'member', + 'invoice' => 'member', + 'meet' => 'member', + ], + ], + ], + 'enterprise' => [ + [ + 'key' => 'doctor', + 'email' => 'demo-enterprise-doctor@ladill.com', + 'name' => 'Dr. Kwame Mensah', + 'apps' => ['care'], + 'roles' => ['care' => 'doctor'], + ], + [ + 'key' => 'nurse', + 'email' => 'demo-enterprise-nurse@ladill.com', + 'name' => 'Akosua Nurse', + 'apps' => ['care'], + 'roles' => ['care' => 'nurse'], + ], + [ + 'key' => 'receptionist', + 'email' => 'demo-enterprise-receptionist@ladill.com', + 'name' => 'Abena Reception', + 'apps' => ['care', 'frontdesk', 'queue'], + 'roles' => [ + 'care' => 'receptionist', + 'frontdesk' => 'receptionist', + 'queue' => 'receptionist', + ], + ], + [ + 'key' => 'pharmacist', + 'email' => 'demo-enterprise-pharmacist@ladill.com', + 'name' => 'Yaw Pharmacist', + 'apps' => ['care'], + 'roles' => ['care' => 'pharmacist'], + ], + [ + 'key' => 'lab', + 'email' => 'demo-enterprise-lab@ladill.com', + 'name' => 'Efua Lab Tech', + 'apps' => ['care'], + 'roles' => ['care' => 'lab_technician'], + ], + [ + 'key' => 'cashier', + 'email' => 'demo-enterprise-cashier@ladill.com', + 'name' => 'Kojo Cashier', + 'apps' => ['care', 'pos'], + 'roles' => [ + 'care' => 'cashier', + 'pos' => 'cashier', + ], + ], + [ + 'key' => 'accountant', + 'email' => 'demo-enterprise-accountant@ladill.com', + 'name' => 'Adwoa Accountant', + 'apps' => ['accounting', 'invoice', 'care'], + 'roles' => [ + 'accounting' => 'member', + 'invoice' => 'member', + 'care' => 'accountant', + ], + ], + [ + 'key' => 'sales', + 'email' => 'demo-enterprise-sales@ladill.com', + 'name' => 'Kofi Sales', + 'apps' => ['crm', 'invoice', 'meet', 'events'], + 'roles' => [ + 'crm' => 'member', + 'invoice' => 'member', + 'meet' => 'member', + 'events' => 'member', + ], + ], + ], + ]; + + /** @var array owner email → tier */ + public const OWNER_EMAILS = [ + 'demo-free@ladill.com' => 'free', + 'demo-pro@ladill.com' => 'pro', + 'demo-enterprise@ladill.com' => 'enterprise', + ]; + + public static function normalizeTier(string $tier): string + { + $tier = strtolower(trim($tier)); + + return in_array($tier, ['free', 'pro', 'enterprise'], true) ? $tier : 'free'; + } + + public static function ownerEmailForTier(string $tier): string + { + $tier = self::normalizeTier($tier); + + return match ($tier) { + 'pro' => 'demo-pro@ladill.com', + 'enterprise' => 'demo-enterprise@ladill.com', + default => 'demo-free@ladill.com', + }; + } + + public static function tierForOwnerEmail(?string $email): ?string + { + $email = strtolower(trim((string) $email)); + + return self::OWNER_EMAILS[$email] ?? null; + } + + /** + * @return array{name: string, legal_name: string, phone: string, email: string, address: string, city: string, region: string, timezone: string} + */ + public static function business(string $tier): array + { + return self::BUSINESS[self::normalizeTier($tier)]; + } + + /** + * @return list + */ + public static function branches(string $tier, ?int $limit = null): array + { + $tier = self::normalizeTier($tier); + $limit ??= match ($tier) { + 'enterprise' => 6, + 'pro' => 3, + default => 1, + }; + + return array_slice(self::BRANCHES, 0, max(1, $limit)); + } + + /** + * @return list + */ + public static function people(?int $limit = null): array + { + if ($limit === null) { + return self::PEOPLE; + } + + return array_slice(self::PEOPLE, 0, max(0, $limit)); + } + + /** + * @return array{key: string, first_name: string, last_name: string, phone: string, email: string, national_id: string, gender: string, dob: string, company_key: string, city: string, address: string}|null + */ + public static function personByKey(string $key): ?array + { + foreach (self::PEOPLE as $person) { + if ($person['key'] === $key) { + return $person; + } + } + + return null; + } + + public static function fullName(array $person): string + { + return trim($person['first_name'].' '.$person['last_name']); + } + + /** + * @return list + */ + public static function companies(?int $limit = null): array + { + if ($limit === null) { + return self::COMPANIES; + } + + return array_slice(self::COMPANIES, 0, max(0, $limit)); + } + + /** + * @return array{key: string, name: string, email: string, phone: string, address: string}|null + */ + public static function companyByKey(string $key): ?array + { + foreach (self::COMPANIES as $company) { + if ($company['key'] === $key) { + return $company; + } + } + + return null; + } + + public static function companyNameForPerson(array $person): string + { + return self::companyByKey($person['company_key'])['name'] ?? 'Demo Co'; + } + + /** + * @return list, roles: array, account_role?: string}> + */ + public static function staff(string $tier): array + { + return self::STAFF[self::normalizeTier($tier)] ?? []; + } + + /** + * @return array{key: string, email: string, name: string, apps: list, roles: array, account_role?: string}|null + */ + public static function staffByEmail(?string $email): ?array + { + $email = strtolower(trim((string) $email)); + if ($email === '') { + return null; + } + + foreach (self::STAFF as $roster) { + foreach ($roster as $member) { + if (strtolower($member['email']) === $email) { + return $member; + } + } + } + + return null; + } + + public static function isOwnerDemoEmail(?string $email): bool + { + return self::tierForOwnerEmail($email) !== null; + } + + public static function isStaffDemoEmail(?string $email): bool + { + return self::staffByEmail($email) !== null; + } + + /** Owner email for a staff member, or null if not staff. */ + public static function ownerEmailForStaff(?string $email): ?string + { + $email = strtolower(trim((string) $email)); + foreach (self::STAFF as $tier => $roster) { + foreach ($roster as $member) { + if (strtolower($member['email']) === $email) { + return self::ownerEmailForTier($tier); + } + } + } + + return null; + } + + /** + * Build Identity AccountTeamMember metadata from a staff roles map. + * + * @param array $roles + * @return array + */ + public static function metadataFromRoles(array $roles): array + { + $metadata = []; + foreach ($roles as $app => $role) { + $metadata[$app] = ['role' => $role]; + } + + return $metadata; + } + + public static function storyDay(): \Carbon\CarbonInterface + { + return now(self::TIMEZONE)->startOfDay()->addDays(self::STORY_DAY_OFFSET); + } + + /** Local phone form used by some apps (024####### without +233). */ + public static function phoneLocal(string $e164): string + { + if (str_starts_with($e164, '+233')) { + return '0'.substr($e164, 4); + } + + return $e164; + } +} diff --git a/tests/Feature/DemoSeedCommandTest.php b/tests/Feature/DemoSeedCommandTest.php index 76c2868..58f8959 100644 --- a/tests/Feature/DemoSeedCommandTest.php +++ b/tests/Feature/DemoSeedCommandTest.php @@ -7,6 +7,7 @@ use App\Models\Woo\ProSubscription; use App\Models\WooOrder; use App\Models\WooProduct; use App\Models\WooStore; +use App\Support\DemoWorld; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; @@ -74,4 +75,22 @@ class DemoSeedCommandTest extends TestCase $this->assertCount(1, WooStore::query()->where('user_id', $user->id)->get()); $this->assertDatabaseMissing('woo_pro_subscriptions', ['user_id' => $user->id]); } + + public function test_pro_plan_uses_demo_world_business_and_customer_continuity(): void + { + $user = User::factory()->create(['email' => 'demo-pro@ladill.com']); + + $this->artisan('demo:seed', ['identity' => $user->email, '--plan' => 'pro']) + ->assertSuccessful(); + + $store = WooStore::query()->where('user_id', $user->id)->first(); + $this->assertStringContainsString(DemoWorld::business('pro')['name'], $store->site_name); + + $firstPerson = DemoWorld::people(1)[0]; + $this->assertDatabaseHas('woo_orders', [ + 'woo_store_id' => $store->id, + 'customer_name' => DemoWorld::fullName($firstPerson), + 'customer_email' => $firstPerson['email'], + ]); + } }