275 lines
9.4 KiB
PHP
275 lines
9.4 KiB
PHP
<?php
|
||
|
||
namespace App\Services;
|
||
|
||
use App\Models\Department;
|
||
use App\Models\MedicalHistorySnapshot;
|
||
use App\Models\MetrikaResult;
|
||
use App\Models\MisStationarBranch;
|
||
use App\Models\Report;
|
||
use App\Models\User;
|
||
use Carbon\Carbon;
|
||
use Carbon\CarbonPeriod;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Log;
|
||
|
||
class AutoReportService
|
||
{
|
||
public function __construct(
|
||
protected ReportService $reportService,
|
||
protected DateRangeService $dateRangeService,
|
||
protected PatientService $patientQueryService
|
||
) {}
|
||
|
||
/**
|
||
* Заполнить отчеты для пользователя за период
|
||
*/
|
||
public function fillReportsForUser(
|
||
User $user,
|
||
string $startDate,
|
||
string $endDate,
|
||
$departmentId,
|
||
bool $force = false
|
||
): int {
|
||
$createdCount = 0;
|
||
|
||
// Создаем период по дням
|
||
$period = CarbonPeriod::create($startDate, $endDate);
|
||
|
||
foreach ($period as $date) {
|
||
try {
|
||
$reportCreated = $this->createReportForDate($user, $date, $departmentId, $force);
|
||
|
||
if ($reportCreated) {
|
||
$createdCount++;
|
||
}
|
||
} catch (\Exception $e) {
|
||
Log::error("Ошибка создания отчета для {$user->id} на {$date->format('Y-m-d')}: {$e->getMessage()}");
|
||
throw $e; // или continue в зависимости от требований
|
||
}
|
||
}
|
||
|
||
return $createdCount;
|
||
}
|
||
|
||
/**
|
||
* Создать отчет для конкретной даты
|
||
*/
|
||
public function createReportForDate(User $user, Carbon $date, $departmentId, bool $force = false): bool
|
||
{
|
||
$user->rf_department_id = $departmentId;
|
||
// Проверяем, существует ли уже отчет на эту дату
|
||
$existingReport = Report::where('rf_department_id', $departmentId)
|
||
->whereDate('created_at', $date)
|
||
->whereDate('sent_at', $date)
|
||
->first();
|
||
|
||
if ($existingReport && !$force) {
|
||
return false; // Отчет уже существует
|
||
}
|
||
|
||
// Если есть существующий отчет и force=true - удаляем его
|
||
if ($existingReport && $force) {
|
||
MetrikaResult::where('rf_report_id', $existingReport->report_id)->delete();
|
||
MedicalHistorySnapshot::where('rf_report_id', $existingReport->report_id)->delete();
|
||
$existingReport->delete();
|
||
}
|
||
|
||
// Создаем DateRange для этой даты
|
||
// Приводим к Illuminate\Carbon если нужно
|
||
if (!$date instanceof \Illuminate\Support\Carbon) {
|
||
$date = \Illuminate\Support\Carbon::instance($date);
|
||
}
|
||
$dateRange = $this->dateRangeService->createDateRangeForDate($date, $user);
|
||
|
||
// Получаем данные для отчета
|
||
$reportData = $this->prepareReportData($user, $dateRange, $date, $departmentId);
|
||
|
||
// Создаем отчет
|
||
DB::transaction(function () use ($user, $reportData, $date) {
|
||
$this->reportService->storeReport($reportData, $user);
|
||
});
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Подготовить данные для отчета
|
||
*/
|
||
private function prepareReportData(User $user, DateRange $dateRange, Carbon $date, $departmentId): array
|
||
{
|
||
$department = Department::where('department_id', $departmentId)->first();
|
||
$branchId = $this->getBranchId($department->rf_mis_department_id);
|
||
$isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin();
|
||
|
||
// Получаем метрики
|
||
$metrics = $this->calculateMetrics(
|
||
$user,
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange
|
||
);
|
||
|
||
// Получаем количество коек
|
||
$beds = $this->getBedCount($department);
|
||
|
||
// Формируем данные отчета
|
||
return [
|
||
'departmentId' => $department->department_id,
|
||
'userId' => $user->rf_lpudoctor_id ?? $user->id,
|
||
'dates' => [
|
||
$dateRange->startTimestamp(),
|
||
$dateRange->endTimestamp()
|
||
],
|
||
'sent_at' => $this->dateRangeService->toSqlFormat($date),
|
||
'created_at' => $this->dateRangeService->toSqlFormat($date),
|
||
'metrics' => $this->formatMetrics($metrics),
|
||
'observationPatients' => $this->getObservationPatients($departmentId, $date),
|
||
'unwantedEvents' => [],
|
||
];
|
||
}
|
||
|
||
/**
|
||
* Рассчитать метрики для отчета
|
||
*/
|
||
private function calculateMetrics(
|
||
User $user,
|
||
bool $isHeadOrAdmin,
|
||
int $branchId,
|
||
DateRange $dateRange
|
||
): array {
|
||
$metrics = [];
|
||
|
||
// 1. Плановые пациенты
|
||
$metrics['plan'] = $this->patientQueryService->getPlanOrEmergencyPatients(
|
||
'plan',
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange,
|
||
true,
|
||
false,
|
||
true,
|
||
true
|
||
);
|
||
|
||
// 2. Экстренные пациенты
|
||
$metrics['emergency'] = $this->patientQueryService->getPlanOrEmergencyPatients(
|
||
'emergency',
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange,
|
||
true,
|
||
false,
|
||
true,
|
||
true
|
||
);
|
||
|
||
// 3. Поступившие сегодня
|
||
$metrics['recipient'] = $this->patientQueryService->getPlanOrEmergencyPatients(
|
||
null,
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange,
|
||
true,
|
||
false,
|
||
false,
|
||
true
|
||
);
|
||
|
||
// 4. Выписанные
|
||
$metrics['discharged'] = $this->patientQueryService->getOutcomePatients(
|
||
$branchId,
|
||
$dateRange,
|
||
'discharged'
|
||
)->count();
|
||
|
||
// 5. Переведенные
|
||
$metrics['transferred'] = $this->patientQueryService->getOutcomePatients(
|
||
$branchId,
|
||
$dateRange,
|
||
'transferred'
|
||
)->count();
|
||
|
||
// 6. Умершие
|
||
$metrics['deceased'] = $this->patientQueryService->getOutcomePatients(
|
||
$branchId,
|
||
$dateRange,
|
||
'deceased'
|
||
)->count();
|
||
|
||
// 7. Текущие пациенты
|
||
$metrics['current'] = $this->patientQueryService->getAllPatientsInDepartment(
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange,
|
||
true
|
||
);
|
||
|
||
// 8. Плановые операции
|
||
$metrics['plan_surgery'] = $this->patientQueryService->getSurgicalPatients(
|
||
'plan',
|
||
$branchId,
|
||
$dateRange,
|
||
true
|
||
);
|
||
|
||
// 9. Экстренные операции
|
||
$metrics['emergency_surgery'] = $this->patientQueryService->getSurgicalPatients(
|
||
'emergency',
|
||
$branchId,
|
||
$dateRange,
|
||
true
|
||
);
|
||
|
||
return $metrics;
|
||
}
|
||
|
||
/**
|
||
* Форматировать метрики для сохранения
|
||
*/
|
||
private function formatMetrics(array $metrics): array
|
||
{
|
||
return [
|
||
'metrika_item_4' => $metrics['plan'] ?? 0, // плановые
|
||
'metrika_item_12' => $metrics['emergency'] ?? 0, // экстренные
|
||
'metrika_item_3' => $metrics['recipient'] ?? 0, // поступившие
|
||
// 'metrika_item_6' => ($metrics['plan_surgery'] ?? 0) + ($metrics['emergency_surgery'] ?? 0), // всего операций
|
||
'metrika_item_7' => $metrics['discharged'] ?? 0, // выписанные
|
||
'metrika_item_8' => $metrics['current'] ?? 0, // текущие
|
||
'metrika_item_9' => $metrics['deceased'] ?? 0, // умершие
|
||
'metrika_item_11' => $metrics['plan_surgery'] ?? 0, // плановые операции
|
||
'metrika_item_10' => $metrics['emergency_surgery'] ?? 0, // экстренные операции
|
||
'metrika_item_13' => $metrics['transferred'] ?? 0, // переведенные
|
||
'metrika_item_14' => 0, // под наблюдением (будет заполнено отдельно)
|
||
];
|
||
}
|
||
|
||
/**
|
||
* Получить пациентов под наблюдением на дату
|
||
*/
|
||
private function getObservationPatients(int $departmentId, Carbon $date): array
|
||
{
|
||
// Здесь нужно реализовать логику получения пациентов под наблюдением
|
||
// на конкретную дату. Возможно, из снапшотов или истории.
|
||
return []; // временно возвращаем пустой массив
|
||
}
|
||
|
||
/**
|
||
* Получить ID отделения
|
||
*/
|
||
private function getBranchId(int $misDepartmentId): ?int
|
||
{
|
||
return MisStationarBranch::where('rf_DepartmentID', $misDepartmentId)
|
||
->value('StationarBranchID');
|
||
}
|
||
|
||
/**
|
||
* Получить количество коек
|
||
*/
|
||
private function getBedCount(Department $department): int
|
||
{
|
||
$default = $department->metrikaDefault()->where('rf_metrika_item_id', 1)->first();
|
||
return (int)($default->value ?? 0);
|
||
}
|
||
}
|