161 lines
6.9 KiB
PHP
161 lines
6.9 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
use App\Models\SalesAdAudienceFirm;
|
||
use App\Models\SalesAdAudiencePlatform;
|
||
use App\Models\SalesAdAudienceState;
|
||
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() (у SalesUser
|
||
* нет HasFactory/factory()) + $this->actingAs(..., 'sales'). Паттерн $this->
|
||
* (не test()->) — чтобы larastan понимал тип TestCase.
|
||
*/
|
||
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
|
||
|
||
function warmingHead(): SalesUser
|
||
{
|
||
return SalesUser::create([
|
||
'name' => 'Начальник '.uniqid(),
|
||
'email' => 'warminghead'.uniqid().'@sales.local',
|
||
'password' => bcrypt('secret'),
|
||
'role' => 'head',
|
||
'is_active' => true,
|
||
]);
|
||
}
|
||
|
||
function warmingManager(): SalesUser
|
||
{
|
||
return SalesUser::create([
|
||
'name' => 'Менеджер '.uniqid(),
|
||
'email' => 'warmingmgr'.uniqid().'@sales.local',
|
||
'password' => bcrypt('secret'),
|
||
'role' => 'manager',
|
||
'is_active' => true,
|
||
]);
|
||
}
|
||
|
||
it('отдаёт настройки именно запрошенной площадки', function () {
|
||
SalesAdAudiencePlatform::forCode('vk')->update(['status' => 'waiting_volume']);
|
||
|
||
$this->actingAs(warmingHead(), 'sales')
|
||
->getJson('/api/sales/warming/vk')
|
||
->assertOk()
|
||
->assertJsonPath('data.platform', 'vk')
|
||
->assertJsonPath('data.min_phones', 2000)
|
||
->assertJsonPath('data.status', 'waiting_volume');
|
||
});
|
||
|
||
it('неизвестную площадку отвергает', function () {
|
||
$this->actingAs(warmingHead(), 'sales')
|
||
->getJson('/api/sales/warming/facebook')
|
||
->assertNotFound();
|
||
});
|
||
|
||
it('рубильник пишется в строку площадки', function () {
|
||
$this->actingAs(warmingHead(), 'sales')
|
||
->patchJson('/api/sales/warming/vk', ['enabled' => true])
|
||
->assertOk();
|
||
|
||
expect(SalesAdAudiencePlatform::forCode('vk')->enabled)->toBeTrue();
|
||
});
|
||
|
||
it('менеджеру доступ закрыт', function () {
|
||
$this->actingAs(warmingManager(), 'sales')
|
||
->getJson('/api/sales/warming/yandex')
|
||
->assertForbidden();
|
||
});
|
||
|
||
it('на вкладке площадки виден ВЕСЬ список фирм, отметка отражает подписку', function () {
|
||
SalesAdAudienceFirm::create(['firm_name' => 'Только Яндекс', 'ch_yandex' => true, 'ch_vk' => false]);
|
||
SalesAdAudienceFirm::create(['firm_name' => 'Только ВК', 'ch_yandex' => false, 'ch_vk' => true]);
|
||
|
||
// Состав одинаков на всех вкладках (синхронизирован по Яндексу): на вкладке ВК
|
||
// видны ОБЕ фирмы, а отметка ch_vk у каждой отражает подписку именно на ВК.
|
||
$resp = $this->actingAs(warmingHead(), 'sales')
|
||
->getJson('/api/sales/warming/vk/firms')
|
||
->assertOk()
|
||
->assertJsonCount(2, 'firms');
|
||
|
||
$firms = collect($resp->json('firms'))->keyBy('firm_name');
|
||
expect($firms['Только ВК']['ch_vk'])->toBeTrue()
|
||
->and($firms['Только Яндекс']['ch_vk'])->toBeFalse();
|
||
});
|
||
|
||
it('переключатель добавляет и убирает фирму с площадки', function () {
|
||
$firm = SalesAdAudienceFirm::create(['firm_name' => 'Плавающая', 'ch_vk' => false]);
|
||
$head = warmingHead();
|
||
|
||
$this->actingAs($head, 'sales')
|
||
->postJson("/api/sales/warming/vk/firms/{$firm->id}/toggle", ['on' => true])
|
||
->assertOk();
|
||
expect($firm->fresh()->ch_vk)->toBeTrue();
|
||
|
||
$this->actingAs($head, 'sales')
|
||
->postJson("/api/sales/warming/vk/firms/{$firm->id}/toggle", ['on' => false])
|
||
->assertOk();
|
||
expect($firm->fresh()->ch_vk)->toBeFalse();
|
||
});
|
||
|
||
it('отдаёт ВСЕ фирмы прогрева, без фильтра площадки (для модуля СМС)', function () {
|
||
SalesAdAudienceFirm::create(['firm_name' => 'Только Яндекс', 'ch_yandex' => true]);
|
||
SalesAdAudienceFirm::create(['firm_name' => 'Только ВК', 'ch_vk' => true]);
|
||
SalesAdAudienceFirm::create(['firm_name' => 'Нигде', 'ch_yandex' => false, 'ch_vk' => false, 'ch_mts' => false]);
|
||
|
||
$this->actingAs(warmingHead(), 'sales')
|
||
->getJson('/api/sales/ad-audience/firms')
|
||
->assertOk()
|
||
->assertJsonCount(3, 'firms');
|
||
});
|
||
|
||
it('список всех фирм закрыт для менеджера', function () {
|
||
$this->actingAs(warmingManager(), 'sales')
|
||
->getJson('/api/sales/ad-audience/firms')
|
||
->assertForbidden();
|
||
});
|
||
|
||
it('PATCH сроков пишет в строку площадки, не в state и не в другие площадки', function () {
|
||
$head = warmingHead();
|
||
|
||
$this->actingAs($head, 'sales')
|
||
->patchJson('/api/sales/warming/yandex', ['in_work_days' => 20])
|
||
->assertOk()
|
||
->assertJsonPath('data.durations.in_work_days', 20);
|
||
|
||
expect(SalesAdAudiencePlatform::forCode('yandex')->in_work_days)->toBe(20)
|
||
->and(SalesAdAudiencePlatform::forCode('vk')->in_work_days)->toBe(14) // default, не тронут
|
||
->and(SalesAdAudiencePlatform::forCode('mts')->in_work_days)->toBe(14)
|
||
->and(SalesAdAudienceState::current()->in_work_days)->toBe(14); // state не тронут
|
||
});
|
||
|
||
it('сроки площадок независимы: yandex=20, vk=5', function () {
|
||
$head = warmingHead();
|
||
|
||
$this->actingAs($head, 'sales')->patchJson('/api/sales/warming/yandex', ['in_work_days' => 20])->assertOk();
|
||
$this->actingAs($head, 'sales')->patchJson('/api/sales/warming/vk', ['in_work_days' => 5])->assertOk();
|
||
|
||
$this->actingAs($head, 'sales')->getJson('/api/sales/warming/yandex')->assertJsonPath('data.durations.in_work_days', 20);
|
||
$this->actingAs($head, 'sales')->getJson('/api/sales/warming/vk')->assertJsonPath('data.durations.in_work_days', 5);
|
||
expect(SalesAdAudiencePlatform::forCode('yandex')->in_work_days)->toBe(20);
|
||
});
|
||
|
||
it('PATCH days пишется в строку площадки', function () {
|
||
$head = warmingHead();
|
||
$this->actingAs($head, 'sales')
|
||
->patchJson('/api/sales/warming/mts', ['days' => 45])
|
||
->assertOk()
|
||
->assertJsonPath('data.days', 45);
|
||
expect(SalesAdAudiencePlatform::forCode('mts')->days)->toBe(45);
|
||
});
|