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');