Files
onboard/app/Services/AutoReportService.php
brusnitsyn 10fb138c30 * работа над функционалом автоматического заполнения
* исправил фантомный сдвиг даты
* переделал получение ФИО врачей из отделений
* добавил возможность поиска врача
* переписал сохранение отчета
2026-02-05 17:11:43 +09:00

280 lines
9.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Services;
use App\Models\Department;
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,
bool $force = false
): int {
$createdCount = 0;
// Создаем период по дням
$period = CarbonPeriod::create($startDate, $endDate);
foreach ($period as $date) {
try {
$reportCreated = $this->createReportForDate($user, $date, $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, bool $force = false): bool
{
// Проверяем, существует ли уже отчет на эту дату
$existingReport = Report::where('rf_department_id', $user->rf_department_id)
->whereDate('created_at', $date)
->whereDate('sent_at', $date)
->first();
if ($existingReport && !$force) {
return false; // Отчет уже существует
}
// Если есть существующий отчет и force=true - удаляем его
if ($existingReport && $force) {
$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);
// Создаем отчет
DB::transaction(function () use ($user, $reportData, $date) {
$this->reportService->storeReport($reportData, $user);
});
return true;
}
/**
* Подготовить данные для отчета
*/
private function prepareReportData(User $user, DateRange $dateRange, Carbon $date): array
{
$department = $user->department;
$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($user->rf_department_id, $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
);
Log::info($this->patientQueryService->getPlanOrEmergencyPatients(
'plan',
$isHeadOrAdmin,
$branchId,
$dateRange,
false,
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_3' => $metrics['plan'] ?? 0, // плановые
'metrika_item_4' => $metrics['emergency'] ?? 0, // экстренные
'metrika_item_5' => $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_10' => $metrics['plan_surgery'] ?? 0, // плановые операции
'metrika_item_11' => $metrics['emergency_surgery'] ?? 0, // экстренные операции
'metrika_item_12' => $metrics['transferred'] ?? 0, // переведенные
'metrika_item_13' => 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);
}
}