Gate Queue to doctors and land specialty modules on list indexes.
Deploy Ladill Care / deploy (push) Successful in 34s
Deploy Ladill Care / deploy (push) Successful in 34s
Hide the patient-flow Queue board from nurses, reception, and other non-doctors; specialty home routes now render the queue board list instead of auto-opening the first open visit. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -150,7 +150,12 @@ class AppointmentController extends Controller
|
||||
->with('success', 'Walk-in checked in. Complete the current patient journey stage before Queue release.');
|
||||
}
|
||||
|
||||
return redirect()->route('care.queue.index')
|
||||
if (app(CarePermissions::class)->canAccessPatientQueue($this->member($request))) {
|
||||
return redirect()->route('care.queue.index')
|
||||
->with('success', 'Walk-in added to queue.');
|
||||
}
|
||||
|
||||
return redirect()->route('care.appointments.show', $appointment)
|
||||
->with('success', 'Walk-in added to queue.');
|
||||
}
|
||||
|
||||
@@ -217,7 +222,12 @@ class AppointmentController extends Controller
|
||||
->with('success', 'Patient checked in. Complete the current patient journey stage before Queue release.');
|
||||
}
|
||||
|
||||
return redirect()->route('care.queue.index')
|
||||
if (app(CarePermissions::class)->canAccessPatientQueue($this->member($request))) {
|
||||
return redirect()->route('care.queue.index')
|
||||
->with('success', 'Patient checked in and added to queue.');
|
||||
}
|
||||
|
||||
return redirect()->route('care.appointments.show', $appointment)
|
||||
->with('success', 'Patient checked in and added to queue.');
|
||||
}
|
||||
|
||||
|
||||
@@ -278,8 +278,11 @@ class ConsultationController extends Controller
|
||||
->with('success', 'Consultation completed. Continue the patient journey from the next stage.');
|
||||
}
|
||||
|
||||
return redirect()->route('care.queue.index')
|
||||
->with('success', 'Consultation completed.');
|
||||
return redirect()->route(
|
||||
app(CarePermissions::class)->canAccessPatientQueue($this->member($request))
|
||||
? 'care.queue.index'
|
||||
: 'care.appointments.index'
|
||||
)->with('success', 'Consultation completed.');
|
||||
}
|
||||
|
||||
protected function authorizeConsultation(Request $request, Consultation $consultation): void
|
||||
|
||||
@@ -8,7 +8,8 @@ use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Legacy Ladill Queue console routes — redirect to the Care patient queue.
|
||||
* Legacy Ladill Queue console routes — redirect to the Care patient queue (doctors)
|
||||
* or appointments list when the actor cannot open the patient-flow board.
|
||||
*/
|
||||
class ServiceQueueController extends Controller
|
||||
{
|
||||
@@ -18,20 +19,29 @@ class ServiceQueueController extends Controller
|
||||
{
|
||||
$this->authorizeAbility($request, 'service_queues.console');
|
||||
|
||||
return redirect()->route('care.queue.index');
|
||||
return $this->redirectAwayFromLegacyConsole($request);
|
||||
}
|
||||
|
||||
public function console(Request $request, string $counterUuid): RedirectResponse
|
||||
{
|
||||
$this->authorizeAbility($request, 'service_queues.console');
|
||||
|
||||
return redirect()->route('care.queue.index');
|
||||
return $this->redirectAwayFromLegacyConsole($request);
|
||||
}
|
||||
|
||||
public function action(Request $request, string $counterUuid): RedirectResponse
|
||||
{
|
||||
$this->authorizeAbility($request, 'service_queues.console');
|
||||
|
||||
return redirect()->route('care.queue.index');
|
||||
return $this->redirectAwayFromLegacyConsole($request);
|
||||
}
|
||||
|
||||
protected function redirectAwayFromLegacyConsole(Request $request): RedirectResponse
|
||||
{
|
||||
if (app(\App\Services\Care\CarePermissions::class)->canAccessPatientQueue($this->member($request))) {
|
||||
return redirect()->route('care.queue.index');
|
||||
}
|
||||
|
||||
return redirect()->route('care.appointments.index');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,20 +31,9 @@ class SpecialtyModuleController extends Controller
|
||||
SpecialtyModuleService $modules,
|
||||
SpecialtyShellService $shell,
|
||||
CareQueueBridge $queueBridge,
|
||||
): RedirectResponse {
|
||||
$definition = $modules->definition($module);
|
||||
abort_unless($definition, 404);
|
||||
abort_unless(
|
||||
$modules->memberCanAccess($this->organization($request), $this->member($request), $module),
|
||||
403,
|
||||
);
|
||||
|
||||
// Specialty patient flow lives on Queue; nurses stay on the specialty workspace.
|
||||
if (app(\App\Services\Care\CarePermissions::class)->canAccessPatientQueue($this->member($request))) {
|
||||
return redirect()->route('care.queue.index');
|
||||
}
|
||||
|
||||
return redirect()->route('care.specialty.workspace', $module);
|
||||
): View {
|
||||
// Everyone lands on the specialty list/index — never auto-open a patient.
|
||||
return $this->renderShell($request, $module, 'visits', $modules, $shell, $queueBridge);
|
||||
}
|
||||
|
||||
public function visits(
|
||||
@@ -53,19 +42,8 @@ class SpecialtyModuleController extends Controller
|
||||
SpecialtyModuleService $modules,
|
||||
SpecialtyShellService $shell,
|
||||
CareQueueBridge $queueBridge,
|
||||
): RedirectResponse {
|
||||
$definition = $modules->definition($module);
|
||||
abort_unless($definition, 404);
|
||||
abort_unless(
|
||||
$modules->memberCanAccess($this->organization($request), $this->member($request), $module),
|
||||
403,
|
||||
);
|
||||
|
||||
if (app(\App\Services\Care\CarePermissions::class)->canAccessPatientQueue($this->member($request))) {
|
||||
return redirect()->route('care.queue.index');
|
||||
}
|
||||
|
||||
return redirect()->route('care.specialty.workspace', $module);
|
||||
): View {
|
||||
return $this->renderShell($request, $module, 'visits', $modules, $shell, $queueBridge);
|
||||
}
|
||||
|
||||
public function history(
|
||||
@@ -95,7 +73,12 @@ class SpecialtyModuleController extends Controller
|
||||
SpecialtyShellService $shell,
|
||||
CareQueueBridge $queueBridge,
|
||||
?Visit $visit = null,
|
||||
): View {
|
||||
): View|RedirectResponse {
|
||||
// Bare /workspace (no visit) is the old auto-open entry — send users to the list.
|
||||
if ($visit === null) {
|
||||
return redirect()->route('care.specialty.show', $module);
|
||||
}
|
||||
|
||||
return $this->renderShell($request, $module, 'workspace', $modules, $shell, $queueBridge, $visit);
|
||||
}
|
||||
|
||||
@@ -589,14 +572,7 @@ class SpecialtyModuleController extends Controller
|
||||
);
|
||||
|
||||
return redirect()
|
||||
->route(
|
||||
app(\App\Services\Care\CarePermissions::class)->canAccessPatientQueue($member)
|
||||
? 'care.queue.index'
|
||||
: 'care.specialty.workspace',
|
||||
app(\App\Services\Care\CarePermissions::class)->canAccessPatientQueue($member)
|
||||
? []
|
||||
: ['module' => $module],
|
||||
)
|
||||
->route('care.specialty.show', $module)
|
||||
->with('success', 'Referred '.$patient->fullName().' to '.($definition['label'] ?? $module).'.');
|
||||
}
|
||||
|
||||
@@ -792,25 +768,6 @@ class SpecialtyModuleController extends Controller
|
||||
);
|
||||
$timeline = $shell->patientTimeline($visit->patient);
|
||||
}
|
||||
} elseif ($section === 'workspace') {
|
||||
$first = $openVisits->first();
|
||||
if ($first?->patient) {
|
||||
$first->load([
|
||||
'patient.allergies',
|
||||
'patient.emergencyContacts',
|
||||
'patient.attachments',
|
||||
'appointment.practitioner',
|
||||
'appointment.consultation.investigationRequests.investigationType',
|
||||
'bill.lineItems',
|
||||
'consultations.investigationRequests.investigationType',
|
||||
]);
|
||||
$workspaceVisit = $first;
|
||||
$patientHeader = array_merge(
|
||||
['patient' => $first->patient, 'visit' => $first, 'appointment' => $first->appointment],
|
||||
$shell->patientHeaderMeta($first->patient),
|
||||
);
|
||||
$timeline = $shell->patientTimeline($first->patient);
|
||||
}
|
||||
}
|
||||
|
||||
if ($workspaceVisit && $section === 'workspace') {
|
||||
|
||||
@@ -111,15 +111,13 @@ class CarePermissions
|
||||
}
|
||||
|
||||
/**
|
||||
* Dedicated patient-flow board (GP / specialty Queue homes).
|
||||
* Nurses keep specialty workspaces and vitals — not the call-next board.
|
||||
* Dedicated patient-flow board (GP Queue home / call-next board).
|
||||
* Doctors only — nurses, reception, pharmacy, and other floor roles use
|
||||
* specialty module lists and service queues instead.
|
||||
* Facility admins manage settings/staff and do not staff this board.
|
||||
*/
|
||||
public function canAccessPatientQueue(?Member $member): bool
|
||||
{
|
||||
if (! $this->handlesFloorCare($member)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $member->role !== 'nurse';
|
||||
return $member !== null && $member->role === 'doctor';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,6 +284,8 @@ class OrganizationResolver
|
||||
|
||||
/**
|
||||
* Explicit branch IDs for a doctor's linked practitioner desks (pivot + legacy branch_id).
|
||||
* GPs with no practitioner desk fall back to their member branch so they can still
|
||||
* open the shared consultation Queue board.
|
||||
*
|
||||
* @return list<int>
|
||||
*/
|
||||
@@ -304,7 +306,13 @@ class OrganizationResolver
|
||||
$ids = array_merge($ids, $practitioner->assignedBranchIds());
|
||||
}
|
||||
|
||||
return array_values(array_unique(array_map('intval', $ids)));
|
||||
$ids = array_values(array_unique(array_map('intval', $ids)));
|
||||
|
||||
if ($ids === [] && $member->branch_id) {
|
||||
return [(int) $member->branch_id];
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
public function mayAccessBranch(?Member $member, ?int $branchId): bool
|
||||
@@ -357,8 +365,9 @@ class OrganizationResolver
|
||||
}
|
||||
|
||||
/**
|
||||
* Practitioner IDs a doctor is locked to. Null = no practitioner lock.
|
||||
* Empty array = doctor with no linked desk.
|
||||
* Practitioner IDs a doctor is locked to. Null = no practitioner lock
|
||||
* (non-doctors, or GPs with no linked desk — they work the shared consultation board).
|
||||
* Non-empty = desk-locked specialist / assigned GP.
|
||||
*
|
||||
* @return list<int>|null
|
||||
*/
|
||||
@@ -368,7 +377,7 @@ class OrganizationResolver
|
||||
return null;
|
||||
}
|
||||
|
||||
return Practitioner::owned((string) $organization->owner_ref)
|
||||
$ids = Practitioner::owned((string) $organization->owner_ref)
|
||||
->where('organization_id', $organization->id)
|
||||
->where('is_active', true)
|
||||
->where(function ($query) use ($member) {
|
||||
@@ -380,5 +389,7 @@ class OrganizationResolver
|
||||
->map(fn ($id) => (int) $id)
|
||||
->values()
|
||||
->all();
|
||||
|
||||
return $ids === [] ? null : $ids;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user