Fix specialty Call next vs WAITING KPI mismatch.
Deploy Ladill Care / deploy (push) Successful in 1m44s

Admins without a desk now scan all specialty service points, KPIs use the same branch as queue ops, and empty Call next flashes explain tickets vs other branches.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-18 11:41:45 +00:00
co-authored by Cursor
parent 4c4dfc7dbf
commit bd8218fb45
5 changed files with 235 additions and 21 deletions
@@ -304,10 +304,50 @@ class SpecialtyModuleController extends Controller
$result = $queueBridge->callNext($organization, $module, $branchId, $member, $practitionerId);
$ticket = $result['ticket'] ?? null;
if (! $ticket) {
$owner = $this->ownerRef($request);
$departmentIds = Department::owned($owner)
->where('type', $definition['department_type'] ?? 'general')
->where('is_active', true)
->when($branchScope, fn ($q) => $q->where('branch_id', $branchScope))
->pluck('id');
$waitingAtBranch = Appointment::owned($owner)
->where('organization_id', $organization->id)
->where('branch_id', $branchId)
->whereIn('status', [Appointment::STATUS_WAITING, Appointment::STATUS_CHECKED_IN])
->when($departmentIds->isNotEmpty(), fn ($q) => $q->whereIn('department_id', $departmentIds))
->when($departmentIds->isEmpty(), fn ($q) => $q->whereRaw('1 = 0'))
->count();
$waitingOrg = Appointment::owned($owner)
->where('organization_id', $organization->id)
->whereIn('status', [Appointment::STATUS_WAITING, Appointment::STATUS_CHECKED_IN])
->when($departmentIds->isNotEmpty(), fn ($q) => $q->whereIn('department_id', $departmentIds))
->when($departmentIds->isEmpty(), fn ($q) => $q->whereRaw('1 = 0'))
->count();
$branchName = \App\Models\Branch::owned($owner)->whereKey($branchId)->value('name') ?: 'this branch';
if ($waitingAtBranch > 0) {
return back()->with(
'info',
"{$waitingAtBranch} patient(s) are waiting in {$definition['label']} at {$branchName}, but none have a callable ticket at a service desk yet. Open Visits and use Start consultation, or check in again so a ticket is issued."
);
}
if ($waitingOrg > $waitingAtBranch) {
return back()->with(
'info',
"No patients waiting in {$definition['label']} at {$branchName}. {$waitingOrg} are waiting at other branches — open Visits or switch branch."
);
}
return back()->with('info', 'No patients waiting in this specialty queue.');
}
return back()->with('success', 'Called '.$ticket['ticket_number'].'.');
$name = $ticket['customer_name'] ?? 'patient';
return back()->with('success', 'Called '.$ticket['ticket_number'].' — '.$name.'.');
}
protected function renderShell(
@@ -341,22 +381,6 @@ class SpecialtyModuleController extends Controller
$departmentIds = $departments->pluck('id')->all();
$waiting = Appointment::owned($owner)
->where('organization_id', $organization->id)
->whereIn('status', [Appointment::STATUS_WAITING, Appointment::STATUS_CHECKED_IN])
->when($departmentIds !== [], fn ($q) => $q->whereIn('department_id', $departmentIds))
->when($departmentIds === [], fn ($q) => $q->whereRaw('1 = 0'))
->when($branchScope, fn ($q) => $q->where('branch_id', $branchScope))
->when(
$practitionerScope !== null,
fn ($q) => $q->whereIn('practitioner_id', $practitionerScope ?: [0]),
)
->with(['patient', 'practitioner', 'department', 'visit'])
->orderBy('queue_position')
->orderBy('checked_in_at')
->limit(25)
->get();
$branchId = (int) ($branchScope ?: $departments->first()?->branch_id);
if ($practitionerScope !== null && $practitionerScope !== []) {
$pracBranch = (int) \App\Models\Practitioner::owned($owner)
@@ -367,11 +391,32 @@ class SpecialtyModuleController extends Controller
}
}
// Match Call next: when the member has no branch scope (e.g. hospital admin),
// KPIs / waiting lists use the same branch as queue ops so WAITING isn't org-wide
// while Call next is local.
$kpiBranch = $branchScope ?? ($branchId > 0 ? $branchId : null);
$waiting = Appointment::owned($owner)
->where('organization_id', $organization->id)
->whereIn('status', [Appointment::STATUS_WAITING, Appointment::STATUS_CHECKED_IN])
->when($departmentIds !== [], fn ($q) => $q->whereIn('department_id', $departmentIds))
->when($departmentIds === [], fn ($q) => $q->whereRaw('1 = 0'))
->when($kpiBranch, fn ($q) => $q->where('branch_id', $kpiBranch))
->when(
$practitionerScope !== null,
fn ($q) => $q->whereIn('practitioner_id', $practitionerScope ?: [0]),
)
->with(['patient', 'practitioner', 'department', 'visit'])
->orderBy('queue_position')
->orderBy('checked_in_at')
->limit(25)
->get();
$shellDefinition = $shell->definition($module);
$kpis = $shell->kpis($organization, $module, $owner, $branchScope, $practitionerScope);
$openVisits = $shell->openVisits($organization, $module, $owner, $branchScope, $practitionerScope);
$kpis = $shell->kpis($organization, $module, $owner, $kpiBranch, $practitionerScope);
$openVisits = $shell->openVisits($organization, $module, $owner, $kpiBranch, $practitionerScope);
$visitHistory = $section === 'history'
? $shell->visitHistory($organization, $module, $owner, $branchScope, $practitionerScope)
? $shell->visitHistory($organization, $module, $owner, $kpiBranch, $practitionerScope)
: collect();
$services = $shell->provisionedServices($organization, $module);
@@ -472,6 +517,7 @@ class SpecialtyModuleController extends Controller
'visitDocuments' => $visitDocuments,
'queueStubs' => $modules->queueStubsFor($organization, $module),
'branchId' => $branchId,
'practitionerScope' => $practitionerScope,
'queueIntegration' => $branchId
? $queueBridge->listMeta($organization, $module, $branchId)
: ['enabled' => false],