diff --git a/app/Http/Controllers/Care/SpecialtyModuleController.php b/app/Http/Controllers/Care/SpecialtyModuleController.php index b611d79..4b49132 100644 --- a/app/Http/Controllers/Care/SpecialtyModuleController.php +++ b/app/Http/Controllers/Care/SpecialtyModuleController.php @@ -8,7 +8,9 @@ use App\Models\Appointment; use App\Models\Department; use App\Models\PatientAttachment; use App\Models\Visit; +use App\Services\Care\AppointmentService; use App\Services\Care\CareQueueBridge; +use App\Services\Care\ConsultationService; use App\Services\Care\OrganizationResolver; use App\Services\Care\SpecialtyClinicalRecordService; use App\Services\Care\SpecialtyModuleService; @@ -107,6 +109,69 @@ class SpecialtyModuleController extends Controller return back()->with('success', 'Added to invoice '.$bill->invoice_number.'.'); } + public function startConsultation( + Request $request, + string $module, + Visit $visit, + SpecialtyModuleService $modules, + AppointmentService $appointments, + ConsultationService $consultations, + ): RedirectResponse { + $this->authorizeAbility($request, 'consultations.manage'); + + $definition = $modules->definition($module); + abort_unless($definition, 404); + + $organization = $this->organization($request); + $member = $this->member($request); + abort_unless($modules->memberCanAccess($organization, $member, $module), 403); + abort_unless($visit->organization_id === $organization->id, 404); + $this->authorizeBranch($request, (int) $visit->branch_id); + + $visit->loadMissing(['appointment.consultation', 'appointment.practitioner']); + $appointment = $visit->appointment; + if (! $appointment || $appointment->organization_id !== $organization->id) { + return back()->with('error', 'This visit has no appointment to start a consultation from.'); + } + + $owner = $this->ownerRef($request); + $openConsultation = $appointment->consultation; + if ($openConsultation && $openConsultation->status !== \App\Models\Consultation::STATUS_COMPLETED) { + return redirect() + ->route('care.consultations.show', $openConsultation) + ->with('success', 'Consultation already in progress.'); + } + + try { + if (in_array($appointment->status, [ + Appointment::STATUS_WAITING, + Appointment::STATUS_CHECKED_IN, + ], true)) { + $appointments->startConsultation( + $appointment, + $owner, + $appointment->practitioner_id, + $owner, + ); + $appointment = $appointment->fresh(['practitioner', 'visit']); + } elseif ($appointment->status !== Appointment::STATUS_IN_CONSULTATION) { + return back()->with('error', 'This appointment cannot start a consultation from its current status.'); + } + + $consultation = $consultations->startFromAppointment( + $appointment, + $owner, + $owner, + ); + } catch (\InvalidArgumentException $e) { + return back()->with('error', $e->getMessage()); + } + + return redirect() + ->route('care.consultations.show', $consultation) + ->with('success', 'Consultation started.'); + } + public function saveClinical( Request $request, string $module, @@ -327,6 +392,7 @@ class SpecialtyModuleController extends Controller 'patient.emergencyContacts', 'patient.attachments', 'appointment.practitioner', + 'appointment.consultation', 'bill.lineItems', 'consultations', ]); @@ -346,6 +412,7 @@ class SpecialtyModuleController extends Controller 'patient.emergencyContacts', 'patient.attachments', 'appointment.practitioner', + 'appointment.consultation', 'bill.lineItems', 'consultations', ]); diff --git a/resources/views/care/specialty/shell.blade.php b/resources/views/care/specialty/shell.blade.php index cb8ed34..241a3f2 100644 --- a/resources/views/care/specialty/shell.blade.php +++ b/resources/views/care/specialty/shell.blade.php @@ -75,9 +75,35 @@ ]) @if ($workspaceVisit) + @php + $appointment = $workspaceVisit->appointment; + $openConsultation = $appointment?->consultation; + $canStartConsultation = $appointment && in_array($appointment->status, [ + \App\Models\Appointment::STATUS_WAITING, + \App\Models\Appointment::STATUS_CHECKED_IN, + ], true); + $consultationInProgress = $appointment + && ( + $appointment->status === \App\Models\Appointment::STATUS_IN_CONSULTATION + || ($openConsultation && $openConsultation->status !== \App\Models\Consultation::STATUS_COMPLETED) + ); + @endphp + @if ($consultationInProgress && $openConsultation) + + Open consultation + + @elseif ($canStartConsultation) +
+ @csrf + +
+ @endif - {{ $actions['start'] ?? 'Open workspace' }} + Specialty workspace @if ($workspaceVisit->patient) group(function () { Route::post('/specialty/{module}/workspace/{visit}/clinical', [SpecialtyModuleController::class, 'saveClinical'])->name('care.specialty.clinical.save'); Route::post('/specialty/{module}/workspace/{visit}/documents', [SpecialtyModuleController::class, 'uploadDocument'])->name('care.specialty.documents.upload'); Route::post('/specialty/{module}/workspace/{visit}/services', [SpecialtyModuleController::class, 'addService'])->name('care.specialty.services.add'); + Route::post('/specialty/{module}/workspace/{visit}/start-consultation', [SpecialtyModuleController::class, 'startConsultation'])->name('care.specialty.consultation.start'); Route::get('/specialty/{module}', [SpecialtyModuleController::class, 'show'])->name('care.specialty.show'); Route::post('/specialty/{module}/call-next', [SpecialtyModuleController::class, 'callNext'])->name('care.specialty.call-next'); diff --git a/tests/Feature/CareSpecialtyShellTest.php b/tests/Feature/CareSpecialtyShellTest.php index 3495aec..4785052 100644 --- a/tests/Feature/CareSpecialtyShellTest.php +++ b/tests/Feature/CareSpecialtyShellTest.php @@ -205,4 +205,66 @@ class CareSpecialtyShellTest extends TestCase $bill->lineItems()->where('description', 'Emergency consultation')->exists() ); } + + public function test_specialty_start_consultation_opens_consultation_page(): void + { + app(SpecialtyModuleService::class)->activate( + $this->organization, + $this->owner->public_id, + 'dentistry', + ); + + $department = Department::query() + ->where('branch_id', $this->branch->id) + ->where('type', 'dental') + ->firstOrFail(); + + $patient = Patient::create([ + 'owner_ref' => $this->owner->public_id, + 'organization_id' => $this->organization->id, + 'branch_id' => $this->branch->id, + 'patient_number' => 'P-DEN-1', + 'first_name' => 'Abena', + 'last_name' => 'Osei', + 'gender' => 'female', + 'date_of_birth' => '1993-01-01', + ]); + + $visit = Visit::create([ + 'owner_ref' => $this->owner->public_id, + 'organization_id' => $this->organization->id, + 'branch_id' => $this->branch->id, + 'patient_id' => $patient->id, + 'status' => Visit::STATUS_OPEN, + 'checked_in_at' => now(), + ]); + + $appointment = Appointment::create([ + 'owner_ref' => $this->owner->public_id, + 'organization_id' => $this->organization->id, + 'branch_id' => $this->branch->id, + 'patient_id' => $patient->id, + 'department_id' => $department->id, + 'visit_id' => $visit->id, + 'type' => Appointment::TYPE_WALK_IN, + 'status' => Appointment::STATUS_WAITING, + 'scheduled_at' => now(), + 'waiting_at' => now(), + 'checked_in_at' => now(), + ]); + + $response = $this->actingAs($this->owner) + ->post(route('care.specialty.consultation.start', [ + 'module' => 'dentistry', + 'visit' => $visit, + ])); + + $consultation = \App\Models\Consultation::query() + ->where('appointment_id', $appointment->id) + ->first(); + $this->assertNotNull($consultation); + + $response->assertRedirect(route('care.consultations.show', $consultation)); + $this->assertSame(Appointment::STATUS_IN_CONSULTATION, $appointment->fresh()->status); + } }