a028af4bc8
Экстрактор кода страницы ловил любые 11 цифр (7/8 + телефонная группировка) без проверки, что это настоящий российский номер — со страниц-агрегаторов пролезал мусор с несуществующими кодами (227/303/453/613/761) и подписывался «городской». PhoneValidityGate между CandidateBuilder и SourceAggregator: - слой 1 (бесплатно, всегда): реестр Россвязи (phone_ranges) — нет в реестре → выкидываем; - слой 2 (платно, за флагом autopodbor.phone_dadata_enabled, по умолчанию ВЫКЛ): DaDataValidityLayer перепроверяет прошедшие реестр номера, снимает qc 2/7, под дневным бюджетом + кэш вердикта; платим только за выживших (мусор отсекается ДО ДаДаты). - fail-open при пустом реестре / сбое БД (иначе внешний catch в SiteOpener съел бы все номера); - короткие/uncertain номера не трогаем (нельзя сверить). Закрыты ОБА пути шага 2: обычный (RealCompetitorAgent) и глубокий (SiteOpener). Миграций нет — реестр уже на проде (453k диапазонов). Тесты: PhoneValidityGateTest (7), DaDataValidityLayerTest (6), SiteOpenerValidityTest (1); весь набор автоподбора 519 зелёных, Pint + Larastan чисто. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
68 lines
2.1 KiB
PHP
68 lines
2.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Services\Autopodbor\Agent\Fetch\FetchedSite;
|
|
use App\Services\Autopodbor\Agent\Fetch\Fetcher;
|
|
use App\Services\Autopodbor\Agent\Study\SiteOpener;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Tests\Concerns\SharesSupplierPdo;
|
|
|
|
uses(DatabaseTransactions::class);
|
|
uses(SharesSupplierPdo::class);
|
|
|
|
function seedOpenerRange(): void
|
|
{
|
|
$importId = (int) DB::table('phone_ranges_imports')->insertGetId([
|
|
'source_url' => 'https://rossvyaz.gov.ru/test',
|
|
'checksum_sha256' => str_repeat('c', 64),
|
|
'status' => 'completed',
|
|
'imported_at' => now(),
|
|
]);
|
|
|
|
DB::table('phone_ranges')->insert([
|
|
'def_code' => 391,
|
|
'from_num' => 2000000,
|
|
'to_num' => 2999999,
|
|
'operator' => 'Ростелеком',
|
|
'region' => 'Красноярский край',
|
|
'subject_code' => 24,
|
|
'imported_at' => now(),
|
|
'import_id' => $importId,
|
|
]);
|
|
}
|
|
|
|
/** Fetcher, отдающий фиксированный HTML. */
|
|
function openerFetcher(string $html): Fetcher
|
|
{
|
|
return new class($html) implements Fetcher
|
|
{
|
|
public function __construct(private string $html) {}
|
|
|
|
public function site(string $url): FetchedSite
|
|
{
|
|
return new FetchedSite($url, $this->html);
|
|
}
|
|
|
|
public function directory(string $url): array
|
|
{
|
|
return [];
|
|
}
|
|
};
|
|
}
|
|
|
|
it('глубокий путь: мусорный номер (код вне реестра) не попадает в numbers', function (): void {
|
|
seedOpenerRange(); // есть только 391 2000000..2999999
|
|
|
|
// Настоящий 73912920000 (391) + мусор 76132306130 (код 613, вне реестра).
|
|
$html = '<a href="tel:+73912920000">звонок</a>'
|
|
.' <span>+7 613 230 61 30</span>';
|
|
|
|
$r = (new SiteOpener(openerFetcher($html)))->open('kraslombard24.ru', '391');
|
|
|
|
$numbers = collect($r->numbers)->pluck('number');
|
|
expect($numbers)->toContain('73912920000')
|
|
->and($numbers)->not->toContain('76132306130');
|
|
});
|