* работа над функционалом автоматического заполнения

* исправил фантомный сдвиг даты
* переделал получение ФИО врачей из отделений
* добавил возможность поиска врача
* переписал сохранение отчета
This commit is contained in:
brusnitsyn
2026-02-05 17:11:43 +09:00
parent eab78a0291
commit 10fb138c30
22 changed files with 1192 additions and 654 deletions

View File

@@ -0,0 +1,279 @@
<?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);
}
}