Перевод на доменную архитектуру

This commit is contained in:
brusnitsyn
2026-04-26 23:37:50 +09:00
parent 75ca01ffd8
commit f107ebd167
70 changed files with 4656 additions and 2070 deletions

View File

@@ -2,12 +2,11 @@
namespace App\Services;
use App\Data\UnifiedPatientData;
use App\Domain\Reports\ValueObjects\MetrikaConfig;
use App\Infrastructure\Reports\Services\SnapshotPersistenceService;
use App\Infrastructure\Reports\Sources\SnapshotPatientSource;
use App\Models\Department;
use App\Models\DepartmentPatientOperation;
use App\Models\MedicalHistorySnapshot;
use App\Models\MetrikaResult;
use App\Models\MisMedicalHistory;
use App\Models\MisStationarBranch;
use App\Models\Report;
use App\Models\User;
@@ -20,7 +19,16 @@ class SnapshotService
protected UnifiedPatientService $unifiedPatientService,
protected PatientService $patientService,
protected DateRangeService $dateRangeService,
) {}
?SnapshotPersistenceService $snapshotPersistenceService = null,
?SnapshotPatientSource $snapshotPatientSource = null,
) {
$this->snapshotPersistenceService = $snapshotPersistenceService ?? app(SnapshotPersistenceService::class);
$this->snapshotPatientSource = $snapshotPatientSource ?? app(SnapshotPatientSource::class);
}
protected SnapshotPersistenceService $snapshotPersistenceService;
protected SnapshotPatientSource $snapshotPatientSource;
/**
* Создать снапшоты пациентов для отчета
@@ -42,9 +50,7 @@ class SnapshotService
return;
}
MedicalHistorySnapshot::query()
->where('rf_report_id', $report->report_id)
->delete();
$this->snapshotPersistenceService->clearReportSnapshots($report);
$this->logSnapshotMemory('snapshots:after_delete_old', [
'report_id' => $report->report_id,
]);
@@ -69,9 +75,9 @@ class SnapshotService
'report_id' => $report->report_id,
'count' => $planPatients->count(),
]);
$this->createSnapshotsForType($report, 'plan', $planPatients);
$this->snapshotPersistenceService->createSnapshotsForType($report, 'plan', $planPatients);
$this->logSnapshotMemory('snapshots:after_plan_save', ['report_id' => $report->report_id]);
$metrics[4] = $planPatients->count();
$metrics[MetrikaConfig::PLAN] = $planPatients->count();
$this->logSnapshotMemory('snapshots:before_emergency_load', ['report_id' => $report->report_id]);
$emergencyPatients = $this->unifiedPatientService->getLivePatientsByStatus(
@@ -89,9 +95,9 @@ class SnapshotService
'report_id' => $report->report_id,
'count' => $emergencyPatients->count(),
]);
$this->createSnapshotsForType($report, 'emergency', $emergencyPatients);
$this->snapshotPersistenceService->createSnapshotsForType($report, 'emergency', $emergencyPatients);
$this->logSnapshotMemory('snapshots:after_emergency_save', ['report_id' => $report->report_id]);
$metrics[12] = $emergencyPatients->count();
$metrics[MetrikaConfig::EMERGENCY] = $emergencyPatients->count();
$this->logSnapshotMemory('snapshots:before_discharged_load', ['report_id' => $report->report_id]);
$dischargedPatients = $this->unifiedPatientService->getLivePatientsByStatus(
@@ -109,9 +115,9 @@ class SnapshotService
'report_id' => $report->report_id,
'count' => $dischargedPatients->count(),
]);
$this->createSnapshotsForType($report, 'discharged', $dischargedPatients);
$this->snapshotPersistenceService->createSnapshotsForType($report, 'discharged', $dischargedPatients);
$this->logSnapshotMemory('snapshots:after_discharged_save', ['report_id' => $report->report_id]);
$metrics[15] = $dischargedPatients->count();
$metrics[MetrikaConfig::DISCHARGED] = $dischargedPatients->count();
$this->logSnapshotMemory('snapshots:before_transferred_load', ['report_id' => $report->report_id]);
$transferredPatients = $this->unifiedPatientService->getLivePatientsByStatus(
@@ -129,9 +135,9 @@ class SnapshotService
'report_id' => $report->report_id,
'count' => $transferredPatients->count(),
]);
$this->createSnapshotsForType($report, 'transferred', $transferredPatients);
$this->snapshotPersistenceService->createSnapshotsForType($report, 'transferred', $transferredPatients);
$this->logSnapshotMemory('snapshots:after_transferred_save', ['report_id' => $report->report_id]);
$metrics[13] = $transferredPatients->count();
$metrics[MetrikaConfig::TRANSFERRED] = $transferredPatients->count();
$this->logSnapshotMemory('snapshots:before_deceased_load', ['report_id' => $report->report_id]);
$deceasedPatients = $this->unifiedPatientService->getLivePatientsByStatus(
@@ -149,7 +155,7 @@ class SnapshotService
'report_id' => $report->report_id,
'count' => $deceasedPatients->count(),
]);
$this->createSnapshotsForType($report, 'deceased', $deceasedPatients);
$this->snapshotPersistenceService->createSnapshotsForType($report, 'deceased', $deceasedPatients);
$this->logSnapshotMemory('snapshots:after_deceased_save', ['report_id' => $report->report_id]);
$this->logSnapshotMemory('snapshots:before_recipient_load', ['report_id' => $report->report_id]);
@@ -168,7 +174,7 @@ class SnapshotService
'report_id' => $report->report_id,
'count' => $recipientPatients->count(),
]);
$this->createSnapshotsForType($report, 'recipient', $recipientPatients);
$this->snapshotPersistenceService->createSnapshotsForType($report, 'recipient', $recipientPatients);
$this->logSnapshotMemory('snapshots:after_recipient_save', ['report_id' => $report->report_id]);
$this->logSnapshotMemory('snapshots:before_current_load', ['report_id' => $report->report_id]);
@@ -187,7 +193,7 @@ class SnapshotService
'report_id' => $report->report_id,
'count' => $currentPatients->count(),
]);
$this->createSnapshotsForType($report, 'current', $currentPatients);
$this->snapshotPersistenceService->createSnapshotsForType($report, 'current', $currentPatients);
$this->logSnapshotMemory('snapshots:after_current_save', ['report_id' => $report->report_id]);
$planSurgeryCount = $this->patientService->getSurgicalPatients(
@@ -203,7 +209,7 @@ class SnapshotService
true
);
$this->saveMetrics($report, $metrics);
$this->snapshotPersistenceService->saveMetrics($report, $metrics);
$this->logSnapshotMemory('snapshots:after_save_metrics', ['report_id' => $report->report_id]);
}
@@ -217,38 +223,12 @@ class SnapshotService
]);
}
/**
* Сохранить метрики в базу
*/
private function saveMetrics(Report $report, array $metrics): void
{
foreach ($metrics as $metrikaItemId => $value) {
MetrikaResult::updateOrCreate(
[
'rf_report_id' => $report->report_id,
'rf_metrika_item_id' => $metrikaItemId,
],
[
'value' => $value,
]
);
}
}
/**
* Получить статистику из снапшотов
*/
public function getStatisticsFromSnapshots(array $reportIds): array
{
return [
'plan' => $this->getCountFromSnapshots('plan', $reportIds),
'emergency' => $this->getCountFromSnapshots('emergency', $reportIds),
'outcome' => $this->getCountFromSnapshots('outcome', $reportIds),
'deceased' => $this->getCountFromSnapshots('deceased', $reportIds),
'discharged' => $this->getCountFromSnapshots('discharged', $reportIds),
'transferred' => $this->getCountFromSnapshots('transferred', $reportIds),
'recipient' => $this->getCountFromSnapshots('recipient', $reportIds),
];
return $this->snapshotPatientSource->getStatisticsFromSnapshots($reportIds);
}
/**
@@ -262,62 +242,13 @@ class SnapshotService
bool $markRecipients = false,
?array $recipientReportIds = null
): Collection {
$snapshots = MedicalHistorySnapshot::query()
->whereIn('rf_report_id', $reportIds)
->where('patient_type', $type)
->get()
->unique(fn (MedicalHistorySnapshot $snapshot) => $snapshot->patient_uid ?: ($snapshot->rf_medicalhistory_id ? "mis:{$snapshot->rf_medicalhistory_id}" : "snapshot:{$snapshot->medical_history_snapshot_id}"))
->values();
if ($snapshots->isEmpty()) {
return collect();
}
$recipientIds = [];
if ($markRecipients) {
$recipientReportIds ??= $reportIds;
$recipientIds = MedicalHistorySnapshot::query()
->whereIn('rf_report_id', $recipientReportIds)
->where('patient_type', 'recipient')
->get()
->map(fn (MedicalHistorySnapshot $snapshot) => UnifiedPatientData::fromSnapshot($snapshot)->id)
->unique()
->values()
->all();
}
$operationsByHistoryId = $this->getOperationsByMedicalHistoryId($snapshots);
$operationsByDepartmentPatientId = $this->getOperationsByDepartmentPatientId($snapshots);
$patients = $snapshots->map(function (MedicalHistorySnapshot $snapshot) use ($recipientIds, $operationsByHistoryId, $operationsByDepartmentPatientId) {
$patientId = $snapshot->rf_department_patient_id
? "manual:{$snapshot->rf_department_patient_id}"
: ($snapshot->patient_uid ?: "mis:{$snapshot->rf_medicalhistory_id}");
$misOperations = $snapshot->rf_medicalhistory_id
? ($operationsByHistoryId[$snapshot->rf_medicalhistory_id] ?? [])
: [];
$manualOperations = $snapshot->rf_department_patient_id
? ($operationsByDepartmentPatientId[$snapshot->rf_department_patient_id] ?? [])
: [];
$operations = collect($misOperations)
->merge($manualOperations)
->unique(fn (array $operation) => ($operation['code'] ?? '').'|'.($operation['name'] ?? ''))
->values()
->all();
return UnifiedPatientData::fromSnapshot(
$snapshot,
in_array($patientId, $recipientIds, true),
$operations
);
})->sortByDesc(fn (UnifiedPatientData $patient) => $patient->admittedAt ?? '')->values();
if ($onlyIds) {
return $patients->pluck('id');
}
return $patients;
return $this->snapshotPatientSource->getPatientsFromSnapshots(
$type,
$reportIds,
$onlyIds,
$markRecipients,
$recipientReportIds
);
}
public function getPatientsFromOneDayCurrentSnapshots(
@@ -326,112 +257,12 @@ class SnapshotService
bool $onlyIds = false,
?array $recipientReportIds = null
): Collection {
$snapshots = MedicalHistorySnapshot::query()
->whereIn('rf_report_id', $reportIds)
->where('patient_type', 'current')
->get();
if ($snapshots->isEmpty()) {
return $this->getPatientsFromSnapshots(
$type,
$reportIds,
null,
$onlyIds,
true,
$recipientReportIds
);
}
$recipientReportIds ??= $reportIds;
$recipientIds = MedicalHistorySnapshot::query()
->whereIn('rf_report_id', $recipientReportIds)
->where('patient_type', 'recipient')
->get()
->map(fn (MedicalHistorySnapshot $snapshot) => UnifiedPatientData::fromSnapshot($snapshot)->id)
->unique()
->values()
->all();
$operationsByHistoryId = $this->getOperationsByMedicalHistoryId($snapshots);
$operationsByDepartmentPatientId = $this->getOperationsByDepartmentPatientId($snapshots);
$patients = $snapshots
->filter(fn (MedicalHistorySnapshot $snapshot) => $snapshot->patient_kind === $type)
->unique(fn (MedicalHistorySnapshot $snapshot) => $snapshot->patient_uid ?: ($snapshot->rf_medicalhistory_id ? "mis:{$snapshot->rf_medicalhistory_id}" : "snapshot:{$snapshot->medical_history_snapshot_id}"))
->map(function (MedicalHistorySnapshot $snapshot) use ($recipientIds, $operationsByHistoryId, $operationsByDepartmentPatientId) {
$misOperations = $snapshot->rf_medicalhistory_id
? ($operationsByHistoryId[$snapshot->rf_medicalhistory_id] ?? [])
: [];
$manualOperations = $snapshot->rf_department_patient_id
? ($operationsByDepartmentPatientId[$snapshot->rf_department_patient_id] ?? [])
: [];
$operations = collect($misOperations)
->merge($manualOperations)
->unique(fn (array $operation) => ($operation['code'] ?? '').'|'.($operation['name'] ?? ''))
->values()
->all();
$patient = UnifiedPatientData::fromSnapshot(
$snapshot,
false,
$operations
);
$patient->isRecipientToday = in_array($patient->id, $recipientIds, true);
return $patient;
})
->sortByDesc(fn (UnifiedPatientData $patient) => $patient->admittedAt ?? '')
->values();
if ($onlyIds) {
return $patients->pluck('id');
}
return $patients;
}
/**
* Получить количество пациентов из снапшотов
*/
private function getCountFromSnapshots(string $type, array $reportIds): int
{
$query = MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds);
if ($type === 'outcome') {
$query->whereIn('patient_type', ['discharged', 'deceased']);
} else {
$query->where('patient_type', $type);
}
return $query->get()
->map(fn (MedicalHistorySnapshot $snapshot) => $snapshot->patient_uid ?: ($snapshot->rf_medicalhistory_id ? "mis:{$snapshot->rf_medicalhistory_id}" : "snapshot:{$snapshot->medical_history_snapshot_id}"))
->unique()
->count();
}
/**
* Создать снапшоты для определенного типа пациентов
*/
private function createSnapshotsForType(Report $report, string $type, Collection $patients): void
{
foreach ($patients as $patient) {
if (! $patient instanceof UnifiedPatientData) {
continue;
}
MedicalHistorySnapshot::updateOrCreate(
[
'rf_report_id' => $report->report_id,
'patient_uid' => $patient->patientUid,
'patient_type' => $type,
],
[
'rf_report_id' => $report->report_id,
'patient_type' => $type,
...$patient->toSnapshotPayload($type),
]
);
}
return $this->snapshotPatientSource->getPatientsFromOneDayCurrentSnapshots(
$type,
$reportIds,
$onlyIds,
$recipientReportIds
);
}
/**
@@ -453,47 +284,4 @@ class SnapshotService
Carbon::createFromTimestampMs($dates[1])->setTimezone('Asia/Yakutsk'),
];
}
private function getOperationsByMedicalHistoryId(Collection $snapshots): array
{
$historyIds = $snapshots->pluck('rf_medicalhistory_id')->filter()->unique()->values();
if ($historyIds->isEmpty()) {
return [];
}
return MisMedicalHistory::query()
->whereIn('MedicalHistoryID', $historyIds)
->with(['surgicalOperations.serviceMedical'])
->get()
->mapWithKeys(function (MisMedicalHistory $history) {
return [
$history->MedicalHistoryID => $history->surgicalOperations->map(fn ($operation) => [
'code' => $operation->serviceMedical?->ServiceMedicalCode,
'name' => $operation->serviceMedical?->ServiceMedicalName,
])->values()->all(),
];
})
->all();
}
private function getOperationsByDepartmentPatientId(Collection $snapshots): array
{
$departmentPatientIds = $snapshots->pluck('rf_department_patient_id')->filter()->unique()->values();
if ($departmentPatientIds->isEmpty()) {
return [];
}
return DepartmentPatientOperation::query()
->whereIn('rf_department_patient_id', $departmentPatientIds)
->with('serviceMedical')
->get()
->groupBy('rf_department_patient_id')
->map(fn (Collection $operations) => $operations->map(fn (DepartmentPatientOperation $operation) => [
'code' => $operation->serviceMedical?->ServiceMedicalCode ?? $operation->service_code,
'name' => $operation->serviceMedical?->ServiceMedicalName ?? $operation->service_name,
])->values()->all())
->all();
}
}