self::URGENCY_URGENT, 2 => self::URGENCY_PLANNED, default => self::URGENCY_UNKNOWN, }; } /** * Определяет поступил ли пациент в диапазоне. */ public static function classifyAdmitted(Carbon|string|null $ingoingDate): bool { if (is_null($ingoingDate)) {return false;} $ingoingLocal = Carbon::parse($ingoingDate); $now = Carbon::now(); // Окно смены: вчера 09:00 → сегодня 09:00 $shiftStart = $now->copy()->subDay()->setTime(9, 0); $shiftEnd = $now->copy()->setTime(9, 0); return $ingoingLocal->between($shiftStart, $shiftEnd); } /** * Определяет статус пациента на основе "сырых" полей из БД. * Логика изолирована и может быть легко протестирована. */ public static function classify(UnifiedMedicalHistory|MedicalHistory $history, DateRange $dateRange): string { // 1. Смерть — приоритет №1 (не зависит от дат) if (!empty($history->death_date)) { return self::STATUS_DECEASED; } // 2. Если есть дата выбытия if (!empty($history->extract_date)) { // Переведён (коды 3, 4) if (in_array($history->visit_result_id, [3, 4], true)) { return self::STATUS_TRANSFERRED; } // Выписан домой/иное (исключаем коды 3-6) if (in_array($history->visit_result_id, [1], true)) { return self::STATUS_DISCHARGED; } } // 3. Поступившие if ($history->latestMigration?->getAdmittedInCurrentAttribute()) { return self::STATUS_RECIPIENT; } // 4. В отделении if (empty($history->latestMigration?->out_date) && $history->latestMigration?->ingoing_date < $dateRange->startDate) { return self::STATUS_IN_DEPARTMENT; } return 'unknown'; } }