ec6bdbfb19
GET/PATCH /api/sales/warming/{platform}, GET .../firms, POST .../toggle
и .../assign заменяют общую /api/sales/ad-audience*; настройки и статус
площадки читаются из sales_ad_audience_platforms, членство фирмы —
по ch_yandex/ch_vk/ch_mts. Метод channels() (массовый мультивыбор)
убран — заменён точечным toggle. Неизвестная площадка → 404 через
platformOr404() в контроллере (не через route whereIn — иначе
непойманный сегмент проваливается в Route::fallback).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
100 lines
3.6 KiB
PHP
100 lines
3.6 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
use App\Models\SalesAdAudienceFirm;
|
||
use App\Models\SalesAdAudiencePlatform;
|
||
use App\Models\SalesUser;
|
||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||
use Tests\Concerns\SharesSupplierPdo;
|
||
|
||
/**
|
||
* API «Реклама на кандидатов» по площадкам (Task 4+5 плана трёх площадок).
|
||
*
|
||
* Одна общая ручка /api/sales/ad-audience разъезжается на три:
|
||
* /api/sales/warming/{yandex|vk|mts}. Настройки и статус — построчно
|
||
* в sales_ad_audience_platforms; days/сроки воронки пока общие
|
||
* (sales_ad_audience_state). Членство фирмы в площадке — булевы
|
||
* ch_yandex/ch_vk/ch_mts на sales_ad_audience_firms.
|
||
*
|
||
* Аутентификация — как в AdAudienceScreenTest: SalesUser::create() + actingAs('sales')
|
||
* (у SalesUser нет HasFactory/factory()).
|
||
*/
|
||
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
|
||
|
||
function actingHead(): SalesUser
|
||
{
|
||
$head = SalesUser::create([
|
||
'name' => 'Начальник '.uniqid(),
|
||
'email' => 'warminghead'.uniqid().'@sales.local',
|
||
'password' => bcrypt('secret'),
|
||
'role' => 'head',
|
||
'is_active' => true,
|
||
]);
|
||
test()->actingAs($head, 'sales');
|
||
|
||
return $head;
|
||
}
|
||
|
||
it('отдаёт настройки именно запрошенной площадки', function () {
|
||
actingHead();
|
||
SalesAdAudiencePlatform::forCode('vk')->update(['status' => 'waiting_volume']);
|
||
|
||
test()->getJson('/api/sales/warming/vk')
|
||
->assertOk()
|
||
->assertJsonPath('data.platform', 'vk')
|
||
->assertJsonPath('data.min_phones', 2000)
|
||
->assertJsonPath('data.status', 'waiting_volume');
|
||
});
|
||
|
||
it('неизвестную площадку отвергает', function () {
|
||
actingHead();
|
||
|
||
test()->getJson('/api/sales/warming/facebook')->assertNotFound();
|
||
});
|
||
|
||
it('рубильник пишется в строку площадки', function () {
|
||
actingHead();
|
||
|
||
test()->patchJson('/api/sales/warming/vk', ['enabled' => true])->assertOk();
|
||
|
||
expect(SalesAdAudiencePlatform::forCode('vk')->enabled)->toBeTrue();
|
||
});
|
||
|
||
it('менеджеру доступ закрыт', function () {
|
||
$m = SalesUser::create([
|
||
'name' => 'Менеджер '.uniqid(),
|
||
'email' => 'warmingmgr'.uniqid().'@sales.local',
|
||
'password' => bcrypt('secret'),
|
||
'role' => 'manager',
|
||
'is_active' => true,
|
||
]);
|
||
test()->actingAs($m, 'sales');
|
||
|
||
test()->getJson('/api/sales/warming/yandex')->assertForbidden();
|
||
});
|
||
|
||
it('в список площадки попадают только её подписанные фирмы', function () {
|
||
actingHead();
|
||
|
||
SalesAdAudienceFirm::create(['firm_name' => 'Только Яндекс', 'ch_yandex' => true]);
|
||
SalesAdAudienceFirm::create(['firm_name' => 'Только ВК', 'ch_vk' => true]);
|
||
|
||
test()->getJson('/api/sales/warming/vk/firms')
|
||
->assertOk()
|
||
->assertJsonCount(1, 'firms')
|
||
->assertJsonPath('firms.0.firm_name', 'Только ВК');
|
||
});
|
||
|
||
it('переключатель добавляет и убирает фирму с площадки', function () {
|
||
actingHead();
|
||
|
||
$firm = SalesAdAudienceFirm::create(['firm_name' => 'Плавающая', 'ch_vk' => false]);
|
||
|
||
test()->postJson("/api/sales/warming/vk/firms/{$firm->id}/toggle", ['on' => true])->assertOk();
|
||
expect($firm->fresh()->ch_vk)->toBeTrue();
|
||
|
||
test()->postJson("/api/sales/warming/vk/firms/{$firm->id}/toggle", ['on' => false])->assertOk();
|
||
expect($firm->fresh()->ch_vk)->toBeFalse();
|
||
});
|