'date:Y-m-d', 'recipient_date' => 'datetime:Y-m-d H:i:s', 'extract_date' => 'datetime:Y-m-d H:i:s', 'death_date' => 'datetime:Y-m-d H:i:s', 'male' => 'boolean', ]; public function medicalHistory() { return $this->belongsTo(MedicalHistory::class, 'medical_history_id', 'id'); } public function operations() { return $this->hasMany(SurgicalOperation::class, 'migration_patient_id', 'id') ->orderBy('end_date', 'desc'); } public function reanimations() { return $this->hasMany(Reanimation::class, 'migration_patient_id', 'id') ->orderBy('out_date', 'desc'); } // Пересечение с отчетным периодом public function scopeDateRange($query, string $from, string $to) { return $query->where('ingoing_date', '<=', $to) ->where(function ($q) use ($from) { $q->whereNull('out_date')->orWhere('out_date', '>=', $from); }); } // Фильтр по подразделению (получает ID отделений) public function scopeDepartment($query, int $departmentId) { $branchIds = DB::table('stt_stationarbranch') ->where('rf_DepartmentID', $departmentId) ->pluck('StationarBranchID'); return $query->whereIn('stationar_branch_id', $branchIds); } // Быстрые фильтры по статусам (используют индексы MV, а не computed column) public function scopeAdmitted($query, string $from, string $to) { return $query->where('ingoing_date', '>', $from) ->where('ingoing_date', '<=', $to); } public function scopeDischarged($query, string $from, string $to) { return $query->where('out_date', '>', $from) ->where('out_date', '<=', $to) ->whereNotIn('visit_result_id', [3, 4, 5, 6]) ->whereNull('death_date'); // умершие не считаются "выбывшими домой" } public function scopeTransferred($query, string $from, string $to) { return $query->where('out_date', '>', $from) ->where('out_date', '<=', $to) ->whereIn('visit_result_id', [3, 4]); } public function scopeDeceased($query, string $from, string $to) { return $query->whereNotNull('death_date') ->where('death_date', '>', $from) ->where('death_date', '<=', $to); } public function scopeCurrent($query, DateRange $dateRange) { return $query->whereNull('out_date') ->whereNotNull('medical_history_id') ->where('ingoing_date', '<', $dateRange->startSql()) ->wherehas('medicalHistory', function ($query) use ($dateRange) { $query->whereNull('extract_date'); }); } public function scopeCurrentOrAdmitted($query, DateRange $dateRange) { return $query->where(function ($q) use ($dateRange) { // Вариант А: Пациент уже лежит (текущий) $q->whereNull('out_date') ->whereNotNull('medical_history_id') ->where('ingoing_date', '<', $dateRange->startSql()) ->wherehas('medicalHistory', function ($query) use ($dateRange) { $query->whereNull('extract_date'); }); }) ->orWhere(function ($q) use ($dateRange) { $q->where('ingoing_date', '<=', $dateRange->endSql()) ->where('ingoing_date', '>', $dateRange->startSql()); }); } public function scopeCurrentMigration($query, $historyId, $departmentId) { return $query->where('medical_history_id', $historyId) ->department($departmentId) ->orderBy('ingoing_date', 'desc') ->limit(1)->first(); } public function getAdmittedInCurrentAttribute(): bool { // Получаем дату поступления из последнего движения $ingoing = $this->ingoing_date; if (!$ingoing) { return false; } $ingoingLocal = Carbon::parse($ingoing)->setTimezone(config('app.timezone', 'Europe/Moscow')); $now = Carbon::now(config('app.timezone', 'Europe/Moscow')); // Окно смены: вчера 09:00 → сегодня 09:00 $shiftStart = $now->copy()->subDay()->setTime(9, 0); $shiftEnd = $now->copy()->setTime(9, 0); return $ingoingLocal->between($shiftStart, $shiftEnd); } }