create(); $user = User::factory()->create(['tenant_id' => $tenant->id]); DB::statement('SET app.current_tenant_id = '.$tenant->id); $run = AutopodborRun::create(['tenant_id' => $tenant->id, 'kind' => 'search', 'status' => 'done', 'region_code' => 16, 'params' => []]); $field = AutopodborCompetitor::create([ 'tenant_id' => $tenant->id, 'search_run_id' => $run->id, 'study_run_id' => $run->id, 'studied_at' => now(), 'name' => 'Яричъ', 'box' => 'field', 'site_url' => 'yarich.ru', 'dedup_key' => 'site:yarich.ru', ]); $oldSrc = AutopodborSource::create([ 'tenant_id' => $tenant->id, 'competitor_id' => $field->id, 'study_run_id' => $run->id, 'signal_type' => 'site', 'identifier' => 'yarich.ru', 'box' => 'field', 'dedup_key' => 'site:yarich.ru', ]); return [$tenant, $user, $run, $field, $oldSrc]; } it('actualize add — новый сайт заводится источником, старый цел', function () { [$tenant, $user, $run, $field, $oldSrc] = actualizeSetup(); $resp = $this->actingAs($user)->postJson("/api/autopodbor/competitors/{$field->id}/actualize", [ 'action' => 'add', 'new_site' => 'https://www.Yarich-New.ru/contacts', ])->assertOk(); $new = AutopodborSource::find($resp->json('source_id')); expect($new)->not->toBeNull() ->and($new->signal_type)->toBe('site') ->and($new->identifier)->toBe('yarich-new.ru') // нормализован ->and($new->box)->toBe('field'); // старый сайт-источник не тронут (оба сайта живут) expect($oldSrc->fresh()->box)->toBe('field'); }); it('actualize replace без активного проекта — старый сайт в архив, новый заводится', function () { [$tenant, $user, $run, $field, $oldSrc] = actualizeSetup(); $resp = $this->actingAs($user)->postJson("/api/autopodbor/competitors/{$field->id}/actualize", [ 'action' => 'replace', 'new_site' => 'yarich-new.ru', ])->assertOk(); expect($oldSrc->fresh()->box)->toBe('archived'); // старый умер — в архив $new = AutopodborSource::find($resp->json('source_id')); expect($new->identifier)->toBe('yarich-new.ru')->and($new->box)->toBe('field'); }); it('actualize replace при активном проекте по старому сайту — 409 manage_via_project', function () { [$tenant, $user, $run, $field, $oldSrc] = actualizeSetup(); $project = Project::factory()->create(['tenant_id' => $tenant->id, 'is_active' => true, 'preflight_blocked_at' => null]); $oldSrc->update(['created_project_id' => $project->id]); $this->actingAs($user)->postJson("/api/autopodbor/competitors/{$field->id}/actualize", [ 'action' => 'replace', 'new_site' => 'yarich-new.ru', ])->assertStatus(409)->assertJsonPath('error', 'manage_via_project'); // ничего не тронуто — управлять надо через проект expect($oldSrc->fresh()->box)->toBe('field'); }); it('actualize чужой тенант — 404', function () { [$tenant, $user, $run, $field, $oldSrc] = actualizeSetup(); $other = User::factory()->create(['tenant_id' => Tenant::factory()->create()->id]); $this->actingAs($other)->postJson("/api/autopodbor/competitors/{$field->id}/actualize", [ 'action' => 'add', 'new_site' => 'x.ru', ])->assertStatus(404); }); it('GET /proposals — actualize-карточка несёт matched с текущими сайтами фирмы', function () { $tenant = Tenant::factory()->create(); $user = User::factory()->create(['tenant_id' => $tenant->id]); DB::statement('SET app.current_tenant_id = '.$tenant->id); $run = AutopodborRun::create(['tenant_id' => $tenant->id, 'kind' => 'search', 'status' => 'done', 'region_code' => 16, 'params' => []]); // в поле: Яричъ, сайт yarich.ru, карточка 2ГИС 111 $field = AutopodborCompetitor::create([ 'tenant_id' => $tenant->id, 'search_run_id' => $run->id, 'study_run_id' => $run->id, 'studied_at' => now(), 'name' => 'Яричъ', 'box' => 'field', 'site_url' => 'yarich.ru', 'directory_urls' => ['https://2gis.ru/x/firm/111'], 'dedup_key' => 'site:yarich.ru', ]); // предложение: та же карточка 2ГИС 111, но новый сайт → на актуализацию AutopodborCompetitor::create([ 'tenant_id' => $tenant->id, 'search_run_id' => $run->id, 'name' => 'Яричъ (нашли заново)', 'box' => 'proposal', 'site_url' => 'yarich-new.ru', 'directory_urls' => ['https://2gis.ru/y/firm/111'], 'dedup_key' => 'site:yarich-new.ru', ]); $resp = $this->actingAs($user)->getJson('/api/autopodbor/proposals')->assertOk(); $resp->assertJsonPath('groups.actualize.0.matched_id', $field->id) ->assertJsonPath('groups.actualize.0.matched.name', 'Яричъ'); expect(collect($resp->json('groups.actualize.0.matched.sites')))->toContain('yarich.ru'); });