*/ public function unitReport( CareUnit $unit, string $ownerRef, ?CarbonInterface $from = null, ?CarbonInterface $to = null, ): array { $from = Carbon::parse($from ?? now()->subDays(7))->startOfDay(); $to = Carbon::parse($to ?? now())->endOfDay(); $visitIds = Visit::owned($ownerRef) ->where('care_unit_id', $unit->id) ->pluck('id'); $mar = MarAdministration::owned($ownerRef) ->where('care_unit_id', $unit->id) ->whereBetween('recorded_at', [$from, $to]) ->get(); $marGiven = $mar->where('status', MarAdministration::STATUS_GIVEN)->count(); $marHeld = $mar->where('status', MarAdministration::STATUS_HELD)->count(); $marRefused = $mar->where('status', MarAdministration::STATUS_REFUSED)->count(); $marMissed = $mar->where('status', MarAdministration::STATUS_MISSED)->count(); $marTotal = $mar->count(); $marOnTime = $mar->filter(function (MarAdministration $a) { if ($a->status !== MarAdministration::STATUS_GIVEN || ! $a->scheduled_for) { return false; } return $a->recorded_at->between( $a->scheduled_for->copy()->subMinutes(30), $a->scheduled_for->copy()->addMinutes(60), ); })->count(); $notes = NursingNote::owned($ownerRef) ->where('care_unit_id', $unit->id) ->whereBetween('recorded_at', [$from, $to]) ->get(); $vitals = VisitVital::owned($ownerRef) ->where('care_unit_id', $unit->id) ->whereBetween('recorded_at', [$from, $to]) ->count(); $nursingCodes = NursingAssessmentService::NURSING_PACK_CODES; $assessments = Assessment::owned($ownerRef) ->whereIn('visit_id', $visitIds->isEmpty() ? [0] : $visitIds->all()) ->whereBetween('created_at', [$from, $to]) ->whereHas('template', fn ($q) => $q->whereIn('code', $nursingCodes)) ->with('template') ->get(); $assessmentsCompleted = $assessments->where('status', Assessment::STATUS_COMPLETED)->count(); $assessmentsDraft = $assessments->where('status', Assessment::STATUS_DRAFT)->count(); $handovers = WardHandover::owned($ownerRef) ->where('care_unit_id', $unit->id) ->whereBetween('created_at', [$from, $to]) ->get(); $assignedStaff = StaffAssignment::owned($ownerRef) ->where('care_unit_id', $unit->id) ->where('status', 'active') ->unitPlacements() ->effectiveOn($to) ->with('member') ->get(); $byActor = $this->byActor( $mar, $notes, $assessments->where('status', Assessment::STATUS_COMPLETED), $handovers->where('status', WardHandover::STATUS_COMPLETED), ); return [ 'from' => $from, 'to' => $to, 'placed_patients' => app(CareUnitCensusService::class) ->visitsForUnit($unit, $ownerRef) ->count(), 'mar' => [ 'total' => $marTotal, 'given' => $marGiven, 'held' => $marHeld, 'refused' => $marRefused, 'missed' => $marMissed, 'on_time_given' => $marOnTime, 'on_time_rate' => $marGiven > 0 ? round(($marOnTime / $marGiven) * 100, 1) : null, 'compliance_rate' => $marTotal > 0 ? round((($marGiven) / $marTotal) * 100, 1) : null, ], 'notes' => [ 'total' => $notes->count(), 'by_type' => $notes->groupBy('note_type')->map->count()->all(), ], 'vitals' => [ 'total' => $vitals, ], 'assessments' => [ 'started' => $assessments->count(), 'completed' => $assessmentsCompleted, 'draft' => $assessmentsDraft, 'completion_rate' => $assessments->count() > 0 ? round(($assessmentsCompleted / $assessments->count()) * 100, 1) : null, 'by_template' => $assessments ->groupBy(fn (Assessment $a) => $a->template?->code ?? 'unknown') ->map(fn (Collection $group, $code) => [ 'code' => $code, 'name' => $group->first()->template?->name ?? $code, 'completed' => $group->where('status', Assessment::STATUS_COMPLETED)->count(), 'total' => $group->count(), ]) ->values() ->all(), ], 'handovers' => [ 'total' => $handovers->count(), 'completed' => $handovers->where('status', WardHandover::STATUS_COMPLETED)->count(), ], 'assigned_staff' => $assignedStaff->count(), 'by_actor' => $byActor, ]; } /** * @param Collection $mar * @param Collection $notes * @param Collection $assessments * @param Collection $handovers * @return list> */ protected function byActor( Collection $mar, Collection $notes, Collection $assessments, Collection $handovers, ): array { $refs = collect() ->merge($mar->pluck('administered_by')) ->merge($notes->pluck('recorded_by')) ->merge($assessments->pluck('completed_by')) ->merge($handovers->pluck('handed_over_by')) ->filter() ->unique() ->values(); $emails = User::query()->whereIn('public_id', $refs)->pluck('email', 'public_id'); $names = User::query()->whereIn('public_id', $refs)->pluck('name', 'public_id'); $rows = []; foreach ($refs as $ref) { $rows[] = [ 'actor_ref' => $ref, 'label' => $names[$ref] ?? $emails[$ref] ?? $ref, 'mar_given' => $mar->where('administered_by', $ref)->where('status', MarAdministration::STATUS_GIVEN)->count(), 'mar_total' => $mar->where('administered_by', $ref)->count(), 'notes' => $notes->where('recorded_by', $ref)->count(), 'assessments_completed' => $assessments->where('completed_by', $ref)->count(), 'handovers' => $handovers->where('handed_over_by', $ref)->count(), ]; } usort($rows, fn ($a, $b) => ($b['mar_total'] + $b['notes'] + $b['assessments_completed']) <=> ($a['mar_total'] + $a['notes'] + $a['assessments_completed'])); return $rows; } }