Deploy Ladill Care / deploy (push) Failing after 13s
Healthcare management app: patients, appointments, consultations, lab, pharmacy inventory, billing, and reports at care.ladill.com. Co-authored-by: Cursor <cursoragent@cursor.com>
159 lines
6.4 KiB
PHP
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);
|
|
}
|
|
}
|