Добавил ограничение по отказникам
This commit is contained in:
@@ -31,6 +31,7 @@ class SnapshotPatientSource
|
||||
?array $recipientReportIds = null
|
||||
): Collection {
|
||||
$snapshots = MedicalHistorySnapshot::query()
|
||||
->withoutDenials()
|
||||
->whereIn('rf_report_id', $reportIds)
|
||||
->where('patient_type', $type)
|
||||
->get()
|
||||
@@ -45,6 +46,7 @@ class SnapshotPatientSource
|
||||
if ($markRecipients) {
|
||||
$recipientReportIds ??= $reportIds;
|
||||
$recipientIds = MedicalHistorySnapshot::query()
|
||||
->withoutDenials()
|
||||
->whereIn('rf_report_id', $recipientReportIds)
|
||||
->where('patient_type', 'recipient')
|
||||
->get()
|
||||
@@ -91,6 +93,7 @@ class SnapshotPatientSource
|
||||
?array $recipientReportIds = null
|
||||
): Collection {
|
||||
$snapshots = MedicalHistorySnapshot::query()
|
||||
->withoutDenials()
|
||||
->whereIn('rf_report_id', $reportIds)
|
||||
->where('patient_type', 'current')
|
||||
->get();
|
||||
@@ -107,6 +110,7 @@ class SnapshotPatientSource
|
||||
|
||||
$recipientReportIds ??= $reportIds;
|
||||
$recipientIds = MedicalHistorySnapshot::query()
|
||||
->withoutDenials()
|
||||
->whereIn('rf_report_id', $recipientReportIds)
|
||||
->where('patient_type', 'recipient')
|
||||
->get()
|
||||
@@ -151,7 +155,7 @@ class SnapshotPatientSource
|
||||
|
||||
private function getCountFromSnapshots(string $type, array $reportIds): int
|
||||
{
|
||||
$query = MedicalHistorySnapshot::whereIn('rf_report_id', $reportIds);
|
||||
$query = MedicalHistorySnapshot::withoutDenials()->whereIn('rf_report_id', $reportIds);
|
||||
|
||||
if ($type === 'outcome') {
|
||||
$query->whereIn('patient_type', ['discharged', 'deceased']);
|
||||
|
||||
@@ -53,6 +53,24 @@ class MedicalHistory extends MaterializedViewModel
|
||||
->latest('observable_in');
|
||||
}
|
||||
|
||||
public function denial()
|
||||
{
|
||||
return $this->hasOne(MisDenial::class, 'rf_MedicalHistoryID', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Исключить отказников от госпитализации.
|
||||
* Безопасно: пока таблицы отказов нет в реплике — no-op (см. MisDenial::tableAvailable()).
|
||||
*/
|
||||
public function scopeWithoutDenials($query)
|
||||
{
|
||||
if (MisDenial::tableAvailable()) {
|
||||
$query->whereDoesntHave('denial');
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function operationsInDepartment($query, $departmentId)
|
||||
{
|
||||
return $this->operations()->where('department_id', $departmentId);
|
||||
|
||||
@@ -72,4 +72,25 @@ class MedicalHistorySnapshot extends Model
|
||||
$q->department($departmentId);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Исключить из снимка карты, по которым в МИС оформлен отказ от госпитализации.
|
||||
* Снимок остаётся неизменным (immutable) — отсекаем только при чтении.
|
||||
* Безопасно: пока таблицы отказов нет в реплике — no-op (см. MisDenial::tableAvailable()).
|
||||
*/
|
||||
public function scopeWithoutDenials($query)
|
||||
{
|
||||
if (! MisDenial::tableAvailable()) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
$denialTable = (new MisDenial)->getTable();
|
||||
$snapshotTable = $this->getTable();
|
||||
|
||||
return $query->whereNotExists(function ($sub) use ($denialTable, $snapshotTable) {
|
||||
$sub->selectRaw('1')
|
||||
->from($denialTable)
|
||||
->whereColumn("{$denialTable}.rf_MedicalHistoryID", "{$snapshotTable}.rf_medicalhistory_id");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
41
app/Models/MisDenial.php
Normal file
41
app/Models/MisDenial.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Отказ от госпитализации (МИС).
|
||||
*
|
||||
* ВНИМАНИЕ: ЗАГЛУШКА. На момент написания таблицы отказов ещё нет в реплике.
|
||||
* Когда репликатор её добавит — поменять $table на реальное имя.
|
||||
* Пока таблицы нет, MisDenial::tableAvailable() === false и вся
|
||||
* фильтрация отказников превращается в no-op (отчёты не ломаются).
|
||||
*
|
||||
* Структура в МИС:
|
||||
* DenialID (PK), rf_MedicalHistoryID -> mv_medicalhistory_summary.id,
|
||||
* rf_kl_HospRefusalID, DateTime, FAM/Name/OT, rf_StationarTypeID, ...
|
||||
* Признак отказа = сам факт наличия строки с rf_MedicalHistoryID
|
||||
* (по причинам/типам не фильтруем).
|
||||
*/
|
||||
class MisDenial extends MaterializedViewModel
|
||||
{
|
||||
protected $table = 'stt_denial'; // TODO: подставить реальное имя таблицы в реплике
|
||||
protected $primaryKey = 'DenialID';
|
||||
|
||||
private static ?bool $tableExists = null;
|
||||
|
||||
public function medicalHistory()
|
||||
{
|
||||
return $this->belongsTo(MedicalHistory::class, 'rf_MedicalHistoryID', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Доступна ли таблица отказов в текущей БД (реплике).
|
||||
* Мемоизируем на процесс, чтобы не дёргать information_schema на каждый запрос.
|
||||
*/
|
||||
public static function tableAvailable(): bool
|
||||
{
|
||||
return self::$tableExists ??= Schema::hasTable((new self)->getTable());
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ class MedicalHistoryService
|
||||
|
||||
// 1. Один запрос: получаем "сырые" данные (без вычисляемых статусов)
|
||||
$all = MedicalHistory::query()
|
||||
->withoutDenials()
|
||||
->whereHas('migrations', $periodMigrationFilter)
|
||||
->when($search, function ($query, $search) {
|
||||
// Поиск по ФИО (точное совпадение или LIKE)
|
||||
@@ -143,7 +144,8 @@ class MedicalHistoryService
|
||||
{
|
||||
$query = MedicalHistory::query();
|
||||
|
||||
$query->where('recipient_date', '>=', $dateRange->startSql())
|
||||
$query->withoutDenials()
|
||||
->where('recipient_date', '>=', $dateRange->startSql())
|
||||
->where('recipient_date', '<', $dateRange->endSql())
|
||||
// 1. Оставляем только тех пациентов, у которых БЫЛО движение в этом отделении
|
||||
->whereHas('latestMigration', fn($q) => $q->where('department_id', $departmentId))
|
||||
@@ -160,7 +162,8 @@ class MedicalHistoryService
|
||||
{
|
||||
$query = MedicalHistory::query();
|
||||
|
||||
$query->where('recipient_date', '>=', $dateRange->startSql())
|
||||
$query->withoutDenials()
|
||||
->where('recipient_date', '>=', $dateRange->startSql())
|
||||
->where('recipient_date', '<', $dateRange->endSql())
|
||||
->urgency($urgencyId)
|
||||
->whereHas('migrations', function ($m) use ($departmentId) {
|
||||
@@ -179,6 +182,7 @@ class MedicalHistoryService
|
||||
public function getDepartmentHistories(DateRange $dateRange, int $departmentId)
|
||||
{
|
||||
return MedicalHistory::query()
|
||||
->withoutDenials()
|
||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||
$q->department($departmentId)->currentOrAdmitted($dateRange);
|
||||
})
|
||||
@@ -194,6 +198,7 @@ class MedicalHistoryService
|
||||
public function getPlannedHistories(DateRange $dateRange, int $departmentId)
|
||||
{
|
||||
return MedicalHistory::query()
|
||||
->withoutDenials()
|
||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||
$q->department($departmentId)->currentOrAdmitted($dateRange);
|
||||
})
|
||||
@@ -211,6 +216,7 @@ class MedicalHistoryService
|
||||
public function getEmergencyHistories(DateRange $dateRange, int $departmentId)
|
||||
{
|
||||
return MedicalHistory::query()
|
||||
->withoutDenials()
|
||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||
$q->department($departmentId)->currentOrAdmitted($dateRange);
|
||||
})
|
||||
@@ -234,6 +240,7 @@ class MedicalHistoryService
|
||||
$now = Carbon::now();
|
||||
|
||||
return MedicalHistory::query()
|
||||
->withoutDenials()
|
||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||
$q->department($departmentId)->admitted($dateRange->startSql(), $dateRange->endSql());
|
||||
})
|
||||
@@ -246,6 +253,7 @@ class MedicalHistoryService
|
||||
public function getDischargedHistories(DateRange $dateRange, int $departmentId)
|
||||
{
|
||||
return MedicalHistory::query()
|
||||
->withoutDenials()
|
||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||
$q->department($departmentId)->discharged($dateRange->startSql(), $dateRange->endSql());
|
||||
})
|
||||
@@ -258,6 +266,7 @@ class MedicalHistoryService
|
||||
public function getDeceasedHistories(DateRange $dateRange, int $departmentId)
|
||||
{
|
||||
return MedicalHistory::query()
|
||||
->withoutDenials()
|
||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||
$q->department($departmentId)->deceased($dateRange->startSql(), $dateRange->endSql());
|
||||
})
|
||||
@@ -270,6 +279,7 @@ class MedicalHistoryService
|
||||
public function getTransferredHistories(DateRange $dateRange, int $departmentId)
|
||||
{
|
||||
return MedicalHistory::query()
|
||||
->withoutDenials()
|
||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||
$q->department($departmentId)->transferred($dateRange->startSql(), $dateRange->endSql());
|
||||
})
|
||||
@@ -282,6 +292,7 @@ class MedicalHistoryService
|
||||
public function getReanimationHistories(DateRange $dateRange, int $departmentId)
|
||||
{
|
||||
return MedicalHistory::query()
|
||||
->withoutDenials()
|
||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||
$q->department($departmentId)->currentOrAdmitted($dateRange);
|
||||
})
|
||||
|
||||
@@ -32,6 +32,12 @@ class PlanCalculator extends BaseMetricService implements MetricCalculatorInterf
|
||||
$startCurrentMonth = $endDate->copy()->startOfMonth()->setHours(9);
|
||||
$currentMonth = $endDate->month;
|
||||
|
||||
// Кол-во календарных месяцев, затронутых выбранным диапазоном (для нормы за период)
|
||||
$monthsInRange = max(
|
||||
1,
|
||||
($endDate->year * 12 + $endDate->month) - ($startDate->year * 12 + $startDate->month) + 1
|
||||
);
|
||||
|
||||
// Получаем фактические выписки с начала года по прошлый месяц
|
||||
$previousOutcomeMonth = DB::table('report_duties as r')
|
||||
->join('duty_report_metric_results as mr', 'r.id', '=', 'mr.rf_report_id')
|
||||
@@ -99,6 +105,7 @@ class PlanCalculator extends BaseMetricService implements MetricCalculatorInterf
|
||||
$results[$departmentId] = [
|
||||
'year_plan' => $annualPlan,
|
||||
'month_plan' => $oneMonthPlan,
|
||||
'period_plan' => $oneMonthPlan * $monthsInRange, // норма за выбранный период (мес. × кол-во месяцев)
|
||||
'total_debt' => $totalDebt,
|
||||
'current_mouth_dept' => $currentMonthPlanOnly,
|
||||
'cumulative_plan' => $cumulativePlan,
|
||||
|
||||
Reference in New Issue
Block a user