9bc587c2de
Коммит d2c2ec43 от 19.07 оторвался от main (dangling, ни в одной ветке): чистка ПДн и YandexAudienceClient в основную ветку так и не попали. Номера заменены на фиктивные 7999000000X, клиент и его тесты внесены заново. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
107 lines
4.9 KiB
PHP
107 lines
4.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\SalesAdAudiencePhone;
|
|
use App\Models\SalesAdAudienceState;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
use Tests\Concerns\SharesSupplierPdo;
|
|
|
|
/**
|
|
* Приём номеров в рекламную аудиторию сервис-каналом «Поиск → Портал».
|
|
*
|
|
* Токен канала — config('sales.integration_token') (middleware SalesIntegrationToken).
|
|
* В тестовом окружении env пуст, поэтому задаём его здесь, как в SalesIntegrationApiTest.
|
|
*
|
|
* SharesSupplierPdo обязателен: обе модели прибиты к соединению pgsql_supplier
|
|
* (отдельный PDO), и без шаринга DatabaseTransactions откатывал бы только
|
|
* соединение по умолчанию — записи текли бы из теста в тест.
|
|
*/
|
|
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
|
|
|
|
beforeEach(function () {
|
|
config(['sales.integration_token' => 'TESTTOKEN']);
|
|
});
|
|
|
|
test('без токена канал закрыт', function () {
|
|
$this->postJson('/api/sales/integration/ad-audience', ['phones' => []])
|
|
->assertUnauthorized();
|
|
});
|
|
|
|
test('принимает номера и ставит срок по настройке', function () {
|
|
SalesAdAudienceState::current()->update(['days' => 10]);
|
|
|
|
$this->postJson('/api/sales/integration/ad-audience', ['phones' => [[
|
|
'phone' => '79990000002', 'firm_inn' => '5505219940',
|
|
'firm_name' => 'Демидовы', 'city' => 'Омск', 'rubric' => 'chastnye-stomatologii',
|
|
]]], ['X-Sales-Token' => 'TESTTOKEN'])
|
|
->assertOk()->assertJson(['added' => 1, 'renewed' => 0]);
|
|
|
|
$row = SalesAdAudiencePhone::query()->where('phone', '79990000002')->firstOrFail();
|
|
|
|
expect($row->firm_name)->toBe('Демидовы')
|
|
->and($row->city)->toBe('Омск')
|
|
->and($row->firm_inn)->toBe('5505219940')
|
|
->and($row->removed_at)->toBeNull()
|
|
->and($row->synced_at)->toBeNull();
|
|
|
|
// Срок = момент приёма + 10 дней (минута допуска на время прогона теста).
|
|
expect($row->expires_at->timestamp)
|
|
->toBeGreaterThan(now()->addDays(10)->subMinute()->timestamp)
|
|
->toBeLessThan(now()->addDays(10)->addMinute()->timestamp);
|
|
});
|
|
|
|
test('повторная отправка продлевает срок, а не плодит дубль', function () {
|
|
$this->postJson('/api/sales/integration/ad-audience',
|
|
['phones' => [['phone' => '79990000002', 'firm_name' => 'Демидовы']]],
|
|
['X-Sales-Token' => 'TESTTOKEN'])->assertOk();
|
|
|
|
$first = SalesAdAudiencePhone::query()->where('phone', '79990000002')->firstOrFail()->expires_at;
|
|
|
|
$this->travel(2)->days();
|
|
|
|
$this->postJson('/api/sales/integration/ad-audience',
|
|
['phones' => [['phone' => '79990000002', 'firm_name' => 'Демидовы']]],
|
|
['X-Sales-Token' => 'TESTTOKEN'])
|
|
->assertOk()->assertJson(['added' => 0, 'renewed' => 1]);
|
|
|
|
expect(SalesAdAudiencePhone::query()->where('phone', '79990000002')->count())->toBe(1);
|
|
|
|
$again = SalesAdAudiencePhone::query()->where('phone', '79990000002')->firstOrFail();
|
|
expect($again->expires_at->timestamp)->toBeGreaterThan($first->timestamp);
|
|
});
|
|
|
|
test('вернувшийся номер снимает пометку удаления и просит пересинк', function () {
|
|
$this->postJson('/api/sales/integration/ad-audience',
|
|
['phones' => [['phone' => '79990000002']]],
|
|
['X-Sales-Token' => 'TESTTOKEN'])->assertOk();
|
|
|
|
SalesAdAudiencePhone::query()->where('phone', '79990000002')
|
|
->update(['removed_at' => now(), 'synced_at' => now()]);
|
|
|
|
$this->postJson('/api/sales/integration/ad-audience',
|
|
['phones' => [['phone' => '79990000002']]],
|
|
['X-Sales-Token' => 'TESTTOKEN'])
|
|
->assertOk()->assertJson(['renewed' => 1]);
|
|
|
|
$row = SalesAdAudiencePhone::query()->where('phone', '79990000002')->firstOrFail();
|
|
expect($row->removed_at)->toBeNull()->and($row->synced_at)->toBeNull();
|
|
});
|
|
|
|
test('отвергает номер не в формате Яндекса', function () {
|
|
foreach (['+79990000002', '89990000009', '7906197416', '799900000020'] as $bad) {
|
|
$this->postJson('/api/sales/integration/ad-audience',
|
|
['phones' => [['phone' => $bad]]],
|
|
['X-Sales-Token' => 'TESTTOKEN'])->assertStatus(422);
|
|
}
|
|
|
|
expect(SalesAdAudiencePhone::query()->count())->toBe(0);
|
|
});
|
|
|
|
test('пустой список номеров отвергается', function () {
|
|
$this->postJson('/api/sales/integration/ad-audience', [], ['X-Sales-Token' => 'TESTTOKEN'])
|
|
->assertStatus(422);
|
|
$this->postJson('/api/sales/integration/ad-audience', ['phones' => []], ['X-Sales-Token' => 'TESTTOKEN'])
|
|
->assertStatus(422);
|
|
});
|