Files
ladill-care/app/Http/Controllers/Care/ConsultationController.php
T
isaaccladandCursor 6c9c742ed8
Deploy Ladill Care / deploy (push) Failing after 13s
Initial Ladill Care release.
Healthcare management app: patients, appointments, consultations, lab,
pharmacy inventory, billing, and reports at care.ladill.com.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 11:36:22 +00:00

159 lines
6.4 KiB
PHP

<?php
namespace App\Http\Controllers\Care;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Care\Concerns\ScopesToAccount;
use App\Models\Consultation;
use App\Models\InvestigationType;
use App\Models\Practitioner;
use App\Services\Care\ConsultationService;
use App\Services\Care\OrganizationResolver;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class ConsultationController extends Controller
{
use ScopesToAccount;
public function __construct(
protected ConsultationService $consultations,
) {}
public function show(Request $request, Consultation $consultation): View
{
$this->authorizeAbility($request, 'consultations.view');
$this->authorizeConsultation($request, $consultation);
$consultation->load([
'patient', 'practitioner', 'visit', 'appointment',
'vitalSigns', 'diagnoses', 'documents',
'investigationRequests.investigationType', 'prescriptions.items',
]);
$canManage = app(\App\Services\Care\CarePermissions::class)
->can($this->member($request), 'consultations.manage');
$canVitals = app(\App\Services\Care\CarePermissions::class)
->can($this->member($request), 'vitals.manage');
$canRequestInvestigations = app(\App\Services\Care\CarePermissions::class)
->can($this->member($request), 'investigations.request');
$canPrescribe = app(\App\Services\Care\CarePermissions::class)
->can($this->member($request), 'prescriptions.manage');
$canGenerateBill = app(\App\Services\Care\CarePermissions::class)
->can($this->member($request), 'bills.manage');
$practitioners = Practitioner::owned($this->ownerRef($request))
->where('organization_id', $this->organization($request)->id)
->where('is_active', true)
->orderBy('name')
->get();
$investigationTypes = InvestigationType::owned($this->ownerRef($request))
->where('organization_id', $this->organization($request)->id)
->where('is_active', true)
->orderBy('name')
->get();
return view('care.consultations.show', [
'consultation' => $consultation,
'practitioners' => $practitioners,
'investigationTypes' => $investigationTypes,
'canManage' => $canManage,
'canVitals' => $canVitals,
'canRequestInvestigations' => $canRequestInvestigations,
'canPrescribe' => $canPrescribe,
'canGenerateBill' => $canGenerateBill,
'isCompleted' => $consultation->status === Consultation::STATUS_COMPLETED,
]);
}
public function update(Request $request, Consultation $consultation): RedirectResponse
{
$canManage = app(\App\Services\Care\CarePermissions::class)
->can($this->member($request), 'consultations.manage');
$canVitals = app(\App\Services\Care\CarePermissions::class)
->can($this->member($request), 'vitals.manage');
abort_unless($canManage || $canVitals, 403);
$this->authorizeConsultation($request, $consultation);
abort_if($consultation->status === Consultation::STATUS_COMPLETED, 422);
$validated = $this->validatedConsultationData($request, $canManage, $canVitals);
$this->consultations->save(
$consultation,
$this->ownerRef($request),
$validated,
$this->ownerRef($request),
);
return back()->with('success', 'Consultation saved.');
}
public function complete(Request $request, Consultation $consultation): RedirectResponse
{
$this->authorizeAbility($request, 'consultations.manage');
$this->authorizeConsultation($request, $consultation);
$this->consultations->complete(
$consultation,
$this->ownerRef($request),
$this->ownerRef($request),
);
return redirect()->route('care.patients.show', $consultation->patient)
->with('success', 'Consultation completed.');
}
protected function authorizeConsultation(Request $request, Consultation $consultation): void
{
$this->authorizeOwner($request, $consultation);
$consultation->loadMissing('visit');
abort_unless($consultation->visit->organization_id === $this->organization($request)->id, 404);
$branchId = app(OrganizationResolver::class)->branchScope($this->member($request));
if ($branchId !== null && $consultation->visit->branch_id !== $branchId) {
abort(404);
}
}
/**
* @return array<string, mixed>
*/
protected function validatedConsultationData(Request $request, bool $canManage, bool $canVitals): array
{
$rules = [];
if ($canManage) {
$rules = array_merge($rules, [
'symptoms' => ['nullable', 'string', 'max:10000'],
'clinical_notes' => ['nullable', 'string', 'max:20000'],
'practitioner_id' => ['nullable', 'integer', 'exists:care_practitioners,id'],
'diagnoses' => ['nullable', 'array'],
'diagnoses.*.code' => ['nullable', 'string', 'max:50'],
'diagnoses.*.description' => ['nullable', 'string', 'max:500'],
'diagnoses.*.is_primary' => ['nullable', 'boolean'],
'diagnoses.*.notes' => ['nullable', 'string', 'max:2000'],
'documents' => ['nullable', 'array'],
'documents.*' => ['file', 'max:10240', 'mimes:pdf,jpeg,png,jpg,webp'],
]);
$canVitals = true;
}
if ($canVitals) {
$rules['vitals'] = ['nullable', 'array'];
$rules['vitals.bp_systolic'] = ['nullable', 'integer', 'min:50', 'max:300'];
$rules['vitals.bp_diastolic'] = ['nullable', 'integer', 'min:30', 'max:200'];
$rules['vitals.pulse'] = ['nullable', 'integer', 'min:20', 'max:250'];
$rules['vitals.temperature'] = ['nullable', 'numeric', 'min:30', 'max:45'];
$rules['vitals.weight_kg'] = ['nullable', 'numeric', 'min:0', 'max:500'];
$rules['vitals.height_cm'] = ['nullable', 'numeric', 'min:0', 'max:300'];
$rules['vitals.spo2'] = ['nullable', 'integer', 'min:50', 'max:100'];
$rules['vitals.respiratory_rate'] = ['nullable', 'integer', 'min:5', 'max:80'];
}
return $request->validate($rules);
}
}