$data */ public function storeReport(array $data, User $user, bool $fillableAuto = false): Report { $this->reportRuntimeService->prepareForHeavySave(); $snapshot = $this->buildSnapshot($data, $user, $fillableAuto); $report = DB::transaction(function () use ($snapshot, $user, $data, $fillableAuto) { $report = $this->reportStorageService->createOrUpdateReport($snapshot, $user); $this->reportStorageService->saveMetrics($report, $snapshot); $this->reportStorageService->saveUnwantedEvents($report, $snapshot); $this->reportStorageService->saveObservationPatients($report, $snapshot); $this->snapshotService->createPatientSnapshots( $report, $user, [ $snapshot->periodStart->getTimestamp(), $snapshot->periodEnd->getTimestamp(), ], $fillableAuto ); $this->syncCalculatedMetrics($report, $user, $data); return $report; }); DB::transaction(function () use ($report) { $this->finalizeStoredReport($report); $this->saveLethalMetricFromSnapshots($report); }); $this->reportRuntimeService->clearCacheAfterReportCreation($user, $report); return $report; } public function syncCalculatedMetrics(Report $report, User $user, array $data): void { $this->calculatedMetricsSynchronizer->sync($report, $user, $data); } public function finalizeStoredReport(Report $report): void { $this->reportMetricsFinalizer->finalize($report); } public function saveLethalMetricFromSnapshots(Report $report): void { $snapshots = MedicalHistorySnapshot::query() ->where('rf_report_id', $report->report_id) ->whereIn('patient_type', ['discharged', 'deceased']) ->with('medicalHistory') ->get(); if ($snapshots->isNotEmpty()) { return; } MetrikaResult::query()->updateOrCreate( [ 'rf_report_id' => $report->report_id, 'rf_metrika_item_id' => MetrikaConfig::AVERAGE_BED_DAYS, ], ['value' => 0] ); \Log::info("No discharged patients in report {$report->report_id}, saved 0"); } private function buildSnapshot(array $data, User $user, bool $fillableAuto): ReportSnapshot { $dateRange = $this->dateRangeService->getNormalizedDateRange( $user, (string) ($data['dates'][0] ?? null), (string) ($data['dates'][1] ?? null) ); $rangeEndAt = $dateRange->endSql(); $createdAt = $data['created_at'] ?? $rangeEndAt; $sentAt = $data['sent_at'] ?? $rangeEndAt; return new ReportSnapshot( departmentId: (int) $data['departmentId'], userId: (int) $data['userId'], actorUserId: (int) $user->id, periodStart: new DateTimeImmutable($dateRange->startSql()), periodEnd: new DateTimeImmutable($dateRange->endSql()), status: (string) ($data['status'] ?? 'draft'), autoFill: $fillableAuto, metrics: MetrikaConfig::normalizeMetrics((array) ($data['metrics'] ?? [])), observationPatients: $this->normalizeObservationPatients((array) ($data['observationPatients'] ?? [])), unwantedEvents: $this->normalizeUnwantedEvents((array) ($data['unwantedEvents'] ?? [])), reportId: isset($data['reportId']) && $data['reportId'] ? (int) $data['reportId'] : null, createdAt: new DateTimeImmutable((string) $createdAt), sentAt: new DateTimeImmutable((string) $sentAt), ); } /** * @param array> $patients * @return array> */ private function normalizeObservationPatients(array $patients): array { return array_values(array_map(static function (array $patient): array { return [ 'medical_history_id' => $patient['medical_history_id'] ?? $patient['id'] ?? null, 'department_patient_id' => $patient['department_patient_id'] ?? null, 'comment' => $patient['comment'] ?? null, ]; }, $patients)); } /** * @param array> $events * @return array> */ private function normalizeUnwantedEvents(array $events): array { return array_values(array_map(static function (array $event): array { return [ 'unwanted_event_id' => $event['unwanted_event_id'] ?? null, 'title' => $event['title'] ?? '', 'comment' => $event['comment'] ?? '', 'is_visible' => (bool) ($event['is_visible'] ?? true), ]; }, $events)); } }