214 lines
8.4 KiB
PHP
214 lines
8.4 KiB
PHP
<?php
|
|
|
|
namespace App\Infrastructure\Reports\Services;
|
|
|
|
use App\Domain\Reports\ValueObjects\MetrikaConfig;
|
|
use App\Models\Department;
|
|
use App\Models\Report;
|
|
use App\Models\User;
|
|
use App\Services\DateRange;
|
|
use App\Services\PatientService;
|
|
use App\Services\SnapshotService;
|
|
use App\Services\UnifiedPatientService;
|
|
|
|
/**
|
|
* Сервис чтения сводной статистики отчёта.
|
|
*
|
|
* Инкапсулирует выбор источника данных: submitted-снапшоты для закрытых
|
|
* отчётов или live-реплика для текущей рабочей формы.
|
|
*/
|
|
class ReportStatisticsReadService
|
|
{
|
|
public function __construct(
|
|
private readonly UnifiedPatientService $unifiedPatientService,
|
|
private readonly PatientService $patientService,
|
|
private readonly SnapshotService $snapshotService,
|
|
private readonly ReportReadContextResolver $contextResolver,
|
|
private readonly CalculatedMetricsSynchronizer $calculatedMetricsSynchronizer,
|
|
) {}
|
|
|
|
/**
|
|
* Получить статистику для шапки отчёта.
|
|
*/
|
|
public function getReportStatistics(Department $department, User $user, DateRange $dateRange): array
|
|
{
|
|
$branchId = $this->contextResolver->resolveBranchId($department);
|
|
|
|
if (! $branchId) {
|
|
return $this->emptyStatistics();
|
|
}
|
|
|
|
if ($this->contextResolver->shouldUseSnapshots($department, $dateRange)) {
|
|
return $this->getStatisticsFromSnapshots($department, $dateRange);
|
|
}
|
|
|
|
return $this->getStatisticsFromReplica($department, $user, $dateRange, $branchId);
|
|
}
|
|
|
|
/**
|
|
* Получить статистику из сохранённых снапшотов submitted-отчётов.
|
|
*/
|
|
private function getStatisticsFromSnapshots(Department $department, DateRange $dateRange): array
|
|
{
|
|
$reports = $this->contextResolver->getReportsForDateRange(
|
|
$department->department_id,
|
|
$dateRange
|
|
);
|
|
|
|
$reportIds = $reports->pluck('report_id')->all();
|
|
$lastReportId = $reportIds[0] ?? null;
|
|
$recipientReportIds = $this->contextResolver->getRecipientReportIds($reportIds);
|
|
|
|
$snapshotStats = [
|
|
'plan' => $this->getMetrikaResultCount(MetrikaConfig::PLAN, $reportIds),
|
|
'emergency' => $this->getMetrikaResultCount(MetrikaConfig::EMERGENCY, $reportIds),
|
|
'outcome' => $this->getMetrikaResultCount(MetrikaConfig::OUTCOME, $reportIds),
|
|
'deceased' => $this->getMetrikaResultCount(MetrikaConfig::DECEASED, $reportIds),
|
|
'current' => $this->getMetrikaResultCount(MetrikaConfig::CURRENT, $reportIds, false),
|
|
'transferred' => $this->getMetrikaResultCount(MetrikaConfig::TRANSFERRED, $reportIds),
|
|
'recipient' => $this->getMetrikaResultCount(MetrikaConfig::RECIPIENT, $reportIds),
|
|
'beds' => $this->getMetrikaResultCount(MetrikaConfig::BEDS, $reportIds, false),
|
|
'countStaff' => $lastReportId
|
|
? $this->getMetrikaResultCount(MetrikaConfig::STAFF_COUNT, [$lastReportId], false)
|
|
: 0,
|
|
];
|
|
|
|
$recipientIds = $this->snapshotService
|
|
->getPatientsFromSnapshots('recipient', $recipientReportIds)
|
|
->pluck('id')
|
|
->all();
|
|
|
|
$surgicalCount = [
|
|
$this->getMetrikaResultCount(MetrikaConfig::EMERGENCY_SURGERY, $reportIds),
|
|
$this->getMetrikaResultCount(MetrikaConfig::PLAN_SURGERY, $reportIds),
|
|
];
|
|
|
|
return [
|
|
'recipientCount' => $snapshotStats['recipient'] ?? 0,
|
|
'extractCount' => $snapshotStats['outcome'] ?? 0,
|
|
'currentCount' => $snapshotStats['current'] ?? 0,
|
|
'deadCount' => $snapshotStats['deceased'] ?? 0,
|
|
'countStaff' => $snapshotStats['countStaff'] ?? 0,
|
|
'surgicalCount' => $surgicalCount,
|
|
'recipientIds' => $recipientIds,
|
|
'beds' => $snapshotStats['beds'] ?? 0,
|
|
'percentDead' => $this->calculatePercentDead($snapshotStats['deceased'], $snapshotStats['outcome']),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Получить статистику из live-реплики МИС и manual-источников.
|
|
*/
|
|
private function getStatisticsFromReplica(
|
|
Department $department,
|
|
User $user,
|
|
DateRange $dateRange,
|
|
int $branchId
|
|
): array {
|
|
$planCount = $this->unifiedPatientService->getLivePatientCountByStatus($department, $user, 'plan', $dateRange, $branchId, true);
|
|
$emergencyCount = $this->unifiedPatientService->getLivePatientCountByStatus($department, $user, 'emergency', $dateRange, $branchId, true);
|
|
$currentCount = $this->unifiedPatientService->getLivePatientCountByStatus($department, $user, 'current', $dateRange, $branchId);
|
|
$recipientCount = $this->unifiedPatientService->getLivePatientCountByStatus($department, $user, 'recipient', $dateRange, $branchId);
|
|
$outcomeCount = $this->unifiedPatientService->getLivePatientCountByStatus($department, $user, 'outcome', $dateRange, $branchId);
|
|
$deadCount = $this->unifiedPatientService->getLivePatientCountByStatus($department, $user, 'outcome-deceased', $dateRange, $branchId);
|
|
|
|
$misSurgicalCount = [
|
|
$this->patientService->getSurgicalPatients('emergency', $branchId, $dateRange, true),
|
|
$this->patientService->getSurgicalPatients('plan', $branchId, $dateRange, true),
|
|
];
|
|
$manualSurgicalCount = $this->calculatedMetricsSynchronizer->getManualSurgicalCounts($department, $dateRange);
|
|
$surgicalCount = [
|
|
($misSurgicalCount[0] ?? 0) + ($manualSurgicalCount[0] ?? 0),
|
|
($misSurgicalCount[1] ?? 0) + ($manualSurgicalCount[1] ?? 0),
|
|
];
|
|
|
|
$recipientIds = $this->unifiedPatientService
|
|
->getRecipientIdsForReport($department, $user, $dateRange, $branchId);
|
|
|
|
return [
|
|
'recipientCount' => $recipientCount,
|
|
'extractCount' => $outcomeCount,
|
|
'currentCount' => $currentCount,
|
|
'deadCount' => $deadCount,
|
|
'surgicalCount' => $surgicalCount,
|
|
'recipientIds' => $recipientIds,
|
|
'planCount' => $planCount,
|
|
'emergencyCount' => $emergencyCount,
|
|
'percentDead' => $this->calculatePercentDead($deadCount, $outcomeCount),
|
|
'beds' => (int) ($department->metrikaDefault
|
|
->where('rf_metrika_item_id', MetrikaConfig::BEDS)
|
|
->first()
|
|
?->value ?? 0),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Получить агрегированное значение метрики из набора отчётов.
|
|
*
|
|
* @param array<int, int> $reportIds
|
|
*/
|
|
private function getMetrikaResultCount(int $metrikaItemId, array $reportIds, bool $sum = true): int
|
|
{
|
|
if (empty($reportIds)) {
|
|
return 0;
|
|
}
|
|
|
|
$reports = Report::query()
|
|
->whereIn('report_id', $reportIds)
|
|
->with('metrikaResults')
|
|
->orderBy('created_at', 'DESC')
|
|
->get();
|
|
|
|
if (! $sum) {
|
|
foreach ($reports as $report) {
|
|
$metric = $report->metrikaResults
|
|
->firstWhere('rf_metrika_item_id', $metrikaItemId);
|
|
|
|
if ($metric) {
|
|
return (int) $metric->value;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
$count = 0;
|
|
|
|
foreach ($reports as $report) {
|
|
foreach ($report->metrikaResults as $metrikaResult) {
|
|
if ((int) $metrikaResult->rf_metrika_item_id === $metrikaItemId) {
|
|
$count += (int) $metrikaResult->value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $count;
|
|
}
|
|
|
|
private function calculatePercentDead(int $deadCount, int $outcomeCount): float|int
|
|
{
|
|
if ($outcomeCount === 0) {
|
|
return 0;
|
|
}
|
|
|
|
return round(($deadCount / $outcomeCount) * 100, 2);
|
|
}
|
|
|
|
private function emptyStatistics(): array
|
|
{
|
|
return [
|
|
'recipientCount' => 0,
|
|
'extractCount' => 0,
|
|
'currentCount' => 0,
|
|
'deadCount' => 0,
|
|
'surgicalCount' => [0, 0],
|
|
'recipientIds' => [],
|
|
'planCount' => 0,
|
|
'emergencyCount' => 0,
|
|
'percentDead' => 0,
|
|
'beds' => 0,
|
|
'countStaff' => 0,
|
|
];
|
|
}
|
|
}
|