Wire specialty Start consultation to the real consultation page.
Deploy Ladill Care / deploy (push) Successful in 58s

Doctors leave the specialty shell into Care consultations instead of a no-op workspace link.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-18 11:36:57 +00:00
co-authored by Cursor
parent 34ca1365b9
commit 4c4dfc7dbf
4 changed files with 157 additions and 1 deletions
@@ -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',
]);
+27 -1
View File
@@ -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)
<a href="{{ route('care.consultations.show', $openConsultation) }}"
class="flex w-full items-center justify-center rounded-xl bg-indigo-600 px-3 py-2 text-sm font-semibold text-white hover:bg-indigo-700">
Open consultation
</a>
@elseif ($canStartConsultation)
<form method="POST" action="{{ route('care.specialty.consultation.start', ['module' => $moduleKey, 'visit' => $workspaceVisit]) }}">
@csrf
<button type="submit" class="flex w-full items-center justify-center rounded-xl bg-indigo-600 px-3 py-2 text-sm font-semibold text-white hover:bg-indigo-700">
{{ $actions['start'] ?? 'Start consultation' }}
</button>
</form>
@endif
<a href="{{ route('care.specialty.workspace', ['module' => $moduleKey, 'visit' => $workspaceVisit]) }}"
class="flex w-full items-center justify-center rounded-xl border border-slate-200 bg-slate-50 px-3 py-2 text-sm font-medium text-slate-800 hover:bg-slate-100">
{{ $actions['start'] ?? 'Open workspace' }}
Specialty workspace
</a>
@if ($workspaceVisit->patient)
<a href="{{ route('care.patients.show', $workspaceVisit->patient) }}"
+1
View File
@@ -115,6 +115,7 @@ Route::middleware(['auth', 'platform.session'])->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');
+62
View File
@@ -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);
}
}