128 lines
5.2 KiB
PHP
128 lines
5.2 KiB
PHP
|
|
<?php
|
|||
|
|
|
|||
|
|
declare(strict_types=1);
|
|||
|
|
|
|||
|
|
use App\Models\SalesAdAudienceFirm;
|
|||
|
|
use App\Models\SalesAdAudiencePhone;
|
|||
|
|
use App\Models\SalesUser;
|
|||
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|||
|
|
use Tests\Concerns\SharesSupplierPdo;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Раздел «Прогрев СМС» в кабинете начальника (Task 9, бэк).
|
|||
|
|
*
|
|||
|
|
* GET /api/sales/sms/campaigns — список рассылок + песочница + отправители
|
|||
|
|
* POST /api/sales/sms/campaigns — запуск рассылки
|
|||
|
|
* GET /api/sales/sms/campaigns/{id} — карточка с журналом
|
|||
|
|
* POST /api/sales/sms/preview — цена и причины пропуска ДО отправки
|
|||
|
|
*
|
|||
|
|
* Все методы — ТОЛЬКО начальник (role=head), как у SalesAdAudienceController.
|
|||
|
|
* Менеджер → 403. Аутентификация: $this->actingAs($user, 'sales').
|
|||
|
|
*
|
|||
|
|
* SharesSupplierPdo обязателен: модели sales_sms_* прибиты к pgsql_supplier
|
|||
|
|
* (отдельный PDO), без шаринга DatabaseTransactions откатывал бы только
|
|||
|
|
* соединение по умолчанию — записи текли бы из теста в тест (правило 10 плана).
|
|||
|
|
*/
|
|||
|
|
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
|
|||
|
|
|
|||
|
|
// ── helpers (уникальный префикс sms_, чтобы не столкнуться с ads_* соседнего файла) ──
|
|||
|
|
//
|
|||
|
|
// SalesUser::factory() в проекте НЕТ (правило 11 плана) — заводим через create()
|
|||
|
|
// с uniqid(), как в AdAudienceScreenTest.php.
|
|||
|
|
|
|||
|
|
function sms_head(): SalesUser
|
|||
|
|
{
|
|||
|
|
return SalesUser::create([
|
|||
|
|
'name' => 'Начальник '.uniqid(),
|
|||
|
|
'email' => 'smshead'.uniqid().'@sales.local',
|
|||
|
|
'password' => bcrypt('secret'),
|
|||
|
|
'role' => 'head',
|
|||
|
|
'is_active' => true,
|
|||
|
|
]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function sms_manager(): SalesUser
|
|||
|
|
{
|
|||
|
|
return SalesUser::create([
|
|||
|
|
'name' => 'Менеджер '.uniqid(),
|
|||
|
|
'email' => 'smsmgr'.uniqid().'@sales.local',
|
|||
|
|
'password' => bcrypt('secret'),
|
|||
|
|
'role' => 'manager',
|
|||
|
|
'is_active' => true,
|
|||
|
|
]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
it('менеджеру раздел закрыт', function () {
|
|||
|
|
$manager = sms_manager();
|
|||
|
|
|
|||
|
|
$this->actingAs($manager, 'sales')
|
|||
|
|
->getJson('/api/sales/sms/campaigns')
|
|||
|
|
->assertStatus(403);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('начальник видит список рассылок', function () {
|
|||
|
|
$head = sms_head();
|
|||
|
|
|
|||
|
|
$this->actingAs($head, 'sales')
|
|||
|
|
->getJson('/api/sales/sms/campaigns')
|
|||
|
|
->assertOk()
|
|||
|
|
->assertJsonStructure(['campaigns', 'sandbox']);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('предпросмотр показывает цену и причины пропуска до отправки', function () {
|
|||
|
|
$head = sms_head();
|
|||
|
|
|
|||
|
|
$this->actingAs($head, 'sales')
|
|||
|
|
->postJson('/api/sales/sms/preview', [
|
|||
|
|
'body' => str_repeat('а', 80),
|
|||
|
|
'phones' => ['79990000001'],
|
|||
|
|
])
|
|||
|
|
->assertOk()
|
|||
|
|
->assertJsonStructure(['segments', 'sendable_count', 'skipped', 'estimated_cost_kopecks'])
|
|||
|
|
->assertJsonPath('segments', 2);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('не создаёт рассылку с пустым текстом', function () {
|
|||
|
|
$head = sms_head();
|
|||
|
|
|
|||
|
|
$this->actingAs($head, 'sales')
|
|||
|
|
->postJson('/api/sales/sms/campaigns', ['title' => 'Пустая', 'body' => '', 'phones' => ['79990000001']])
|
|||
|
|
->assertStatus(422);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// ── Task 10.5: номера отмеченных фирм ─────────────────────────────────────────
|
|||
|
|
//
|
|||
|
|
// Начальник отмечает фирмы галочками, а не переписывает 177 номеров руками.
|
|||
|
|
// POST /api/sales/sms/recipients — по списку id фирм отдаёт их живые номера.
|
|||
|
|
|
|||
|
|
it('отдаёт номера отмеченных фирм', function () {
|
|||
|
|
$firm = SalesAdAudienceFirm::create(['firm_name' => 'ООО Ромашка', 'firm_inn' => '2452108518']);
|
|||
|
|
|
|||
|
|
SalesAdAudiencePhone::create([
|
|||
|
|
'phone' => '79990000010', 'firm_id' => $firm->id, 'firm_name' => 'ООО Ромашка',
|
|||
|
|
'expires_at' => now()->addDays(30), 'state' => 'active',
|
|||
|
|
'operator' => 'МТС', 'phone_type' => 'mobile',
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$this->actingAs(sms_head(), 'sales')
|
|||
|
|
->postJson('/api/sales/sms/recipients', ['firm_ids' => [$firm->id]])
|
|||
|
|
->assertOk()
|
|||
|
|
->assertJsonPath('phones.0.phone', '79990000010')
|
|||
|
|
->assertJsonPath('phones.0.firm_name', 'ООО Ромашка');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('не отдаёт погашенные номера', function () {
|
|||
|
|
$firm = SalesAdAudienceFirm::create(['firm_name' => 'ООО Ушедшая', 'firm_inn' => '2452108519']);
|
|||
|
|
|
|||
|
|
SalesAdAudiencePhone::create([
|
|||
|
|
'phone' => '79990000011', 'firm_id' => $firm->id,
|
|||
|
|
'expires_at' => now()->addDays(30), 'state' => 'active',
|
|||
|
|
'removed_at' => now(), 'operator' => 'МТС', 'phone_type' => 'mobile',
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
$this->actingAs(sms_head(), 'sales')
|
|||
|
|
->postJson('/api/sales/sms/recipients', ['firm_ids' => [$firm->id]])
|
|||
|
|
->assertOk()
|
|||
|
|
->assertJsonPath('phones', []);
|
|||
|
|
});
|