Добавил ограничение по отказникам
This commit is contained in:
@@ -31,6 +31,7 @@ class SnapshotPatientSource
|
|||||||
?array $recipientReportIds = null
|
?array $recipientReportIds = null
|
||||||
): Collection {
|
): Collection {
|
||||||
$snapshots = MedicalHistorySnapshot::query()
|
$snapshots = MedicalHistorySnapshot::query()
|
||||||
|
->withoutDenials()
|
||||||
->whereIn('rf_report_id', $reportIds)
|
->whereIn('rf_report_id', $reportIds)
|
||||||
->where('patient_type', $type)
|
->where('patient_type', $type)
|
||||||
->get()
|
->get()
|
||||||
@@ -45,6 +46,7 @@ class SnapshotPatientSource
|
|||||||
if ($markRecipients) {
|
if ($markRecipients) {
|
||||||
$recipientReportIds ??= $reportIds;
|
$recipientReportIds ??= $reportIds;
|
||||||
$recipientIds = MedicalHistorySnapshot::query()
|
$recipientIds = MedicalHistorySnapshot::query()
|
||||||
|
->withoutDenials()
|
||||||
->whereIn('rf_report_id', $recipientReportIds)
|
->whereIn('rf_report_id', $recipientReportIds)
|
||||||
->where('patient_type', 'recipient')
|
->where('patient_type', 'recipient')
|
||||||
->get()
|
->get()
|
||||||
@@ -91,6 +93,7 @@ class SnapshotPatientSource
|
|||||||
?array $recipientReportIds = null
|
?array $recipientReportIds = null
|
||||||
): Collection {
|
): Collection {
|
||||||
$snapshots = MedicalHistorySnapshot::query()
|
$snapshots = MedicalHistorySnapshot::query()
|
||||||
|
->withoutDenials()
|
||||||
->whereIn('rf_report_id', $reportIds)
|
->whereIn('rf_report_id', $reportIds)
|
||||||
->where('patient_type', 'current')
|
->where('patient_type', 'current')
|
||||||
->get();
|
->get();
|
||||||
@@ -107,6 +110,7 @@ class SnapshotPatientSource
|
|||||||
|
|
||||||
$recipientReportIds ??= $reportIds;
|
$recipientReportIds ??= $reportIds;
|
||||||
$recipientIds = MedicalHistorySnapshot::query()
|
$recipientIds = MedicalHistorySnapshot::query()
|
||||||
|
->withoutDenials()
|
||||||
->whereIn('rf_report_id', $recipientReportIds)
|
->whereIn('rf_report_id', $recipientReportIds)
|
||||||
->where('patient_type', 'recipient')
|
->where('patient_type', 'recipient')
|
||||||
->get()
|
->get()
|
||||||
@@ -151,7 +155,7 @@ class SnapshotPatientSource
|
|||||||
|
|
||||||
private function getCountFromSnapshots(string $type, array $reportIds): int
|
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') {
|
if ($type === 'outcome') {
|
||||||
$query->whereIn('patient_type', ['discharged', 'deceased']);
|
$query->whereIn('patient_type', ['discharged', 'deceased']);
|
||||||
|
|||||||
@@ -53,6 +53,24 @@ class MedicalHistory extends MaterializedViewModel
|
|||||||
->latest('observable_in');
|
->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)
|
public function operationsInDepartment($query, $departmentId)
|
||||||
{
|
{
|
||||||
return $this->operations()->where('department_id', $departmentId);
|
return $this->operations()->where('department_id', $departmentId);
|
||||||
|
|||||||
@@ -72,4 +72,25 @@ class MedicalHistorySnapshot extends Model
|
|||||||
$q->department($departmentId);
|
$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. Один запрос: получаем "сырые" данные (без вычисляемых статусов)
|
// 1. Один запрос: получаем "сырые" данные (без вычисляемых статусов)
|
||||||
$all = MedicalHistory::query()
|
$all = MedicalHistory::query()
|
||||||
|
->withoutDenials()
|
||||||
->whereHas('migrations', $periodMigrationFilter)
|
->whereHas('migrations', $periodMigrationFilter)
|
||||||
->when($search, function ($query, $search) {
|
->when($search, function ($query, $search) {
|
||||||
// Поиск по ФИО (точное совпадение или LIKE)
|
// Поиск по ФИО (точное совпадение или LIKE)
|
||||||
@@ -143,7 +144,8 @@ class MedicalHistoryService
|
|||||||
{
|
{
|
||||||
$query = MedicalHistory::query();
|
$query = MedicalHistory::query();
|
||||||
|
|
||||||
$query->where('recipient_date', '>=', $dateRange->startSql())
|
$query->withoutDenials()
|
||||||
|
->where('recipient_date', '>=', $dateRange->startSql())
|
||||||
->where('recipient_date', '<', $dateRange->endSql())
|
->where('recipient_date', '<', $dateRange->endSql())
|
||||||
// 1. Оставляем только тех пациентов, у которых БЫЛО движение в этом отделении
|
// 1. Оставляем только тех пациентов, у которых БЫЛО движение в этом отделении
|
||||||
->whereHas('latestMigration', fn($q) => $q->where('department_id', $departmentId))
|
->whereHas('latestMigration', fn($q) => $q->where('department_id', $departmentId))
|
||||||
@@ -160,7 +162,8 @@ class MedicalHistoryService
|
|||||||
{
|
{
|
||||||
$query = MedicalHistory::query();
|
$query = MedicalHistory::query();
|
||||||
|
|
||||||
$query->where('recipient_date', '>=', $dateRange->startSql())
|
$query->withoutDenials()
|
||||||
|
->where('recipient_date', '>=', $dateRange->startSql())
|
||||||
->where('recipient_date', '<', $dateRange->endSql())
|
->where('recipient_date', '<', $dateRange->endSql())
|
||||||
->urgency($urgencyId)
|
->urgency($urgencyId)
|
||||||
->whereHas('migrations', function ($m) use ($departmentId) {
|
->whereHas('migrations', function ($m) use ($departmentId) {
|
||||||
@@ -179,6 +182,7 @@ class MedicalHistoryService
|
|||||||
public function getDepartmentHistories(DateRange $dateRange, int $departmentId)
|
public function getDepartmentHistories(DateRange $dateRange, int $departmentId)
|
||||||
{
|
{
|
||||||
return MedicalHistory::query()
|
return MedicalHistory::query()
|
||||||
|
->withoutDenials()
|
||||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||||
$q->department($departmentId)->currentOrAdmitted($dateRange);
|
$q->department($departmentId)->currentOrAdmitted($dateRange);
|
||||||
})
|
})
|
||||||
@@ -194,6 +198,7 @@ class MedicalHistoryService
|
|||||||
public function getPlannedHistories(DateRange $dateRange, int $departmentId)
|
public function getPlannedHistories(DateRange $dateRange, int $departmentId)
|
||||||
{
|
{
|
||||||
return MedicalHistory::query()
|
return MedicalHistory::query()
|
||||||
|
->withoutDenials()
|
||||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||||
$q->department($departmentId)->currentOrAdmitted($dateRange);
|
$q->department($departmentId)->currentOrAdmitted($dateRange);
|
||||||
})
|
})
|
||||||
@@ -211,6 +216,7 @@ class MedicalHistoryService
|
|||||||
public function getEmergencyHistories(DateRange $dateRange, int $departmentId)
|
public function getEmergencyHistories(DateRange $dateRange, int $departmentId)
|
||||||
{
|
{
|
||||||
return MedicalHistory::query()
|
return MedicalHistory::query()
|
||||||
|
->withoutDenials()
|
||||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||||
$q->department($departmentId)->currentOrAdmitted($dateRange);
|
$q->department($departmentId)->currentOrAdmitted($dateRange);
|
||||||
})
|
})
|
||||||
@@ -234,6 +240,7 @@ class MedicalHistoryService
|
|||||||
$now = Carbon::now();
|
$now = Carbon::now();
|
||||||
|
|
||||||
return MedicalHistory::query()
|
return MedicalHistory::query()
|
||||||
|
->withoutDenials()
|
||||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||||
$q->department($departmentId)->admitted($dateRange->startSql(), $dateRange->endSql());
|
$q->department($departmentId)->admitted($dateRange->startSql(), $dateRange->endSql());
|
||||||
})
|
})
|
||||||
@@ -246,6 +253,7 @@ class MedicalHistoryService
|
|||||||
public function getDischargedHistories(DateRange $dateRange, int $departmentId)
|
public function getDischargedHistories(DateRange $dateRange, int $departmentId)
|
||||||
{
|
{
|
||||||
return MedicalHistory::query()
|
return MedicalHistory::query()
|
||||||
|
->withoutDenials()
|
||||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||||
$q->department($departmentId)->discharged($dateRange->startSql(), $dateRange->endSql());
|
$q->department($departmentId)->discharged($dateRange->startSql(), $dateRange->endSql());
|
||||||
})
|
})
|
||||||
@@ -258,6 +266,7 @@ class MedicalHistoryService
|
|||||||
public function getDeceasedHistories(DateRange $dateRange, int $departmentId)
|
public function getDeceasedHistories(DateRange $dateRange, int $departmentId)
|
||||||
{
|
{
|
||||||
return MedicalHistory::query()
|
return MedicalHistory::query()
|
||||||
|
->withoutDenials()
|
||||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||||
$q->department($departmentId)->deceased($dateRange->startSql(), $dateRange->endSql());
|
$q->department($departmentId)->deceased($dateRange->startSql(), $dateRange->endSql());
|
||||||
})
|
})
|
||||||
@@ -270,6 +279,7 @@ class MedicalHistoryService
|
|||||||
public function getTransferredHistories(DateRange $dateRange, int $departmentId)
|
public function getTransferredHistories(DateRange $dateRange, int $departmentId)
|
||||||
{
|
{
|
||||||
return MedicalHistory::query()
|
return MedicalHistory::query()
|
||||||
|
->withoutDenials()
|
||||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||||
$q->department($departmentId)->transferred($dateRange->startSql(), $dateRange->endSql());
|
$q->department($departmentId)->transferred($dateRange->startSql(), $dateRange->endSql());
|
||||||
})
|
})
|
||||||
@@ -282,6 +292,7 @@ class MedicalHistoryService
|
|||||||
public function getReanimationHistories(DateRange $dateRange, int $departmentId)
|
public function getReanimationHistories(DateRange $dateRange, int $departmentId)
|
||||||
{
|
{
|
||||||
return MedicalHistory::query()
|
return MedicalHistory::query()
|
||||||
|
->withoutDenials()
|
||||||
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
->whereHas('migrations', function ($q) use ($departmentId, $dateRange) {
|
||||||
$q->department($departmentId)->currentOrAdmitted($dateRange);
|
$q->department($departmentId)->currentOrAdmitted($dateRange);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ class PlanCalculator extends BaseMetricService implements MetricCalculatorInterf
|
|||||||
$startCurrentMonth = $endDate->copy()->startOfMonth()->setHours(9);
|
$startCurrentMonth = $endDate->copy()->startOfMonth()->setHours(9);
|
||||||
$currentMonth = $endDate->month;
|
$currentMonth = $endDate->month;
|
||||||
|
|
||||||
|
// Кол-во календарных месяцев, затронутых выбранным диапазоном (для нормы за период)
|
||||||
|
$monthsInRange = max(
|
||||||
|
1,
|
||||||
|
($endDate->year * 12 + $endDate->month) - ($startDate->year * 12 + $startDate->month) + 1
|
||||||
|
);
|
||||||
|
|
||||||
// Получаем фактические выписки с начала года по прошлый месяц
|
// Получаем фактические выписки с начала года по прошлый месяц
|
||||||
$previousOutcomeMonth = DB::table('report_duties as r')
|
$previousOutcomeMonth = DB::table('report_duties as r')
|
||||||
->join('duty_report_metric_results as mr', 'r.id', '=', 'mr.rf_report_id')
|
->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] = [
|
$results[$departmentId] = [
|
||||||
'year_plan' => $annualPlan,
|
'year_plan' => $annualPlan,
|
||||||
'month_plan' => $oneMonthPlan,
|
'month_plan' => $oneMonthPlan,
|
||||||
|
'period_plan' => $oneMonthPlan * $monthsInRange, // норма за выбранный период (мес. × кол-во месяцев)
|
||||||
'total_debt' => $totalDebt,
|
'total_debt' => $totalDebt,
|
||||||
'current_mouth_dept' => $currentMonthPlanOnly,
|
'current_mouth_dept' => $currentMonthPlanOnly,
|
||||||
'cumulative_plan' => $cumulativePlan,
|
'cumulative_plan' => $cumulativePlan,
|
||||||
|
|||||||
Reference in New Issue
Block a user