* исправил фантомный сдвиг даты * переделал получение ФИО врачей из отделений * добавил возможность поиска врача * переписал сохранение отчета
821 lines
29 KiB
PHP
821 lines
29 KiB
PHP
<?php
|
||
|
||
namespace App\Services;
|
||
|
||
use App\Models\Department;
|
||
use App\Models\MedicalHistorySnapshot;
|
||
use App\Models\MetrikaResult;
|
||
use App\Models\MisLpuDoctor;
|
||
use App\Models\MisMigrationPatient;
|
||
use App\Models\MisMedicalHistory;
|
||
use App\Models\MisStationarBranch;
|
||
use App\Models\ObservationPatient;
|
||
use App\Models\Report;
|
||
use App\Models\UnwantedEvent;
|
||
use App\Models\User;
|
||
use Carbon\Carbon;
|
||
use Illuminate\Support\Facades\Auth;
|
||
use Illuminate\Support\Facades\DB;
|
||
|
||
class ReportService
|
||
{
|
||
public function __construct(
|
||
protected DateRangeService $dateRangeService,
|
||
protected PatientService $patientQueryService,
|
||
protected SnapshotService $snapshotService
|
||
) {}
|
||
|
||
/**
|
||
* Получить статистику для отчета
|
||
*/
|
||
public function getReportStatistics(User $user, DateRange $dateRange): array
|
||
{
|
||
$department = $user->department;
|
||
$misDepartmentId = $department->rf_mis_department_id;
|
||
$branchId = $this->getBranchId($misDepartmentId);
|
||
|
||
// Определяем, используем ли мы снапшоты
|
||
$useSnapshots = $this->shouldUseSnapshots($user, $dateRange);
|
||
|
||
if ($useSnapshots) {
|
||
return $this->getStatisticsFromSnapshots($user, $dateRange, $branchId);
|
||
}
|
||
|
||
return $this->getStatisticsFromReplica($user, $dateRange, $branchId);
|
||
}
|
||
|
||
/**
|
||
* Создать или обновить отчет
|
||
*/
|
||
public function storeReport(array $data, User $user, $fillableAuto = false): Report
|
||
{
|
||
DB::beginTransaction();
|
||
|
||
try {
|
||
$report = $this->createOrUpdateReport($data, $user);
|
||
|
||
$this->saveMetrics($report, $data['metrics'] ?? []);
|
||
$this->saveUnwantedEvents($report, $data['unwantedEvents'] ?? []);
|
||
$this->saveObservationPatients($report, $data['observationPatients'] ?? [], $user->rf_department_id);
|
||
|
||
// Сохраняем снапшоты пациентов
|
||
$this->snapshotService->createPatientSnapshots($report, $user, $data['dates'], $fillableAuto);
|
||
|
||
DB::commit();
|
||
return $report;
|
||
} catch (\Exception $e) {
|
||
DB::rollBack();
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Получить пациентов по статусу
|
||
*/
|
||
public function getPatientsByStatus(
|
||
User $user,
|
||
string $status,
|
||
DateRange $dateRange,
|
||
bool $onlyIds = false,
|
||
bool $beforeCreate = false,
|
||
?bool $includeCurrentPatients = null
|
||
) {
|
||
$branchId = $this->getBranchId($user->department->rf_mis_department_id);
|
||
|
||
$useSnapshots = $this->shouldUseSnapshots($user, $dateRange, $beforeCreate);
|
||
|
||
if ($useSnapshots) {
|
||
return $this->getPatientsFromSnapshots($user, $status, $dateRange, $branchId);
|
||
}
|
||
|
||
return $this->getPatientsFromReplica($user, $status, $dateRange, $branchId, $onlyIds, $includeCurrentPatients);
|
||
}
|
||
|
||
/**
|
||
* Получить количество пациентов по статусу
|
||
*/
|
||
public function getPatientsCountByStatus(
|
||
User $user,
|
||
string $status,
|
||
DateRange $dateRange
|
||
): int {
|
||
$branchId = $this->getBranchId($user->department->rf_mis_department_id);
|
||
|
||
$useSnapshots = $this->shouldUseSnapshots($user, $dateRange);
|
||
|
||
if ($useSnapshots) {
|
||
return $this->getPatientsCountFromSnapshots($user, $status, $dateRange);
|
||
}
|
||
|
||
return $this->getPatientsCountFromReplica($user, $status, $dateRange, $branchId);
|
||
}
|
||
|
||
/**
|
||
* Получить ID отделения из стационарного отделения
|
||
*/
|
||
private function getBranchId(int $misDepartmentId): ?int
|
||
{
|
||
return MisStationarBranch::where('rf_DepartmentID', $misDepartmentId)
|
||
->value('StationarBranchID');
|
||
}
|
||
|
||
/**
|
||
* Определить, нужно ли использовать снапшоты
|
||
*/
|
||
private function shouldUseSnapshots(User $user, DateRange $dateRange, bool $beforeCreate = false): bool
|
||
{
|
||
if (($user->isAdmin() || $user->isHeadOfDepartment()) && !$beforeCreate) {
|
||
return true;
|
||
}
|
||
|
||
// Проверяем, есть ли отчет на сегодня
|
||
$reportToday = Report::whereDate('sent_at', $dateRange->end())
|
||
->whereDate('created_at', $dateRange->end())
|
||
->first();
|
||
|
||
return !$dateRange->isEndDateToday() || $reportToday;
|
||
}
|
||
|
||
/**
|
||
* Создать или обновить отчет
|
||
*/
|
||
private function createOrUpdateReport(array $data, User $user): Report
|
||
{
|
||
$reportData = [
|
||
'rf_department_id' => $data['departmentId'],
|
||
'rf_user_id' => $user->id,
|
||
'rf_lpudoctor_id' => $data['userId'],
|
||
'sent_at' => $data['sent_at'] ?? $this->dateRangeService->toSqlFormat(\Illuminate\Support\Carbon::now()),
|
||
'created_at' => $data['created_at'] ?? $this->dateRangeService->toSqlFormat(\Illuminate\Support\Carbon::now()),
|
||
];
|
||
|
||
if (isset($data['reportId']) && $data['reportId']) {
|
||
$report = Report::updateOrCreate(
|
||
['report_id' => $data['reportId']],
|
||
$reportData
|
||
);
|
||
} else {
|
||
$report = Report::create($reportData);
|
||
$department = Department::where('department_id', $reportData['rf_department_id'])->first();
|
||
$beds = $department->metrikaDefault->where('rf_metrika_item_id', 1)->first();
|
||
MetrikaResult::create([
|
||
'rf_report_id' => $report->report_id,
|
||
'rf_metrika_item_id' => 1,
|
||
'value' => $beds->value
|
||
]);
|
||
}
|
||
|
||
return $report;
|
||
}
|
||
|
||
/**
|
||
* Сохранить метрики отчета
|
||
*/
|
||
private function saveMetrics(Report $report, array $metrics): void
|
||
{
|
||
foreach ($metrics as $key => $value) {
|
||
$metrikaId = (int)str_replace('metrika_item_', '', $key);
|
||
|
||
MetrikaResult::updateOrCreate(
|
||
[
|
||
'rf_report_id' => $report->report_id,
|
||
'rf_metrika_item_id' => $metrikaId,
|
||
],
|
||
[
|
||
'value' => $value,
|
||
]
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Сохранить нежелательные события
|
||
*/
|
||
private function saveUnwantedEvents(Report $report, array $unwantedEvents): void
|
||
{
|
||
if (empty($unwantedEvents)) {
|
||
$report->unwantedEvents()->delete();
|
||
return;
|
||
}
|
||
|
||
foreach ($unwantedEvents as $event) {
|
||
if (isset($event['unwanted_event_id']) && $event['unwanted_event_id']) {
|
||
UnwantedEvent::updateOrCreate(
|
||
['unwanted_event_id' => $event['unwanted_event_id']],
|
||
[
|
||
'rf_report_id' => $report->report_id,
|
||
'comment' => $event['comment'] ?? '',
|
||
'title' => $event['title'] ?? '',
|
||
'is_visible' => $event['is_visible'] ?? true,
|
||
]
|
||
);
|
||
} else {
|
||
UnwantedEvent::create([
|
||
'rf_report_id' => $report->report_id,
|
||
'comment' => $event['comment'] ?? '',
|
||
'title' => $event['title'] ?? '',
|
||
'is_visible' => $event['is_visible'] ?? true,
|
||
]);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Сохранить пациентов под наблюдением
|
||
*/
|
||
private function saveObservationPatients(
|
||
Report $report,
|
||
array $observationPatients,
|
||
int $departmentId
|
||
): void {
|
||
if (empty($observationPatients)) {
|
||
ObservationPatient::where('rf_department_id', $departmentId)
|
||
->where('rf_report_id', $report->report_id)
|
||
->delete();
|
||
return;
|
||
}
|
||
|
||
foreach ($observationPatients as $patient) {
|
||
ObservationPatient::updateOrCreate(
|
||
[
|
||
'rf_medicalhistory_id' => $patient['id'],
|
||
'rf_department_id' => $departmentId,
|
||
],
|
||
[
|
||
'rf_report_id' => $report->report_id,
|
||
'rf_mkab_id' => null,
|
||
'comment' => $patient['comment'] ?? null,
|
||
]
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Получить информацию о текущем отчете
|
||
*/
|
||
public function getCurrentReportInfo(User $user, DateRange $dateRange): array
|
||
{
|
||
$department = $user->department;
|
||
$reportToday = Report::whereDate('sent_at', $dateRange->endSql())
|
||
->whereDate('created_at', $dateRange->endSql())
|
||
->first();
|
||
|
||
$isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin();
|
||
$useSnapshots = $isHeadOrAdmin || !$dateRange->isEndDateToday() || $reportToday;
|
||
|
||
// Получаем ID пользователя для заполнения отчета
|
||
if ($useSnapshots && $isHeadOrAdmin && $reportToday) {
|
||
$fillableUserId = $reportToday->rf_lpudoctor_id ?? null;
|
||
} else {
|
||
$fillableUserId = request()->query('userId', $user->rf_lpudoctor_id);
|
||
}
|
||
|
||
// Получаем нежелательные события
|
||
$unwantedEvents = $this->getUnwantedEvents($user, $dateRange);
|
||
|
||
// Определяем активность кнопки отправки
|
||
$isActiveSendButton = $this->isSendButtonActive($user, $dateRange, $reportToday, $fillableUserId);
|
||
|
||
$message = null;
|
||
if ($reportToday) {
|
||
$reportDoctor = $reportToday->lpuDoctor;
|
||
$message = "Отчет уже создан пользователем: $reportDoctor->FAM_V $reportDoctor->IM_V $reportDoctor->OT_V";
|
||
}
|
||
|
||
// Получаем информацию о враче
|
||
$lpuDoctor = $this->getDoctorInfo($fillableUserId, $dateRange);
|
||
|
||
// Проверяем, является ли диапазон одним днем
|
||
// $isRangeOneDay = $this->dateRangeService->isRangeOneDay(
|
||
// $endDate->copy()->subDay()->format('Y-m-d H:i:s'),
|
||
// $endDate->format('Y-m-d H:i:s')
|
||
// );
|
||
|
||
// Формируем даты для ответа
|
||
// $date = $isHeadOrAdmin ? [
|
||
// $endDate->copy()->subDay()->getTimestampMs(),
|
||
// $endDate->getTimestampMs()
|
||
// ] : $endDate->getTimestampMs();
|
||
$date = $isHeadOrAdmin ? [
|
||
$dateRange->startDate->getTimestampMs(),
|
||
$dateRange->endDate->getTimestampMs()
|
||
] : $dateRange->endDate->getTimestampMs();
|
||
|
||
return [
|
||
'report_id' => $reportToday?->report_id,
|
||
'unwantedEvents' => $unwantedEvents,
|
||
'isActiveSendButton' => $isActiveSendButton,
|
||
'message' => $message,
|
||
'isOneDay' => $dateRange->isOneDay,
|
||
'isHeadOrAdmin' => $isHeadOrAdmin,
|
||
'dates' => $date,
|
||
'userId' => $fillableUserId,
|
||
'userName' => $lpuDoctor ? "$lpuDoctor->FAM_V $lpuDoctor->IM_V $lpuDoctor->OT_V" : null
|
||
];
|
||
}
|
||
|
||
/**
|
||
* Удалить пациента из наблюдения
|
||
*/
|
||
public function removeObservationPatient(int $medicalHistoryId): void
|
||
{
|
||
ObservationPatient::where('rf_medicalhistory_id', $medicalHistoryId)->delete();
|
||
}
|
||
|
||
/**
|
||
* Получить статистику из снапшотов
|
||
*/
|
||
private function getStatisticsFromSnapshots(User $user, DateRange $dateRange, int $branchId): array
|
||
{
|
||
// Получаем отчеты за период
|
||
$reports = $this->getReportsForDateRange(
|
||
$user->rf_department_id,
|
||
$dateRange
|
||
);
|
||
|
||
$reportIds = $reports->pluck('report_id')->toArray();
|
||
|
||
// Получаем статистику из снапшотов
|
||
$snapshotStats = [
|
||
'plan' => $this->getMetrikaResultCount(4, $reportIds),
|
||
'emergency' => $this->getMetrikaResultCount(12, $reportIds),
|
||
'outcome' => $this->getMetrikaResultCount(7, $reportIds),
|
||
'deceased' => $this->getMetrikaResultCount(9, $reportIds),
|
||
'current' => $this->getMetrikaResultCount(8, $reportIds),
|
||
// 'discharged' => $this->getMetrikaResultCount('discharged', $reportIds),
|
||
'transferred' => $this->getMetrikaResultCount(13, $reportIds),
|
||
'recipient' => $this->getMetrikaResultCount(3, $reportIds),
|
||
'beds' => $this->getMetrikaResultCount(1, $reportIds)
|
||
];
|
||
|
||
// Получаем ID поступивших пациентов
|
||
$recipientIds = MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
|
||
->where('patient_type', 'recipient')
|
||
->pluck('rf_medicalhistory_id')
|
||
->unique()
|
||
->toArray();
|
||
|
||
// Получаем количество операций из метрик
|
||
$surgicalCount = [
|
||
$this->getMetrikaResultCount(10, $reportIds), // экстренные операции
|
||
$this->getMetrikaResultCount(11, $reportIds) // плановые операции
|
||
];
|
||
|
||
return [
|
||
'recipientCount' => $snapshotStats['recipient'] ?? 0,
|
||
'extractCount' => $snapshotStats['outcome'] ?? 0,
|
||
'currentCount' => $snapshotStats['current'] ?? 0,//$this->calculateCurrentPatientsFromSnapshots($reportIds, $branchId),
|
||
'deadCount' => $snapshotStats['deceased'] ?? 0,
|
||
'surgicalCount' => $surgicalCount,
|
||
'recipientIds' => $recipientIds,
|
||
'beds' => $snapshotStats['beds'] ?? 0
|
||
];
|
||
}
|
||
|
||
/**
|
||
* Получить статистику из реплики БД
|
||
*/
|
||
private function getStatisticsFromReplica(User $user, DateRange $dateRange, int $branchId): array
|
||
{
|
||
$isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin();
|
||
|
||
// Плановые: поступившие сегодня + уже лечащиеся
|
||
$planCount = $this->patientQueryService->getPatientsCountWithCurrent(
|
||
'plan',
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange
|
||
);
|
||
|
||
// Экстренные: поступившие сегодня + уже лечащиеся
|
||
$emergencyCount = $this->patientQueryService->getPatientsCountWithCurrent(
|
||
'emergency',
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange
|
||
);
|
||
|
||
// Все пациенты в отделении: поступившие + лечащиеся
|
||
$currentCount = $this->patientQueryService->getAllPatientsInDepartment(
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange,
|
||
true
|
||
);
|
||
|
||
// Поступившие сегодня (только новые поступления)
|
||
$recipientCount = $this->patientQueryService->getPlanOrEmergencyPatients(
|
||
null, // все типы
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange,
|
||
true,
|
||
false,
|
||
false // не включаем уже лечащихся
|
||
);
|
||
|
||
// Выбывшие за период
|
||
$outcomeCount = $this->patientQueryService->getOutcomePatients(
|
||
$branchId,
|
||
$dateRange,
|
||
'all'
|
||
)->count();
|
||
|
||
// Умершие за период
|
||
$deadCount = $this->patientQueryService->getOutcomePatients(
|
||
$branchId,
|
||
$dateRange,
|
||
'deceased'
|
||
)->count();
|
||
|
||
// Операции
|
||
$surgicalCount = [
|
||
$this->patientQueryService->getSurgicalPatients(
|
||
'emergency',
|
||
$branchId,
|
||
$dateRange,
|
||
true
|
||
),
|
||
$this->patientQueryService->getSurgicalPatients(
|
||
'plan',
|
||
$branchId,
|
||
$dateRange,
|
||
true
|
||
)
|
||
];
|
||
|
||
// ID поступивших сегодня (для отметки в таблице)
|
||
$recipientIds = $this->patientQueryService->getPlanOrEmergencyPatients(
|
||
null,
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange,
|
||
false,
|
||
true,
|
||
false // только поступившие сегодня
|
||
);
|
||
|
||
$misBranch = MisStationarBranch::where('StationarBranchID', $branchId)->first();
|
||
$beds = Department::where('rf_mis_department_id', $misBranch->rf_DepartmentID)
|
||
->first()->metrikaDefault->where('rf_metrika_item_id', 1)->first();
|
||
|
||
return [
|
||
'recipientCount' => $recipientCount, // только поступившие сегодня
|
||
'extractCount' => $outcomeCount,
|
||
'currentCount' => $currentCount, // все в отделении
|
||
'deadCount' => $deadCount,
|
||
'surgicalCount' => $surgicalCount,
|
||
'recipientIds' => $recipientIds, // ID поступивших сегодня
|
||
'planCount' => $planCount, // плановые (поступившие + уже лечащиеся)
|
||
'emergencyCount' => $emergencyCount, // экстренные (поступившие + уже лечащиеся)
|
||
'beds' => $beds->value
|
||
];
|
||
}
|
||
|
||
/**
|
||
* Получить пациентов из снапшотов
|
||
*/
|
||
private function getPatientsFromSnapshots(
|
||
User $user,
|
||
string $status,
|
||
DateRange $dateRange,
|
||
int $branchId,
|
||
bool $onlyIds = false
|
||
) {
|
||
$reports = $this->getReportsForDateRange(
|
||
$user->rf_department_id,
|
||
$dateRange
|
||
);
|
||
|
||
$reportIds = $reports->pluck('report_id')->toArray();
|
||
|
||
$patientTypeMap = [
|
||
'plan' => 'plan',
|
||
'emergency' => 'emergency',
|
||
'outcome-discharged' => 'discharged',
|
||
'outcome-transferred' => 'transferred',
|
||
'outcome-deceased' => 'deceased',
|
||
'observation' => 'observation'
|
||
];
|
||
|
||
$patientType = $patientTypeMap[$status] ?? null;
|
||
|
||
if ($patientType === 'observation') {
|
||
return $this->patientQueryService->getObservationPatients($user->rf_department_id, $onlyIds); //$this->getObservationPatientsFromSnapshots($user->rf_department_id, $reportIds, $onlyIds);
|
||
}
|
||
|
||
return $this->snapshotService->getPatientsFromSnapshots($patientType, $reportIds, $branchId, $onlyIds);
|
||
}
|
||
|
||
/**
|
||
* Получить пациентов из реплики БД
|
||
*/
|
||
private function getPatientsFromReplica(
|
||
User $user,
|
||
string $status,
|
||
DateRange $dateRange,
|
||
int $branchId,
|
||
bool $onlyIds = false,
|
||
?bool $isIncludeCurrent = null
|
||
) {
|
||
$isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin();
|
||
|
||
// Для плановых и экстренных включаем уже лечащихся
|
||
$includeCurrent = $isIncludeCurrent ?? in_array($status, ['plan', 'emergency']);
|
||
|
||
return match($status) {
|
||
'plan', 'emergency' => $this->patientQueryService->getPlanOrEmergencyPatients(
|
||
$status,
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange,
|
||
false,
|
||
$onlyIds,
|
||
$includeCurrent
|
||
),
|
||
'observation' => $this->patientQueryService->getObservationPatients($user->rf_department_id, $onlyIds),
|
||
'outcome' => $this->patientQueryService->getOutcomePatients(
|
||
$branchId,
|
||
$dateRange,
|
||
'without-transferred',
|
||
$onlyIds
|
||
), // Выписанные без перевода
|
||
'outcome-discharged' => $this->patientQueryService->getOutcomePatients(
|
||
$branchId,
|
||
$dateRange,
|
||
'discharged',
|
||
$onlyIds
|
||
),
|
||
'outcome-transferred' => $this->patientQueryService->getOutcomePatients(
|
||
$branchId,
|
||
$dateRange,
|
||
'transferred',
|
||
$onlyIds
|
||
),
|
||
'outcome-deceased' => $this->patientQueryService->getOutcomePatients(
|
||
$branchId,
|
||
$dateRange,
|
||
'deceased',
|
||
$onlyIds
|
||
),
|
||
'current' => $this->patientQueryService->getAllPatientsInDepartment(
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange,
|
||
false,
|
||
$onlyIds
|
||
),
|
||
'recipient' => $this->patientQueryService->getPlanOrEmergencyPatients(
|
||
null,
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange,
|
||
false,
|
||
$onlyIds,
|
||
false // только поступившие
|
||
),
|
||
default => collect()
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Получить количество пациентов из снапшотов
|
||
*/
|
||
private function getPatientsCountFromSnapshots(User $user, string $status, DateRange $dateRange): int
|
||
{
|
||
$reports = $this->getReportsForDateRange(
|
||
$user->rf_department_id,
|
||
$dateRange
|
||
);
|
||
|
||
$reportIds = $reports->pluck('report_id')->toArray();
|
||
|
||
if ($status === 'outcome') {
|
||
return MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
|
||
->whereIn('patient_type', ['discharged', 'transferred', 'deceased'])
|
||
->distinct('rf_medicalhistory_id')
|
||
->count('rf_medicalhistory_id');
|
||
}
|
||
|
||
$patientTypeMap = [
|
||
'plan' => 'plan',
|
||
'emergency' => 'emergency',
|
||
'observation' => 'observation',
|
||
'outcome-discharged' => 'discharged',
|
||
'outcome-transferred' => 'transferred',
|
||
'outcome-deceased' => 'deceased'
|
||
];
|
||
|
||
$patientType = $patientTypeMap[$status] ?? null;
|
||
|
||
if (!$patientType) {
|
||
return 0;
|
||
}
|
||
|
||
if ($patientType === 'observation') {
|
||
return ObservationPatient::whereIn('rf_report_id', $reportIds)
|
||
->distinct('rf_medicalhistory_id')
|
||
->count('rf_medicalhistory_id');
|
||
}
|
||
|
||
return MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
|
||
->where('patient_type', $patientType)
|
||
->distinct('rf_medicalhistory_id')
|
||
->count('rf_medicalhistory_id');
|
||
}
|
||
|
||
/**
|
||
* Получить количество пациентов из реплики БД
|
||
*/
|
||
private function getPatientsCountFromReplica(User $user, string $status, DateRange $dateRange, int $branchId): int
|
||
{
|
||
$isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin();
|
||
|
||
return match($status) {
|
||
'plan', 'emergency' => $this->patientQueryService->getPatientsCountWithCurrent(
|
||
$status,
|
||
$isHeadOrAdmin,
|
||
$branchId,
|
||
$dateRange,
|
||
),
|
||
'observation' => ObservationPatient::where('rf_department_id', $user->rf_department_id)->count(),
|
||
'outcome' => $this->patientQueryService->getOutcomePatients(
|
||
$branchId,
|
||
$dateRange,
|
||
'all'
|
||
)->count(),
|
||
'outcome-discharged' => $this->patientQueryService->getOutcomePatients(
|
||
$branchId,
|
||
$dateRange,
|
||
'discharged'
|
||
)->count(),
|
||
'outcome-transferred' => $this->patientQueryService->getOutcomePatients(
|
||
$branchId,
|
||
$dateRange,
|
||
'transferred'
|
||
)->count(),
|
||
'outcome-deceased' => $this->patientQueryService->getOutcomePatients(
|
||
$branchId,
|
||
$dateRange,
|
||
'deceased'
|
||
)->count(),
|
||
default => 0
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Получить нежелательные события за дату
|
||
*/
|
||
private function getUnwantedEvents(User $user, DateRange $dateRange)
|
||
{
|
||
return UnwantedEvent::whereHas('report', function ($query) use ($user, $dateRange) {
|
||
$query->where('rf_department_id', $user->rf_department_id)
|
||
->whereDate('created_at', $dateRange->endSql());
|
||
})
|
||
->get()
|
||
->map(function ($item) {
|
||
return [
|
||
...$item->toArray(),
|
||
'created_at' => Carbon::parse($item->created_at)->format('Создано d.m.Y в H:i'),
|
||
];
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Проверить активность кнопки отправки отчета
|
||
*/
|
||
private function isSendButtonActive(User $user, DateRange $dateRange, ?Report $reportToday, ?int $fillableUserId): bool
|
||
{
|
||
// Для врача: только сегодня и если отчета еще нет
|
||
if (!$user->isHeadOfDepartment() && !$user->isAdmin()) {
|
||
return $dateRange->isEndDateToday() && !$reportToday;
|
||
}
|
||
|
||
// Для заведующего/админа: если есть отчет и он заполнен текущим пользователем
|
||
if ($reportToday && $reportToday->rf_lpudoctor_id === intval($fillableUserId)) {
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Получить информацию о враче
|
||
*/
|
||
private function getDoctorInfo(?int $doctorId, DateRange $dateRange): ?MisLpuDoctor
|
||
{
|
||
if (!$doctorId) {
|
||
return null;
|
||
}
|
||
|
||
// Если дата это период, не показываем врача
|
||
if (!$dateRange->isOneDay) {
|
||
return null;
|
||
}
|
||
|
||
return MisLpuDoctor::where('LPUDoctorID', $doctorId)->first();
|
||
}
|
||
|
||
/**
|
||
* Получить отчеты за диапазон дат
|
||
*/
|
||
private function getReportsForDateRange(int $departmentId, DateRange $dateRange)
|
||
{
|
||
if ($dateRange->isOneDay) {
|
||
return Report::where('rf_department_id', $departmentId)
|
||
->whereDate('created_at', $dateRange->endSql())
|
||
->orderBy('created_at', 'ASC')
|
||
->get();
|
||
}
|
||
|
||
return Report::where('rf_department_id', $departmentId)
|
||
->whereBetween('created_at', [$dateRange->startSql(), $dateRange->endSql()])
|
||
->orderBy('created_at', 'ASC')
|
||
->get();
|
||
}
|
||
|
||
/**
|
||
* Получить количество из метрик
|
||
*/
|
||
private function getMetrikaResultCount(int $metrikaItemId, array $reportIds): int
|
||
{
|
||
$count = 0;
|
||
$reports = Report::whereIn('report_id', $reportIds)
|
||
->with('metrikaResults')
|
||
->get();
|
||
|
||
foreach ($reports as $report) {
|
||
foreach ($report->metrikaResults as $metrikaResult) {
|
||
if ($metrikaResult->rf_metrika_item_id === $metrikaItemId) {
|
||
$count += intval($metrikaResult->value) ?? 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
return $count;
|
||
}
|
||
|
||
/**
|
||
* Рассчитать текущих пациентов из снапшотов
|
||
*/
|
||
private function calculateCurrentPatientsFromSnapshots(array $reportIds, int $branchId): int
|
||
{
|
||
// Получаем ID всех пациентов из снапшотов
|
||
$allPatientIds = MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
|
||
->pluck('rf_medicalhistory_id')
|
||
->unique()
|
||
->toArray();
|
||
|
||
if (empty($allPatientIds)) {
|
||
return 0;
|
||
}
|
||
|
||
// Получаем ID выбывших пациентов
|
||
$outcomePatientIds = MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds)
|
||
->whereIn('patient_type', ['discharged', 'transferred', 'deceased'])
|
||
->pluck('rf_medicalhistory_id')
|
||
->unique()
|
||
->toArray();
|
||
|
||
// Текущие = все - выбывшие
|
||
$currentPatientIds = array_diff($allPatientIds, $outcomePatientIds);
|
||
|
||
return count($currentPatientIds);
|
||
}
|
||
|
||
/**
|
||
* Получить пациентов под наблюдением из снапшотов
|
||
*/
|
||
private function getObservationPatientsFromSnapshots(int $departmentId, array $reportIds, bool $onlyIds = false)
|
||
{
|
||
$medicalHistoryIds = ObservationPatient::whereIn('rf_report_id', $reportIds)
|
||
->where('rf_department_id', $departmentId)
|
||
->pluck('rf_medicalhistory_id')
|
||
->unique()
|
||
->toArray();
|
||
|
||
if (empty($medicalHistoryIds)) {
|
||
return collect();
|
||
}
|
||
|
||
if ($onlyIds) {
|
||
return collect($medicalHistoryIds);
|
||
}
|
||
|
||
return MisMedicalHistory::whereIn('MedicalHistoryID', $medicalHistoryIds)
|
||
->with(['observationPatient' => function($query) use ($departmentId) {
|
||
$query->where('rf_department_id', $departmentId)
|
||
->select(['rf_medicalhistory_id', 'observation_patient_id', 'comment']);
|
||
}])
|
||
->orderBy('DateRecipient', 'DESC')
|
||
->get()
|
||
->map(function ($patient) {
|
||
$patient->comment = $patient->observationPatient
|
||
->pluck('comment')
|
||
->filter()
|
||
->implode('; ');
|
||
return $patient;
|
||
});
|
||
}
|
||
}
|