assertTrue(collect(Artisan::all())->has('demo:seed')); } public function test_free_plan_respects_branch_cap_and_skips_paid_modules(): void { $user = User::create([ 'public_id' => 'demo-free-public-id', 'name' => 'Ladill Demo (Free)', 'email' => 'demo-free@ladill.com', ]); $this->artisan('demo:seed', [ 'identity' => 'demo-free@ladill.com', '--plan' => 'free', ])->assertSuccessful(); $org = Organization::query()->where('owner_ref', $user->public_id)->first(); $this->assertNotNull($org); $this->assertSame('free', data_get($org->settings, 'plan')); $this->assertTrue((bool) data_get($org->settings, 'onboarded')); $this->assertSame(1, (int) data_get($org->settings, 'billed_branches')); $this->assertNotEmpty(data_get($org->settings, 'plan_expires_at')); $this->assertTrue(\Carbon\Carbon::parse(data_get($org->settings, 'plan_expires_at'))->isFuture()); $this->assertSame(1, Branch::query()->where('owner_ref', $user->public_id)->where('is_active', true)->count()); $this->assertSame(1, app(PlanService::class)->maxBranches($org)); $this->assertGreaterThanOrEqual(12, Patient::query()->where('owner_ref', $user->public_id)->count()); $this->assertGreaterThanOrEqual(20, Appointment::query()->where('owner_ref', $user->public_id)->count()); $this->assertSame(0, InvestigationType::query()->where('owner_ref', $user->public_id)->count()); $this->assertSame(0, InvestigationRequest::query()->where('owner_ref', $user->public_id)->count()); $this->assertSame(0, Drug::query()->where('owner_ref', $user->public_id)->count()); $this->assertSame(0, Prescription::query()->where('owner_ref', $user->public_id)->count()); $this->assertSame(0, Bill::query()->where('owner_ref', $user->public_id)->count()); } public function test_pro_plan_seeds_multi_branch_and_paid_modules(): void { $user = User::create([ 'public_id' => 'demo-pro-public-id', 'name' => 'Ladill Demo (Pro)', 'email' => 'demo-pro@ladill.com', ]); $this->artisan('demo:seed', [ 'identity' => 'demo-pro@ladill.com', '--plan' => 'pro', ])->assertSuccessful(); $org = Organization::query()->where('owner_ref', $user->public_id)->firstOrFail(); $this->assertSame('pro', app(PlanService::class)->planKey($org)); $this->assertSame(3, Branch::query()->where('owner_ref', $user->public_id)->count()); $this->assertTrue(app(PlanService::class)->canUseProModules($org)); $this->assertGreaterThanOrEqual(12, InvestigationType::query()->where('organization_id', $org->id)->count()); $this->assertGreaterThan(0, InvestigationRequest::query()->where('owner_ref', $user->public_id)->count()); $this->assertGreaterThan(0, Drug::query()->where('owner_ref', $user->public_id)->count()); $this->assertGreaterThan(0, Prescription::query()->where('owner_ref', $user->public_id)->count()); $this->assertGreaterThan(0, Bill::query()->where('owner_ref', $user->public_id)->count()); $this->actingAs($user) ->withoutMiddleware(\App\Http\Middleware\EnsurePlatformSession::class) ->get(route('care.lab.catalog.index')) ->assertOk() ->assertSee('Full Blood Count') ->assertSee('Chest X-Ray') ->assertDontSee('No tests in catalog.'); $catalog = array_keys(config('care.specialty_modules', [])); $this->assertNotEmpty($catalog); foreach ($catalog as $key) { $this->assertTrue( (bool) data_get($org->settings, "specialty_modules.{$key}"), "Expected specialty module [{$key}] enabled for pro demo" ); $type = config("care.specialty_modules.{$key}.department_type"); $this->assertGreaterThan( 0, \App\Models\Department::query() ->where('owner_ref', $user->public_id) ->where('type', $type) ->where('is_active', true) ->count(), "Expected active departments for [{$key}]" ); $this->assertGreaterThan( 0, Appointment::query() ->where('owner_ref', $user->public_id) ->whereIn('status', [Appointment::STATUS_WAITING, Appointment::STATUS_CHECKED_IN]) ->whereHas('department', fn ($q) => $q->where('type', $type)) ->count(), "Expected waiting specialty appointments for [{$key}]" ); } } public function test_free_demo_does_not_enable_specialty_modules(): void { $user = User::create([ 'public_id' => 'demo-free-specialty-id', 'name' => 'Ladill Demo (Free)', 'email' => 'demo-free@ladill.com', ]); $this->artisan('demo:seed', [ 'identity' => 'demo-free@ladill.com', '--plan' => 'free', ])->assertSuccessful(); $org = Organization::query()->where('owner_ref', $user->public_id)->firstOrFail(); foreach (array_keys(config('care.specialty_modules', [])) as $key) { $this->assertFalse((bool) data_get($org->settings, "specialty_modules.{$key}")); } } public function test_enterprise_seeds_assessments_and_more_branches(): void { $user = User::create([ 'public_id' => 'demo-enterprise-public-id', 'name' => 'Accra Healthcare Group', 'email' => 'demo-enterprise@ladill.com', ]); $this->artisan('demo:seed', [ 'identity' => $user->public_id, '--plan' => 'enterprise', ])->assertSuccessful(); $org = Organization::query()->where('owner_ref', $user->public_id)->firstOrFail(); $this->assertSame('enterprise', app(PlanService::class)->planKey($org)); $this->assertSame(6, Branch::query()->where('owner_ref', $user->public_id)->count()); $this->assertGreaterThan(0, Assessment::query()->where('owner_ref', $user->public_id)->count()); $this->assertGreaterThan(0, Bill::query()->where('owner_ref', $user->public_id)->count()); } public function test_idempotent_reseed_without_reset_does_not_duplicate(): void { $user = User::create([ 'public_id' => 'demo-idempotent-id', 'name' => 'Idempotent Demo', 'email' => 'demo-idempotent@ladill.com', ]); $this->artisan('demo:seed', [ 'identity' => 'demo-idempotent@ladill.com', '--plan' => 'free', ])->assertSuccessful(); $patients = Patient::query()->where('owner_ref', $user->public_id)->count(); $appointments = Appointment::query()->where('owner_ref', $user->public_id)->count(); $orgs = Organization::query()->where('owner_ref', $user->public_id)->count(); $this->artisan('demo:seed', [ 'identity' => 'demo-idempotent@ladill.com', '--plan' => 'free', ])->assertSuccessful(); $this->assertSame($patients, Patient::query()->where('owner_ref', $user->public_id)->count()); $this->assertSame($appointments, Appointment::query()->where('owner_ref', $user->public_id)->count()); $this->assertSame($orgs, Organization::query()->where('owner_ref', $user->public_id)->count()); $this->assertSame(1, Branch::query()->where('owner_ref', $user->public_id)->count()); $organization = Organization::query()->where('owner_ref', $user->public_id)->first(); $this->assertTrue((bool) data_get($organization?->settings, 'demo')); $this->assertFalse((bool) data_get($organization?->settings, 'rollout.workflow_engine')); $this->assertFalse((bool) data_get($organization?->settings, 'rollout.financial_gates')); } public function test_reset_wipes_only_tenant_scoped_data_then_reseeds(): void { $keep = User::create([ 'public_id' => 'other-owner', 'name' => 'Other', 'email' => 'other@ladill.com', ]); Organization::create([ 'owner_ref' => $keep->public_id, 'name' => 'Keep Me', 'slug' => 'keep-me', 'settings' => ['onboarded' => true, 'plan' => 'free'], ]); Branch::create([ 'owner_ref' => $keep->public_id, 'organization_id' => Organization::query()->where('owner_ref', $keep->public_id)->value('id'), 'name' => 'Keep Branch', 'is_active' => true, ]); $user = User::create([ 'public_id' => 'demo-reset-id', 'name' => 'Reset Demo', 'email' => 'demo-reset@ladill.com', ]); $this->artisan('demo:seed', [ 'identity' => 'demo-reset@ladill.com', '--plan' => 'pro', ])->assertSuccessful(); $patientCount = Patient::query()->where('owner_ref', $user->public_id)->count(); $this->assertGreaterThan(0, $patientCount); $this->assertGreaterThan(0, Bill::query()->where('owner_ref', $user->public_id)->count()); $this->artisan('demo:seed', [ 'identity' => 'demo-reset@ladill.com', '--plan' => 'free', '--reset' => true, ])->assertSuccessful(); $this->assertSame(1, Branch::query()->where('owner_ref', $user->public_id)->count()); $this->assertSame(0, Bill::query()->where('owner_ref', $user->public_id)->count()); $this->assertSame(0, Drug::query()->where('owner_ref', $user->public_id)->count()); $this->assertSame('free', data_get( Organization::query()->where('owner_ref', $user->public_id)->value('settings'), 'plan' )); // Other tenant untouched. $this->assertSame(1, Organization::query()->where('owner_ref', $keep->public_id)->count()); $this->assertSame(1, Branch::query()->where('owner_ref', $keep->public_id)->count()); } public function test_reset_keeps_organization_onboarded_mid_wipe(): void { $user = User::create([ 'public_id' => 'demo-mid-reset-id', 'name' => 'Mid Reset Demo', 'email' => 'demo-mid-reset@ladill.com', ]); $this->artisan('demo:seed', [ 'identity' => 'demo-mid-reset@ladill.com', '--plan' => 'free', ])->assertSuccessful(); $orgId = (int) Organization::query()->where('owner_ref', $user->public_id)->value('id'); $this->assertGreaterThan(0, $orgId); app(DemoTenantSeeder::class)->resetTenant($user->public_id); $org = Organization::query()->find($orgId); $this->assertNotNull($org); $this->assertTrue((bool) data_get($org->settings, 'onboarded')); $this->assertTrue(app(\App\Services\Care\OrganizationResolver::class)->isOnboarded($user)); $this->assertSame(0, Branch::query()->where('owner_ref', $user->public_id)->count()); } public function test_creates_local_mirror_when_public_id_and_email_provided(): void { $this->assertDatabaseMissing('users', ['email' => 'new-demo@ladill.com']); $this->artisan('demo:seed', [ '--public-id' => 'brand-new-public-id', '--email' => 'new-demo@ladill.com', '--name' => 'New Demo', '--plan' => 'free', ])->assertSuccessful(); $user = User::query()->where('email', 'new-demo@ladill.com')->first(); $this->assertNotNull($user); $this->assertSame('brand-new-public-id', $user->public_id); $this->assertSame(1, Organization::query()->where('owner_ref', $user->public_id)->count()); } public function test_fails_when_mirror_missing_and_insufficient_identity(): void { $this->artisan('demo:seed', [ 'identity' => 'missing@ladill.com', '--plan' => 'free', ])->assertFailed(); } public function test_volumes_helper_marks_free_without_paid_modules(): void { $volumes = app(DemoTenantSeeder::class)->volumes('free'); $this->assertFalse($volumes['paid_modules']); $this->assertSame(1, $volumes['branches']); $this->assertSame(0, $volumes['assessments']); $pro = app(DemoTenantSeeder::class)->volumes('pro'); $this->assertTrue($pro['paid_modules']); $this->assertSame(3, $pro['branches']); } public function test_demo_world_continuity_and_staff_roles(): void { $user = User::create([ 'public_id' => 'demo-world-care-id', 'name' => 'Ladill Demo (Pro)', 'email' => 'demo-pro@ladill.com', ]); $this->artisan('demo:seed', [ 'identity' => 'demo-pro@ladill.com', '--plan' => 'pro', ])->assertSuccessful(); $org = Organization::query()->where('owner_ref', $user->public_id)->firstOrFail(); $this->assertSame(\App\Support\DemoWorld::business('pro')['name'], $org->name); $ama = \App\Support\DemoWorld::personByKey('ama-mensah'); $this->assertNotNull($ama); $patient = Patient::query() ->where('owner_ref', $user->public_id) ->where('phone', $ama['phone']) ->first(); $this->assertNotNull($patient); $this->assertSame($ama['email'], $patient->email); $this->assertSame($ama['national_id'], $patient->national_id); $this->assertTrue( \App\Models\Member::query() ->where('owner_ref', $user->public_id) ->where('user_ref', 'demo-pro-doctor@ladill.com') ->where('role', 'doctor') ->exists() ); $this->assertTrue( \App\Models\Member::query() ->where('owner_ref', $user->public_id) ->where('user_ref', 'demo-pro-receptionist@ladill.com') ->where('role', 'receptionist') ->exists() ); $waiters = Appointment::query() ->where('owner_ref', $user->public_id) ->whereIn('status', [Appointment::STATUS_WAITING, Appointment::STATUS_CHECKED_IN]) ->get(); $this->assertNotEmpty($waiters); foreach ($waiters as $waiter) { $this->assertNotNull($waiter->practitioner_id, 'Demo waiters must all have a doctor assigned'); $this->assertNotSame('unresolved', $waiter->queue_routing_status); } } }