Files
onboard/app/Services/ReportService.php
brusnitsyn 52a80ccd3b nothing
2026-02-20 17:28:16 +09:00

976 lines
36 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Services;
use App\Models\Department;
use App\Models\MedicalHistorySnapshot;
use App\Models\MetrikaResult;
use App\Models\MisLpuDoctor;
use App\Models\MisMigrationPatient;
use App\Models\MisMedicalHistory;
use App\Models\MisStationarBranch;
use App\Models\ObservationPatient;
use App\Models\Report;
use App\Models\UnwantedEvent;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
class ReportService
{
public function __construct(
protected DateRangeService $dateRangeService,
protected PatientService $patientQueryService,
protected SnapshotService $snapshotService,
protected StatisticsService $statisticsService
) {}
/**
* Получить статистику для отчета
*/
public function getReportStatistics(Department $department, User $user, DateRange $dateRange): array
{
$misDepartmentId = $department->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;
});
}
}