_». Строка без метки → лид от неё * приходит с project без метки → webhook пишет platform=DIRECT вместо B1/B2/B3. * * Команда возвращает метку на место. Payload собирается ИЗ ЖИВОЙ СТРОКИ кабинета * (лимит/дни/регионы/вкл-выкл — как есть), меняется ровно одно поле — name. Регионы * из кабинета уже в кодах поставщика, повторно их переводить нельзя. */ beforeEach(function (): void { Cache::store('redis')->put('supplier:session', [ 'phpsessid' => 'test-session', 'csrf' => 'test-csrf', ], now()->addHour()); config(['services.supplier.portal_url' => 'https://crm.bp-gr.ru']); }); /** @param array> $rows */ function fakeCabinet(array $rows): void { Http::fake([ 'crm.bp-gr.ru/admin/visit/rt-projects-load*' => Http::response(['projects' => $rows], 200), 'crm.bp-gr.ru/admin/visit/rt-project-save' => Http::response(['status' => 'OK', 'message' => '', 'id' => '1'], 200), ]); } /** Строка кабинета с потерянной меткой канала. */ function bareCabinetRow(string $id, string $src, string $content): array { return [ 'id' => $id, 'src' => $src, 'tag' => 'РФ', 'name' => $content, 'content' => $content, 'type' => 'calls', 'lim' => '5', 'status' => true, 'workdays' => ['1', '2', '3', '4', '5'], 'regions' => '24;66', 'regions_reverse' => false, ]; } it('dry-run: показывает строки с потерянной меткой, но НИЧЕГО не пишет в кабинет', function (): void { SupplierProject::factory()->create([ 'platform' => 'B1', 'signal_type' => 'call', 'unique_key' => '79135397707', 'supplier_external_id' => '6001', 'inactive_since' => null, ]); fakeCabinet([bareCabinetRow('6001', 'rt', '79135397707')]); $this->artisan('supplier:repair-project-names') ->expectsOutputToContain('B1_79135397707') ->assertExitCode(0); Http::assertNotSent(fn (Request $r): bool => str_contains($r->url(), 'rt-project-save')); }); it('--apply: возвращает метку канала, сохраняя лимит/дни/регионы/вкл-выкл как есть', function (): void { SupplierProject::factory()->create([ 'platform' => 'B2', 'signal_type' => 'call', 'unique_key' => '79135397707', 'supplier_external_id' => '6002', 'inactive_since' => null, ]); fakeCabinet([bareCabinetRow('6002', 'bl', '79135397707')]); $this->artisan('supplier:repair-project-names', ['--apply' => true])->assertExitCode(0); Http::assertSent(function (Request $r): bool { if (! str_contains($r->url(), 'rt-project-save')) { return false; } return $r['id'] === 6002 && $r['name'] === 'B2_79135397707' && $r['content'] === '79135397707' && $r['srcbl'] === true && $r['srcrt'] === false && $r['srcmt'] === false && $r['limit'] === 5 && $r['status'] === true && $r['workdays'] === ['1', '2', '3', '4', '5'] // Регионы из кабинета — уже коды поставщика, отдаём обратно без перевода. && $r['regions'] === [24, 66]; }); }); it('не трогает строки, у которых метка на месте, и чужие строки кабинета', function (): void { SupplierProject::factory()->create([ 'platform' => 'B1', 'signal_type' => 'call', 'unique_key' => '79135397707', 'supplier_external_id' => '6003', 'inactive_since' => null, ]); $withPrefix = bareCabinetRow('6003', 'rt', '79135397707'); $withPrefix['name'] = 'B1_79135397707'; $foreign = bareCabinetRow('9999', 'rt', 'chужой.ru'); // не наш external_id fakeCabinet([$withPrefix, $foreign]); $this->artisan('supplier:repair-project-names', ['--apply' => true])->assertExitCode(0); Http::assertNotSent(fn (Request $r): bool => str_contains($r->url(), 'rt-project-save')); }); it('--only-active: чинит только включённые у нас строки (выключенные лидов не носят)', function (): void { SupplierProject::factory()->create([ 'platform' => 'B1', 'signal_type' => 'call', 'unique_key' => '79135397707', 'supplier_external_id' => '6004', 'inactive_since' => null, ]); SupplierProject::factory()->create([ 'platform' => 'B3', 'signal_type' => 'call', 'unique_key' => '79990001122', 'supplier_external_id' => '6005', 'inactive_since' => now(), ]); fakeCabinet([ bareCabinetRow('6004', 'rt', '79135397707'), bareCabinetRow('6005', 'mt', '79990001122'), ]); $this->artisan('supplier:repair-project-names', ['--apply' => true, '--only-active' => true]) ->assertExitCode(0); Http::assertSent(fn (Request $r): bool => str_contains($r->url(), 'rt-project-save') && $r['id'] === 6004); Http::assertNotSent(fn (Request $r): bool => str_contains($r->url(), 'rt-project-save') && $r['id'] === 6005); });