Lock doctors to their assigned patients and hide branch filters.
Deploy Ladill Care / deploy (push) Successful in 1m2s

Doctors no longer see branch/practitioner pickers; queue, appointments, patients, and dashboard only include visits on their linked desk.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-18 06:28:07 +00:00
co-authored by Cursor
parent 5264035705
commit dcbc62d1d3
11 changed files with 361 additions and 89 deletions
+73 -6
View File
@@ -38,9 +38,15 @@ class AppointmentService
/**
* @param array<string, mixed> $filters
* @param list<int>|null $practitionerIds When set, only appointments assigned to these desks.
*/
public function list(string $ownerRef, int $organizationId, array $filters = [], ?int $branchId = null): LengthAwarePaginator
{
public function list(
string $ownerRef,
int $organizationId,
array $filters = [],
?int $branchId = null,
?array $practitionerIds = null,
): LengthAwarePaginator {
$query = $this->queryForOrganization($ownerRef, $organizationId)
->with(['patient', 'practitioner', 'branch', 'department'])
->orderByDesc('scheduled_at');
@@ -49,6 +55,14 @@ class AppointmentService
$query->where('branch_id', $branchId);
}
if ($practitionerIds !== null) {
if ($practitionerIds === []) {
$query->whereRaw('1 = 0');
} else {
$query->whereIn('practitioner_id', $practitionerIds);
}
}
if ($status = $filters['status'] ?? null) {
$query->where('status', $status);
}
@@ -69,10 +83,20 @@ class AppointmentService
}
/**
* @param list<int>|null $practitionerIds
* @return Collection<int, Appointment>
*/
public function queue(string $ownerRef, int $branchId, ?int $practitionerId = null): Collection
{
public function queue(
string $ownerRef,
int $branchId,
?int $practitionerId = null,
bool $includeUnassigned = true,
?array $practitionerIds = null,
): Collection {
if ($practitionerIds !== null) {
return $this->queueForPractitioners($ownerRef, $practitionerIds, $branchId > 0 ? $branchId : null);
}
$this->repairDuplicateQueuePositions($ownerRef, $branchId);
$query = Appointment::owned($ownerRef)
@@ -84,8 +108,11 @@ class AppointmentService
->orderBy('checked_in_at');
if ($practitionerId !== null) {
$query->where(function (Builder $q) use ($practitionerId) {
$q->where('practitioner_id', $practitionerId)->orWhereNull('practitioner_id');
$query->where(function (Builder $q) use ($practitionerId, $includeUnassigned) {
$q->where('practitioner_id', $practitionerId);
if ($includeUnassigned) {
$q->orWhereNull('practitioner_id');
}
});
}
@@ -105,6 +132,46 @@ class AppointmentService
->values();
}
/**
* Doctor queue: only appointments assigned to their linked practitioner desk(s).
*
* @param list<int> $practitionerIds
* @return Collection<int, Appointment>
*/
public function queueForPractitioners(string $ownerRef, array $practitionerIds, ?int $branchId = null): Collection
{
if ($practitionerIds === []) {
return new Collection;
}
$query = Appointment::owned($ownerRef)
->whereIn('practitioner_id', $practitionerIds)
->whereIn('status', [Appointment::STATUS_WAITING, Appointment::STATUS_CHECKED_IN])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->with(['patient', 'practitioner', 'visit', 'organization'])
->orderBy('queue_position')
->orderBy('waiting_at')
->orderBy('checked_in_at');
return new Collection(
$query->get()
->filter(function (Appointment $appointment) {
$organization = $appointment->organization;
if (! $organization) {
return true;
}
return $this->workflowGate->canRelease(
$organization,
$appointment->visit,
$this->queueBridge->contextForAppointment($organization, $appointment),
);
})
->values()
->all()
);
}
/**
* @param array<string, mixed> $data
*/