put('supplier:session', [ 'phpsessid' => 'test', 'csrf' => 'test', ], now()->addHour()); config(['services.supplier.portal_url' => 'https://crm.bp-gr.ru']); }); it('AjaxProjectChannel implements SupplierProjectChannel', function (): void { expect(app(AjaxProjectChannel::class))->toBeInstanceOf(SupplierProjectChannel::class); }); it('createProject delegates to SupplierPortalClient::saveProject and returns external id', function (): void { Http::fake([ 'crm.bp-gr.ru/admin/visit/rt-project-save' => Http::response( ['status' => 'OK', 'message' => '', 'result' => null, 'id' => '700777'], 200, ), ]); $dto = new SupplierProjectDto( platform: 'B1', signalType: 'site', uniqueKey: 'foo.com', limit: 5, workdays: [1, 2, 3], regions: [], regionsReverse: false, status: 'active', ); $id = app(AjaxProjectChannel::class)->createProject($dto); expect($id)->toBe(700777); }); it('updateProject delegates to SupplierPortalClient::updateProject with id:N', function (): void { Http::fake([ 'crm.bp-gr.ru/admin/visit/rt-project-save' => Http::response( ['status' => 'OK', 'message' => '', 'result' => null, 'id' => '700777'], 200, ), ]); $dto = new SupplierProjectDto( platform: 'B1', signalType: 'site', uniqueKey: 'foo.com', limit: 10, workdays: [1], regions: [], regionsReverse: false, status: 'active', ); app(AjaxProjectChannel::class)->updateProject(700777, $dto); Http::assertSent(fn ($r) => $r['id'] === 700777); }); it('listProjects normalizes raw rt-rows to channel contract (platform/signal_type/unique_key)', function (): void { // Сырая форма портала (verified 2026-05-19): конверт {projects:[...]}, // строка {id, name:"B_", type, content}. Адаптер маппит в контракт. Http::fake([ 'crm.bp-gr.ru/admin/visit/rt-projects-load*' => Http::response([ 'projects' => [ ['id' => '700001', 'name' => 'B1_okna.ru', 'type' => 'hosts', 'content' => 'okna.ru'], ['id' => '700002', 'name' => 'B3_79991112233', 'type' => 'calls', 'content' => '79991112233'], ['id' => '700003', 'name' => 'noPrefix', 'type' => 'sms', 'content' => 'KEYWORD'], ], ], 200), ]); $list = app(AjaxProjectChannel::class)->listProjects(); expect($list)->toHaveCount(3); expect($list[0]['platform'])->toBe('B1'); expect($list[0]['signal_type'])->toBe('site'); expect($list[0]['unique_key'])->toBe('okna.ru'); expect($list[0]['id'])->toBe('700001'); // сырое поле сохранено expect($list[1]['platform'])->toBe('B3'); expect($list[1]['signal_type'])->toBe('call'); expect($list[1]['unique_key'])->toBe('79991112233'); // name без B_ префикса → platform null (контракт не ломается) expect($list[2]['platform'])->toBeNull(); expect($list[2]['signal_type'])->toBe('sms'); expect($list[2]['unique_key'])->toBe('KEYWORD'); });