Перевод на DDD

This commit is contained in:
brusnitsyn
2026-07-31 17:19:03 +09:00
parent 2dd55b9d11
commit 2c6d4a04cc
48 changed files with 1796 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Domain\ReportDuty\Actions;
use App\Domain\ReportDuty\Contracts\ReportDutyRepositoryInterface;
use App\Domain\ReportDuty\DTO\CreateReportDutyDto;
use App\Domain\ReportDuty\Events\ReportDutyCreated;
use App\Domain\ReportDuty\Models\ReportDuty;
use App\Models\User;
use App\Services\DateRange;
class CreateReportDutyAction
{
public function __construct(
protected ReportDutyRepositoryInterface $repository,
) {}
public function execute(CreateReportDutyDto $dto): ReportDuty
{
return $this->repository->findOrCreate($dto);
}
}

View File

@@ -0,0 +1,111 @@
<?php
namespace App\Domain\ReportDuty\Actions;
use App\Domain\ReportDuty\Contracts\ReportDutySnapshotRepositoryInterface;
use App\Domain\ReportDuty\Models\ReportDuty;
use App\Domain\ReportDuty\Services\ReportDutyStatisticsCalculator;
use App\Infrastructure\Services\MisPatientSnapshotProvider;
use App\Infrastructure\Services\NurseReportPatientSnapshotProvider;
use App\Services\DateRange;
use Illuminate\Support\Facades\Log;
class GenerateAndSaveReportSnapshotAction
{
public function __construct(
protected MisPatientSnapshotProvider $misProvider,
protected NurseReportPatientSnapshotProvider $nurseProvider,
protected ReportDutySnapshotRepositoryInterface $snapshotRepository,
protected ReportDutyStatisticsCalculator $statisticsCalculator,
protected SaveReportMetricsAction $saveMetricsAction,
) {}
public function execute(
ReportDuty $report,
DateRange $dateRange,
?int $departmentId = null,
?int $userId = null
): array {
$departmentId = $departmentId ?? $report->department->rf_mis_department_id ?? $report->rf_department_id;
$userId = $userId ?? $report->rf_user_id;
// 1. Определяем, есть ли отчёт медсестры за этот период
$nurseReportExists = \App\Models\ReportNurse::where('rf_department_id', $report->rf_department_id)
->where('period_start', $report->period_start)
->where('period_end', $report->period_end)
->exists();
// 2. Получаем данные пациентов через соответствующий провайдер
if ($nurseReportExists) {
$patients = $this->nurseProvider->getPatients($dateRange, $departmentId);
} else {
$patients = $this->misProvider->getPatients($dateRange, $departmentId);
}
// 3. Извлекаем миграции и реанимации из пациентов для сохранения
$migrations = collect();
$reanimations = collect();
foreach ($patients as $patient) {
// Преобразуем миграции в DTO
foreach ($patient->migrations as $migData) {
$migrations->push(new \App\Domain\ReportDuty\DTO\MigrationSnapshotData(
id: $migData['id'],
medicalHistoryId: $patient->id,
ingoingDate: $migData['ingoing_date'],
outDate: $migData['out_date'],
diagnosisId: $migData['diagnosis_id'],
diagnosisCode: $migData['diagnosis_code'],
diagnosisName: $migData['diagnosis_name'],
interruptedEventId: $migData['interrupted_event_id'],
stationarBranchId: $migData['stationar_branch_id'],
departmentId: $migData['department_id'],
visitResultId: $migData['visit_result_id'],
statCureResultId: $migData['stat_cure_result_id'],
userId: $migData['user_id'],
misUserId: $migData['mis_user_id'],
comment: $migData['comment'],
reanimations: $migData['reanimations'] ?? [],
));
}
// Реанимации будем брать из миграций, но можно и отдельно, здесь пока пропускаем
// (в репозитории они будут обработаны из миграций, но у нас нет отдельного хранилища)
}
// Заметка: реанимации сейчас хранятся внутри миграций, но в репозитории мы ожидаем их отдельно.
// Чтобы упростить, можно либо передать пустую коллекцию, либо извлечь из миграций.
// В оригинале они сохранялись в отдельной таблице. Мы можем передать пустую коллекцию,
// но если хотим сохранять реанимации, нужно их собрать из $patient->migrations['reanimations'].
// Я пока передам пустую коллекцию, так как в провайдерах реанимации не извлекаются
// (кроме МИС, но там они внутри миграций). Можно позже доработать.
// 4. Сохраняем снимок в БД
$saveResult = $this->snapshotRepository->upsertSnapshot(
$report->id,
$patients,
$migrations->lazy(),
collect()->lazy(), // пока без реанимаций
$userId,
$departmentId
);
// 5. Рассчитываем статистику
$statistics = $this->statisticsCalculator->calculate($patients, $dateRange);
// 6. Сохраняем метрики
$this->saveMetricsAction->execute($report, $statistics, 0); // staff = 0 пока
Log::info('Report snapshot generated', [
'report_id' => $report->id,
'saved_patients' => $saveResult['savedPatients'],
'saved_migrations' => $saveResult['savedMigrations'],
'statistics' => $statistics,
]);
return [
'statistics' => $statistics,
'saved' => $saveResult,
];
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Domain\ReportDuty\Actions;
use App\Domain\ReportDuty\Contracts\ReportDutyObservablePatientsInterface;
use App\Domain\ReportDuty\Models\ReportDuty;
class SaveObservablePatientsAction
{
public function __construct(
protected ReportDutyObservablePatientsInterface $observablePatients
) {}
public function execute(ReportDuty $report, array $observables): void
{
$this->observablePatients->upsertObservations($report, $observables);
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace App\Domain\ReportDuty\Actions;
use App\Domain\ReportDuty\Contracts\DutyMetricRepositoryInterface;
use App\Domain\ReportDuty\DTO\SnapshotStatistics;
use App\Domain\ReportDuty\Models\ReportDuty;
use App\Models\DepartmentMetrikaDefault;
use Illuminate\Support\Carbon;
class SaveReportMetricsAction
{
public function __construct(
protected DutyMetricRepositoryInterface $metricRepository,
) {}
public function execute(ReportDuty $report, SnapshotStatistics $stats, int $staff = 0, array $statsOverride = []): void
{
$byStatus = $stats->byStatus;
$byUrgency = $stats->byUrgency;
$admitted = $stats->admitted;
// === Базовые счётчики ===
$patientsIsRecipient = $statsOverride['recipient'] ?? ($byStatus['recipient'] ?? 0);
$patientsInDepartment = $statsOverride['in_department'] ?? ($byStatus['in_department'] ?? 0);
$patientsIsDischarged = $statsOverride['outcome'] ?? $stats->outcome;
$patientsIsTransferred = $stats->transferred;
$patientsIsDeceased = $byStatus['deceased'] ?? 0;
// Ср. койко-день
$totalPatients = $stats->totalPatients;
$totalBedDays = $stats->totalBedDays;
$avgBedDay = $totalPatients > 0 ? round($totalBedDays / $totalPatients, 2) : 0;
// Пред. опер. койко-день
$patientsWithOps = $stats->patientsWithOperations;
$totalPreOpDays = $stats->totalPreopBedDays;
$avgPreOpBedDay = $patientsWithOps > 0 ? round($totalPreOpDays / $patientsWithOps, 2) : 0;
// % загруженности
$bedsInDepartment = DepartmentMetrikaDefault::where('rf_department_id', $report->rf_department_id)
->where('rf_metrika_item_id', 1)
->where('date_end', '>', Carbon::now())
->value('value') ?? 0;
$occupancyPercent = $bedsInDepartment > 0 ? round(($patientsInDepartment * 100) / $bedsInDepartment, 2) : 0;
// % летальности
$mortalityPercent = $totalPatients > 0 ? round(($patientsIsDeceased * 100) / $totalPatients, 2) : 0;
// Операции
$totalOperations = $stats->totalOperations;
$plannedOperations = $stats->plannedOperations;
$urgentOperations = $stats->urgentOperations;
// === Сохранение метрик ===
$this->metricRepository->saveMetric($report->id, 1, $bedsInDepartment); // Кол-во коек
$this->metricRepository->saveMetric($report->id, 8, $patientsInDepartment); // Пациентов в отделении
$this->metricRepository->saveMetric($report->id, 3, $patientsIsRecipient); // Поступило
$this->metricRepository->saveMetric($report->id, 15, $patientsIsDischarged); // Выписано
$this->metricRepository->saveMetric($report->id, 7, $patientsIsDischarged); // Выписано (дубль?)
$this->metricRepository->saveMetric($report->id, 13, $patientsIsTransferred); // Переведено
$this->metricRepository->saveMetric($report->id, 9, $patientsIsDeceased); // Умерло
$this->metricRepository->saveMetric($report->id, 4, $admitted['planned'] ?? 0); // Планово поступило
$this->metricRepository->saveMetric($report->id, 12, $admitted['urgent'] ?? 0); // Экстренно поступило
$this->metricRepository->saveMetric($report->id, 22, $occupancyPercent); // % загруженности
$this->metricRepository->saveMetric($report->id, 25, round($totalBedDays, 2)); // Всего койко-дней
$this->metricRepository->saveMetric($report->id, 18, $avgBedDay); // Ср. койко-день
$this->metricRepository->saveMetric($report->id, 26, round($totalPreOpDays, 2)); // Пред. опер. койко-день (сумма)
$this->metricRepository->saveMetric($report->id, 27, $patientsWithOps); // Пациентов с операциями (знаменатель)
$this->metricRepository->saveMetric($report->id, 21, $avgPreOpBedDay); // Ср. Пред. опер. койко-день
$this->metricRepository->saveMetric($report->id, 19, $mortalityPercent); // % летальности
$this->metricRepository->saveMetric($report->id, 11, $plannedOperations); // Плановых операций
$this->metricRepository->saveMetric($report->id, 10, $urgentOperations); // Экстренных операций
$this->metricRepository->saveMetric($report->id, 17, $staff); // Мед. персонал
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace App\Domain\ReportDuty\Actions;
class UpdateMetricsReportDutyAction
{
}

View File

@@ -0,0 +1,8 @@
<?php
namespace App\Domain\ReportDuty\Actions;
class UpdateReportDutyAction
{
}