Link demo specialty desks after SSO remap and tighten keyword matching.
Deploy Ladill Care / deploy (push) Successful in 58s
Deploy Ladill Care / deploy (push) Successful in 58s
Specialty seeder looked up members by email user_ref only, so remapped demo logins never got practitioner.member_id and saw every module. Also stop short keywords like "ent" matching "dentistry". Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -249,10 +249,7 @@ class DemoTenantSeeder
|
||||
return;
|
||||
}
|
||||
|
||||
$member = Member::query()
|
||||
->where('organization_id', $organization->id)
|
||||
->where('user_ref', $doctorEmail)
|
||||
->first();
|
||||
$member = $this->findStaffMemberByEmail($organization, $doctorEmail);
|
||||
|
||||
// Link the demo doctor to a single desk on their home branch (not every site).
|
||||
$homeBranchId = (int) ($member?->branch_id ?: ($branches[0]->id ?? 0));
|
||||
@@ -265,7 +262,7 @@ class DemoTenantSeeder
|
||||
}
|
||||
|
||||
$practitioner->forceFill([
|
||||
'user_ref' => $doctorEmail,
|
||||
'user_ref' => $member?->user_ref ?: $doctorEmail,
|
||||
'member_id' => $member?->id,
|
||||
'name' => $doctorName !== '' ? $doctorName : $practitioner->name,
|
||||
])->save();
|
||||
@@ -649,6 +646,34 @@ class DemoTenantSeeder
|
||||
return $branches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a demo staff Member by login email, including SSO-remapped public_id user_ref.
|
||||
*/
|
||||
private function findStaffMemberByEmail(Organization $organization, string $email): ?Member
|
||||
{
|
||||
$email = strtolower(trim($email));
|
||||
if ($email === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$publicId = User::query()
|
||||
->whereRaw('LOWER(email) = ?', [$email])
|
||||
->value('public_id');
|
||||
|
||||
return Member::query()
|
||||
->where('organization_id', $organization->id)
|
||||
->where(function ($query) use ($email, $publicId) {
|
||||
$query->where('user_ref', $email);
|
||||
if (is_string($publicId) && $publicId !== '') {
|
||||
$query->orWhere('user_ref', $publicId);
|
||||
}
|
||||
})
|
||||
->orderByRaw('CASE WHEN user_ref = ? THEN 0 ELSE 1 END', [
|
||||
is_string($publicId) && $publicId !== '' ? $publicId : $email,
|
||||
])
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Member rows for DemoWorld staff (user_ref = email until SSO remaps to public_id).
|
||||
* Multi-branch demos spread staff across branches so each site has a role roster.
|
||||
@@ -872,10 +897,8 @@ class DemoTenantSeeder
|
||||
|
||||
$moduleReasons = $reasons[$key] ?? ['Specialty visit'];
|
||||
$staffEmail = sprintf('demo-%s-%s@ladill.com', $plan, $key);
|
||||
$moduleMembers[$key] = Member::query()
|
||||
->where('organization_id', $organization->id)
|
||||
->where('user_ref', $staffEmail)
|
||||
->first();
|
||||
// Resolve by email or SSO-remapped public_id (seedStaffMembers prefers public_id).
|
||||
$moduleMembers[$key] = $this->findStaffMemberByEmail($organization, $staffEmail);
|
||||
|
||||
foreach ($branches as $branchIndex => $branch) {
|
||||
$department = Department::owned($ownerRef)
|
||||
|
||||
@@ -421,8 +421,7 @@ class SpecialtyModuleService
|
||||
continue;
|
||||
}
|
||||
foreach ($keywords as $keyword) {
|
||||
$needle = strtolower((string) $keyword);
|
||||
if ($needle !== '' && str_contains($hay, $needle)) {
|
||||
if ($this->specialtyKeywordMatches($hay, strtolower((string) $keyword))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -431,6 +430,36 @@ class SpecialtyModuleService
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match specialty text to a keyword without short-token false positives
|
||||
* (e.g. "ent" must not match "dentistry"; "ear" must not match "year").
|
||||
*/
|
||||
protected function specialtyKeywordMatches(string $haystackLower, string $needleLower): bool
|
||||
{
|
||||
$needleLower = trim($needleLower);
|
||||
if ($needleLower === '' || $haystackLower === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($haystackLower === $needleLower) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$quoted = preg_quote($needleLower, '/');
|
||||
|
||||
// Whole-word match covers short tokens (ent, ear, eye) and multi-word labels.
|
||||
if (preg_match('/\b'.$quoted.'\b/u', $haystackLower) === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Longer stems may prefix a token (dent→dentistry, cardio→cardiology).
|
||||
if (strlen($needleLower) >= 4 && preg_match('/\b'.$quoted.'/u', $haystackLower) === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isGeneralPracticeSpecialty(string $specialtyLower): bool
|
||||
{
|
||||
if (in_array($specialtyLower, [
|
||||
|
||||
Reference in New Issue
Block a user