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>
138 lines
6.5 KiB
PHP
138 lines
6.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Jobs\Autopodbor\RunAutopodborSearchJob;
|
|
use App\Models\AutopodborCompetitor;
|
|
use App\Models\AutopodborRun;
|
|
use App\Models\SystemSetting;
|
|
use App\Models\Tenant;
|
|
use App\Models\User;
|
|
use App\Services\Autopodbor\Agent\CompetitorAgent;
|
|
use App\Services\Autopodbor\Agent\Dto\FindCompetitorsRequest;
|
|
use App\Services\Autopodbor\Agent\Dto\FindCompetitorsResult;
|
|
use App\Services\Autopodbor\Agent\Dto\ResolveByNameRequest;
|
|
use App\Services\Autopodbor\Agent\Dto\ResolveByNameResult;
|
|
use App\Services\Autopodbor\Agent\Dto\StudyCompetitorRequest;
|
|
use App\Services\Autopodbor\Agent\Dto\StudyCompetitorResult;
|
|
use App\Services\Autopodbor\Agent\FakeCompetitorAgent;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use Tests\Concerns\SharesSupplierPdo;
|
|
|
|
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
|
|
|
|
/** Подставной агент: findCompetitors отдаёт заданный список; study/resolve — из заглушки. */
|
|
function agentReturning(array $competitors): CompetitorAgent
|
|
{
|
|
return new class($competitors) implements CompetitorAgent
|
|
{
|
|
private FakeCompetitorAgent $inner;
|
|
|
|
public function __construct(private array $competitors)
|
|
{
|
|
$this->inner = new FakeCompetitorAgent;
|
|
}
|
|
|
|
public function findCompetitors(FindCompetitorsRequest $r): FindCompetitorsResult
|
|
{
|
|
return new FindCompetitorsResult($this->competitors);
|
|
}
|
|
|
|
public function studyCompetitor(StudyCompetitorRequest $r): StudyCompetitorResult
|
|
{
|
|
return $this->inner->studyCompetitor($r);
|
|
}
|
|
|
|
public function resolveByName(ResolveByNameRequest $r): ResolveByNameResult
|
|
{
|
|
return $this->inner->resolveByName($r);
|
|
}
|
|
};
|
|
}
|
|
|
|
function groupsTestSettings(): void
|
|
{
|
|
SystemSetting::updateOrCreate(['key' => 'autopodbor_price_search_rub'], ['value' => '300', 'type' => 'decimal']);
|
|
SystemSetting::updateOrCreate(['key' => 'autopodbor_max_competitors'], ['value' => '15', 'type' => 'int']);
|
|
}
|
|
|
|
function mkSearchRun(int $tenantId): AutopodborRun
|
|
{
|
|
return AutopodborRun::create([
|
|
'tenant_id' => $tenantId, 'kind' => 'search', 'status' => 'queued', 'region_code' => 16,
|
|
'params' => ['examples' => [], 'about_self' => ['ломбард'], 'include_federal' => false],
|
|
]);
|
|
}
|
|
|
|
it('находка, совпавшая с АРХИВОМ, сохраняется в предложения (не прячется на записи)', function () {
|
|
Mail::fake();
|
|
$tenant = Tenant::factory()->create(['balance_rub' => '100000.00']);
|
|
DB::statement('SET app.current_tenant_id = '.$tenant->id);
|
|
groupsTestSettings();
|
|
|
|
// В архиве — ранее удалённый «Яричъ» с сайтом yarich.ru
|
|
AutopodborCompetitor::create([
|
|
'tenant_id' => $tenant->id, 'name' => 'Яричъ', 'origin' => 'auto', 'box' => 'archived',
|
|
'site_url' => 'yarich.ru', 'dedup_key' => 'site:yarich.ru',
|
|
]);
|
|
|
|
app()->bind(CompetitorAgent::class, fn () => agentReturning([
|
|
['name' => 'Яричъ', 'site_url' => 'yarich.ru', 'description' => 'ломбард', 'is_federal' => false,
|
|
'directory_urls' => [], 'relevance_pct' => 90, 'provenance' => []],
|
|
]));
|
|
|
|
$run = mkSearchRun($tenant->id);
|
|
app()->call([new RunAutopodborSearchJob($run->id), 'handle']);
|
|
|
|
expect(AutopodborCompetitor::where('tenant_id', $tenant->id)->where('box', 'proposal')->where('name', 'Яричъ')->exists())
|
|
->toBeTrue();
|
|
});
|
|
|
|
it('находка — полный дубль АКТИВНОЙ фирмы поля — на записи выкидывается (пусто)', function () {
|
|
Mail::fake();
|
|
$tenant = Tenant::factory()->create(['balance_rub' => '100000.00']);
|
|
DB::statement('SET app.current_tenant_id = '.$tenant->id);
|
|
groupsTestSettings();
|
|
|
|
AutopodborCompetitor::create([
|
|
'tenant_id' => $tenant->id, 'name' => 'Яричъ', 'origin' => 'auto', 'box' => 'field',
|
|
'site_url' => 'yarich.ru', 'dedup_key' => 'site:yarich.ru',
|
|
]);
|
|
|
|
app()->bind(CompetitorAgent::class, fn () => agentReturning([
|
|
['name' => 'Яричъ', 'site_url' => 'yarich.ru', 'description' => 'ломбард', 'is_federal' => false,
|
|
'directory_urls' => [], 'relevance_pct' => 90, 'provenance' => []],
|
|
]));
|
|
|
|
$run = mkSearchRun($tenant->id);
|
|
app()->call([new RunAutopodborSearchJob($run->id), 'handle']);
|
|
|
|
expect(AutopodborCompetitor::where('tenant_id', $tenant->id)->where('box', 'proposal')->exists())->toBeFalse()
|
|
->and($run->fresh()->status)->toBe('empty');
|
|
});
|
|
|
|
it('GET /proposals раскладывает по группам; bulk убирает всю группу «ранее удалённые»', function () {
|
|
$tenant = Tenant::factory()->create();
|
|
$user = User::factory()->create(['tenant_id' => $tenant->id]);
|
|
DB::statement('SET app.current_tenant_id = '.$tenant->id);
|
|
|
|
// в поле — Alpha (a.ru); в архиве — Beta (b.ru)
|
|
AutopodborCompetitor::create(['tenant_id' => $tenant->id, 'name' => 'Alpha', 'origin' => 'auto', 'box' => 'field', 'site_url' => 'a.ru', 'dedup_key' => 'site:a.ru']);
|
|
AutopodborCompetitor::create(['tenant_id' => $tenant->id, 'name' => 'Beta', 'origin' => 'auto', 'box' => 'archived', 'site_url' => 'b.ru', 'dedup_key' => 'site:b.ru']);
|
|
// предложения: Gamma (новый), «Beta заново» (совпал с архивом b.ru → ранее удалён)
|
|
$new = AutopodborCompetitor::create(['tenant_id' => $tenant->id, 'name' => 'Gamma', 'origin' => 'auto', 'box' => 'proposal', 'site_url' => 'g.ru', 'dedup_key' => 'site:g.ru']);
|
|
$del = AutopodborCompetitor::create(['tenant_id' => $tenant->id, 'name' => 'Beta заново', 'origin' => 'auto', 'box' => 'proposal', 'site_url' => 'b.ru', 'dedup_key' => 'site:b.ru']);
|
|
|
|
$groups = $this->actingAs($user)->getJson('/api/autopodbor/proposals')->assertOk()->json('groups');
|
|
expect($groups['new'][0]['name'])->toBe('Gamma')
|
|
->and($groups['archived'][0]['name'])->toBe('Beta заново');
|
|
|
|
// bulk: убрать всю группу «ранее удалённые»
|
|
$this->actingAs($user)->postJson('/api/autopodbor/proposals/dismiss-archived')->assertOk();
|
|
|
|
expect(AutopodborCompetitor::find($del->id)->box)->toBe('archived') // ранее удалённый снова в архив
|
|
->and(AutopodborCompetitor::find($new->id)->box)->toBe('proposal'); // новых не трогаем
|
|
});
|