From dd5da05e6f137ca55e528df3e0c923e868da5c4e Mon Sep 17 00:00:00 2001 From: brusnitsyn Date: Thu, 11 Jun 2026 15:27:14 +0900 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=B4=D0=B0=D0=BB=D0=B8=D0=BB=20=D0=BD?= =?UTF-8?q?=D0=B5=D0=B0=D0=BA=D1=82=D1=83=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B?= =?UTF-8?q?=D0=B5=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/Feature/AutoFillReportsTest.php | 467 -------- tests/Feature/ExampleTest.php | 7 - tests/Feature/ReportPatientsServicesTest.php | 1022 ----------------- .../Reports/EloquentReportRepositoryTest.php | 150 --- tests/Unit/ExampleTest.php | 5 - tests/Unit/Reports/BedDaysCalculatorTest.php | 38 - .../CompareLegacyAndNewReportUseCaseTest.php | 47 - .../Reports/DepartmentLoadCalculatorTest.php | 15 - .../Reports/GenerateReportUseCaseTest.php | 92 -- tests/Unit/Reports/MetrikaConfigTest.php | 28 - .../PreoperativeDaysCalculatorTest.php | 38 - tests/Unit/Reports/ReportInputFactoryTest.php | 58 - .../Reports/ReportPatientsReadServiceTest.php | 148 --- tests/Unit/Reports/ReportSnapshotTest.php | 36 - .../ReportStatisticsReadServiceTest.php | 147 --- 15 files changed, 2298 deletions(-) delete mode 100644 tests/Feature/AutoFillReportsTest.php delete mode 100644 tests/Feature/ExampleTest.php delete mode 100644 tests/Feature/ReportPatientsServicesTest.php delete mode 100644 tests/Feature/Reports/EloquentReportRepositoryTest.php delete mode 100644 tests/Unit/ExampleTest.php delete mode 100644 tests/Unit/Reports/BedDaysCalculatorTest.php delete mode 100644 tests/Unit/Reports/CompareLegacyAndNewReportUseCaseTest.php delete mode 100644 tests/Unit/Reports/DepartmentLoadCalculatorTest.php delete mode 100644 tests/Unit/Reports/GenerateReportUseCaseTest.php delete mode 100644 tests/Unit/Reports/MetrikaConfigTest.php delete mode 100644 tests/Unit/Reports/PreoperativeDaysCalculatorTest.php delete mode 100644 tests/Unit/Reports/ReportInputFactoryTest.php delete mode 100644 tests/Unit/Reports/ReportPatientsReadServiceTest.php delete mode 100644 tests/Unit/Reports/ReportSnapshotTest.php delete mode 100644 tests/Unit/Reports/ReportStatisticsReadServiceTest.php diff --git a/tests/Feature/AutoFillReportsTest.php b/tests/Feature/AutoFillReportsTest.php deleted file mode 100644 index 84cd99b..0000000 --- a/tests/Feature/AutoFillReportsTest.php +++ /dev/null @@ -1,467 +0,0 @@ -id('department_id'); - $table->string('name_short')->nullable(); - $table->integer('rf_mis_department_id')->nullable(); - $table->integer('rf_department_type')->nullable(); - }); - - Schema::create('roles', function (Blueprint $table) { - $table->id('role_id'); - $table->string('name')->nullable(); - $table->string('slug'); - $table->boolean('is_active')->default(true); - }); - - Schema::create('users', function (Blueprint $table) { - $table->id(); - $table->string('name'); - $table->string('login')->unique(); - $table->string('password'); - $table->boolean('is_active')->default(true); - $table->unsignedBigInteger('rf_lpudoctor_id')->nullable(); - $table->unsignedBigInteger('rf_department_id')->nullable(); - $table->unsignedBigInteger('current_role_id')->nullable(); - $table->rememberToken()->nullable(); - $table->timestamps(); - }); - - Schema::create('user_roles', function (Blueprint $table) { - $table->id('user_role_id'); - $table->unsignedBigInteger('rf_user_id'); - $table->unsignedBigInteger('rf_role_id'); - $table->boolean('is_active')->default(true); - $table->boolean('is_default')->default(false); - }); - - Schema::create('user_departments', function (Blueprint $table) { - $table->id(); - $table->unsignedBigInteger('rf_user_id'); - $table->unsignedBigInteger('rf_department_id'); - $table->boolean('is_favorite')->default(false); - $table->integer('order')->default(0); - $table->string('user_name')->nullable(); - }); - - Schema::create('reports', function (Blueprint $table) { - $table->id('report_id'); - $table->date('created_at'); - $table->dateTime('sent_at')->nullable(); - $table->unsignedBigInteger('rf_department_id'); - $table->unsignedBigInteger('rf_user_id')->nullable(); - $table->unsignedBigInteger('rf_lpudoctor_id')->nullable(); - }); - - Schema::create('metrika_results', function (Blueprint $table) { - $table->id('metrika_result_id'); - $table->unsignedBigInteger('rf_report_id'); - $table->unsignedBigInteger('rf_metrika_item_id'); - $table->string('value')->nullable(); - }); - - Schema::create('medical_history_snapshots', function (Blueprint $table) { - $table->id('medical_history_snapshot_id'); - $table->unsignedBigInteger('rf_report_id'); - $table->unsignedBigInteger('rf_medicalhistory_id')->nullable(); - $table->unsignedBigInteger('rf_department_patient_id')->nullable(); - $table->string('patient_type'); - $table->string('patient_uid')->nullable(); - $table->string('patient_source_type')->nullable(); - $table->string('patient_kind')->nullable(); - $table->string('full_name')->nullable(); - $table->date('birth_date')->nullable(); - $table->string('diagnosis_code')->nullable(); - $table->string('diagnosis_name')->nullable(); - $table->dateTime('admitted_at')->nullable(); - $table->string('outcome_type')->nullable(); - $table->dateTime('outcome_at')->nullable(); - $table->boolean('is_manual')->default(false); - $table->timestamps(); - }); - - Schema::create('department_patients', function (Blueprint $table) { - $table->id('department_patient_id'); - $table->unsignedBigInteger('rf_department_id'); - $table->string('source_type')->default('manual'); - $table->unsignedBigInteger('rf_medicalhistory_id')->nullable(); - $table->string('full_name'); - $table->date('birth_date')->nullable(); - $table->string('patient_kind')->nullable(); - $table->string('diagnosis_code')->nullable(); - $table->string('diagnosis_name')->nullable(); - $table->dateTime('admitted_at')->nullable(); - $table->boolean('is_current')->default(true); - $table->string('outcome_type')->nullable(); - $table->dateTime('outcome_at')->nullable(); - $table->unsignedBigInteger('created_by')->nullable(); - $table->dateTime('linked_to_mis_at')->nullable(); - $table->timestamps(); - }); - - Schema::create('unwanted_events', function (Blueprint $table) { - $table->id('unwanted_event_id'); - $table->unsignedBigInteger('rf_report_id')->nullable(); - }); - - Schema::create('observation_patients', function (Blueprint $table) { - $table->id('observation_patient_id'); - $table->unsignedBigInteger('rf_report_id')->nullable(); - $table->unsignedBigInteger('rf_department_id')->nullable(); - $table->unsignedBigInteger('rf_medicalhistory_id')->nullable(); - $table->unsignedBigInteger('rf_department_patient_id')->nullable(); - }); - - Schema::create('stt_stationarbranch', function (Blueprint $table) { - $table->integer('StationarBranchID')->primary(); - $table->integer('rf_DepartmentID'); - }); -}); - -afterEach(function () { - Carbon::setTestNow(); - \Mockery::close(); -}); - -function autoFillRange(): DateRange -{ - return new DateRange( - startDate: Carbon::parse('2026-04-08 06:00:00', 'Asia/Yakutsk'), - endDate: Carbon::parse('2026-04-09 06:00:00', 'Asia/Yakutsk'), - startDateRaw: '2026-04-08 06:00:00', - endDateRaw: '2026-04-09 06:00:00', - isOneDay: true, - ); -} - -it('builds auto fill payload from the same patient metrics that are stored in reports', function () { - DB::table('stt_stationarbranch')->insert([ - 'StationarBranchID' => 10, - 'rf_DepartmentID' => 100, - ]); - - $department = new Department; - $department->department_id = 10; - $department->rf_mis_department_id = 100; - - $user = new class extends User - { - public function isHeadOfDepartment() - { - return false; - } - - public function isAdmin() - { - return false; - } - }; - $user->id = 15; - $user->rf_lpudoctor_id = 5015; - - $patientService = \Mockery::mock(PatientService::class); - $unifiedPatientService = \Mockery::mock(UnifiedPatientService::class); - $unifiedPatientService - ->shouldReceive('getLivePatientCountByStatus') - ->once()->with($department, $user, 'plan', \Mockery::type(DateRange::class), 10, true)->andReturn(11); - $unifiedPatientService - ->shouldReceive('getLivePatientCountByStatus') - ->once()->with($department, $user, 'emergency', \Mockery::type(DateRange::class), 10, true)->andReturn(7); - $unifiedPatientService - ->shouldReceive('getLivePatientCountByStatus') - ->once()->with($department, $user, 'recipient', \Mockery::type(DateRange::class), 10)->andReturn(4); - $unifiedPatientService - ->shouldReceive('getLivePatientCountByStatus') - ->once()->with($department, $user, 'outcome-discharged', \Mockery::type(DateRange::class), 10)->andReturn(3); - $unifiedPatientService - ->shouldReceive('getLivePatientCountByStatus') - ->once()->with($department, $user, 'outcome-transferred', \Mockery::type(DateRange::class), 10)->andReturn(2); - $unifiedPatientService - ->shouldReceive('getLivePatientCountByStatus') - ->once()->with($department, $user, 'outcome-deceased', \Mockery::type(DateRange::class), 10)->andReturn(1); - $unifiedPatientService - ->shouldReceive('getLivePatientCountByStatus') - ->once()->with($department, $user, 'current', \Mockery::type(DateRange::class), 10)->andReturn(21); - $patientService - ->shouldReceive('getSurgicalPatients') - ->once()->with('plan', 10, \Mockery::type(DateRange::class), true)->andReturn(8); - $patientService - ->shouldReceive('getSurgicalPatients') - ->once()->with('emergency', 10, \Mockery::type(DateRange::class), true)->andReturn(5); - - $service = new ReportService( - app(DateRangeService::class), - $unifiedPatientService, - $patientService, - \Mockery::mock(SnapshotService::class), - \Mockery::mock(\App\Services\StatisticsService::class) - ); - - $payload = $service->buildAutoFillReportPayload($user, $department, autoFillRange()); - - expect($payload['departmentId'])->toBe(10) - ->and($payload['userId'])->toBe(5015) - ->and($payload['metrics']['metrika_item_4'])->toBe(11) - ->and($payload['metrics']['metrika_item_12'])->toBe(7) - ->and($payload['metrics']['metrika_item_13'])->toBe(2) - ->and($payload['metrics']['metrika_item_8'])->toBe(21) - ->and($payload['metrics']['metrika_item_7'])->toBe(4); -}); - -it('creates auto-filled report through report service with auto flag and scoped department user', function () { - $department = new Department; - $department->department_id = 10; - $department->rf_mis_department_id = 100; - - $user = new User; - $user->id = 15; - $user->rf_lpudoctor_id = 5015; - $user->rf_department_id = 999; - - $payload = ['departmentId' => 10, 'metrics' => ['metrika_item_4' => 11], 'dates' => [1, 2]]; - - $reportService = \Mockery::mock(ReportService::class); - $reportService - ->shouldReceive('buildAutoFillReportPayload') - ->once() - ->withArgs(function (User $scopedUser, Department $argDepartment, DateRange $dateRange) use ($department) { - return $argDepartment->department_id === $department->department_id - && $dateRange->endSql() === '2026-04-09 06:00:00' - && $scopedUser !== null - && $scopedUser->rf_department_id === 10 - && $scopedUser->department->department_id === 10; - }) - ->andReturn($payload); - $reportService - ->shouldReceive('storeReport') - ->once() - ->withArgs(function (array $data, User $scopedUser, bool $fillableAuto) use ($payload) { - return $data === $payload - && $fillableAuto === true - && $scopedUser->rf_department_id === 10 - && $scopedUser->department->department_id === 10; - }) - ->andReturn(new \App\Models\Report); - - $service = new AutoReportService( - $reportService, - app(DateRangeService::class), - \Mockery::mock(ReportSavePathService::class), - ); - - expect($service->createReportForDate($user, $department, autoFillRange(), false))->toBeTrue(); -}); - -it('force recreation removes previous report scoped data before storing a new auto-filled report', function () { - $department = new Department; - $department->department_id = 10; - $department->rf_mis_department_id = 100; - - $user = new User; - $user->id = 15; - $user->rf_lpudoctor_id = 5015; - $user->rf_department_id = 10; - - DB::table('reports')->insert([ - 'report_id' => 55, - 'created_at' => '2026-04-09', - 'sent_at' => '2026-04-09 06:00:00', - 'rf_department_id' => 10, - 'rf_user_id' => 15, - 'rf_lpudoctor_id' => 5015, - ]); - - DB::table('metrika_results')->insert([ - 'rf_report_id' => 55, - 'rf_metrika_item_id' => 4, - 'value' => '99', - ]); - - DB::table('medical_history_snapshots')->insert([ - 'rf_report_id' => 55, - 'rf_medicalhistory_id' => 100, - 'patient_type' => 'plan', - 'patient_uid' => 'mis:100', - 'patient_source_type' => 'mis', - 'patient_kind' => 'plan', - 'full_name' => 'Old Snapshot', - 'created_at' => now(), - 'updated_at' => now(), - ]); - - DB::table('unwanted_events')->insert([ - 'rf_report_id' => 55, - ]); - - DB::table('observation_patients')->insert([ - 'rf_report_id' => 55, - 'rf_department_id' => 10, - 'rf_medicalhistory_id' => 100, - ]); - - $payload = ['departmentId' => 10, 'metrics' => ['metrika_item_4' => 11], 'dates' => [1, 2]]; - - $reportService = \Mockery::mock(ReportService::class); - $reportService - ->shouldReceive('buildAutoFillReportPayload') - ->once() - ->andReturn($payload); - $reportService - ->shouldReceive('storeReport') - ->once() - ->andReturn(new \App\Models\Report); - - $service = new AutoReportService( - $reportService, - app(DateRangeService::class), - \Mockery::mock(ReportSavePathService::class), - ); - - expect($service->createReportForDate($user, $department, autoFillRange(), true))->toBeTrue() - ->and(DB::table('reports')->where('report_id', 55)->exists())->toBeFalse() - ->and(DB::table('metrika_results')->where('rf_report_id', 55)->exists())->toBeFalse() - ->and(DB::table('medical_history_snapshots')->where('rf_report_id', 55)->exists())->toBeFalse() - ->and(DB::table('unwanted_events')->where('rf_report_id', 55)->exists())->toBeFalse() - ->and(DB::table('observation_patients')->where('rf_report_id', 55)->exists())->toBeFalse(); -}); - -it('reports fill command chooses doctor by default and honors explicit user option', function () { - DB::table('departments')->insert([ - 'department_id' => 10, - 'name_short' => 'Отд. 10', - 'rf_mis_department_id' => 100, - ]); - - DB::table('roles')->insert([ - ['role_id' => 1, 'name' => 'Doctor', 'slug' => 'doctor', 'is_active' => true], - ['role_id' => 2, 'name' => 'Head', 'slug' => 'head_of_department', 'is_active' => true], - ]); - - DB::table('users')->insert([ - [ - 'id' => 101, - 'name' => 'Doctor A', - 'login' => 'doc-a', - 'password' => 'secret', - 'is_active' => true, - 'rf_lpudoctor_id' => 1001, - 'rf_department_id' => 10, - 'created_at' => now(), - 'updated_at' => now(), - ], - [ - 'id' => 102, - 'name' => 'Head B', - 'login' => 'head-b', - 'password' => 'secret', - 'is_active' => true, - 'rf_lpudoctor_id' => 1002, - 'rf_department_id' => 10, - 'created_at' => now(), - 'updated_at' => now(), - ], - [ - 'id' => 103, - 'name' => 'Doctor C', - 'login' => 'doc-c', - 'password' => 'secret', - 'is_active' => true, - 'rf_lpudoctor_id' => 1003, - 'rf_department_id' => 10, - 'created_at' => now(), - 'updated_at' => now(), - ], - ]); - - DB::table('user_roles')->insert([ - ['user_role_id' => 1, 'rf_user_id' => 101, 'rf_role_id' => 1, 'is_active' => true, 'is_default' => true], - ['user_role_id' => 2, 'rf_user_id' => 102, 'rf_role_id' => 2, 'is_active' => true, 'is_default' => true], - ['user_role_id' => 3, 'rf_user_id' => 103, 'rf_role_id' => 1, 'is_active' => true, 'is_default' => true], - ]); - - DB::table('user_departments')->insert([ - ['id' => 1, 'rf_user_id' => 101, 'rf_department_id' => 10, 'is_favorite' => true, 'order' => 2, 'user_name' => 'Doctor A'], - ['id' => 2, 'rf_user_id' => 102, 'rf_department_id' => 10, 'is_favorite' => true, 'order' => 1, 'user_name' => 'Head B'], - ['id' => 3, 'rf_user_id' => 103, 'rf_department_id' => 10, 'is_favorite' => false, 'order' => 1, 'user_name' => 'Doctor C'], - ]); - - $autoReportService = \Mockery::mock(AutoReportService::class); - $autoReportService - ->shouldReceive('fillReportsForUser') - ->once() - ->withArgs(function (User $user, string $startDate, string $endDate, Department $department, bool $force) { - return $user->id === 101 - && $startDate === '2026-01-01' - && $endDate === '2026-01-02' - && $department->department_id === 10 - && $force === false; - }) - ->andReturn(2); - $autoReportService - ->shouldReceive('fillReportsForUser') - ->once() - ->withArgs(function (User $user, string $startDate, string $endDate, Department $department, bool $force) { - return $user->id === 103 - && $startDate === '2026-01-01' - && $endDate === '2026-01-02' - && $department->department_id === 10 - && $force === false; - }) - ->andReturn(2); - - app()->instance(AutoReportService::class, $autoReportService); - - $command = app(FillReportsFromDate::class); - $command->setLaravel(app()); - $tester = new CommandTester($command); - - expect($tester->execute([ - '--date' => '2026-01-01', - '--end-date' => '2026-01-02', - '--department' => 10, - ]))->toBe(0); - - expect($tester->execute([ - '--date' => '2026-01-01', - '--end-date' => '2026-01-02', - '--department' => 10, - '--user' => 103, - ]))->toBe(0); -}); diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php deleted file mode 100644 index 8b5843f..0000000 --- a/tests/Feature/ExampleTest.php +++ /dev/null @@ -1,7 +0,0 @@ -get('/'); - - $response->assertStatus(200); -}); diff --git a/tests/Feature/ReportPatientsServicesTest.php b/tests/Feature/ReportPatientsServicesTest.php deleted file mode 100644 index 6ad6471..0000000 --- a/tests/Feature/ReportPatientsServicesTest.php +++ /dev/null @@ -1,1022 +0,0 @@ -integer('StationarBranchID')->primary(); - $table->integer('rf_DepartmentID'); - }); - - Schema::create('reports', function (Blueprint $table) { - $table->integer('report_id')->primary(); - $table->date('created_at'); - $table->dateTime('sent_at')->nullable(); - $table->integer('rf_department_id'); - $table->integer('rf_user_id')->nullable(); - $table->integer('rf_lpudoctor_id')->nullable(); - }); - - Schema::create('medical_history_snapshots', function (Blueprint $table) { - $table->integer('medical_history_snapshot_id')->primary(); - $table->integer('rf_report_id'); - $table->integer('rf_medicalhistory_id')->nullable(); - $table->integer('rf_department_patient_id')->nullable(); - $table->string('patient_type'); - $table->string('patient_uid')->nullable(); - $table->string('patient_source_type')->nullable(); - $table->string('patient_kind')->nullable(); - $table->string('full_name')->nullable(); - $table->date('birth_date')->nullable(); - $table->string('diagnosis_code')->nullable(); - $table->string('diagnosis_name')->nullable(); - $table->dateTime('admitted_at')->nullable(); - $table->string('outcome_type')->nullable(); - $table->dateTime('outcome_at')->nullable(); - $table->boolean('is_manual')->default(false); - $table->timestamps(); - }); - - Schema::create('department_patients', function (Blueprint $table) { - $table->integer('department_patient_id')->primary(); - $table->integer('rf_department_id'); - $table->string('source_type')->default('manual'); - $table->integer('rf_medicalhistory_id')->nullable(); - $table->string('full_name'); - $table->date('birth_date')->nullable(); - $table->string('patient_kind')->nullable(); - $table->string('diagnosis_code')->nullable(); - $table->string('diagnosis_name')->nullable(); - $table->dateTime('admitted_at')->nullable(); - $table->boolean('is_current')->default(true); - $table->string('outcome_type')->nullable(); - $table->dateTime('outcome_at')->nullable(); - $table->integer('created_by')->nullable(); - $table->dateTime('linked_to_mis_at')->nullable(); - $table->timestamps(); - }); - - Schema::create('observation_patients', function (Blueprint $table) { - $table->integer('observation_patient_id')->primary(); - $table->integer('rf_report_id')->nullable(); - $table->integer('rf_department_id')->nullable(); - $table->integer('rf_medicalhistory_id')->nullable(); - $table->integer('rf_department_patient_id')->nullable(); - $table->text('comment')->nullable(); - }); - - Schema::create('stt_medicalhistory', function (Blueprint $table) { - $table->integer('MedicalHistoryID')->primary(); - $table->integer('rf_EmerSignID')->nullable(); - $table->integer('rf_kl_VisitResultID')->default(0); - $table->dateTime('DateRecipient')->nullable(); - $table->dateTime('DateExtract')->nullable(); - }); - - Schema::create('stt_migrationpatient', function (Blueprint $table) { - $table->integer('MigrationPatientID')->primary(); - $table->integer('rf_MedicalHistoryID'); - $table->integer('rf_StationarBranchID'); - $table->integer('rf_kl_VisitResultID')->default(0); - $table->integer('rf_kl_StatCureResultID')->default(0); - $table->dateTime('DateIngoing')->nullable(); - $table->dateTime('DateOut')->nullable(); - }); - - Schema::create('stt_surgicaloperation', function (Blueprint $table) { - $table->integer('SurgicalOperationID')->primary(); - $table->integer('rf_MedicalHistoryID')->nullable(); - $table->integer('rf_StationarBranchID')->nullable(); - $table->integer('rf_kl_ServiceMedicalID')->nullable(); - $table->dateTime('Date')->nullable(); - }); - - Schema::create('stt_operationpurpose', function (Blueprint $table) { - $table->integer('OperationPurposeID')->primary(); - $table->integer('rf_SurgicalOperationID'); - $table->integer('rf_OperationStatusID'); - }); - - Schema::create('stt_diagnos', function (Blueprint $table) { - $table->integer('DiagnosID')->primary(); - $table->integer('rf_MigrationPatientID')->nullable(); - $table->integer('rf_DiagnosTypeID')->nullable(); - $table->integer('rf_MKBID')->nullable(); - }); - - Schema::create('oms_mkb', function (Blueprint $table) { - $table->integer('MKBID')->primary(); - $table->string('DS')->nullable(); - $table->string('NAME')->nullable(); - }); - - Schema::create('oms_servicemedical', function (Blueprint $table) { - $table->integer('ServiceMedicalID')->primary(); - }); -}); - -afterEach(function () { - Carbon::setTestNow(); - \Mockery::close(); -}); - -function reportDateRange(string $start, string $end): DateRange -{ - return new DateRange( - startDate: Carbon::parse($start, 'Asia/Yakutsk'), - endDate: Carbon::parse($end, 'Asia/Yakutsk'), - startDateRaw: $start, - endDateRaw: $end, - isOneDay: true, - ); -} - -function makeUser(bool $isHead = false, bool $isAdmin = false): User -{ - $user = new class extends User - { - public bool $head = false; - - public bool $admin = false; - - public function isHeadOfDepartment() - { - return $this->head; - } - - public function isAdmin() - { - return $this->admin; - } - }; - - $user->head = $isHead; - $user->admin = $isAdmin; - - return $user; -} - -function makeUnifiedPatientService(?PatientService $patientService = null): UnifiedPatientService -{ - return new UnifiedPatientService($patientService ?? app(PatientService::class)); -} - -it('returns only today recipients and current in-department patients for plan and emergency', function () { - $service = app(PatientService::class); - $dateRange = reportDateRange('2026-04-08 06:00:00', '2026-04-09 06:00:00'); - - DB::table('stt_medicalhistory')->insert([ - [ - 'MedicalHistoryID' => 1, - 'rf_EmerSignID' => 1, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-08 08:00:00', - 'DateExtract' => '1900-01-01 00:00:00', - ], - [ - 'MedicalHistoryID' => 2, - 'rf_EmerSignID' => 1, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-07 08:00:00', - 'DateExtract' => '1900-01-01 00:00:00', - ], - [ - 'MedicalHistoryID' => 3, - 'rf_EmerSignID' => 1, - 'rf_kl_VisitResultID' => 1, - 'DateRecipient' => '2026-04-08 09:00:00', - 'DateExtract' => '2026-04-08 22:00:00', - ], - [ - 'MedicalHistoryID' => 4, - 'rf_EmerSignID' => 2, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-08 10:00:00', - 'DateExtract' => '1900-01-01 00:00:00', - ], - [ - 'MedicalHistoryID' => 5, - 'rf_EmerSignID' => 2, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-06 08:00:00', - 'DateExtract' => '1900-01-01 00:00:00', - ], - [ - 'MedicalHistoryID' => 6, - 'rf_EmerSignID' => 2, - 'rf_kl_VisitResultID' => 1, - 'DateRecipient' => '2026-04-08 11:00:00', - 'DateExtract' => '2026-04-08 23:00:00', - ], - [ - 'MedicalHistoryID' => 7, - 'rf_EmerSignID' => 4, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-08 12:00:00', - 'DateExtract' => '1900-01-01 00:00:00', - ], - ]); - - DB::table('stt_migrationpatient')->insert([ - [ - 'MigrationPatientID' => 1, - 'rf_MedicalHistoryID' => 1, - 'rf_StationarBranchID' => 10, - 'rf_kl_VisitResultID' => 0, - 'rf_kl_StatCureResultID' => 0, - 'DateIngoing' => '2026-04-08 08:00:00', - 'DateOut' => '1900-01-01 00:00:00', - ], - [ - 'MigrationPatientID' => 2, - 'rf_MedicalHistoryID' => 2, - 'rf_StationarBranchID' => 10, - 'rf_kl_VisitResultID' => 0, - 'rf_kl_StatCureResultID' => 0, - 'DateIngoing' => '2026-04-07 08:00:00', - 'DateOut' => '1900-01-01 00:00:00', - ], - [ - 'MigrationPatientID' => 3, - 'rf_MedicalHistoryID' => 3, - 'rf_StationarBranchID' => 10, - 'rf_kl_VisitResultID' => 1, - 'rf_kl_StatCureResultID' => 1, - 'DateIngoing' => '2026-04-08 09:00:00', - 'DateOut' => '2026-04-08 22:00:00', - ], - [ - 'MigrationPatientID' => 4, - 'rf_MedicalHistoryID' => 4, - 'rf_StationarBranchID' => 10, - 'rf_kl_VisitResultID' => 0, - 'rf_kl_StatCureResultID' => 0, - 'DateIngoing' => '2026-04-08 10:00:00', - 'DateOut' => '1900-01-01 00:00:00', - ], - [ - 'MigrationPatientID' => 5, - 'rf_MedicalHistoryID' => 5, - 'rf_StationarBranchID' => 10, - 'rf_kl_VisitResultID' => 0, - 'rf_kl_StatCureResultID' => 0, - 'DateIngoing' => '2026-04-06 08:00:00', - 'DateOut' => '1900-01-01 00:00:00', - ], - [ - 'MigrationPatientID' => 6, - 'rf_MedicalHistoryID' => 6, - 'rf_StationarBranchID' => 10, - 'rf_kl_VisitResultID' => 1, - 'rf_kl_StatCureResultID' => 1, - 'DateIngoing' => '2026-04-08 11:00:00', - 'DateOut' => '2026-04-08 23:00:00', - ], - [ - 'MigrationPatientID' => 7, - 'rf_MedicalHistoryID' => 7, - 'rf_StationarBranchID' => 10, - 'rf_kl_VisitResultID' => 0, - 'rf_kl_StatCureResultID' => 0, - 'DateIngoing' => '2026-04-08 12:00:00', - 'DateOut' => '1900-01-01 00:00:00', - ], - ]); - - $planPatients = $service->getPlanOrEmergencyPatients('plan', false, 10, $dateRange, false, false, true); - $emergencyPatients = $service->getPlanOrEmergencyPatients('emergency', false, 10, $dateRange, false, false, true); - - expect($planPatients->pluck('MedicalHistoryID')->all())->toBe([3, 1, 2]) - ->and($planPatients->where('MedicalHistoryID', 1)->first()->is_recipient_today)->toBeTrue() - ->and($planPatients->where('MedicalHistoryID', 2)->first()->is_recipient_today)->toBeFalse() - ->and($planPatients->where('MedicalHistoryID', 3)->first()->is_recipient_today)->toBeTrue() - ->and($service->getPatientsCountWithCurrent('plan', false, 10, $dateRange))->toBe(3) - ->and($emergencyPatients->pluck('MedicalHistoryID')->all())->toBe([7, 6, 4, 5]) - ->and($emergencyPatients->where('MedicalHistoryID', 6)->first()->is_recipient_today)->toBeTrue() - ->and($service->getPatientsCountWithCurrent('emergency', false, 10, $dateRange))->toBe(4); -}); - -it('treats 2222-01-01 as current hospitalization sentinel', function () { - $service = app(PatientService::class); - $dateRange = reportDateRange('2026-04-08 06:00:00', '2026-04-09 06:00:00'); - - DB::table('stt_medicalhistory')->insert([ - [ - 'MedicalHistoryID' => 31, - 'rf_EmerSignID' => 1, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-08 08:00:00', - 'DateExtract' => '2222-01-01 00:00:00', - ], - ]); - - DB::table('stt_migrationpatient')->insert([ - [ - 'MigrationPatientID' => 31, - 'rf_MedicalHistoryID' => 31, - 'rf_StationarBranchID' => 10, - 'rf_kl_VisitResultID' => 0, - 'rf_kl_StatCureResultID' => 0, - 'DateIngoing' => '2026-04-08 08:00:00', - 'DateOut' => '1900-01-01 00:00:00', - ], - ]); - - $patients = $service->getPlanOrEmergencyPatients('plan', false, 10, $dateRange, false, false, true); - - expect($patients->pluck('MedicalHistoryID')->all())->toBe([31]) - ->and($service->getPatientsCountWithCurrent('plan', false, 10, $dateRange))->toBe(1); -}); - -it('uses snapshots for head on current-day plan requests', function () { - DB::table('stt_stationarbranch')->insert([ - 'StationarBranchID' => 10, - 'rf_DepartmentID' => 100, - ]); - - $dateRange = reportDateRange('2026-04-08 06:00:00', '2026-04-09 06:00:00'); - $department = new Department; - $department->department_id = 1; - $department->rf_mis_department_id = 100; - $user = makeUser(isHead: true); - $expected = collect([(object) ['MedicalHistoryID' => 1]]); - - $patientService = \Mockery::mock(PatientService::class); - $snapshotService = \Mockery::mock(SnapshotService::class); - $snapshotService - ->shouldReceive('getPatientsFromOneDayCurrentSnapshots') - ->once() - ->with('plan', [], false, []) - ->andReturn($expected); - - $service = new ReportService( - app(DateRangeService::class), - makeUnifiedPatientService($patientService), - $patientService, - $snapshotService, - \Mockery::mock(\App\Services\StatisticsService::class) - ); - - expect($service->getPatientsByStatus($department, $user, 'plan', $dateRange))->toBe($expected); -}); - -it('uses snapshots for historical head plan requests and counts unique snapshot patients', function () { - DB::table('stt_stationarbranch')->insert([ - 'StationarBranchID' => 10, - 'rf_DepartmentID' => 100, - ]); - - DB::table('reports')->insert([ - 'report_id' => 77, - 'created_at' => '2026-04-08', - 'sent_at' => '2026-04-08 06:00:00', - 'rf_department_id' => 1, - 'rf_user_id' => 1, - 'rf_lpudoctor_id' => 1, - ]); - - DB::table('medical_history_snapshots')->insert([ - [ - 'medical_history_snapshot_id' => 1, - 'rf_report_id' => 77, - 'rf_medicalhistory_id' => 10, - 'patient_type' => 'plan', - 'patient_uid' => 'mis:10', - 'patient_source_type' => 'mis', - 'patient_kind' => 'plan', - 'full_name' => 'Patient 10', - 'created_at' => now(), - 'updated_at' => now(), - ], - [ - 'medical_history_snapshot_id' => 2, - 'rf_report_id' => 77, - 'rf_medicalhistory_id' => 10, - 'patient_type' => 'plan', - 'patient_uid' => 'mis:10', - 'patient_source_type' => 'mis', - 'patient_kind' => 'plan', - 'full_name' => 'Patient 10', - 'created_at' => now(), - 'updated_at' => now(), - ], - [ - 'medical_history_snapshot_id' => 3, - 'rf_report_id' => 77, - 'rf_medicalhistory_id' => 11, - 'patient_type' => 'plan', - 'patient_uid' => 'mis:11', - 'patient_source_type' => 'mis', - 'patient_kind' => 'plan', - 'full_name' => 'Patient 11', - 'created_at' => now(), - 'updated_at' => now(), - ], - ]); - - $dateRange = new DateRange( - startDate: Carbon::parse('2026-04-07 06:00:00', 'Asia/Yakutsk'), - endDate: Carbon::parse('2026-04-08 06:00:00', 'Asia/Yakutsk'), - startDateRaw: '2026-04-07 06:00:00', - endDateRaw: '2026-04-08 06:00:00', - isOneDay: false, - ); - $department = new Department; - $department->department_id = 1; - $department->rf_mis_department_id = 100; - $user = makeUser(isHead: true); - $expected = collect([(object) ['MedicalHistoryID' => 10]]); - - $patientService = \Mockery::mock(PatientService::class); - $snapshotService = \Mockery::mock(SnapshotService::class); - $snapshotService - ->shouldReceive('getPatientsFromSnapshots') - ->once() - ->with('plan', [77], 10, false, true, [77]) - ->andReturn($expected); - - $service = new ReportService( - app(DateRangeService::class), - makeUnifiedPatientService($patientService), - $patientService, - $snapshotService, - \Mockery::mock(\App\Services\StatisticsService::class) - ); - - expect($service->getPatientsByStatus($department, $user, 'plan', $dateRange))->toBe($expected) - ->and($service->getPatientsCountByStatus($department, $user, 'plan', $dateRange))->toBe(2); -}); - -it('filters historical head plan snapshots by latest report and marks only latest recipients', function () { - DB::table('stt_stationarbranch')->insert([ - 'StationarBranchID' => 10, - 'rf_DepartmentID' => 100, - ]); - - DB::table('reports')->insert([ - [ - 'report_id' => 76, - 'created_at' => '2026-04-07', - 'sent_at' => '2026-04-07 06:00:00', - 'rf_department_id' => 1, - 'rf_user_id' => 1, - 'rf_lpudoctor_id' => 1, - ], - [ - 'report_id' => 77, - 'created_at' => '2026-04-08', - 'sent_at' => '2026-04-08 06:00:00', - 'rf_department_id' => 1, - 'rf_user_id' => 1, - 'rf_lpudoctor_id' => 1, - ], - ]); - - DB::table('stt_medicalhistory')->insert([ - [ - 'MedicalHistoryID' => 10, - 'rf_EmerSignID' => 1, - 'rf_kl_VisitResultID' => 1, - 'DateRecipient' => '2026-04-07 08:00:00', - 'DateExtract' => '2026-04-08 12:00:00', - ], - [ - 'MedicalHistoryID' => 11, - 'rf_EmerSignID' => 1, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-07 10:00:00', - 'DateExtract' => '1900-01-01 00:00:00', - ], - [ - 'MedicalHistoryID' => 12, - 'rf_EmerSignID' => 1, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-08 08:00:00', - 'DateExtract' => '1900-01-01 00:00:00', - ], - ]); - - DB::table('medical_history_snapshots')->insert([ - [ - 'medical_history_snapshot_id' => 1, - 'rf_report_id' => 76, - 'rf_medicalhistory_id' => 10, - 'patient_type' => 'plan', - 'patient_uid' => 'mis:10', - 'patient_source_type' => 'mis', - 'patient_kind' => 'plan', - 'full_name' => 'Patient 10', - 'admitted_at' => '2026-04-07 08:00:00', - 'created_at' => now(), - 'updated_at' => now(), - ], - [ - 'medical_history_snapshot_id' => 2, - 'rf_report_id' => 77, - 'rf_medicalhistory_id' => 11, - 'patient_type' => 'plan', - 'patient_uid' => 'mis:11', - 'patient_source_type' => 'mis', - 'patient_kind' => 'plan', - 'full_name' => 'Patient 11', - 'admitted_at' => '2026-04-07 10:00:00', - 'created_at' => now(), - 'updated_at' => now(), - ], - [ - 'medical_history_snapshot_id' => 3, - 'rf_report_id' => 77, - 'rf_medicalhistory_id' => 12, - 'patient_type' => 'plan', - 'patient_uid' => 'mis:12', - 'patient_source_type' => 'mis', - 'patient_kind' => 'plan', - 'full_name' => 'Patient 12', - 'admitted_at' => '2026-04-08 08:00:00', - 'created_at' => now(), - 'updated_at' => now(), - ], - [ - 'medical_history_snapshot_id' => 4, - 'rf_report_id' => 77, - 'rf_medicalhistory_id' => 12, - 'patient_type' => 'recipient', - 'patient_uid' => 'mis:12', - 'patient_source_type' => 'mis', - 'patient_kind' => 'plan', - 'full_name' => 'Patient 12', - 'admitted_at' => '2026-04-08 08:00:00', - 'created_at' => now(), - 'updated_at' => now(), - ], - ]); - - $dateRange = new DateRange( - startDate: Carbon::parse('2026-04-07 06:00:00', 'Asia/Yakutsk'), - endDate: Carbon::parse('2026-04-08 06:00:00', 'Asia/Yakutsk'), - startDateRaw: '2026-04-07 06:00:00', - endDateRaw: '2026-04-08 06:00:00', - isOneDay: false, - ); - - $department = new Department; - $department->department_id = 1; - $department->rf_mis_department_id = 100; - - $user = makeUser(isHead: true); - $service = new ReportService( - app(DateRangeService::class), - makeUnifiedPatientService(app(PatientService::class)), - app(PatientService::class), - new SnapshotService(makeUnifiedPatientService(app(PatientService::class)), app(PatientService::class), app(DateRangeService::class)), - \Mockery::mock(\App\Services\StatisticsService::class) - ); - - $patients = $service->getPatientsByStatus($department, $user, 'plan', $dateRange); - - expect($patients->pluck('medicalHistoryId')->all())->toBe([12, 11]) - ->and($patients->firstWhere('medicalHistoryId', 12)->isRecipientToday)->toBeTrue() - ->and($patients->firstWhere('medicalHistoryId', 11)->isRecipientToday)->toBeFalse() - ->and($service->getPatientsCountByStatus($department, $user, 'plan', $dateRange))->toBe(2); -}); - -it('uses current snapshots for head one-day plan list and marks recipients separately', function () { - DB::table('stt_stationarbranch')->insert([ - 'StationarBranchID' => 10, - 'rf_DepartmentID' => 100, - ]); - - DB::table('reports')->insert([ - 'report_id' => 88, - 'created_at' => '2026-04-09', - 'sent_at' => '2026-04-09 06:00:00', - 'rf_department_id' => 1, - 'rf_user_id' => 1, - 'rf_lpudoctor_id' => 1, - ]); - - DB::table('stt_medicalhistory')->insert([ - [ - 'MedicalHistoryID' => 21, - 'rf_EmerSignID' => 1, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-08 08:00:00', - 'DateExtract' => '1900-01-01 00:00:00', - ], - [ - 'MedicalHistoryID' => 22, - 'rf_EmerSignID' => 1, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-07 08:00:00', - 'DateExtract' => '1900-01-01 00:00:00', - ], - [ - 'MedicalHistoryID' => 23, - 'rf_EmerSignID' => 2, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-08 09:00:00', - 'DateExtract' => '1900-01-01 00:00:00', - ], - ]); - - DB::table('medical_history_snapshots')->insert([ - [ - 'medical_history_snapshot_id' => 10, - 'rf_report_id' => 88, - 'rf_medicalhistory_id' => 21, - 'patient_type' => 'current', - 'patient_uid' => 'mis:21', - 'patient_source_type' => 'mis', - 'patient_kind' => 'plan', - 'full_name' => 'Patient 21', - 'admitted_at' => '2026-04-08 08:00:00', - 'created_at' => now(), - 'updated_at' => now(), - ], - [ - 'medical_history_snapshot_id' => 11, - 'rf_report_id' => 88, - 'rf_medicalhistory_id' => 22, - 'patient_type' => 'current', - 'patient_uid' => 'mis:22', - 'patient_source_type' => 'mis', - 'patient_kind' => 'plan', - 'full_name' => 'Patient 22', - 'admitted_at' => '2026-04-07 08:00:00', - 'created_at' => now(), - 'updated_at' => now(), - ], - [ - 'medical_history_snapshot_id' => 12, - 'rf_report_id' => 88, - 'rf_medicalhistory_id' => 23, - 'patient_type' => 'current', - 'patient_uid' => 'mis:23', - 'patient_source_type' => 'mis', - 'patient_kind' => 'emergency', - 'full_name' => 'Patient 23', - 'admitted_at' => '2026-04-08 09:00:00', - 'created_at' => now(), - 'updated_at' => now(), - ], - [ - 'medical_history_snapshot_id' => 13, - 'rf_report_id' => 88, - 'rf_medicalhistory_id' => 21, - 'patient_type' => 'recipient', - 'patient_uid' => 'mis:21', - 'patient_source_type' => 'mis', - 'patient_kind' => 'plan', - 'full_name' => 'Patient 21', - 'admitted_at' => '2026-04-08 08:00:00', - 'created_at' => now(), - 'updated_at' => now(), - ], - ]); - - $dateRange = reportDateRange('2026-04-08 06:00:00', '2026-04-09 06:00:00'); - $department = new Department; - $department->department_id = 1; - $department->rf_mis_department_id = 100; - - $service = new SnapshotService(makeUnifiedPatientService(app(PatientService::class)), app(PatientService::class), app(DateRangeService::class)); - $patients = $service->getPatientsFromOneDayCurrentSnapshots('plan', [88], false, [88]); - - expect($patients->pluck('medicalHistoryId')->all())->toBe([21, 22]) - ->and($patients->firstWhere('medicalHistoryId', 21)->isRecipientToday)->toBeTrue() - ->and($patients->firstWhere('medicalHistoryId', 22)->isRecipientToday)->toBeFalse() - ->and($service->getPatientsFromOneDayCurrentSnapshots('plan', [88], false, [88])->count())->toBe(2); -}); - -it('separates special contingent from mis lists while keeping it in aggregate live counters', function () { - DB::table('stt_stationarbranch')->insert([ - 'StationarBranchID' => 10, - 'rf_DepartmentID' => 100, - ]); - - DB::table('department_patients')->insert([ - [ - 'department_patient_id' => 501, - 'rf_department_id' => 1, - 'source_type' => 'special', - 'full_name' => 'Special Plan Patient', - 'birth_date' => '1990-01-01', - 'patient_kind' => 'plan', - 'admitted_at' => '2026-04-08 08:00:00', - 'is_current' => true, - 'created_at' => now(), - 'updated_at' => now(), - ], - ]); - - $dateRange = reportDateRange('2026-04-08 06:00:00', '2026-04-09 06:00:00'); - $department = new Department; - $department->department_id = 1; - $department->rf_mis_department_id = 100; - $user = makeUser(); - - $service = new ReportService( - app(DateRangeService::class), - makeUnifiedPatientService(app(PatientService::class)), - app(PatientService::class), - new SnapshotService(makeUnifiedPatientService(app(PatientService::class)), app(PatientService::class), app(DateRangeService::class)), - \Mockery::mock(\App\Services\StatisticsService::class) - ); - - expect($service->getPatientsByStatus($department, $user, 'mis-plan', $dateRange)->pluck('id')->all())->toBe([]) - ->and($service->getPatientsCountByStatus($department, $user, 'mis-plan', $dateRange))->toBe(0) - ->and($service->getPatientsByStatus($department, $user, 'special-plan', $dateRange)->pluck('id')->all())->toBe(['manual:501']) - ->and($service->getPatientsCountByStatus($department, $user, 'special-plan', $dateRange))->toBe(1) - ->and($service->getPatientsByStatus($department, $user, 'plan', $dateRange)->pluck('id')->all())->toBe(['manual:501']) - ->and($service->getPatientsCountByStatus($department, $user, 'plan', $dateRange))->toBe(1); -}); - -it('separates special contingent from mis lists in snapshot mode', function () { - DB::table('stt_stationarbranch')->insert([ - 'StationarBranchID' => 10, - 'rf_DepartmentID' => 100, - ]); - - DB::table('reports')->insert([ - 'report_id' => 91, - 'created_at' => '2026-04-08', - 'sent_at' => '2026-04-08 06:00:00', - 'rf_department_id' => 1, - 'rf_user_id' => 1, - 'rf_lpudoctor_id' => 1, - ]); - - DB::table('medical_history_snapshots')->insert([ - [ - 'medical_history_snapshot_id' => 201, - 'rf_report_id' => 91, - 'rf_medicalhistory_id' => 10, - 'patient_type' => 'plan', - 'patient_uid' => 'mis:10', - 'patient_source_type' => 'mis', - 'patient_kind' => 'plan', - 'full_name' => 'Mis Patient', - 'admitted_at' => '2026-04-08 08:00:00', - 'is_manual' => false, - 'created_at' => now(), - 'updated_at' => now(), - ], - [ - 'medical_history_snapshot_id' => 202, - 'rf_report_id' => 91, - 'rf_department_patient_id' => 601, - 'patient_type' => 'plan', - 'patient_uid' => 'manual:601', - 'patient_source_type' => 'special', - 'patient_kind' => 'plan', - 'full_name' => 'Special Patient', - 'admitted_at' => '2026-04-08 09:00:00', - 'is_manual' => true, - 'created_at' => now(), - 'updated_at' => now(), - ], - ]); - - $dateRange = new DateRange( - startDate: Carbon::parse('2026-04-07 06:00:00', 'Asia/Yakutsk'), - endDate: Carbon::parse('2026-04-08 06:00:00', 'Asia/Yakutsk'), - startDateRaw: '2026-04-07 06:00:00', - endDateRaw: '2026-04-08 06:00:00', - isOneDay: false, - ); - $department = new Department; - $department->department_id = 1; - $department->rf_mis_department_id = 100; - $user = makeUser(isHead: true); - - $service = new ReportService( - app(DateRangeService::class), - makeUnifiedPatientService(app(PatientService::class)), - app(PatientService::class), - new SnapshotService(makeUnifiedPatientService(app(PatientService::class)), app(PatientService::class), app(DateRangeService::class)), - \Mockery::mock(\App\Services\StatisticsService::class) - ); - - expect($service->getPatientsByStatus($department, $user, 'mis-plan', $dateRange)->pluck('id')->all())->toBe(['mis:10']) - ->and($service->getPatientsCountByStatus($department, $user, 'mis-plan', $dateRange))->toBe(1) - ->and($service->getPatientsByStatus($department, $user, 'special-plan', $dateRange)->pluck('id')->all())->toBe(['manual:601']) - ->and($service->getPatientsCountByStatus($department, $user, 'special-plan', $dateRange))->toBe(1) - ->and($service->getPatientsByStatus($department, $user, 'plan', $dateRange)->pluck('id')->all())->toBe(['manual:601', 'mis:10']) - ->and($service->getPatientsCountByStatus($department, $user, 'plan', $dateRange))->toBe(2); -}); - -it('keeps operations for snapshot patients with medical history ids', function () { - DB::table('medical_history_snapshots')->insert([ - [ - 'medical_history_snapshot_id' => 401, - 'rf_report_id' => 91, - 'rf_medicalhistory_id' => 10, - 'patient_type' => 'plan', - 'patient_uid' => 'mis:10', - 'patient_source_type' => 'mis', - 'patient_kind' => 'plan', - 'full_name' => 'Mis Patient', - 'admitted_at' => '2026-04-08 08:00:00', - 'is_manual' => false, - 'created_at' => now(), - 'updated_at' => now(), - ], - ]); - - DB::table('stt_medicalhistory')->insert([ - 'MedicalHistoryID' => 10, - 'rf_EmerSignID' => 1, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-08 08:00:00', - 'DateExtract' => '1900-01-01 00:00:00', - ]); - - DB::table('stt_surgicaloperation')->insert([ - 'SurgicalOperationID' => 501, - 'rf_MedicalHistoryID' => 10, - 'rf_StationarBranchID' => 10, - 'rf_kl_ServiceMedicalID' => 77, - 'Date' => '2026-04-08 10:00:00', - ]); - - DB::table('stt_operationpurpose')->insert([ - 'OperationPurposeID' => 501, - 'rf_SurgicalOperationID' => 501, - 'rf_OperationStatusID' => 3, - ]); - - DB::table('oms_servicemedical')->insert([ - 'ServiceMedicalID' => 77, - ]); - - $service = new SnapshotService( - makeUnifiedPatientService(app(PatientService::class)), - app(PatientService::class), - app(DateRangeService::class) - ); - - $patients = $service->getPatientsFromSnapshots('plan', [91]); - - expect($patients)->toHaveCount(1) - ->and($patients->first()->operations)->toHaveCount(1); -}); - -it('keeps operations for replica patients on live report requests', function () { - DB::table('stt_stationarbranch')->insert([ - 'StationarBranchID' => 10, - 'rf_DepartmentID' => 100, - ]); - - DB::table('stt_medicalhistory')->insert([ - [ - 'MedicalHistoryID' => 41, - 'rf_EmerSignID' => 1, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-08 08:00:00', - 'DateExtract' => '1900-01-01 00:00:00', - ], - ]); - - DB::table('stt_migrationpatient')->insert([ - [ - 'MigrationPatientID' => 41, - 'rf_MedicalHistoryID' => 41, - 'rf_StationarBranchID' => 10, - 'rf_kl_VisitResultID' => 0, - 'rf_kl_StatCureResultID' => 0, - 'DateIngoing' => '2026-04-08 08:00:00', - 'DateOut' => '1900-01-01 00:00:00', - ], - ]); - - DB::table('stt_surgicaloperation')->insert([ - 'SurgicalOperationID' => 601, - 'rf_MedicalHistoryID' => 41, - 'rf_StationarBranchID' => 10, - 'rf_kl_ServiceMedicalID' => 88, - 'Date' => '2026-04-08 11:00:00', - ]); - - DB::table('stt_operationpurpose')->insert([ - 'OperationPurposeID' => 601, - 'rf_SurgicalOperationID' => 601, - 'rf_OperationStatusID' => 3, - ]); - - DB::table('oms_servicemedical')->insert([ - 'ServiceMedicalID' => 88, - ]); - - $dateRange = reportDateRange('2026-04-08 06:00:00', '2026-04-09 06:00:00'); - $department = new Department; - $department->department_id = 1; - $department->rf_mis_department_id = 100; - $user = makeUser(); - - $service = new ReportService( - app(DateRangeService::class), - makeUnifiedPatientService(app(PatientService::class)), - app(PatientService::class), - new SnapshotService(makeUnifiedPatientService(app(PatientService::class)), app(PatientService::class), app(DateRangeService::class)), - \Mockery::mock(\App\Services\StatisticsService::class) - ); - - $patients = $service->getPatientsByStatus($department, $user, 'mis-plan', $dateRange); - - expect($patients)->toHaveCount(1) - ->and($patients->first()->medicalHistoryId)->toBe(41) - ->and($patients->first()->operations)->toHaveCount(1); -}); - -it('keeps completed operations in patient rows even if operation date is outside report range', function () { - DB::table('stt_stationarbranch')->insert([ - 'StationarBranchID' => 10, - 'rf_DepartmentID' => 100, - ]); - - DB::table('stt_medicalhistory')->insert([ - 'MedicalHistoryID' => 42, - 'rf_EmerSignID' => 1, - 'rf_kl_VisitResultID' => 0, - 'DateRecipient' => '2026-04-08 08:00:00', - 'DateExtract' => '1900-01-01 00:00:00', - ]); - - DB::table('stt_migrationpatient')->insert([ - 'MigrationPatientID' => 42, - 'rf_MedicalHistoryID' => 42, - 'rf_StationarBranchID' => 10, - 'rf_kl_VisitResultID' => 0, - 'rf_kl_StatCureResultID' => 0, - 'DateIngoing' => '2026-04-08 08:00:00', - 'DateOut' => '1900-01-01 00:00:00', - ]); - - DB::table('stt_surgicaloperation')->insert([ - 'SurgicalOperationID' => 602, - 'rf_MedicalHistoryID' => 42, - 'rf_StationarBranchID' => 10, - 'rf_kl_ServiceMedicalID' => 89, - 'Date' => '2026-04-07 12:00:00', - ]); - - DB::table('stt_operationpurpose')->insert([ - 'OperationPurposeID' => 602, - 'rf_SurgicalOperationID' => 602, - 'rf_OperationStatusID' => 3, - ]); - - DB::table('oms_servicemedical')->insert([ - 'ServiceMedicalID' => 89, - ]); - - $dateRange = reportDateRange('2026-04-08 06:00:00', '2026-04-09 06:00:00'); - $department = new Department; - $department->department_id = 1; - $department->rf_mis_department_id = 100; - $user = makeUser(); - - $service = new ReportService( - app(DateRangeService::class), - makeUnifiedPatientService(app(PatientService::class)), - app(PatientService::class), - new SnapshotService(makeUnifiedPatientService(app(PatientService::class)), app(PatientService::class), app(DateRangeService::class)), - \Mockery::mock(\App\Services\StatisticsService::class) - ); - - $patients = $service->getPatientsByStatus($department, $user, 'mis-plan', $dateRange); - - expect($patients)->toHaveCount(1) - ->and($patients->first()->medicalHistoryId)->toBe(42) - ->and($patients->first()->operations)->toHaveCount(1); -}); diff --git a/tests/Feature/Reports/EloquentReportRepositoryTest.php b/tests/Feature/Reports/EloquentReportRepositoryTest.php deleted file mode 100644 index 730960d..0000000 --- a/tests/Feature/Reports/EloquentReportRepositoryTest.php +++ /dev/null @@ -1,150 +0,0 @@ -id(); - $table->string('name')->nullable(); - $table->string('login')->nullable(); - $table->string('password')->nullable(); - $table->timestamps(); - }); - - Schema::create('departments', function (Blueprint $table) { - $table->id('department_id'); - $table->string('name_full')->nullable(); - $table->string('name_short')->nullable(); - $table->integer('rf_mis_department_id')->nullable(); - $table->integer('rf_department_type')->nullable(); - }); - - Schema::create('department_metrika_defaults', function (Blueprint $table) { - $table->id(); - $table->unsignedBigInteger('rf_department_id'); - $table->unsignedBigInteger('rf_metrika_item_id'); - $table->string('value')->nullable(); - }); - - Schema::create('reports', function (Blueprint $table) { - $table->id('report_id'); - $table->dateTime('created_at'); - $table->dateTime('sent_at')->nullable(); - $table->unsignedBigInteger('rf_department_id'); - $table->unsignedBigInteger('rf_user_id')->nullable(); - $table->unsignedBigInteger('rf_lpudoctor_id')->nullable(); - $table->dateTime('period_start')->nullable(); - $table->dateTime('period_end')->nullable(); - $table->string('status')->default('draft'); - }); - - Schema::create('metrika_results', function (Blueprint $table) { - $table->id('metrika_result_id'); - $table->unsignedBigInteger('rf_report_id'); - $table->unsignedBigInteger('rf_metrika_item_id'); - $table->string('value')->nullable(); - }); - - Schema::create('observation_patients', function (Blueprint $table) { - $table->id('observation_patient_id'); - $table->unsignedBigInteger('rf_report_id')->nullable(); - $table->unsignedBigInteger('rf_department_id')->nullable(); - $table->unsignedBigInteger('rf_medicalhistory_id')->nullable(); - $table->unsignedBigInteger('rf_department_patient_id')->nullable(); - $table->text('comment')->nullable(); - }); - - Schema::create('unwanted_events', function (Blueprint $table) { - $table->id('unwanted_event_id'); - $table->unsignedBigInteger('rf_report_id')->nullable(); - $table->text('comment')->nullable(); - $table->string('title')->nullable(); - $table->boolean('is_visible')->default(true); - $table->timestamps(); - }); - - DB::table('users')->insert([ - 'id' => 15, - 'name' => 'Doctor', - 'login' => 'doc', - 'password' => 'secret', - 'created_at' => now(), - 'updated_at' => now(), - ]); - - DB::table('departments')->insert([ - 'department_id' => 10, - 'name_full' => 'Department', - 'name_short' => 'Dept', - 'rf_mis_department_id' => 100, - ]); - - DB::table('department_metrika_defaults')->insert([ - 'rf_department_id' => 10, - 'rf_metrika_item_id' => 1, - 'value' => '30', - ]); -}); - -afterEach(function () { - \Mockery::close(); -}); - -it('saves report snapshot idempotently through eloquent repository', function () { - $adapter = \Mockery::mock(LegacyReportServiceAdapter::class); - $adapter->shouldReceive('prepareMemoryForHeavySave')->twice(); - $adapter->shouldReceive('createPatientSnapshots')->twice(); - $adapter->shouldReceive('syncCalculatedMetrics')->twice(); - $adapter->shouldReceive('saveLethalMetricFromSnapshots')->twice(); - $adapter->shouldReceive('clearCacheAfterReportCreation')->twice(); - - $repository = new EloquentReportRepository($adapter); - - $snapshot = new ReportSnapshot( - departmentId: 10, - userId: 5015, - actorUserId: 15, - periodStart: new DateTimeImmutable('2026-04-08 06:00:00'), - periodEnd: new DateTimeImmutable('2026-04-09 06:00:00'), - status: 'draft', - metrics: [4 => 11], - observationPatients: [['medical_history_id' => 100, 'comment' => 'watch']], - unwantedEvents: [['title' => 'event', 'comment' => 'test', 'is_visible' => true]], - ); - - $first = $repository->save($snapshot); - $second = $repository->save(new ReportSnapshot( - departmentId: 10, - userId: 5015, - actorUserId: 15, - periodStart: new DateTimeImmutable('2026-04-08 06:00:00'), - periodEnd: new DateTimeImmutable('2026-04-09 06:00:00'), - status: 'draft', - metrics: [4 => 12], - observationPatients: [['medical_history_id' => 100, 'comment' => 'watch-2']], - unwantedEvents: [['title' => 'event-2', 'comment' => 'test-2', 'is_visible' => true]], - reportId: $first->reportId, - )); - - expect($first->reportId)->toBe($second->reportId) - ->and(DB::table('reports')->count())->toBe(1) - ->and(DB::table('metrika_results')->where('rf_report_id', $first->reportId)->where('rf_metrika_item_id', 4)->value('value'))->toBe('12') - ->and(DB::table('observation_patients')->where('rf_report_id', $first->reportId)->value('comment'))->toBe('watch-2'); -}); diff --git a/tests/Unit/ExampleTest.php b/tests/Unit/ExampleTest.php deleted file mode 100644 index 44a4f33..0000000 --- a/tests/Unit/ExampleTest.php +++ /dev/null @@ -1,5 +0,0 @@ -toBeTrue(); -}); diff --git a/tests/Unit/Reports/BedDaysCalculatorTest.php b/tests/Unit/Reports/BedDaysCalculatorTest.php deleted file mode 100644 index c212bc1..0000000 --- a/tests/Unit/Reports/BedDaysCalculatorTest.php +++ /dev/null @@ -1,38 +0,0 @@ -calculate([ - new StayInterval( - startAt: new DateTimeImmutable('2026-04-01 10:00:00'), - endAt: new DateTimeImmutable('2026-04-04 09:00:00'), - ), - new StayInterval( - startAt: new DateTimeImmutable('2026-04-05 10:00:00'), - endAt: new DateTimeImmutable('2026-04-07 09:00:00'), - ), - ]); - - expect($result->total)->toBe(5) - ->and($result->count)->toBe(2) - ->and($result->average)->toBe(2.5); -}); - -it('ignores invalid bed day intervals', function () { - $calculator = new BedDaysCalculator; - - $result = $calculator->calculate([ - new StayInterval( - startAt: new DateTimeImmutable('2026-04-04 10:00:00'), - endAt: new DateTimeImmutable('2026-04-01 09:00:00'), - ), - ]); - - expect($result->total)->toBe(0) - ->and($result->count)->toBe(0) - ->and($result->average)->toBe(0.0); -}); diff --git a/tests/Unit/Reports/CompareLegacyAndNewReportUseCaseTest.php b/tests/Unit/Reports/CompareLegacyAndNewReportUseCaseTest.php deleted file mode 100644 index 0e73a66..0000000 --- a/tests/Unit/Reports/CompareLegacyAndNewReportUseCaseTest.php +++ /dev/null @@ -1,47 +0,0 @@ - 10, - 'userId' => 5015, - 'dates' => [1744063200, 1744149600], - 'metrics' => ['metrika_item_4' => 11], - 'observationPatients' => [], - 'unwantedEvents' => [], - ], - persistedReportId: 55, - ); - - $snapshot = new ReportSnapshot( - departmentId: 10, - userId: 5015, - actorUserId: 15, - periodStart: new DateTimeImmutable('2026-04-08 06:00:00'), - periodEnd: new DateTimeImmutable('2026-04-09 06:00:00'), - metrics: [4 => 11], - ); - - $repository = \Mockery::mock(ReportRepository::class); - $repository->shouldReceive('findSnapshot')->once()->with(55)->andReturn($snapshot); - - $adapter = \Mockery::mock(LegacyReportServiceAdapter::class); - $adapter->shouldReceive('buildSnapshotFromInput')->once()->with($input)->andReturn($snapshot); - - $result = (new CompareLegacyAndNewReportUseCase($repository, $adapter))->handle($input); - - expect($result->status)->toBe('matched') - ->and($result->diff)->toBe([]); -}); diff --git a/tests/Unit/Reports/DepartmentLoadCalculatorTest.php b/tests/Unit/Reports/DepartmentLoadCalculatorTest.php deleted file mode 100644 index cadbf9b..0000000 --- a/tests/Unit/Reports/DepartmentLoadCalculatorTest.php +++ /dev/null @@ -1,15 +0,0 @@ -calculate(27, 30))->toBe(90); -}); - -it('returns zero when beds count is zero', function () { - $calculator = new DepartmentLoadCalculator; - - expect($calculator->calculate(27, 0))->toBe(0); -}); diff --git a/tests/Unit/Reports/GenerateReportUseCaseTest.php b/tests/Unit/Reports/GenerateReportUseCaseTest.php deleted file mode 100644 index 6b5f30e..0000000 --- a/tests/Unit/Reports/GenerateReportUseCaseTest.php +++ /dev/null @@ -1,92 +0,0 @@ - [ - 'departmentId' => $context->departmentId, - 'userId' => $context->userId, - 'dates' => [$context->periodStart->getTimestamp(), $context->periodEnd->getTimestamp()], - 'status' => 'submitted', - 'metrics' => ['metrika_item_4' => 11], - 'observationPatients' => [], - 'unwantedEvents' => [], - ], - ]); - } - }; - - $snapshot = new ReportSnapshot( - departmentId: 10, - userId: 5015, - actorUserId: 15, - periodStart: new DateTimeImmutable('2026-04-08 06:00:00'), - periodEnd: new DateTimeImmutable('2026-04-09 06:00:00'), - status: 'submitted', - autoFill: true, - metrics: [4 => 11], - ); - - $repository = \Mockery::mock(ReportRepository::class); - $repository->shouldReceive('save') - ->once() - ->andReturn(new SavedReportResult(88, $snapshot)); - - $repository->shouldReceive('findSnapshot') - ->once() - ->with(88) - ->andReturn($snapshot); - - $adapter = \Mockery::mock(LegacyReportServiceAdapter::class); - $adapter->shouldReceive('buildSnapshotFromInput') - ->once() - ->andReturn($snapshot); - - $comparator = new CompareLegacyAndNewReportUseCase($repository, $adapter); - - $auditLogger = \Mockery::mock(AuditLogger::class); - $auditLogger->shouldReceive('logComparison')->once(); - - $useCase = new GenerateReportUseCase( - reportRepository: $repository, - auditLogger: $auditLogger, - comparator: $comparator, - patientSource: $patientSource, - calculators: [], - compareBeforeCutover: true, - ); - - $result = $useCase->handle($input); - - expect($result->reportId)->toBe(88) - ->and($result->usedNewArchitecture)->toBeTrue() - ->and($result->comparison?->status)->toBe('matched') - ->and($result->comparison?->diff)->toBe([]) - ->and($result->comparison?->reportId)->toBe(88); -}); diff --git a/tests/Unit/Reports/MetrikaConfigTest.php b/tests/Unit/Reports/MetrikaConfigTest.php deleted file mode 100644 index 7d53ce7..0000000 --- a/tests/Unit/Reports/MetrikaConfigTest.php +++ /dev/null @@ -1,28 +0,0 @@ - 7, - 4 => 11, - 'invalid' => 100, - '15' => 3, - ]); - - expect($normalized)->toBe([ - 4 => 11, - 12 => 7, - 15 => 3, - ]); -}); - -it('converts normalized metrics back to payload keys', function () { - expect(MetrikaConfig::toPayloadMetrics([ - 4 => 11, - 12 => 7, - ]))->toBe([ - 'metrika_item_4' => 11, - 'metrika_item_12' => 7, - ]); -}); diff --git a/tests/Unit/Reports/PreoperativeDaysCalculatorTest.php b/tests/Unit/Reports/PreoperativeDaysCalculatorTest.php deleted file mode 100644 index 2962003..0000000 --- a/tests/Unit/Reports/PreoperativeDaysCalculatorTest.php +++ /dev/null @@ -1,38 +0,0 @@ -calculate([ - new OperationInterval( - admittedAt: new DateTimeImmutable('2026-04-01 10:00:00'), - operationAt: new DateTimeImmutable('2026-04-03 09:00:00'), - ), - new OperationInterval( - admittedAt: new DateTimeImmutable('2026-04-05 10:00:00'), - operationAt: new DateTimeImmutable('2026-04-06 09:00:00'), - ), - ]); - - expect($result->total)->toBe(3) - ->and($result->count)->toBe(2) - ->and($result->average)->toBe(1.5); -}); - -it('ignores invalid preoperative intervals', function () { - $calculator = new PreoperativeDaysCalculator; - - $result = $calculator->calculate([ - new OperationInterval( - admittedAt: new DateTimeImmutable('2026-04-03 10:00:00'), - operationAt: new DateTimeImmutable('2026-04-01 09:00:00'), - ), - ]); - - expect($result->total)->toBe(0) - ->and($result->count)->toBe(0) - ->and($result->average)->toBe(0.0); -}); diff --git a/tests/Unit/Reports/ReportInputFactoryTest.php b/tests/Unit/Reports/ReportInputFactoryTest.php deleted file mode 100644 index e99be19..0000000 --- a/tests/Unit/Reports/ReportInputFactoryTest.php +++ /dev/null @@ -1,58 +0,0 @@ -id = 15; - - $factory = new ReportInputFactory(app(DateRangeService::class)); - - $input = $factory->forManualSave($user, [ - 'departmentId' => 10, - 'userId' => 5015, - 'dates' => [1744063200, 1744149600], - 'metrics' => ['metrika_item_4' => 11], - 'observationPatients' => [['id' => 100]], - 'unwantedEvents' => [['title' => 'A']], - 'status' => 'draft', - 'reportId' => 55, - ]); - - expect($input->departmentId)->toBe(10) - ->and($input->userId)->toBe(5015) - ->and($input->actorUserId)->toBe(15) - ->and($input->reportId)->toBe(55) - ->and($input->metrics)->toBe(['metrika_item_4' => 11]) - ->and($input->rawPayload['actorUserId'])->toBe(15); -}); - -it('builds auto fill generate report input from scoped user and date range', function () { - $user = new User; - $user->id = 15; - $user->rf_lpudoctor_id = 5015; - - $department = new Department; - $department->department_id = 10; - - $dateRange = new DateRange( - startDate: Carbon::parse('2026-04-08 06:00:00', 'Asia/Yakutsk'), - endDate: Carbon::parse('2026-04-09 06:00:00', 'Asia/Yakutsk'), - startDateRaw: '2026-04-08 06:00:00', - endDateRaw: '2026-04-09 06:00:00', - isOneDay: true, - ); - - $factory = new ReportInputFactory(app(DateRangeService::class)); - $input = $factory->forAutoFill($user, $department, $dateRange); - - expect($input->autoFill)->toBeTrue() - ->and($input->status)->toBe('submitted') - ->and($input->departmentId)->toBe(10) - ->and($input->userId)->toBe(5015); -}); diff --git a/tests/Unit/Reports/ReportPatientsReadServiceTest.php b/tests/Unit/Reports/ReportPatientsReadServiceTest.php deleted file mode 100644 index 957e5ca..0000000 --- a/tests/Unit/Reports/ReportPatientsReadServiceTest.php +++ /dev/null @@ -1,148 +0,0 @@ -forceFill([ - 'department_id' => 100, - 'rf_mis_department_id' => 200, - ]); - $user = \Mockery::mock(User::class); - $dateRange = new DateRange( - Carbon::parse('2026-04-08 06:00:00'), - Carbon::parse('2026-04-09 06:00:00'), - '2026-04-08 06:00:00', - '2026-04-09 06:00:00', - true, - ); - - $snapshotPatients = collect([ - (object) ['id' => 'mis:10', 'sourceType' => 'mis'], - (object) ['id' => 'manual:501', 'sourceType' => 'manual'], - ]); - - $unifiedPatientService = \Mockery::mock(UnifiedPatientService::class); - $snapshotService = \Mockery::mock(SnapshotService::class); - $contextResolver = \Mockery::mock(ReportReadContextResolver::class); - - $contextResolver->shouldReceive('resolveBranchId') - ->once() - ->with($department) - ->andReturn(10); - $contextResolver->shouldReceive('shouldUseReplicaForLiveStatus') - ->once() - ->with($user, 'plan', $dateRange) - ->andReturn(false); - $contextResolver->shouldReceive('shouldUseSnapshots') - ->once() - ->with($department, $dateRange, false) - ->andReturn(true); - $contextResolver->shouldReceive('getReportsForDateRange') - ->once() - ->with(100, $dateRange) - ->andReturn(collect([(object) ['report_id' => 91]])); - $contextResolver->shouldReceive('getRecipientReportIds') - ->once() - ->with([91]) - ->andReturn([91]); - - $snapshotService->shouldReceive('getPatientsFromOneDayCurrentSnapshots') - ->once() - ->with('plan', [91], false, [91]) - ->andReturn($snapshotPatients); - - $service = new ReportPatientsReadService( - unifiedPatientService: $unifiedPatientService, - snapshotService: $snapshotService, - contextResolver: $contextResolver, - ); - - $patientIds = $service->getPatientsByStatus($department, $user, 'mis-plan', $dateRange, true); - - expect($patientIds)->toBeInstanceOf(Collection::class) - ->and($patientIds->all())->toBe(['mis:10']); -}); - -it('always reads reanimation patients from replica sources', function () { - $department = (new Department())->forceFill([ - 'department_id' => 100, - 'rf_mis_department_id' => 200, - ]); - $user = \Mockery::mock(User::class); - $dateRange = new DateRange( - Carbon::parse('2026-04-08 06:00:00'), - Carbon::parse('2026-04-09 06:00:00'), - '2026-04-08 06:00:00', - '2026-04-09 06:00:00', - true, - ); - - $expected = collect([(object) ['id' => 'mis:55']]); - - $unifiedPatientService = \Mockery::mock(UnifiedPatientService::class); - $snapshotService = \Mockery::mock(SnapshotService::class); - $contextResolver = \Mockery::mock(ReportReadContextResolver::class); - - $contextResolver->shouldReceive('resolveBranchId') - ->once() - ->with($department) - ->andReturn(10); - - $unifiedPatientService->shouldReceive('getLivePatientsByStatus') - ->once() - ->with($department, $user, 'reanimation', $dateRange, 10, false, true) - ->andReturn($expected); - - $service = new ReportPatientsReadService( - unifiedPatientService: $unifiedPatientService, - snapshotService: $snapshotService, - contextResolver: $contextResolver, - ); - - expect($service->getPatientsByStatus($department, $user, 'reanimation', $dateRange))->toBe($expected); -}); - -it('counts scoped replica patients through unified patient service', function () { - $department = (new Department())->forceFill([ - 'department_id' => 100, - 'rf_mis_department_id' => 200, - ]); - $user = \Mockery::mock(User::class); - $dateRange = new DateRange( - Carbon::parse('2026-04-08 06:00:00'), - Carbon::parse('2026-04-09 06:00:00'), - '2026-04-08 06:00:00', - '2026-04-09 06:00:00', - true, - ); - - $unifiedPatientService = \Mockery::mock(UnifiedPatientService::class); - $snapshotService = \Mockery::mock(SnapshotService::class); - $contextResolver = \Mockery::mock(ReportReadContextResolver::class); - - $contextResolver->shouldReceive('resolveBranchId') - ->once() - ->with($department) - ->andReturn(10); - - $unifiedPatientService->shouldReceive('getLivePatientCountByStatus') - ->once() - ->with($department, $user, 'special-plan', $dateRange, 10, true) - ->andReturn(3); - - $service = new ReportPatientsReadService( - unifiedPatientService: $unifiedPatientService, - snapshotService: $snapshotService, - contextResolver: $contextResolver, - ); - - expect($service->getPatientsCountByStatus($department, $user, 'special-plan', $dateRange))->toBe(3); -}); diff --git a/tests/Unit/Reports/ReportSnapshotTest.php b/tests/Unit/Reports/ReportSnapshotTest.php deleted file mode 100644 index c72db76..0000000 --- a/tests/Unit/Reports/ReportSnapshotTest.php +++ /dev/null @@ -1,36 +0,0 @@ - 7, - 4 => 11, - ], - observationPatients: [['medical_history_id' => 100]], - unwantedEvents: [['title' => 'Event']], - ); - - expect($snapshot->normalizedMetrics())->toBe([ - 4 => 11, - 12 => 7, - ])->and($snapshot->toComparableArray()['auto_fill'])->toBeTrue(); -}); - -it('rejects invalid period ranges', function () { - new ReportSnapshot( - departmentId: 10, - userId: 5015, - actorUserId: 15, - periodStart: new DateTimeImmutable('2026-04-09 06:00:00'), - periodEnd: new DateTimeImmutable('2026-04-08 06:00:00'), - ); -})->throws(InvalidArgumentException::class); diff --git a/tests/Unit/Reports/ReportStatisticsReadServiceTest.php b/tests/Unit/Reports/ReportStatisticsReadServiceTest.php deleted file mode 100644 index c6d36bd..0000000 --- a/tests/Unit/Reports/ReportStatisticsReadServiceTest.php +++ /dev/null @@ -1,147 +0,0 @@ -forceFill([ - 'department_id' => 100, - 'rf_mis_department_id' => 200, - ]); - $user = \Mockery::mock(User::class); - $dateRange = reportStatisticsDateRange(); - - $contextResolver = \Mockery::mock(ReportReadContextResolver::class); - $contextResolver->shouldReceive('resolveBranchId') - ->once() - ->with($department) - ->andReturn(null); - - $service = new ReportStatisticsReadService( - unifiedPatientService: \Mockery::mock(UnifiedPatientService::class), - patientService: \Mockery::mock(PatientService::class), - snapshotService: \Mockery::mock(SnapshotService::class), - contextResolver: $contextResolver, - calculatedMetricsSynchronizer: \Mockery::mock(CalculatedMetricsSynchronizer::class), - ); - - expect($service->getReportStatistics($department, $user, $dateRange))->toMatchArray([ - 'recipientCount' => 0, - 'extractCount' => 0, - 'currentCount' => 0, - 'deadCount' => 0, - 'surgicalCount' => [0, 0], - 'recipientIds' => [], - 'percentDead' => 0, - 'beds' => 0, - ]); -}); - -it('reads live report statistics from replica when snapshots are not active', function () { - $department = (new Department())->forceFill([ - 'department_id' => 100, - 'rf_mis_department_id' => 200, - ]); - $department->setRelation('metrikaDefault', collect([ - (object) ['rf_metrika_item_id' => 1, 'value' => 42], - ])); - - $user = \Mockery::mock(User::class); - $dateRange = reportStatisticsDateRange(); - - $contextResolver = \Mockery::mock(ReportReadContextResolver::class); - $contextResolver->shouldReceive('resolveBranchId') - ->once() - ->with($department) - ->andReturn(10); - $contextResolver->shouldReceive('shouldUseSnapshots') - ->once() - ->with($department, $dateRange) - ->andReturn(false); - - $unifiedPatientService = \Mockery::mock(UnifiedPatientService::class); - $unifiedPatientService->shouldReceive('getLivePatientCountByStatus') - ->once() - ->with($department, $user, 'plan', $dateRange, 10, true) - ->andReturn(7); - $unifiedPatientService->shouldReceive('getLivePatientCountByStatus') - ->once() - ->with($department, $user, 'emergency', $dateRange, 10, true) - ->andReturn(5); - $unifiedPatientService->shouldReceive('getLivePatientCountByStatus') - ->once() - ->with($department, $user, 'current', $dateRange, 10) - ->andReturn(30); - $unifiedPatientService->shouldReceive('getLivePatientCountByStatus') - ->once() - ->with($department, $user, 'recipient', $dateRange, 10) - ->andReturn(4); - $unifiedPatientService->shouldReceive('getLivePatientCountByStatus') - ->once() - ->with($department, $user, 'outcome', $dateRange, 10) - ->andReturn(8); - $unifiedPatientService->shouldReceive('getLivePatientCountByStatus') - ->once() - ->with($department, $user, 'outcome-deceased', $dateRange, 10) - ->andReturn(2); - $unifiedPatientService->shouldReceive('getRecipientIdsForReport') - ->once() - ->with($department, $user, $dateRange, 10) - ->andReturn([11, 12]); - - $patientService = \Mockery::mock(PatientService::class); - $patientService->shouldReceive('getSurgicalPatients') - ->once() - ->with('emergency', 10, $dateRange, true) - ->andReturn(3); - $patientService->shouldReceive('getSurgicalPatients') - ->once() - ->with('plan', 10, $dateRange, true) - ->andReturn(6); - - $calculatedMetricsSynchronizer = \Mockery::mock(CalculatedMetricsSynchronizer::class); - $calculatedMetricsSynchronizer->shouldReceive('getManualSurgicalCounts') - ->once() - ->with($department, $dateRange) - ->andReturn([1, 2]); - - $service = new ReportStatisticsReadService( - unifiedPatientService: $unifiedPatientService, - patientService: $patientService, - snapshotService: \Mockery::mock(SnapshotService::class), - contextResolver: $contextResolver, - calculatedMetricsSynchronizer: $calculatedMetricsSynchronizer, - ); - - expect($service->getReportStatistics($department, $user, $dateRange))->toMatchArray([ - 'recipientCount' => 4, - 'extractCount' => 8, - 'currentCount' => 30, - 'deadCount' => 2, - 'surgicalCount' => [4, 8], - 'recipientIds' => [11, 12], - 'planCount' => 7, - 'emergencyCount' => 5, - 'percentDead' => 25.0, - 'beds' => 42, - ]); -}); - -function reportStatisticsDateRange(): DateRange -{ - return new DateRange( - Carbon::parse('2026-04-08 06:00:00'), - Carbon::parse('2026-04-09 06:00:00'), - '2026-04-08 06:00:00', - '2026-04-09 06:00:00', - true, - ); -}