From 3a07e96e43e804d45ea3f2668f30bcd3db2bbea3 Mon Sep 17 00:00:00 2001 From: brusnitsyn Date: Thu, 11 Jun 2026 15:30:30 +0900 Subject: [PATCH] =?UTF-8?q?=D0=A2=D0=B5=D1=81=D1=82=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8=20=D0=BA?= =?UTF-8?q?=D0=BE=D1=80=D1=80=D0=B5=D0=BA=D1=82=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B8=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BE=D1=82=D1=87=D0=B5=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/Feature/DutyReportNursePatientsTest.php | 582 ++++++++++++++++++ 1 file changed, 582 insertions(+) create mode 100644 tests/Feature/DutyReportNursePatientsTest.php diff --git a/tests/Feature/DutyReportNursePatientsTest.php b/tests/Feature/DutyReportNursePatientsTest.php new file mode 100644 index 0000000..cb4cc92 --- /dev/null +++ b/tests/Feature/DutyReportNursePatientsTest.php @@ -0,0 +1,582 @@ +id('department_id'); + $table->string('name_full'); + $table->string('name_short')->nullable(); + $table->unsignedBigInteger('rf_mis_department_id')->nullable(); + }); + + Schema::create('users', function (Blueprint $table) { + $table->id(); + $table->string('name'); + $table->string('login')->unique(); + $table->string('password'); + $table->unsignedBigInteger('rf_department_id')->nullable(); + $table->timestamps(); + }); + + Schema::create('report_statuses', function (Blueprint $table) { + $table->id(); + $table->string('name'); + $table->string('code')->unique(); + $table->timestamps(); + }); + + Schema::create('report_nurses', function (Blueprint $table) { + $table->id(); + $table->date('report_date'); + $table->dateTime('sent_at')->nullable(); + $table->string('period_type')->default('day'); + $table->dateTime('period_start')->nullable(); + $table->dateTime('period_end')->nullable(); + $table->unsignedBigInteger('status_id')->default(1); + $table->unsignedBigInteger('rf_lpudoctor_id')->nullable(); + $table->unsignedBigInteger('rf_department_id')->default(1); + $table->unsignedBigInteger('rf_user_id')->nullable(); + $table->timestamps(); + }); + + Schema::create('report_nurse_patients', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('report_nurse_id'); + $table->string('source_type')->nullable(); + $table->bigInteger('original_id'); + $table->string('medical_card_number')->nullable(); + $table->string('full_name')->nullable(); + $table->date('birth_date')->nullable(); + $table->dateTime('recipient_date')->nullable(); + $table->dateTime('extract_date')->nullable(); + $table->dateTime('death_date')->nullable(); + $table->boolean('male')->default(true); + $table->integer('urgency_id')->nullable(); + $table->integer('hospital_result_id')->nullable(); + $table->integer('visit_result_id')->nullable(); + $table->text('comment')->nullable(); + $table->unsignedBigInteger('user_id')->nullable(); + $table->timestamps(); + + $table->unique(['report_nurse_id', 'source_type', 'original_id']); + }); + + Schema::create('report_nurse_migration_patients', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('medical_history_id'); + $table->bigInteger('original_id')->nullable(); + $table->dateTime('ingoing_date')->nullable(); + $table->dateTime('out_date')->nullable(); + $table->integer('diagnosis_id')->nullable(); + $table->string('diagnosis_code')->nullable(); + $table->string('diagnosis_name')->nullable(); + $table->integer('interrupted_event_id')->nullable(); + $table->integer('stationar_branch_id')->nullable(); + $table->integer('department_id')->nullable(); + $table->integer('visit_result_id')->nullable(); + $table->integer('stat_cure_result_id')->nullable(); + $table->unsignedBigInteger('user_id')->nullable(); + $table->integer('mis_user_id')->nullable(); + $table->text('comment')->nullable(); + $table->timestamps(); + + $table->unique(['medical_history_id', 'ingoing_date']); + }); + + Schema::create('report_duties', function (Blueprint $table) { + $table->id(); + $table->date('report_date'); + $table->dateTime('sent_at')->nullable(); + $table->string('period_type')->default('day'); + $table->dateTime('period_start')->nullable(); + $table->dateTime('period_end')->nullable(); + $table->unsignedBigInteger('status_id')->default(1); + $table->unsignedBigInteger('rf_lpudoctor_id')->nullable(); + $table->unsignedBigInteger('rf_department_id')->default(1); + $table->unsignedBigInteger('rf_user_id')->nullable(); + $table->timestamps(); + }); + + Schema::create('report_duty_patients', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('report_duty_id'); + $table->string('source_type')->nullable(); + $table->bigInteger('original_id'); + $table->string('medical_card_number')->nullable(); + $table->string('full_name')->nullable(); + $table->date('birth_date')->nullable(); + $table->dateTime('recipient_date')->nullable(); + $table->dateTime('extract_date')->nullable(); + $table->dateTime('death_date')->nullable(); + $table->boolean('male')->default(true); + $table->integer('urgency_id')->nullable(); + $table->integer('hospital_result_id')->nullable(); + $table->integer('visit_result_id')->nullable(); + $table->text('comment')->nullable(); + $table->unsignedBigInteger('user_id')->nullable(); + $table->timestamps(); + + $table->unique(['report_duty_id', 'source_type', 'original_id']); + }); + + Schema::create('report_duty_migration_patients', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('medical_history_id'); + $table->bigInteger('original_id')->nullable(); + $table->dateTime('ingoing_date')->nullable(); + $table->dateTime('out_date')->nullable(); + $table->integer('diagnosis_id')->nullable(); + $table->string('diagnosis_code')->nullable(); + $table->string('diagnosis_name')->nullable(); + $table->integer('interrupted_event_id')->nullable(); + $table->integer('stationar_branch_id')->nullable(); + $table->integer('department_id')->nullable(); + $table->integer('visit_result_id')->nullable(); + $table->integer('stat_cure_result_id')->nullable(); + $table->unsignedBigInteger('user_id')->nullable(); + $table->integer('mis_user_id')->nullable(); + $table->text('comment')->nullable(); + $table->timestamps(); + + $table->unique(['medical_history_id', 'ingoing_date']); + }); + + Schema::create('report_duty_reanimations', function (Blueprint $table) { + $table->id(); + $table->bigInteger('original_id')->nullable(); + $table->unsignedBigInteger('migration_patient_id'); + $table->unsignedBigInteger('medical_history_id'); + $table->dateTime('in_date')->nullable(); + $table->dateTime('out_date')->nullable(); + $table->text('description')->nullable(); + $table->text('comment')->nullable(); + $table->integer('stationar_branch_id')->nullable(); + $table->integer('migration_stationar_branch_id')->nullable(); + $table->integer('migration_department_id')->nullable(); + $table->integer('doctor_id')->nullable(); + $table->unsignedBigInteger('user_id')->nullable(); + $table->integer('mis_user_id')->nullable(); + $table->timestamps(); + + $table->unique(['migration_patient_id', 'in_date']); + }); + + // === МИС (материализованные представления) === + Schema::create('mv_medicalhistory_summary', function (Blueprint $table) { + $table->unsignedBigInteger('id')->primary(); + $table->string('medical_card_number')->nullable(); + $table->string('full_name')->nullable(); + $table->date('birth_date')->nullable(); + $table->dateTime('recipient_date')->nullable(); + $table->dateTime('extract_date')->nullable(); + $table->dateTime('death_date')->nullable(); + $table->boolean('male')->default(true); + $table->integer('urgency_id')->nullable(); + $table->integer('hospital_result_id')->nullable(); + $table->integer('visit_result_id')->nullable(); + $table->text('comment')->nullable(); + }); + + Schema::create('mv_migrationpatient_details', function (Blueprint $table) { + $table->unsignedBigInteger('id')->primary(); + $table->unsignedBigInteger('medical_history_id'); + $table->dateTime('ingoing_date')->nullable(); + $table->dateTime('out_date')->nullable(); + $table->integer('diagnosis_id')->nullable(); + $table->string('diagnosis_code')->nullable(); + $table->string('diagnosis_name')->nullable(); + $table->integer('interrupted_event_id')->nullable(); + $table->integer('stationar_branch_id')->nullable(); + $table->integer('department_id')->nullable(); + $table->integer('visit_result_id')->nullable(); + $table->integer('stat_cure_result_id')->nullable(); + $table->unsignedBigInteger('user_id')->nullable(); + $table->integer('mis_user_id')->nullable(); + $table->text('comment')->nullable(); + }); + + Schema::create('mv_surgical_operations', function (Blueprint $table) { + $table->unsignedBigInteger('id')->primary(); + $table->unsignedBigInteger('medical_history_id')->nullable(); + $table->unsignedBigInteger('migration_patient_id')->nullable(); + $table->integer('department_id')->nullable(); + $table->dateTime('start_date')->nullable(); + $table->dateTime('end_date')->nullable(); + $table->integer('urgent_status')->nullable(); + }); + + Schema::create('mv_reanimation_summary', function (Blueprint $table) { + $table->unsignedBigInteger('id')->primary(); + $table->unsignedBigInteger('migration_patient_id')->nullable(); + $table->unsignedBigInteger('medical_history_id')->nullable(); + $table->dateTime('in_date')->nullable(); + $table->dateTime('out_date')->nullable(); + }); + + Schema::create('observable_medical_histories', function (Blueprint $table) { + $table->id(); + $table->string('source_type')->nullable(); + $table->bigInteger('original_id')->nullable(); + $table->dateTime('observable_in')->nullable(); + $table->dateTime('observable_out')->nullable(); + $table->string('observable_reason')->nullable(); + $table->string('out_reason')->nullable(); + $table->string('medical_card_number')->nullable(); + $table->string('full_name')->nullable(); + $table->date('birth_date')->nullable(); + $table->dateTime('recipient_date')->nullable(); + $table->dateTime('extract_date')->nullable(); + $table->dateTime('death_date')->nullable(); + $table->boolean('male')->default(true); + $table->integer('urgency_id')->nullable(); + $table->integer('hospital_result_id')->nullable(); + $table->integer('visit_result_id')->nullable(); + $table->text('comment')->nullable(); + $table->unsignedBigInteger('user_id')->nullable(); + $table->timestamps(); + }); + + // Базовые справочники + DB::table('departments')->insert([ + 'department_id' => 1, + 'name_full' => 'Тестовое отделение', + 'name_short' => 'ТО', + 'rf_mis_department_id' => 100, + ]); + + DB::table('users')->insert([ + 'id' => 10, + 'name' => 'Дежурный врач', + 'login' => 'duty.doctor', + 'password' => 'secret', + 'rf_department_id' => 1, + ]); + + DB::table('users')->insert([ + 'id' => 20, + 'name' => 'Медсестра', + 'login' => 'nurse', + 'password' => 'secret', + 'rf_department_id' => 1, + ]); +}); + +afterEach(function () { + Carbon::setTestNow(); + \Mockery::close(); +}); + +function dutyDateRange(): DateRange +{ + return new DateRange( + startDate: Carbon::parse('2026-04-08 09:00:00', 'Asia/Yakutsk'), + endDate: Carbon::parse('2026-04-09 09:00:00', 'Asia/Yakutsk'), + startDateRaw: '2026-04-08 09:00:00', + endDateRaw: '2026-04-09 09:00:00', + isOneDay: true, + ); +} + +it('сохраняет пациентов в журнале медсестры', function () { + $reportNurse = ReportNurse::create([ + 'report_date' => '2026-04-09', + 'period_type' => 'day', + 'period_start' => '2026-04-08 09:00:00', + 'period_end' => '2026-04-09 09:00:00', + 'status_id' => 2, + 'rf_department_id' => 1, + 'rf_user_id' => 20, + ]); + + $patient = (object) [ + 'source_type' => 'mis', + 'original_id' => 9001, + 'medical_card_number' => 'MK-9001', + 'full_name' => 'Сидорова Анна Андреевна', + 'birth_date' => '1990-02-02', + 'recipient_date' => '2026-04-08 10:00:00', + 'extract_date' => null, + 'death_date' => null, + 'male' => false, + 'urgency_id' => 1, + 'hospital_result_id' => null, + 'visit_result_id' => null, + 'comment' => 'тестовый пациент', + 'migrations' => [ + (object) [ + 'id' => 8801, + 'ingoing_date' => '2026-04-08 10:00:00', + 'out_date' => null, + 'diagnosis_id' => 11, + 'diagnosis_code' => 'C00', + 'diagnosis_name' => 'Тестовый диагноз', + 'interrupted_event_id' => null, + 'stationar_branch_id' => 10, + 'department_id' => 100, + 'visit_result_id' => null, + 'stat_cure_result_id' => null, + 'user_id' => null, + 'mis_user_id' => null, + 'comment' => null, + ], + ], + ]; + + $stats = (new NurseReportService)->saveReportSnapshot($reportNurse->id, [$patient], 20); + + expect($stats['saved_patients'])->toBe(1) + ->and($stats['saved_migrations'])->toBe(1); + + $savedPatient = DB::table('report_nurse_patients') + ->where('report_nurse_id', $reportNurse->id) + ->where('source_type', 'mis') + ->where('original_id', 9001) + ->first(); + + expect($savedPatient)->not->toBeNull() + ->and($savedPatient->full_name)->toBe('Сидорова Анна Андреевна') + ->and($savedPatient->medical_card_number)->toBe('MK-9001') + ->and($savedPatient->user_id)->toBe(20); + + $savedMigration = DB::table('report_nurse_migration_patients') + ->where('medical_history_id', $savedPatient->id) + ->first(); + + expect($savedMigration)->not->toBeNull() + ->and($savedMigration->original_id)->toBe(8801) + ->and($savedMigration->diagnosis_code)->toBe('C00') + ->and($savedMigration->department_id)->toBe(100); +}); + +it('сохраняет пациентов дежурного врача из МИС, если отчета медсестры за период нет', function () { + $dateRange = dutyDateRange(); + + DB::table('mv_medicalhistory_summary')->insert([ + 'id' => 501, + 'medical_card_number' => 'MK-501', + 'full_name' => 'Иванов Иван Иванович', + 'birth_date' => '1980-01-01', + 'recipient_date' => '2026-04-08 10:00:00', + 'extract_date' => null, + 'death_date' => null, + 'male' => true, + 'urgency_id' => 2, + 'hospital_result_id' => null, + 'visit_result_id' => null, + 'comment' => null, + ]); + + DB::table('mv_migrationpatient_details')->insert([ + 'id' => 601, + 'medical_history_id' => 501, + 'ingoing_date' => '2026-04-08 10:00:00', + 'out_date' => null, + 'diagnosis_id' => 10, + 'diagnosis_code' => 'A00', + 'diagnosis_name' => 'Диагноз из МИС', + 'interrupted_event_id' => null, + 'stationar_branch_id' => 10, + 'department_id' => 100, + 'visit_result_id' => null, + 'stat_cure_result_id' => null, + 'user_id' => null, + 'mis_user_id' => null, + 'comment' => null, + ]); + + $reportDuty = ReportDuty::create([ + 'report_date' => '2026-04-09', + 'period_type' => 'day', + 'period_start' => $dateRange->startSql(), + 'period_end' => $dateRange->endSql(), + 'status_id' => 2, + 'rf_department_id' => 1, + 'rf_user_id' => 10, + ]); + + $service = app(DutyReportService::class); + $stats = $service->saveSnapshot($dateRange, $reportDuty, 100, 10); + + expect($stats['saved_patients'])->toBe(1) + ->and($stats['saved_migrations'])->toBe(1); + + $savedPatient = DB::table('report_duty_patients') + ->where('report_duty_id', $reportDuty->id) + ->where('source_type', 'mis') + ->where('original_id', 501) + ->first(); + + expect($savedPatient)->not->toBeNull() + ->and($savedPatient->full_name)->toBe('Иванов Иван Иванович') + ->and($savedPatient->medical_card_number)->toBe('MK-501'); + + $savedMigration = DB::table('report_duty_migration_patients') + ->where('medical_history_id', $savedPatient->id) + ->where('original_id', 601) + ->first(); + + expect($savedMigration)->not->toBeNull() + ->and($savedMigration->diagnosis_code)->toBe('A00') + ->and($savedMigration->department_id)->toBe(100); +}); + +it('сохраняет пациентов дежурного врача из отчета медсестры, если он есть за период', function () { + $dateRange = dutyDateRange(); + + // "Чужие" данные из МИС - не должны попасть в отчет дежурного врача, + // т.к. за период есть отчет медсестры + DB::table('mv_medicalhistory_summary')->insert([ + 'id' => 999, + 'medical_card_number' => 'MK-999', + 'full_name' => 'Не должен попасть в отчет', + 'birth_date' => '1970-01-01', + 'recipient_date' => '2026-04-08 10:00:00', + 'extract_date' => null, + 'death_date' => null, + 'male' => true, + 'urgency_id' => 1, + 'hospital_result_id' => null, + 'visit_result_id' => null, + 'comment' => null, + ]); + + DB::table('mv_migrationpatient_details')->insert([ + 'id' => 998, + 'medical_history_id' => 999, + 'ingoing_date' => '2026-04-08 10:00:00', + 'out_date' => null, + 'diagnosis_id' => 90, + 'diagnosis_code' => 'X00', + 'diagnosis_name' => 'МИС диагноз', + 'interrupted_event_id' => null, + 'stationar_branch_id' => 10, + 'department_id' => 100, + 'visit_result_id' => null, + 'stat_cure_result_id' => null, + 'user_id' => null, + 'mis_user_id' => null, + 'comment' => null, + ]); + + $reportNurse = ReportNurse::create([ + 'report_date' => '2026-04-09', + 'period_type' => 'day', + 'period_start' => $dateRange->startSql(), + 'period_end' => $dateRange->endSql(), + 'status_id' => 2, + 'rf_department_id' => 1, + 'rf_user_id' => 20, + ]); + + $nursePatientId = DB::table('report_nurse_patients')->insertGetId([ + 'report_nurse_id' => $reportNurse->id, + 'source_type' => 'mis', + 'original_id' => 701, + 'medical_card_number' => 'MK-701', + 'full_name' => 'Петров Петр Петрович', + 'birth_date' => '1975-05-05', + 'recipient_date' => '2026-04-08 11:00:00', + 'extract_date' => null, + 'death_date' => null, + 'male' => true, + 'urgency_id' => 1, + 'hospital_result_id' => null, + 'visit_result_id' => null, + 'comment' => null, + 'user_id' => 20, + ]); + + $nurseMigrationId = DB::table('report_nurse_migration_patients')->insertGetId([ + 'medical_history_id' => $nursePatientId, + 'original_id' => 5555, // MigrationPatientID из МИС + 'ingoing_date' => '2026-04-08 11:00:00', + 'out_date' => null, + 'diagnosis_id' => 20, + 'diagnosis_code' => 'B00', + 'diagnosis_name' => 'Диагноз медсестры', + 'interrupted_event_id' => null, + 'stationar_branch_id' => 10, + 'department_id' => 100, + 'visit_result_id' => null, + 'stat_cure_result_id' => null, + 'user_id' => null, + 'mis_user_id' => null, + 'comment' => null, + ]); + + $reportDuty = ReportDuty::create([ + 'report_date' => '2026-04-09', + 'period_type' => 'day', + 'period_start' => $dateRange->startSql(), + 'period_end' => $dateRange->endSql(), + 'status_id' => 2, + 'rf_department_id' => 1, + 'rf_user_id' => 10, + ]); + + $service = app(DutyReportService::class); + $stats = $service->saveSnapshot($dateRange, $reportDuty, 100, 10); + + expect($stats['saved_patients'])->toBe(1) + ->and($stats['saved_migrations'])->toBe(1); + + // Пациент из отчета медсестры сохранен + $savedPatient = DB::table('report_duty_patients') + ->where('report_duty_id', $reportDuty->id) + ->where('original_id', 701) + ->first(); + + expect($savedPatient)->not->toBeNull() + ->and($savedPatient->source_type)->toBe('mis') + ->and($savedPatient->full_name)->toBe('Петров Петр Петрович') + ->and($savedPatient->medical_card_number)->toBe('MK-701'); + + $savedMigration = DB::table('report_duty_migration_patients') + ->where('medical_history_id', $savedPatient->id) + ->first(); + + expect($savedMigration)->not->toBeNull() + ->and($savedMigration->original_id)->toBe(5555) + ->and($savedMigration->original_id)->not->toBe($nurseMigrationId) + ->and($savedMigration->diagnosis_code)->toBe('B00') + ->and($savedMigration->department_id)->toBe(100); + + // Пациент из МИС не должен попасть в отчет + $misPatient = DB::table('report_duty_patients') + ->where('report_duty_id', $reportDuty->id) + ->where('original_id', 999) + ->first(); + + expect($misPatient)->toBeNull(); +});