Files
ladill-care/app/Services/Care/NursingAssessmentService.php
T
isaaccladandCursor f1bb432324
Deploy Ladill Care / deploy (push) Successful in 2m12s
Include checked-in clinic visits on outpatient nursing boards.
OPD/service units list open department appointments without manual place; nursing actions soft-place the visit onto the unit. Inpatient wards stay placement-only.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-20 17:05:13 +00:00

117 lines
3.6 KiB
PHP

<?php
namespace App\Services\Care;
use App\Models\Assessment;
use App\Models\AssessmentTemplate;
use App\Models\CareUnit;
use App\Models\Visit;
use App\Models\VisitVital;
use Illuminate\Support\Collection;
class NursingAssessmentService
{
/** @var list<string> */
public const NURSING_PACK_CODES = ['news2', 'braden', 'morse', 'pain_nrs'];
/** Compact board labels — full names stay on the assessment form. */
public static function shortLabel(string $code): string
{
return match ($code) {
'news2' => 'NEWS2',
'braden' => 'Braden',
'morse' => 'Morse',
'pain_nrs' => 'Pain',
default => strtoupper(str_replace('_', ' ', $code)),
};
}
/**
* @return Collection<int, AssessmentTemplate>
*/
public function nursingTemplates(): Collection
{
return AssessmentTemplate::query()
->whereNull('organization_id')
->where('is_current', true)
->where('is_active', true)
->whereIn('code', self::NURSING_PACK_CODES)
->orderBy('name')
->get();
}
/**
* Board rows for placed patients: latest nursing assessments + latest vitals.
*
* @return list<array<string, mixed>>
*/
public function unitBoard(CareUnit $unit, string $ownerRef): array
{
$templates = $this->nursingTemplates();
$visits = app(CareUnitCensusService::class)->visitsForUnit($unit, $ownerRef);
$rows = [];
foreach ($visits as $visit) {
$latestByCode = Assessment::owned($ownerRef)
->where('visit_id', $visit->id)
->whereIn('status', [Assessment::STATUS_DRAFT, Assessment::STATUS_COMPLETED])
->whereHas('template', fn ($q) => $q->whereIn('code', $templates->pluck('code')->all()))
->with(['template', 'score'])
->orderByDesc('id')
->get()
->unique(fn (Assessment $a) => $a->template?->code)
->keyBy(fn (Assessment $a) => $a->template?->code);
$latestVitals = VisitVital::owned($ownerRef)
->where('visit_id', $visit->id)
->orderByDesc('recorded_at')
->first();
$rows[] = [
'visit' => $visit,
'patient' => $visit->patient,
'bed' => $visit->bed,
'assessments' => $latestByCode,
'vitals' => $latestVitals,
];
}
return $rows;
}
public function recordVisitVitals(
Visit $visit,
string $ownerRef,
?string $actorRef,
array $data,
): VisitVital {
$vital = VisitVital::create([
'owner_ref' => $ownerRef,
'organization_id' => $visit->organization_id,
'visit_id' => $visit->id,
'patient_id' => $visit->patient_id,
'care_unit_id' => $visit->care_unit_id,
'bp_systolic' => $data['bp_systolic'] ?? null,
'bp_diastolic' => $data['bp_diastolic'] ?? null,
'pulse' => $data['pulse'] ?? null,
'temperature' => $data['temperature'] ?? null,
'spo2' => $data['spo2'] ?? null,
'respiratory_rate' => $data['respiratory_rate'] ?? null,
'notes' => $data['notes'] ?? null,
'recorded_by' => $actorRef,
'recorded_at' => now(),
]);
AuditLogger::record(
$ownerRef,
'visit_vitals.recorded',
$visit->organization_id,
$actorRef,
VisitVital::class,
$vital->id,
);
return $vital;
}
}