From 847d63c1c2218aa48fa04c3d77b9fc25bfb0524b Mon Sep 17 00:00:00 2001 From: isaacclad Date: Sat, 18 Jul 2026 21:26:58 +0000 Subject: [PATCH] Allow consultation assessments when patient home branch differs. Doctors scoped to the visit branch were getting app 404s on nested assessment routes because authorizePatient compared the patient's home branch, unlike consultation/prescription auth which uses the visit. Co-authored-by: Cursor --- .../Controllers/Care/AssessmentController.php | 12 +++++ tests/Feature/CareAssessmentCaptureTest.php | 47 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/app/Http/Controllers/Care/AssessmentController.php b/app/Http/Controllers/Care/AssessmentController.php index a901da9..a3820dd 100644 --- a/app/Http/Controllers/Care/AssessmentController.php +++ b/app/Http/Controllers/Care/AssessmentController.php @@ -72,6 +72,10 @@ class AssessmentController extends Controller $return->remember($consultation); $request->query->set(ConsultationReturnContext::QUERY_KEY, $consultation->uuid); + // Visit branch may differ from the patient's home branch; consultation + // auth already enforced visit-branch scope (same as prescriptions). + $request->attributes->set('care.assessments.skip_patient_branch', true); + return $this->index($request, $consultation->patient); } @@ -92,6 +96,8 @@ class AssessmentController extends Controller } $request->query->set(ConsultationReturnContext::QUERY_KEY, $consultation->uuid); + $request->attributes->set('care.assessments.skip_patient_branch', true); + return $this->create($request, $consultation->patient); } @@ -200,6 +206,8 @@ class AssessmentController extends Controller ]); $consultation->loadMissing(['patient', 'visit']); + // Org/owner only — branch was checked via authorizeConsultation (visit). + $request->attributes->set('care.assessments.skip_patient_branch', true); $this->authorizePatient($request, $consultation->patient); $assessment = $this->assessments->start( @@ -430,6 +438,10 @@ class AssessmentController extends Controller $this->authorizeOwner($request, $patient); abort_unless($patient->organization_id === $this->organization($request)->id, 404); + if ($request->attributes->get('care.assessments.skip_patient_branch')) { + return; + } + $branchId = app(OrganizationResolver::class)->branchScope($this->member($request)); if ($branchId !== null && $patient->branch_id !== $branchId) { abort(404); diff --git a/tests/Feature/CareAssessmentCaptureTest.php b/tests/Feature/CareAssessmentCaptureTest.php index eceb306..19e950c 100644 --- a/tests/Feature/CareAssessmentCaptureTest.php +++ b/tests/Feature/CareAssessmentCaptureTest.php @@ -367,6 +367,53 @@ class CareAssessmentCaptureTest extends TestCase ->assertOk(); } + public function test_consultation_assessments_allow_patient_home_branch_mismatch(): void + { + $this->setMemberRole('doctor'); + + $homeBranch = Branch::create([ + 'owner_ref' => $this->user->public_id, + 'organization_id' => $this->organization->id, + 'name' => 'Home Branch', + 'code' => 'HOME', + 'is_active' => true, + ]); + $this->patient->update(['branch_id' => $homeBranch->id]); + + $visit = Visit::create([ + 'owner_ref' => $this->user->public_id, + 'organization_id' => $this->organization->id, + 'branch_id' => $this->branch->id, + 'patient_id' => $this->patient->id, + 'status' => Visit::STATUS_OPEN, + 'checked_in_at' => now(), + ]); + + $consultation = Consultation::create([ + 'owner_ref' => $this->user->public_id, + 'visit_id' => $visit->id, + 'patient_id' => $this->patient->id, + 'status' => Consultation::STATUS_DRAFT, + 'started_at' => now(), + ]); + + $this->assertNotSame($homeBranch->id, $this->branch->id); + + $this->actingAs($this->user) + ->get(route('care.consultations.assessments.index', $consultation)) + ->assertOk(); + + $this->actingAs($this->user) + ->post(route('care.consultations.assessments.store', $consultation), [ + 'template_code' => 'universal_intake', + ]) + ->assertRedirect(); + + $assessment = Assessment::first(); + $this->assertNotNull($assessment); + $this->assertSame($this->branch->id, $assessment->branch_id); + } + public function test_consultation_scoped_start_links_consultation_and_visit(): void { $this->setMemberRole('doctor');