9fce28fda8
Для застройщиков, которые сидят только в Яндексе. По каждому номеру ищем в
Яндекс.Картах, но список рыхлый — поэтому КАЖДУЮ карточку открываем и оставляем
только те, где искомый номер реально есть. Это отсекает «Похожие места рядом»,
рекламу и рыхлые совпадения по бренду. Оба справочника объединяются
(CompositePhoneReverse), дубли по домену схлопываются.
Переиспользована готовая механика Яндекса: render-yandex-list.cjs (список) +
DirectoryParser::parseYandexCard (карточка). Браузерные адаптеры за интерфейсами
(YandexPhoneSearch/YandexCardReader) — логика TDD-ится на фейках; порог общей
линии считается по подтверждённым карточкам.
За отдельным тумблером AUTOPODBOR_PHONE_REVERSE_YANDEX (по умолчанию ВЫКЛ,
требует phone_reverse). Юнит 267/267, feature 150/150. План и находки —
docs/superpowers/{plans,findings}/2026-07-05-*.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
94 lines
4.3 KiB
PHP
94 lines
4.3 KiB
PHP
<?php
|
|
|
|
use App\Services\Autopodbor\Agent\Study\Yandex\YandexCardReader;
|
|
use App\Services\Autopodbor\Agent\Study\Yandex\YandexPhoneSearch;
|
|
use App\Services\Autopodbor\Agent\Study\YandexPhoneReverseExpander;
|
|
|
|
function fakeSearch(array $map): YandexPhoneSearch
|
|
{
|
|
return new class($map) implements YandexPhoneSearch
|
|
{
|
|
public function __construct(private array $map) {}
|
|
|
|
public function candidates(string $yandexSlug, string $phoneDigits): array
|
|
{
|
|
return $this->map[$phoneDigits] ?? [];
|
|
}
|
|
};
|
|
}
|
|
|
|
function fakeCards(array $map): YandexCardReader
|
|
{
|
|
return new class($map) implements YandexCardReader
|
|
{
|
|
public function __construct(private array $map) {}
|
|
|
|
public function read(string $cardUrl): ?array
|
|
{
|
|
return $this->map[$cardUrl] ?? null;
|
|
}
|
|
};
|
|
}
|
|
|
|
it('оставляет только карточку, где искомый номер РЕАЛЬНО есть (отсекает похожие/рыхлые)', function () {
|
|
$search = fakeSearch(['73912179941' => [
|
|
['name' => 'СМ.Сити', 'card_url' => 'https://yandex.ru/maps/org/sm/1/'],
|
|
['name' => 'Похожее СпецСтрой', 'card_url' => 'https://yandex.ru/maps/org/spec/2/'],
|
|
['name' => 'СМ Сити Капитанская', 'card_url' => 'https://yandex.ru/maps/org/smk/3/'],
|
|
]]);
|
|
$cards = fakeCards([
|
|
'https://yandex.ru/maps/org/sm/1/' => ['phones' => ['73912179941'], 'site' => 'https://sm-city.ru'],
|
|
'https://yandex.ru/maps/org/spec/2/' => ['phones' => ['73912990000'], 'site' => 'https://specstroy.ru'],
|
|
'https://yandex.ru/maps/org/smk/3/' => ['phones' => ['73912749569'], 'site' => 'https://smk.ru'],
|
|
]);
|
|
|
|
$exp = new YandexPhoneReverseExpander($search, $cards);
|
|
$res = $exp->expand('', ['73912179941'], [], '62/krasnoyarsk');
|
|
|
|
$domains = array_column($res->sites, 'domain');
|
|
expect($domains)->toContain('sm-city.ru')
|
|
->and($domains)->not->toContain('specstroy.ru')
|
|
->and($domains)->not->toContain('smk.ru');
|
|
});
|
|
|
|
it('пустой yandexSlug → разворот невозможен, пусто', function () {
|
|
$exp = new YandexPhoneReverseExpander(fakeSearch([]), fakeCards([]));
|
|
$res = $exp->expand('', ['73912179941'], [], '');
|
|
expect($res->sites)->toBe([])->and($res->phones)->toBe([]);
|
|
});
|
|
|
|
it('порог общей линии — если подтверждённых карточек больше порога, номер общий, пропускаем', function () {
|
|
$cands = [];
|
|
$cardsMap = [];
|
|
foreach (range(1, 5) as $i) {
|
|
$u = "https://yandex.ru/maps/org/o$i/$i/";
|
|
$cands[] = ['name' => "O$i", 'card_url' => $u];
|
|
$cardsMap[$u] = ['phones' => ['78001234567'], 'site' => "https://o$i.ru"];
|
|
}
|
|
$exp = new YandexPhoneReverseExpander(fakeSearch(['78001234567' => $cands]), fakeCards($cardsMap), crowdedCap: 4);
|
|
$res = $exp->expand('', ['78001234567'], [], '62/krasnoyarsk');
|
|
expect($res->sites)->toBe([]);
|
|
});
|
|
|
|
it('уже известный домен фирмы не повторяет', function () {
|
|
$search = fakeSearch(['73912179941' => [['name' => 'СМ', 'card_url' => 'https://yandex.ru/maps/org/sm/1/']]]);
|
|
$cards = fakeCards(['https://yandex.ru/maps/org/sm/1/' => ['phones' => ['73912179941'], 'site' => 'https://sm-city.ru']]);
|
|
$exp = new YandexPhoneReverseExpander($search, $cards);
|
|
$res = $exp->expand('', ['73912179941'], ['sm-city.ru'], '62/krasnoyarsk');
|
|
expect(array_column($res->sites, 'domain'))->not->toContain('sm-city.ru');
|
|
});
|
|
|
|
it('цепочка: телефон найденной карточки разворачивается дальше', function () {
|
|
$search = fakeSearch([
|
|
'73912179941' => [['name' => 'A', 'card_url' => 'https://yandex.ru/maps/org/a/1/']],
|
|
'73912000002' => [['name' => 'B', 'card_url' => 'https://yandex.ru/maps/org/b/2/']],
|
|
]);
|
|
$cards = fakeCards([
|
|
'https://yandex.ru/maps/org/a/1/' => ['phones' => ['73912179941', '73912000002'], 'site' => 'https://a.ru'],
|
|
'https://yandex.ru/maps/org/b/2/' => ['phones' => ['73912000002'], 'site' => 'https://b-proekt.ru'],
|
|
]);
|
|
$exp = new YandexPhoneReverseExpander($search, $cards);
|
|
$res = $exp->expand('', ['73912179941'], [], '62/krasnoyarsk');
|
|
expect(array_column($res->sites, 'domain'))->toContain('b-proekt.ru');
|
|
});
|