6d48503a0e
Stage 1: опознавалка фирмы по сайту/карточкам, ProposalClassifier new/actualize/archived/hidden, box=archived, bulk удалить всех ранее удалённых. Backend 249/249, front autopodbor 61/61. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
73 lines
3.1 KiB
PHP
73 lines
3.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services\Autopodbor;
|
|
|
|
/**
|
|
* Делит находки-предложения относительно состояния клиента (поле/предложения/архив) на группы
|
|
* (спека §3): new / actualize / archived / hidden. «Та же фирма» — по пересечению опознавалок
|
|
* {@see CompetitorIdentity} (сайт+карточки, имя не участвует).
|
|
*/
|
|
final class ProposalClassifier
|
|
{
|
|
public function __construct(private readonly CompetitorIdentity $identity) {}
|
|
|
|
/**
|
|
* @param array<int, array{id:int,name?:string,site_url?:?string,directory_urls?:array}> $finds
|
|
* @param array<int, array{id:int,box:string,name?:string,site_url?:?string,directory_urls?:array}> $existing
|
|
* @return list<array{find:array,group:string,matched_id:?int,delta_keys:list<string>}>
|
|
*/
|
|
public function classify(array $finds, array $existing): array
|
|
{
|
|
// Индекс: ключ-опознавалка → список [existing_id, активна ли] (для приоритета активного).
|
|
$index = [];
|
|
$keysById = [];
|
|
foreach ($existing as $e) {
|
|
$keys = $this->identity->keys($e);
|
|
$keysById[$e['id']] = $keys;
|
|
$active = $e['box'] !== 'archived';
|
|
foreach ($keys as $k) {
|
|
$index[$k][] = ['id' => $e['id'], 'active' => $active];
|
|
}
|
|
}
|
|
|
|
$out = [];
|
|
foreach ($finds as $find) {
|
|
$findKeys = $this->identity->keys($find);
|
|
|
|
// Первое активное и первое архивное совпадение по общим ключам.
|
|
$matchActive = null;
|
|
$matchArchived = null;
|
|
foreach ($findKeys as $k) {
|
|
foreach ($index[$k] ?? [] as $hit) {
|
|
if ($hit['active'] && $matchActive === null) {
|
|
$matchActive = $hit['id'];
|
|
}
|
|
if (! $hit['active'] && $matchArchived === null) {
|
|
$matchArchived = $hit['id'];
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($matchActive !== null) {
|
|
// Дельта = ключи находки, которых нет у совпавшей активной фирмы.
|
|
$have = array_flip($keysById[$matchActive] ?? []);
|
|
$delta = array_values(array_filter($findKeys, static fn (string $k): bool => ! isset($have[$k])));
|
|
$out[] = [
|
|
'find' => $find,
|
|
'group' => $delta === [] ? 'hidden' : 'actualize',
|
|
'matched_id' => $matchActive,
|
|
'delta_keys' => $delta,
|
|
];
|
|
} elseif ($matchArchived !== null) {
|
|
$out[] = ['find' => $find, 'group' => 'archived', 'matched_id' => $matchArchived, 'delta_keys' => []];
|
|
} else {
|
|
$out[] = ['find' => $find, 'group' => 'new', 'matched_id' => null, 'delta_keys' => []];
|
|
}
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
}
|