Перевод на DDD
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\ReportDuty\Services;
|
||||
|
||||
use App\Domain\ReportDuty\DTO\PatientSnapshotData;
|
||||
use App\Domain\ReportDuty\DTO\SnapshotStatistics;
|
||||
use App\Services\DateRange;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\LazyCollection;
|
||||
|
||||
class ReportDutyStatisticsCalculator
|
||||
{
|
||||
public function calculate(LazyCollection $patients, DateRange $dateRange): SnapshotStatistics
|
||||
{
|
||||
$stats = new SnapshotStatistics();
|
||||
|
||||
$periodStart = $dateRange->start();
|
||||
$periodEnd = $dateRange->end();
|
||||
$periodStartCarbon = Carbon::parse($periodStart);
|
||||
$periodEndCarbon = Carbon::parse($periodEnd);
|
||||
|
||||
$uniqueOperationIds = [];
|
||||
|
||||
// Используем LazyCollection, чтобы не загружать всё в память
|
||||
foreach ($patients as $patient) {
|
||||
/** @var PatientSnapshotData $patient */
|
||||
|
||||
// ===== СТАТУСЫ =====
|
||||
// Используем уже вычисленные поля (patientStatus, periodFlags и т.д.)
|
||||
// Но для расчёта койко-дней и операций нам нужны миграции и операции внутри периода.
|
||||
// Также мы можем переиспользовать логику, которая была в saveReportSnapshot.
|
||||
// Но мы перенесём сюда всю обработку, потому что здесь мы вычисляем статистики на основе сырых данных.
|
||||
|
||||
$hasRecipientInPeriod = false;
|
||||
$hasTransferInPeriod = false;
|
||||
$hasDischargeInPeriod = false;
|
||||
$hasDeathInPeriod = false;
|
||||
$hasActiveMigrationInPeriod = false;
|
||||
$hasExtractInPeriod = false;
|
||||
|
||||
// Проверяем extract_date из карты
|
||||
if ($patient->extractDate) {
|
||||
$extractDate = Carbon::parse($patient->extractDate);
|
||||
if ($extractDate >= $periodStartCarbon && $extractDate <= $periodEndCarbon) {
|
||||
$hasExtractInPeriod = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Идём по миграциям пациента (в массиве migrations)
|
||||
$migrations = $patient->migrations; // массив, но можно преобразовать в коллекцию
|
||||
$migrationOutDate = null;
|
||||
$migrationVisitResultId = null;
|
||||
|
||||
foreach ($migrations as $migration) {
|
||||
$ingoingDate = isset($migration['ingoing_date']) ? Carbon::parse($migration['ingoing_date']) : null;
|
||||
$outDate = isset($migration['out_date']) ? Carbon::parse($migration['out_date']) : null;
|
||||
$visitResultId = $migration['visit_result_id'] ?? null;
|
||||
$statCureResultId = $migration['stat_cure_result_id'] ?? null;
|
||||
|
||||
// Поступление в периоде
|
||||
if ($ingoingDate && $ingoingDate >= $periodStartCarbon && $ingoingDate <= $periodEndCarbon) {
|
||||
$hasRecipientInPeriod = true;
|
||||
}
|
||||
|
||||
// Активная миграция на конец периода
|
||||
if ($ingoingDate && $ingoingDate <= $periodEndCarbon) {
|
||||
if (!$outDate || $outDate > $periodEndCarbon) {
|
||||
$hasActiveMigrationInPeriod = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Выбытие в периоде (есть out_date в периоде)
|
||||
if ($outDate && $outDate >= $periodStartCarbon && $outDate <= $periodEndCarbon) {
|
||||
$migrationOutDate = $outDate;
|
||||
$migrationVisitResultId = $visitResultId;
|
||||
if (in_array($visitResultId, [5, 15])) {
|
||||
$hasDeathInPeriod = true;
|
||||
} elseif (in_array($visitResultId, [4, 14])) {
|
||||
$hasTransferInPeriod = true;
|
||||
} else {
|
||||
$hasDischargeInPeriod = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Если нет исхода по миграциям, проверяем extract_date и death_date
|
||||
if (!$hasDeathInPeriod && !$hasTransferInPeriod && !$hasDischargeInPeriod) {
|
||||
if ($hasExtractInPeriod) {
|
||||
$visitResultId = $patient->visitResultId;
|
||||
$deathDate = $patient->deathDate ? Carbon::parse($patient->deathDate) : null;
|
||||
if ($deathDate && $deathDate <= $periodEndCarbon) {
|
||||
$hasDeathInPeriod = true;
|
||||
} elseif (in_array($visitResultId, [4, 14])) {
|
||||
$hasTransferInPeriod = true;
|
||||
} else {
|
||||
$hasDischargeInPeriod = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Заполнение статистики по статусам
|
||||
if ($hasDeathInPeriod) {
|
||||
$stats->deceased++;
|
||||
$stats->byStatus['deceased'] = ($stats->byStatus['deceased'] ?? 0) + 1;
|
||||
} elseif ($hasTransferInPeriod) {
|
||||
$stats->transferred++;
|
||||
$stats->byStatus['transferred'] = ($stats->byStatus['transferred'] ?? 0) + 1;
|
||||
} elseif ($hasDischargeInPeriod) {
|
||||
$stats->discharged++;
|
||||
$stats->outcome++;
|
||||
$stats->byStatus['discharged'] = ($stats->byStatus['discharged'] ?? 0) + 1;
|
||||
} elseif ($hasActiveMigrationInPeriod) {
|
||||
$stats->inDepartment++;
|
||||
$stats->byStatus['in_department'] = ($stats->byStatus['in_department'] ?? 0) + 1;
|
||||
}
|
||||
|
||||
// Поступление (recipient)
|
||||
if ($hasRecipientInPeriod) {
|
||||
$stats->admitted['today']++;
|
||||
$stats->byStatus['recipient'] = ($stats->byStatus['recipient'] ?? 0) + 1;
|
||||
if ($patient->urgencyId == 1) {
|
||||
$stats->admitted['planned']++;
|
||||
$stats->planned++;
|
||||
}
|
||||
if ($patient->urgencyId == 2) {
|
||||
$stats->admitted['urgent']++;
|
||||
}
|
||||
}
|
||||
|
||||
// Срочность (из patientUrgency, но можно из urgencyId)
|
||||
if ($patient->patientUrgency) {
|
||||
$stats->byUrgency[$patient->patientUrgency] = ($stats->byUrgency[$patient->patientUrgency] ?? 0) + 1;
|
||||
}
|
||||
|
||||
// Реанимация
|
||||
if ($patient->inReanimation) {
|
||||
$stats->inReanimation++;
|
||||
}
|
||||
|
||||
// Поступил сегодня (admittedToday)
|
||||
if ($patient->admittedToday) {
|
||||
$stats->admittedToday++;
|
||||
}
|
||||
|
||||
// ===== КОЙКО-ДНИ И ОПЕРАЦИИ =====
|
||||
// Нужно взять первую миграцию (актуальную) для расчёта койко-дней
|
||||
// берём первую миграцию из массива (индекс 0)
|
||||
if (!empty($migrations)) {
|
||||
$firstMigration = $migrations[0];
|
||||
$migrationStart = isset($firstMigration['ingoing_date']) ? Carbon::parse($firstMigration['ingoing_date']) : null;
|
||||
$migrationEnd = isset($firstMigration['out_date']) ? Carbon::parse($firstMigration['out_date']) : null;
|
||||
|
||||
if ($migrationStart) {
|
||||
// Проверяем пересечение с отчетным периодом
|
||||
$hasIntersection = $migrationStart <= $periodEndCarbon &&
|
||||
($migrationEnd === null || $migrationEnd >= $periodStartCarbon);
|
||||
if ($hasIntersection) {
|
||||
$calcStart = $migrationStart > $periodStartCarbon ? $migrationStart : $periodStartCarbon;
|
||||
$calcEnd = $migrationEnd && $migrationEnd < $periodEndCarbon ? $migrationEnd : $periodEndCarbon;
|
||||
|
||||
$bedDays = $calcStart->diffInDays($calcEnd);
|
||||
$stats->totalBedDays += max(0, $bedDays);
|
||||
|
||||
// Предоперационные дни: операции в периоде
|
||||
$opsInPeriod = collect($patient->operations ?? [])
|
||||
->filter(function ($op) use ($periodStartCarbon, $periodEndCarbon) {
|
||||
$opStart = isset($op['start_date']) ? Carbon::parse($op['start_date']) : null;
|
||||
return $opStart && $opStart >= $periodStartCarbon && $opStart < $periodEndCarbon;
|
||||
});
|
||||
|
||||
if ($opsInPeriod->isNotEmpty()) {
|
||||
$stats->patientsWithOperations++;
|
||||
$firstOpInPeriod = $opsInPeriod->sortBy('start_date')->first();
|
||||
if ($firstOpInPeriod && isset($firstOpInPeriod['start_date'])) {
|
||||
$opDate = Carbon::parse($firstOpInPeriod['start_date']);
|
||||
if ($opDate > $migrationStart) {
|
||||
$preOpDays = $migrationStart->copy()->startOfDay()
|
||||
->diffInDays($opDate->copy()->startOfDay());
|
||||
$stats->totalPreopBedDays += max(0, $preOpDays);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Собираем операции для уникализации
|
||||
foreach ($patient->operations ?? [] as $operation) {
|
||||
$opStart = isset($operation['start_date']) ? Carbon::parse($operation['start_date']) : null;
|
||||
if ($opStart && $opStart >= $periodStartCarbon && $opStart < $periodEndCarbon) {
|
||||
$opId = $operation['id'] ?? null;
|
||||
if ($opId) {
|
||||
$uniqueOperationIds[$opId] = [
|
||||
'id' => $opId,
|
||||
'urgent_status' => $operation['urgent_status'] ?? null,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Увеличиваем общее количество пациентов (для среднего)
|
||||
$stats->totalPatients++;
|
||||
}
|
||||
|
||||
// После цикла заполняем итоговые показатели по операциям
|
||||
$stats->totalOperations = count($uniqueOperationIds);
|
||||
$stats->plannedOperations = collect($uniqueOperationIds)->where('urgent_status', 6)->count();
|
||||
$stats->urgentOperations = collect($uniqueOperationIds)->whereIn('urgent_status', [4,5])->count();
|
||||
|
||||
return $stats;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user