Seed Care demos from shared DemoWorld with staff roles.
Deploy Ladill Care / deploy (push) Successful in 1m0s
Deploy Ladill Care / deploy (push) Successful in 1m0s
Patients, branches, and org identity now match suite continuity keys; staff Members are created for training SSO without login reseed. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -8,6 +8,9 @@ use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Reseed Care demo tenants after a fresh SSO login.
|
||||
*
|
||||
* Only owner demo accounts (and legacy enterprise org members) trigger a full
|
||||
* reseed. Staff training logins never wipe mid-demo.
|
||||
*/
|
||||
class DemoLoginReseeder
|
||||
{
|
||||
@@ -18,6 +21,11 @@ class DemoLoginReseeder
|
||||
return;
|
||||
}
|
||||
|
||||
// Staff demos share the owner tenant but must not reseed on login.
|
||||
if (\App\Support\DemoWorld::isStaffDemoEmail($user->email)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$plan = $this->planForEmail($user->email);
|
||||
if ($plan === null) {
|
||||
return;
|
||||
|
||||
@@ -26,6 +26,7 @@ use App\Models\Prescription;
|
||||
use App\Models\User;
|
||||
use App\Models\Visit;
|
||||
use App\Models\VitalSign;
|
||||
use App\Support\DemoWorld;
|
||||
use Faker\Factory as FakerFactory;
|
||||
use Faker\Generator as Faker;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -103,6 +104,7 @@ class DemoTenantSeeder
|
||||
$this->upsertOwnerMember($organization, $ownerRef);
|
||||
|
||||
$branches = $this->seedBranches($organization, $ownerRef, $volumes, $faker);
|
||||
$this->seedStaffMembers($organization, $ownerRef, $plan, $branches);
|
||||
$departments = $this->seedDepartments($branches, $ownerRef, $volumes);
|
||||
$practitioners = $this->seedPractitioners($organization, $branches, $departments, $ownerRef, $volumes, $faker);
|
||||
$patients = $this->seedPatients($organization, $branches, $ownerRef, $volumes, $faker);
|
||||
@@ -298,11 +300,7 @@ class DemoTenantSeeder
|
||||
$slug = 'demo-'.Str::lower(Str::substr($ownerRef, 0, 8));
|
||||
}
|
||||
|
||||
$name = match ($plan) {
|
||||
'enterprise' => 'Accra Healthcare Group (Care Demo)',
|
||||
'pro' => 'Ladill Care Demo (Pro)',
|
||||
default => 'Ladill Care Demo (Free)',
|
||||
};
|
||||
$name = DemoWorld::business($plan)['name'];
|
||||
|
||||
$organization = Organization::withTrashed()
|
||||
->where('owner_ref', $ownerRef)
|
||||
@@ -361,9 +359,12 @@ class DemoTenantSeeder
|
||||
*/
|
||||
private function seedBranches(Organization $organization, string $ownerRef, array $volumes, Faker $faker): array
|
||||
{
|
||||
$catalog = DemoWorld::branches($this->normalizePlan(
|
||||
(string) data_get($organization->settings, 'plan', 'free')
|
||||
), $volumes['branches']);
|
||||
$branches = [];
|
||||
for ($i = 0; $i < $volumes['branches']; $i++) {
|
||||
$code = sprintf('DEMO-BR-%02d', $i + 1);
|
||||
foreach ($catalog as $i => $spec) {
|
||||
$code = $spec['code'] !== '' ? $spec['code'] : sprintf('DEMO-BR-%02d', $i + 1);
|
||||
$branches[] = Branch::withTrashed()->updateOrCreate(
|
||||
[
|
||||
'organization_id' => $organization->id,
|
||||
@@ -371,9 +372,9 @@ class DemoTenantSeeder
|
||||
],
|
||||
[
|
||||
'owner_ref' => $ownerRef,
|
||||
'name' => self::BRANCH_NAMES[$i % count(self::BRANCH_NAMES)],
|
||||
'address' => $faker->streetAddress().', Accra',
|
||||
'phone' => '+23320'.str_pad((string) (1000000 + $i), 7, '0', STR_PAD_LEFT),
|
||||
'name' => $spec['name'],
|
||||
'address' => $spec['address'],
|
||||
'phone' => $spec['phone'],
|
||||
'is_active' => true,
|
||||
'deleted_at' => null,
|
||||
],
|
||||
@@ -383,6 +384,34 @@ class DemoTenantSeeder
|
||||
return $branches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Member rows for DemoWorld staff (user_ref = email until SSO remaps to public_id).
|
||||
*
|
||||
* @param list<Branch> $branches
|
||||
*/
|
||||
private function seedStaffMembers(Organization $organization, string $ownerRef, string $plan, array $branches): void
|
||||
{
|
||||
$hq = $branches[0] ?? null;
|
||||
foreach (DemoWorld::staff($plan) as $staff) {
|
||||
$role = $staff['roles']['care'] ?? null;
|
||||
if (! is_string($role) || $role === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
Member::query()->updateOrCreate(
|
||||
[
|
||||
'organization_id' => $organization->id,
|
||||
'user_ref' => strtolower($staff['email']),
|
||||
],
|
||||
[
|
||||
'owner_ref' => $ownerRef,
|
||||
'role' => $role,
|
||||
'branch_id' => in_array($role, ['hospital_admin'], true) ? null : $hq?->id,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<Branch> $branches
|
||||
* @param array<string, mixed> $volumes
|
||||
@@ -473,10 +502,27 @@ class DemoTenantSeeder
|
||||
array $volumes,
|
||||
Faker $faker,
|
||||
): array {
|
||||
$worldPeople = DemoWorld::people();
|
||||
$patients = [];
|
||||
for ($i = 0; $i < $volumes['patients']; $i++) {
|
||||
$branch = $branches[$i % count($branches)];
|
||||
$number = sprintf('DEMO-%s-%05d', Str::upper(Str::substr(md5($ownerRef), 0, 4)), $i + 1);
|
||||
$person = $worldPeople[$i] ?? null;
|
||||
if ($person === null) {
|
||||
$base = $worldPeople[$i % count($worldPeople)];
|
||||
$seq = $i + 1;
|
||||
$person = [
|
||||
'first_name' => $base['first_name'],
|
||||
'last_name' => $base['last_name'],
|
||||
'gender' => $base['gender'],
|
||||
'dob' => $base['dob'],
|
||||
'phone' => '+23324'.str_pad((string) (1000000 + $seq), 7, '0', STR_PAD_LEFT),
|
||||
'email' => sprintf('patient.%d@demo.ladill.com', $seq),
|
||||
'national_id' => sprintf('GHA-729%06d', $seq),
|
||||
'city' => $base['city'],
|
||||
'address' => $base['address'],
|
||||
];
|
||||
}
|
||||
|
||||
$patients[] = Patient::withTrashed()->updateOrCreate(
|
||||
[
|
||||
@@ -487,15 +533,16 @@ class DemoTenantSeeder
|
||||
'uuid' => $this->demoUuid("patient|{$ownerRef}|{$i}"),
|
||||
'owner_ref' => $ownerRef,
|
||||
'branch_id' => $branch->id,
|
||||
'first_name' => self::FIRST_NAMES[$i % count(self::FIRST_NAMES)],
|
||||
'last_name' => self::LAST_NAMES[($i * 3) % count(self::LAST_NAMES)],
|
||||
'gender' => $i % 2 === 0 ? 'female' : 'male',
|
||||
'date_of_birth' => now()->subYears(18 + ($i % 50))->subDays($i % 28)->toDateString(),
|
||||
'phone' => '+23324'.str_pad((string) (2000000 + $i), 7, '0', STR_PAD_LEFT),
|
||||
'email' => sprintf('demo.patient.%d@example.test', $i + 1),
|
||||
'city' => 'Accra',
|
||||
'first_name' => $person['first_name'],
|
||||
'last_name' => $person['last_name'],
|
||||
'gender' => $person['gender'],
|
||||
'date_of_birth' => $person['dob'],
|
||||
'phone' => $person['phone'],
|
||||
'email' => $person['email'],
|
||||
'national_id' => $person['national_id'],
|
||||
'city' => $person['city'],
|
||||
'region' => 'Greater Accra',
|
||||
'address' => $faker->streetAddress(),
|
||||
'address' => $person['address'],
|
||||
'deleted_at' => null,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Services\Care;
|
||||
|
||||
use App\Models\Member;
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use App\Services\Identity\IdentityTeamClient;
|
||||
|
||||
@@ -35,7 +36,11 @@ class TeamMemberProvisioner
|
||||
}
|
||||
|
||||
$appMeta = (array) data_get($grant, 'metadata.care', []);
|
||||
$ownerRef = (string) ($grant['account'] ?? '');
|
||||
$organizationId = (int) ($appMeta['organization_id'] ?? 0);
|
||||
if ($organizationId <= 0 && $ownerRef !== '') {
|
||||
$organizationId = (int) Organization::query()->where('owner_ref', $ownerRef)->value('id');
|
||||
}
|
||||
if ($organizationId <= 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -46,7 +51,7 @@ class TeamMemberProvisioner
|
||||
'user_ref' => $user->ownerRef(),
|
||||
],
|
||||
[
|
||||
'owner_ref' => (string) ($grant['account'] ?? $user->ownerRef()),
|
||||
'owner_ref' => $ownerRef !== '' ? $ownerRef : $user->ownerRef(),
|
||||
'role' => (string) ($appMeta['role'] ?? 'member'),
|
||||
'branch_id' => $appMeta['branch_id'] ?? null,
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user