diff --git a/app/app/Console/Commands/PhoneRangesImportCommand.php b/app/app/Console/Commands/PhoneRangesImportCommand.php index dbde4860..eeb3afa0 100644 --- a/app/app/Console/Commands/PhoneRangesImportCommand.php +++ b/app/app/Console/Commands/PhoneRangesImportCommand.php @@ -100,7 +100,10 @@ class PhoneRangesImportCommand extends Command $rows = []; foreach ($files as $file) { foreach ($this->parseFile($file) as $rec) { - $subjectCode = RussianRegions::nameToCode()[trim($rec['region'])] ?? null; + $regionNormalized = RussianRegions::canonicalRegionName($rec['region']); + $subjectCode = $regionNormalized === null + ? null + : (RussianRegions::nameToCode()[$regionNormalized] ?? null); if ($subjectCode === null && trim($rec['region']) !== '') { $unmatched[trim($rec['region'])] = true; } @@ -110,6 +113,7 @@ class PhoneRangesImportCommand extends Command 'to_num' => $rec['to_num'], 'operator' => $rec['operator'], 'region' => $rec['region'], + 'region_normalized' => $regionNormalized, 'subject_code' => $subjectCode, 'imported_at' => now(), 'import_id' => $importId, diff --git a/app/tests/Feature/Console/PhoneRangesImportCommandTest.php b/app/tests/Feature/Console/PhoneRangesImportCommandTest.php index 6ec3ad2c..a26b81f8 100644 --- a/app/tests/Feature/Console/PhoneRangesImportCommandTest.php +++ b/app/tests/Feature/Console/PhoneRangesImportCommandTest.php @@ -86,3 +86,25 @@ it('force flag bypasses idempotency note even with matching checksum', function expect(DB::table('phone_ranges_staging')->count())->toBe(3); expect(DB::table('phone_ranges')->count())->toBe(0); }); + +it('normalizes real Россвязь region formats to subject_code and fills region_normalized', function (): void { + // Форматы из реального прод-реестра (топ unmapped 02.06.2026): префикс «г. », + // pipe-сегмент региона, сокращение «обл.», перевёрнутая «Республика Удмуртская», + // и безнадёжный city-only «г.о. Тольятти». def-коды 3-значные (chk_phone_ranges_def_code 300-999). + $this->artisan('phone-ranges:import', ['--file' => base_path('tests/Fixtures/rossvyaz/messy.csv'), '--dry-run' => true]) + ->assertSuccessful(); + + $moscow = DB::selectOne('SELECT subject_code, region_normalized FROM phone_ranges_staging WHERE def_code = 495'); + $orenburg = DB::selectOne('SELECT subject_code, region_normalized FROM phone_ranges_staging WHERE def_code = 922'); + $udmurtia = DB::selectOne('SELECT subject_code, region_normalized FROM phone_ranges_staging WHERE def_code = 987'); + $togliatti = DB::selectOne('SELECT subject_code, region_normalized FROM phone_ranges_staging WHERE def_code = 902'); + + expect((int) $moscow->subject_code)->toBe(82) + ->and($moscow->region_normalized)->toBe('Москва') + ->and((int) $orenburg->subject_code)->toBe(62) + ->and($orenburg->region_normalized)->toBe('Оренбургская область') + ->and((int) $udmurtia->subject_code)->toBe(21) + ->and($udmurtia->region_normalized)->toBe('Удмуртская Республика') + ->and($togliatti->subject_code)->toBeNull() + ->and($togliatti->region_normalized)->toBeNull(); +}); diff --git a/app/tests/fixtures/rossvyaz/messy.csv b/app/tests/fixtures/rossvyaz/messy.csv new file mode 100644 index 00000000..03ecca1a --- /dev/null +++ b/app/tests/fixtures/rossvyaz/messy.csv @@ -0,0 +1,5 @@ +АВС/ DEF;От;До;Емкость;Оператор;Регион +495;2000000;2009999;10000;ОАО МГТС;г. Москва +922;1000000;1099999;100000;ПАО Ростелеком;г. Оренбург|Оренбургская обл. +987;5000000;5099999;100000;ПАО Ростелеком;г. Ижевск|Республика Удмуртская +902;7000000;7009999;10000;ООО Оператор;г.о. Тольятти