whereHas('migrations', function ($q) use ($departmentId, $dateRange) { $q->department($departmentId)->dateRange($dateRange->startSql(), $dateRange->endSql()); }) ->with(['latestMigration' => function ($q) use ($departmentId, $dateRange) { $q->department($departmentId)->dateRange($dateRange->startSql(), $dateRange->endSql()); }]); } /** * Сохранить отчет */ public function saveReport(DateRange $dateRange, ?int $userId = null, ?int $lpuDoctorId = null, ?int $departmentId = null) { $user = $userId ? User::find($userId) : auth()->user(); $lpuDoctorId = $lpuDoctorId ?? $user->rf_lpudoctor_id; $departmentId = $departmentId ?? $user->rf_department_id; $data = [ 'report_date' => Carbon::now()->format('Y-m-d'), 'sent_at' => Carbon::now()->format('Y-m-d H:i:s'), 'period_type' => 'day', 'period_start' => $dateRange->startSql(), 'period_end' => $dateRange->endSql(), 'status_id' => 2, // опубликован 'rf_lpudoctor_id' => $lpuDoctorId, 'rf_department_id' => $departmentId, 'rf_user_id' => $user->id, ]; $report = ReportNurse::create($data); return $report; } /** * Сохранить снимок пациентов за период */ public function saveSnapshot(DateRange $dateRange, ReportNurse $reportNurse, ?int $departmentId = null, ?int $userId = null): array { $departmentId = $departmentId ?? $reportNurse->department->rf_mis_department_id; $userId = $userId ?? $reportNurse->rf_user_id; $startYear = Carbon::now()->startOfYear()->format('Y-m-d'); $query = UnifiedMedicalHistory::query() // Фильтруем движения по отделению + пересечение дат ->whereHas('migrations', function ($q) use ($departmentId, $dateRange, $startYear) { $q->where('department_id', $departmentId) // пребывание пересекается с отчётным периодом ->where('ingoing_date', '<=', $dateRange->endSql()) ->where('ingoing_date', '>=', $startYear) ->where(function ($sub) use ($dateRange) { $sub->whereNull('out_date') ->orWhere('out_date', '>=', $dateRange->startSql()) ->where('out_date', '<=', $dateRange->endSql()); }) ->where(function ($sub) use ($dateRange) { $sub->whereNull('out_date') ->orWhere('out_date', '>=', $dateRange->startSql()) ->where('out_date', '<=', $dateRange->endSql()); }); }) // Подгружаем последнее движение для денормализации ->with(['latestMigration' => function ($q) use ($departmentId, $dateRange, $startYear) { $q->where('department_id', $departmentId) ->where('ingoing_date', '<=', $dateRange->endSql()) ->where('ingoing_date', '>=', $startYear) ->where(function ($sub) use ($dateRange) { $sub->whereNull('out_date') ->orWhere('out_date', '>=', $dateRange->startSql()) ->where('out_date', '<=', $dateRange->endSql()); }) ->latest('ingoing_date'); // если несколько, берём последнее }]); $rawSql = $query->toRawSql(); // Получаем данные (chunk для памяти, если пациентов > 1000) $patients = $query->cursor(); $savedCount = 0; $reportData = []; foreach ($patients as $patient) { // Подготовка данных для сохранения (денормализация) $data = [ 'report_nurse_id' => $reportNurse->id, 'source_type' => $patient->source_type, 'original_id' => $patient->original_id, 'medical_card_number' => $patient->medical_card_number, 'full_name' => $patient->full_name, 'birth_date' => $patient->birth_date, 'recipient_date' => $patient->recipient_date, 'extract_date' => $patient->extract_date, 'death_date' => $patient->death_date, 'male' => $patient->male, 'urgency_id' => $patient->urgency_id, 'hospital_result_id' => $patient->hospital_result_id, 'visit_result_id' => $patient->visit_result_id, 'comment' => $patient->comment, 'user_id' => $userId, ]; // UPSERT: обновляем если запись с таким ключом уже есть, иначе вставляем \DB::table('report_nurse_patients')->upsert( [$data], ['report_nurse_id', 'source_type', 'original_id'], // уникальные ключи [ 'medical_card_number', 'full_name', 'birth_date', 'recipient_date', 'extract_date', 'death_date', 'male', 'urgency_id', 'hospital_result_id', 'visit_result_id', 'comment', 'user_id' ] // обновляемые поля ); $savedCount++; $reportData[] = $data; } return [ 'saved_count' => $savedCount, 'report_date' => $dateRange->startSql(), 'department_id' => $departmentId, ]; } }