rf_mis_department_id; $branchId = $this->getBranchId($misDepartmentId); // Определяем, используем ли мы снапшоты $useSnapshots = $this->shouldUseSnapshots($department, $user, $dateRange); if ($useSnapshots) { return $this->getStatisticsFromSnapshots($department, $dateRange, $branchId); } return $this->getStatisticsFromReplica($user, $dateRange, $branchId); } /** * Создать или обновить отчет */ public function storeReport(array $data, User $user, $fillableAuto = false): Report { DB::beginTransaction(); try { $report = $this->createOrUpdateReport($data, $user); $this->saveMetrics($report, $data['metrics'] ?? []); $this->saveUnwantedEvents($report, $data['unwantedEvents'] ?? []); $this->saveObservationPatients($report, $data['observationPatients'] ?? [], $user->rf_department_id); // Сохраняем снапшоты пациентов $this->snapshotService->createPatientSnapshots($report, $user, $data['dates'], $fillableAuto); // Сохраняем метрику среднего койко-дня из снапшотов $this->saveAverageBedDaysMetricFromSnapshots($report); DB::commit(); // ОЧИСТКА КЭША ПОСЛЕ УСПЕШНОГО СОЗДАНИЯ ОТЧЕТА $this->clearCacheAfterReportCreation($user, $report); return $report; } catch (\Exception $e) { DB::rollBack(); throw $e; } } /** * Сохранить метрику среднего койко-дня из снапшотов отчета */ protected function saveAverageBedDaysMetricFromSnapshots(Report $report): void { try { // Получаем все снапшоты выписанных пациентов из этого отчета $snapshots = MedicalHistorySnapshot::where('rf_report_id', $report->report_id) ->whereIn('patient_type', ['discharged', 'deceased']) // выписанные и умершие ->with('medicalHistory') ->get(); if ($snapshots->isEmpty()) { // Если нет выписанных, сохраняем 0 MetrikaResult::updateOrCreate( [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 18, ], ['value' => 0] ); \Log::info("No discharged patients in report {$report->report_id}, saved 0"); return; } // Рассчитываем средний койко-день по снапшотам $totalDays = 0; $validCount = 0; foreach ($snapshots as $snapshot) { $history = $snapshot->medicalHistory; if ($history && $history->DateRecipient && $history->DateExtract) { // Проверяем что дата выписки не специальная if ($history->DateExtract->format('Y-m-d') === '2222-01-01') { continue; // пропускаем текущих пациентов } $start = Carbon::parse($history->DateRecipient); $end = Carbon::parse($history->DateExtract); // Проверяем что дата выписки позже даты поступления if ($end->gt($start)) { $days = $start->diffInDays($end); $totalDays += $days; $validCount++; } } } $avgBedDays = $validCount > 0 ? round($totalDays / $validCount, 1) : 0; // Сохраняем метрику MetrikaResult::updateOrCreate( [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 18, ], ['value' => $avgBedDays] ); \Log::info("Saved average bed days metric for report {$report->report_id}: {$avgBedDays} (from {$validCount} patients)"); } catch (\Exception $e) { \Log::error("Failed to save average bed days metric: " . $e->getMessage()); // Не прерываем выполнение, если метрика не сохранилась } } /** * Очистить кэш после создания отчета */ private function clearCacheAfterReportCreation(User $user, Report $report): void { // Очищаем кэш статистики для пользователя $this->statisticsService->clearStatisticsCache($user); // Также можно очистить кэш для всех пользователей отдела $this->statisticsService->clearDepartmentStatisticsCache($user->rf_department_id); // Очищаем кэш за сегодня и вчера (так как отчеты влияют на эти даты) $this->clearDailyCache($user, $report->created_at); } /** * Очистить дневной кэш */ private function clearDailyCache(User $user, $reportDate): void { $datesToClear = [ Carbon::parse($reportDate)->format('Y-m-d'), Carbon::parse($reportDate)->subDay()->format('Y-m-d'), ]; foreach ($datesToClear as $date) { $cacheKey = $this->generateDailyCacheKey($user, $date); Cache::forget($cacheKey); } } private function generateDailyCacheKey(User $user, string $date): string { return 'daily_stats:' . $user->rf_department_id . ':' . $date; } /** * Получить пациентов по статусу */ public function getPatientsByStatus( Department $department, User $user, string $status, DateRange $dateRange, bool $onlyIds = false, bool $beforeCreate = false, ?bool $includeCurrentPatients = null ) { $branchId = $this->getBranchId($department->rf_mis_department_id); $useSnapshots = $this->shouldUseSnapshots($department, $user, $dateRange, $beforeCreate); if ($useSnapshots) { return $this->getPatientsFromSnapshots($department, $status, $dateRange, $branchId); } return $this->getPatientsFromReplica($department, $user, $status, $dateRange, $branchId, $onlyIds, $includeCurrentPatients); } /** * Получить количество пациентов по статусу */ public function getPatientsCountByStatus( Department $department, User $user, string $status, DateRange $dateRange ): int { $branchId = $this->getBranchId($department->rf_mis_department_id); $useSnapshots = $this->shouldUseSnapshots($department, $user, $dateRange); if ($useSnapshots) { return $this->getPatientsCountFromSnapshots($department, $status, $dateRange); } return $this->getPatientsCountFromReplica($department, $user, $status, $dateRange, $branchId); } /** * Получить ID отделения из стационарного отделения */ private function getBranchId(int $misDepartmentId): ?int { return MisStationarBranch::where('rf_DepartmentID', $misDepartmentId) ->value('StationarBranchID'); } /** * Определить, нужно ли использовать снапшоты */ private function shouldUseSnapshots(Department $department, User $user, DateRange $dateRange, bool $beforeCreate = false): bool { if (($user->isAdmin() || $user->isHeadOfDepartment()) && !$beforeCreate) { return true; } // Проверяем, есть ли отчет на сегодня $reportToday = Report::whereDate('sent_at', $dateRange->end()) ->whereDate('created_at', $dateRange->end()) ->where('rf_department_id', $department->department_id) ->first(); return !$dateRange->isEndDateToday() || $reportToday; } /** * Создать или обновить отчет */ private function createOrUpdateReport(array $data, User $user): Report { $reportData = [ 'rf_department_id' => $data['departmentId'], 'rf_user_id' => $user->id, 'rf_lpudoctor_id' => $data['userId'], 'sent_at' => $data['sent_at'] ?? $this->dateRangeService->toSqlFormat(\Illuminate\Support\Carbon::now()), 'created_at' => $data['created_at'] ?? $this->dateRangeService->toSqlFormat(\Illuminate\Support\Carbon::now()), ]; if (isset($data['reportId']) && $data['reportId']) { $report = Report::updateOrCreate( ['report_id' => $data['reportId']], $reportData ); } else { $report = Report::create($reportData); $department = Department::where('department_id', $reportData['rf_department_id'])->first(); $beds = $department->metrikaDefault->where('rf_metrika_item_id', 1)->first(); MetrikaResult::create([ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => 1, 'value' => $beds->value ]); } return $report; } /** * Сохранить метрики отчета */ private function saveMetrics(Report $report, array $metrics): void { foreach ($metrics as $key => $value) { $metrikaId = (int)str_replace('metrika_item_', '', $key); MetrikaResult::updateOrCreate( [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => $metrikaId, ], [ 'value' => $value, ] ); } } /** * Сохранить нежелательные события */ private function saveUnwantedEvents(Report $report, array $unwantedEvents): void { if (empty($unwantedEvents)) { $report->unwantedEvents()->delete(); $this->saveMetrics($report, [16 => 0]); return; } foreach ($unwantedEvents as $event) { if (isset($event['unwanted_event_id']) && $event['unwanted_event_id']) { UnwantedEvent::updateOrCreate( ['unwanted_event_id' => $event['unwanted_event_id']], [ 'rf_report_id' => $report->report_id, 'comment' => $event['comment'] ?? '', 'title' => $event['title'] ?? '', 'is_visible' => $event['is_visible'] ?? true, ] ); } else { UnwantedEvent::create([ 'rf_report_id' => $report->report_id, 'comment' => $event['comment'] ?? '', 'title' => $event['title'] ?? '', 'is_visible' => $event['is_visible'] ?? true, ]); } } // Обновить метрику $this->saveMetrics($report, [16 => count($unwantedEvents)]); } /** * Сохранить пациентов под наблюдением */ private function saveObservationPatients( Report $report, array $observationPatients, int $departmentId ): void { if (empty($observationPatients)) { ObservationPatient::where('rf_department_id', $departmentId) ->where('rf_report_id', $report->report_id) ->delete(); // Обновить метрику $this->saveMetrics($report, [14 => 0]); return; } foreach ($observationPatients as $patient) { ObservationPatient::updateOrCreate( [ 'rf_medicalhistory_id' => $patient['id'], 'rf_department_id' => $departmentId, ], [ 'rf_report_id' => $report->report_id, 'rf_mkab_id' => null, 'comment' => $patient['comment'] ?? null, ] ); } // Обновить метрику $this->saveMetrics($report, [14 => count($observationPatients)]); } /** * Получить информацию о текущем отчете */ public function getCurrentReportInfo(Department $department, User $user, DateRange $dateRange): array { $reportToday = Report::whereDate('sent_at', $dateRange->endSql()) ->whereDate('created_at', $dateRange->endSql()) ->where('rf_department_id', $department->department_id) ->first(); $isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin(); $useSnapshots = $isHeadOrAdmin || !$dateRange->isEndDateToday() || $reportToday; // Получаем ID пользователя для заполнения отчета if ($useSnapshots && $isHeadOrAdmin && $reportToday) { $fillableUserId = $reportToday->rf_lpudoctor_id ?? null; } else { $fillableUserId = request()->query('userId', $user->rf_lpudoctor_id); } // Получаем нежелательные события $unwantedEvents = $this->getUnwantedEvents($department, $dateRange); // Определяем активность кнопки отправки $isActiveSendButton = $this->isSendButtonActive($user, $dateRange, $reportToday, $fillableUserId); $message = null; if ($reportToday) { $reportDoctor = $reportToday->lpuDoctor; $message = "Отчет уже создан пользователем: $reportDoctor->FAM_V $reportDoctor->IM_V $reportDoctor->OT_V"; } // Получаем информацию о враче $lpuDoctor = $this->getDoctorInfo($fillableUserId, $dateRange); // Проверяем, является ли диапазон одним днем // $isRangeOneDay = $this->dateRangeService->isRangeOneDay( // $endDate->copy()->subDay()->format('Y-m-d H:i:s'), // $endDate->format('Y-m-d H:i:s') // ); // Формируем даты для ответа // $date = $isHeadOrAdmin ? [ // $endDate->copy()->subDay()->getTimestampMs(), // $endDate->getTimestampMs() // ] : $endDate->getTimestampMs(); $date = $isHeadOrAdmin ? [ $dateRange->startDate->getTimestampMs(), $dateRange->endDate->getTimestampMs() ] : $dateRange->endDate->getTimestampMs(); return [ 'report_id' => $reportToday?->report_id, 'unwantedEvents' => $unwantedEvents, 'isActiveSendButton' => $isActiveSendButton, 'message' => $message, 'isOneDay' => $dateRange->isOneDay, 'isHeadOrAdmin' => $isHeadOrAdmin, 'dates' => $date, 'userId' => $fillableUserId, 'userName' => $lpuDoctor ? "$lpuDoctor->FAM_V $lpuDoctor->IM_V $lpuDoctor->OT_V" : null ]; } /** * Удалить пациента из наблюдения */ public function removeObservationPatient(int $medicalHistoryId): void { ObservationPatient::where('rf_medicalhistory_id', $medicalHistoryId)->delete(); } /** * Получить статистику из снапшотов */ private function getStatisticsFromSnapshots(Department $department, DateRange $dateRange, int $branchId): array { // Получаем отчеты за период $reports = $this->getReportsForDateRange( $department->department_id, $dateRange ); $reportIds = $reports->pluck('report_id')->toArray(); // Получаем статистику из снапшотов $snapshotStats = [ 'plan' => $this->getMetrikaResultCount(4, $reportIds), 'emergency' => $this->getMetrikaResultCount(12, $reportIds), 'outcome' => $this->getMetrikaResultCount(7, $reportIds), 'deceased' => $this->getMetrikaResultCount(9, $reportIds), 'current' => $this->getMetrikaResultCount(8, $reportIds, false), // 'discharged' => $this->getMetrikaResultCount('discharged', $reportIds), 'transferred' => $this->getMetrikaResultCount(13, $reportIds), 'recipient' => $this->getMetrikaResultCount(3, $reportIds), 'beds' => $this->getMetrikaResultCount(1, $reportIds, false) ]; // Получаем ID поступивших пациентов $recipientIds = MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds) ->where('patient_type', 'recipient') ->pluck('rf_medicalhistory_id') ->unique() ->toArray(); // Получаем количество операций из метрик $surgicalCount = [ $this->getMetrikaResultCount(10, $reportIds), // экстренные операции $this->getMetrikaResultCount(11, $reportIds) // плановые операции ]; if ($snapshotStats['outcome'] == 0) { $percentDead = 0; } else { $percentDead = ($snapshotStats['deceased'] / $snapshotStats['outcome']) * 100; $percentDead = round($percentDead, 2); } return [ 'recipientCount' => $snapshotStats['recipient'] ?? 0, 'extractCount' => $snapshotStats['outcome'] ?? 0, 'currentCount' => $snapshotStats['current'] ?? 0,//$this->calculateCurrentPatientsFromSnapshots($reportIds, $branchId), 'deadCount' => $snapshotStats['deceased'] ?? 0, 'surgicalCount' => $surgicalCount, 'recipientIds' => $recipientIds, 'beds' => $snapshotStats['beds'] ?? 0, 'percentDead' => $percentDead, ]; } /** * Получить статистику из реплики БД */ private function getStatisticsFromReplica(User $user, DateRange $dateRange, int $branchId): array { $isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin(); // Плановые: поступившие сегодня + уже лечащиеся $planCount = $this->patientQueryService->getPatientsCountWithCurrent( 'plan', $isHeadOrAdmin, $branchId, $dateRange ); // Экстренные: поступившие сегодня + уже лечащиеся $emergencyCount = $this->patientQueryService->getPatientsCountWithCurrent( 'emergency', $isHeadOrAdmin, $branchId, $dateRange ); // Все пациенты в отделении: поступившие + лечащиеся $currentCount = $this->patientQueryService->getAllPatientsInDepartment( $isHeadOrAdmin, $branchId, $dateRange, true ); // Поступившие сегодня (только новые поступления) $recipientCount = $this->patientQueryService->getPlanOrEmergencyPatients( null, // все типы $isHeadOrAdmin, $branchId, $dateRange, true, false, false // не включаем уже лечащихся ); // Выбывшие за период $outcomeCount = $this->patientQueryService->getOutcomePatients( $branchId, $dateRange, 'without-transferred' )->count(); // Умершие за период $deadCount = $this->patientQueryService->getOutcomePatients( $branchId, $dateRange, 'deceased' )->count(); // Операции $surgicalCount = [ $this->patientQueryService->getSurgicalPatients( 'emergency', $branchId, $dateRange, true ), $this->patientQueryService->getSurgicalPatients( 'plan', $branchId, $dateRange, true ) ]; // ID поступивших сегодня (для отметки в таблице) $recipientIds = $this->patientQueryService->getPlanOrEmergencyPatients( null, $isHeadOrAdmin, $branchId, $dateRange, false, true, false // только поступившие сегодня ); $misBranch = MisStationarBranch::where('StationarBranchID', $branchId)->first(); $beds = Department::where('rf_mis_department_id', $misBranch->rf_DepartmentID) ->first()->metrikaDefault->where('rf_metrika_item_id', 1)->first(); if ($outcomeCount == 0) { $percentDead = 0; } else { $percentDead = ($deadCount / $outcomeCount) * 100; $percentDead = round($percentDead, 2); } return [ 'recipientCount' => $recipientCount, // только поступившие сегодня 'extractCount' => $outcomeCount, 'currentCount' => $currentCount, // все в отделении 'deadCount' => $deadCount, 'surgicalCount' => $surgicalCount, 'recipientIds' => $recipientIds, // ID поступивших сегодня 'planCount' => $planCount, // плановые (поступившие + уже лечащиеся) 'emergencyCount' => $emergencyCount, // экстренные (поступившие + уже лечащиеся) 'percentDead' => $percentDead, 'beds' => $beds->value ]; } /** * Получить пациентов из снапшотов */ public function getPatientsFromSnapshots( Department $department, string $status, DateRange $dateRange, int $branchId, bool $onlyIds = false ) { $reports = $this->getReportsForDateRange( $department->department_id, $dateRange ); $reportIds = $reports->pluck('report_id')->toArray(); $patientTypeMap = [ 'plan' => 'plan', 'emergency' => 'emergency', 'outcome-discharged' => 'discharged', 'outcome-transferred' => 'transferred', 'outcome-deceased' => 'deceased', 'observation' => 'observation' ]; $patientType = $patientTypeMap[$status] ?? null; if ($patientType === 'observation') { return $this->patientQueryService->getObservationPatients($department->department_id, $onlyIds); //$this->getObservationPatientsFromSnapshots($user->rf_department_id, $reportIds, $onlyIds); } return $this->snapshotService->getPatientsFromSnapshots($patientType, $reportIds, $branchId, $onlyIds); } /** * Получить пациентов из реплики БД */ private function getPatientsFromReplica( Department $department, User $user, string $status, DateRange $dateRange, int $branchId, bool $onlyIds = false, ?bool $isIncludeCurrent = null ) { $isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin(); // Для плановых и экстренных включаем уже лечащихся $includeCurrent = $isIncludeCurrent ?? in_array($status, ['plan', 'emergency']); return match($status) { 'plan', 'emergency' => $this->patientQueryService->getPlanOrEmergencyPatients( $status, $isHeadOrAdmin, $branchId, $dateRange, false, $onlyIds, $includeCurrent ), 'observation' => $this->patientQueryService->getObservationPatients($department->department_id, $onlyIds), 'outcome' => $this->patientQueryService->getOutcomePatients( $branchId, $dateRange, 'without-transferred', $onlyIds ), // Выписанные без перевода 'outcome-discharged' => $this->patientQueryService->getOutcomePatients( $branchId, $dateRange, 'discharged', $onlyIds ), 'outcome-transferred' => $this->patientQueryService->getOutcomePatients( $branchId, $dateRange, 'transferred', $onlyIds ), 'outcome-deceased' => $this->patientQueryService->getOutcomePatients( $branchId, $dateRange, 'deceased', $onlyIds ), 'current' => $this->patientQueryService->getAllPatientsInDepartment( $isHeadOrAdmin, $branchId, $dateRange, false, $onlyIds ), 'recipient' => $this->patientQueryService->getPlanOrEmergencyPatients( null, $isHeadOrAdmin, $branchId, $dateRange, false, $onlyIds, false // только поступившие ), default => collect() }; } /** * Получить количество пациентов из снапшотов */ private function getPatientsCountFromSnapshots(Department $department, string $status, DateRange $dateRange): int { $reports = $this->getReportsForDateRange( $department->department_id, $dateRange ); $reportIds = $reports->pluck('report_id')->toArray(); if ($status === 'outcome') { return MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds) ->whereIn('patient_type', ['discharged', 'deceased']) ->distinct('rf_medicalhistory_id') ->count('rf_medicalhistory_id'); } $patientTypeMap = [ 'plan' => 'plan', 'emergency' => 'emergency', 'observation' => 'observation', 'outcome-discharged' => 'discharged', 'outcome-transferred' => 'transferred', 'outcome-deceased' => 'deceased' ]; $patientType = $patientTypeMap[$status] ?? null; if (!$patientType) { return 0; } if ($patientType === 'observation') { return ObservationPatient::whereIn('rf_report_id', $reportIds) ->distinct('rf_medicalhistory_id') ->count('rf_medicalhistory_id'); } return MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds) ->where('patient_type', $patientType) ->distinct('rf_medicalhistory_id') ->count('rf_medicalhistory_id'); } /** * Получить количество пациентов из реплики БД */ private function getPatientsCountFromReplica( Department $department, User $user, string $status, DateRange $dateRange, int $branchId ): int { $isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin(); return match($status) { 'plan', 'emergency' => $this->patientQueryService->getPatientsCountWithCurrent( $status, $isHeadOrAdmin, $branchId, $dateRange, ), 'observation' => ObservationPatient::where('rf_department_id', $department->department_id)->count(), 'outcome' => $this->patientQueryService->getOutcomePatients( $branchId, $dateRange, 'without-transferred' )->count(), 'outcome-discharged' => $this->patientQueryService->getOutcomePatients( $branchId, $dateRange, 'discharged' )->count(), 'outcome-transferred' => $this->patientQueryService->getOutcomePatients( $branchId, $dateRange, 'transferred' )->count(), 'outcome-deceased' => $this->patientQueryService->getOutcomePatients( $branchId, $dateRange, 'deceased' )->count(), default => 0 }; } /** * Получить нежелательные события за дату */ public function getUnwantedEvents(Department $department, DateRange $dateRange) { return UnwantedEvent::whereHas('report', function ($query) use ($department, $dateRange) { $query->where('rf_department_id', $department->department_id) ->whereBetween('sent_at', [$dateRange->startSql(), $dateRange->endSql()]); }) ->get() ->map(function ($item) { return [ ...$item->toArray(), 'created_at' => Carbon::parse($item->created_at)->format('Создано d.m.Y в H:i'), ]; }); } /** * Проверить активность кнопки отправки отчета */ private function isSendButtonActive(User $user, DateRange $dateRange, ?Report $reportToday, ?int $fillableUserId): bool { // Для врача: только сегодня и если отчета еще нет if (!$user->isHeadOfDepartment() && !$user->isAdmin()) { return $dateRange->isEndDateToday() && !$reportToday; } // Для заведующего/админа: если есть отчет & он заполнен текущим пользователем & диапазон дат = 1 дню if ( $reportToday && $reportToday->rf_lpudoctor_id === intval($fillableUserId) && $dateRange->isOneDay ) { return true; } return false; } /** * Получить информацию о враче */ private function getDoctorInfo(?int $doctorId, DateRange $dateRange): ?MisLpuDoctor { if (!$doctorId) { return null; } // Если дата это период, не показываем врача if (!$dateRange->isOneDay) { return null; } return MisLpuDoctor::where('LPUDoctorID', $doctorId)->first(); } /** * Получить отчеты за диапазон дат */ public function getReportsForDateRange(int $departmentId, DateRange $dateRange) { if ($dateRange->isOneDay) { return Report::where('rf_department_id', $departmentId) ->whereDate('created_at', $dateRange->endSql()) ->orderBy('created_at', 'ASC') ->get(); } return Report::where('rf_department_id', $departmentId) ->whereBetween('created_at', [$dateRange->startSql(), $dateRange->endSql()]) ->orderBy('created_at', 'ASC') ->get(); } /** * Получить количество из метрик */ private function getMetrikaResultCount(int $metrikaItemId, array $reportIds, bool $sum = true): int { $count = 0; $reports = Report::whereIn('report_id', $reportIds) ->with('metrikaResults') ->orderBy('created_at', 'DESC') ->get(); foreach ($reports as $report) { foreach ($report->metrikaResults as $metrikaResult) { if ($metrikaResult->rf_metrika_item_id === $metrikaItemId) { if ($sum) $count += intval($metrikaResult->value) ?? 0; else $count = intval($metrikaResult->value) ?? 0; } } } return $count; } /** * Рассчитать текущих пациентов из снапшотов */ private function calculateCurrentPatientsFromSnapshots(array $reportIds, int $branchId): int { // Получаем ID всех пациентов из снапшотов $allPatientIds = MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds) ->pluck('rf_medicalhistory_id') ->unique() ->toArray(); if (empty($allPatientIds)) { return 0; } // Получаем ID выбывших пациентов $outcomePatientIds = MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds) ->whereIn('patient_type', ['discharged', 'transferred', 'deceased']) ->pluck('rf_medicalhistory_id') ->unique() ->toArray(); // Текущие = все - выбывшие $currentPatientIds = array_diff($allPatientIds, $outcomePatientIds); return count($currentPatientIds); } /** * Получить пациентов под наблюдением из снапшотов */ private function getObservationPatientsFromSnapshots(int $departmentId, array $reportIds, bool $onlyIds = false) { $medicalHistoryIds = ObservationPatient::whereIn('rf_report_id', $reportIds) ->where('rf_department_id', $departmentId) ->pluck('rf_medicalhistory_id') ->unique() ->toArray(); if (empty($medicalHistoryIds)) { return collect(); } if ($onlyIds) { return collect($medicalHistoryIds); } return MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds) ->with(['observationPatient' => function($query) use ($departmentId) { $query->where('rf_department_id', $departmentId) ->select(['rf_medicalhistory_id', 'observation_patient_id', 'comment']); }]) ->orderBy('DateRecipient', 'DESC') ->get() ->map(function ($patient) { $patient->comment = $patient->observationPatient ->pluck('comment') ->filter() ->implode('; '); return $patient; }); } }