diff --git a/app/Http/Controllers/Care/NursingDocumentationController.php b/app/Http/Controllers/Care/NursingDocumentationController.php index 884dcbb..5d52df4 100644 --- a/app/Http/Controllers/Care/NursingDocumentationController.php +++ b/app/Http/Controllers/Care/NursingDocumentationController.php @@ -10,6 +10,7 @@ use App\Models\WardHandover; use App\Services\Care\CarePermissions; use App\Services\Care\CareUnitCensusService; use App\Services\Care\NursingDocumentationService; +use App\Services\Care\RosterService; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Validation\Rule; @@ -19,7 +20,7 @@ class NursingDocumentationController extends Controller { use ScopesToAccount; - public function unitNotes(Request $request, CareUnit $careUnit, NursingDocumentationService $docs, CareUnitCensusService $census): View + public function unitNotes(Request $request, CareUnit $careUnit, NursingDocumentationService $docs, CareUnitCensusService $census, RosterService $roster): View { $this->authorizeAbility($request, 'nursing.notes.view'); $this->authorizeOwner($request, $careUnit); @@ -31,18 +32,25 @@ class NursingDocumentationController extends Controller $selectedVisitId = 0; } + $lockedShiftCode = $roster->dutyShiftCodeForMember( + $careUnit, + $this->member($request), + $this->ownerRef($request), + ); + return view('care.nursing.notes', [ 'unit' => $careUnit->load('department.branch'), 'notes' => $docs->notesForUnit($careUnit, $this->ownerRef($request)), 'placedVisits' => $placedVisits, 'selectedVisitId' => $selectedVisitId ?: (int) old('visit_id', 0), + 'lockedShiftCode' => $lockedShiftCode, 'canWrite' => app(CarePermissions::class)->can($this->member($request), 'nursing.notes.manage'), 'noteTypes' => config('care.nursing_note_types'), 'shiftCodes' => config('care.staff_shift_codes'), ]); } - public function storeNote(Request $request, CareUnit $careUnit, NursingDocumentationService $docs, CareUnitCensusService $census): RedirectResponse + public function storeNote(Request $request, CareUnit $careUnit, NursingDocumentationService $docs, CareUnitCensusService $census, RosterService $roster): RedirectResponse { $this->authorizeAbility($request, 'nursing.notes.manage'); $this->authorizeOwner($request, $careUnit); @@ -50,7 +58,6 @@ class NursingDocumentationController extends Controller $validated = $request->validate([ 'visit_id' => ['required', 'integer', 'exists:care_visits,id'], 'note_type' => ['required', 'string', Rule::in(array_keys(config('care.nursing_note_types')))], - 'shift_code' => ['nullable', 'string', Rule::in(array_keys(config('care.staff_shift_codes')))], 'body' => ['required', 'string', 'max:5000'], ]); @@ -61,13 +68,19 @@ class NursingDocumentationController extends Controller $visit = $census->ensurePlaced($visit, $careUnit, $this->ownerRef($request), $this->actorRef($request)); + $shiftCode = $roster->dutyShiftCodeForMember( + $careUnit, + $this->member($request), + $this->ownerRef($request), + ); + $docs->addNote( $visit, $this->ownerRef($request), $this->actorRef($request), $validated['body'], $validated['note_type'], - $validated['shift_code'] ?? null, + $shiftCode, $careUnit->id, ); diff --git a/app/Services/Care/RosterService.php b/app/Services/Care/RosterService.php index 642f036..f1bf209 100644 --- a/app/Services/Care/RosterService.php +++ b/app/Services/Care/RosterService.php @@ -271,4 +271,76 @@ class RosterService return $labels; } + + /** + * Shift code for nursing notes: today's roster on this unit, else clock-based default. + */ + public function dutyShiftCodeForMember( + CareUnit $unit, + ?Member $member, + string $ownerRef, + ?CarbonInterface $at = null, + ): ?string { + $at = Carbon::parse($at ?? now()); + $allowed = array_keys(config('care.staff_shift_codes', [])); + + if ($member) { + $entry = RosterEntry::owned($ownerRef) + ->where('care_unit_id', $unit->id) + ->where('member_id', $member->id) + ->whereDate('duty_date', $at->toDateString()) + ->where('status', '!=', RosterEntry::STATUS_CANCELLED) + ->with('shift') + ->orderBy('shift_id') + ->first(); + + $code = $entry?->shift?->code; + if ($code && in_array($code, $allowed, true)) { + return $code; + } + } + + $organization = $unit->organization + ?? Organization::query()->find($unit->organization_id); + if (! $organization) { + return null; + } + + $shifts = $this->ensureDefaultShifts($organization, $ownerRef); + foreach ($shifts as $shift) { + if (! in_array($shift->code, $allowed, true)) { + continue; + } + if ($this->clockFallsInShift($at, (string) $shift->start_time, (string) $shift->end_time)) { + return $shift->code; + } + } + + return null; + } + + protected function clockFallsInShift(CarbonInterface $at, string $startTime, string $endTime): bool + { + $minutes = ((int) $at->format('H') * 60) + (int) $at->format('i'); + $start = $this->timeToMinutes($startTime); + $end = $this->timeToMinutes($endTime); + + if ($start === $end) { + return true; + } + + // Overnight (e.g. 23:00–07:00) + if ($start > $end) { + return $minutes >= $start || $minutes < $end; + } + + return $minutes >= $start && $minutes < $end; + } + + protected function timeToMinutes(string $time): int + { + $parts = explode(':', substr($time, 0, 5)); + + return ((int) ($parts[0] ?? 0) * 60) + (int) ($parts[1] ?? 0); + } } diff --git a/resources/views/care/nursing/notes.blade.php b/resources/views/care/nursing/notes.blade.php index 5ed59cc..c0b0c0d 100644 --- a/resources/views/care/nursing/notes.blade.php +++ b/resources/views/care/nursing/notes.blade.php @@ -38,12 +38,13 @@