65 lines
3.0 KiB
PHP
65 lines
3.0 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
use App\Models\SalesAdAudienceFirm;
|
||
|
|
use App\Models\SalesAdAudienceWarmingEpisode;
|
||
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||
|
|
use Tests\Concerns\SharesSupplierPdo;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* B6: read-API состояния прогрева для внешней службы «Поиск клиентов» (finder).
|
||
|
|
*
|
||
|
|
* POST /api/sales/integration/warming-state { inns: [...] } (сервис-токен) →
|
||
|
|
* { data: { <inn>: {active, channels:{code:{live,count}}} } } — та же форма значков
|
||
|
|
* витрины, что в воронке (кусок B), считанная из летописи эпизодов, но матч фирм по
|
||
|
|
* firm_inn. finder-сторона (колонки «Греются/Прогреты») — в самой Python-службе, вне репо.
|
||
|
|
*
|
||
|
|
* SharesSupplierPdo обязателен: фирмы/эпизоды на pgsql_supplier.
|
||
|
|
* План: docs/superpowers/plans/2026-07-23-progrev-vitrina-kusok-B.md Task B6.
|
||
|
|
*/
|
||
|
|
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
|
||
|
|
|
||
|
|
beforeEach(function () {
|
||
|
|
config(['sales.integration_token' => 'TESTTOKEN']);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('без токена → 401', function () {
|
||
|
|
$this->postJson('/api/sales/integration/warming-state', ['inns' => ['7700000001']])
|
||
|
|
->assertUnauthorized();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('отдаёт состояние прогрева по ИНН из летописи (live/count)', function () {
|
||
|
|
$firm = SalesAdAudienceFirm::create([
|
||
|
|
'firm_name' => 'Гарант', 'firm_inn' => '7700000001', 'warmup_started_at' => now(),
|
||
|
|
]);
|
||
|
|
// Яндекс — открытый эпизод (идёт сейчас); СМС — два закрытых события (×2).
|
||
|
|
SalesAdAudienceWarmingEpisode::create(['firm_id' => $firm->id, 'channel' => 'yandex', 'started_at' => now()]);
|
||
|
|
foreach ([now()->subDays(3), now()] as $t) {
|
||
|
|
SalesAdAudienceWarmingEpisode::create(['firm_id' => $firm->id, 'channel' => 'sms', 'started_at' => $t, 'ended_at' => $t]);
|
||
|
|
}
|
||
|
|
|
||
|
|
$w = $this->postJson('/api/sales/integration/warming-state', ['inns' => ['7700000001']], ['X-Sales-Token' => 'TESTTOKEN'])
|
||
|
|
->assertOk()
|
||
|
|
->json('data.7700000001');
|
||
|
|
|
||
|
|
expect($w['active'])->toBeTrue()
|
||
|
|
->and($w['channels']['yandex']['live'])->toBeTrue()
|
||
|
|
->and($w['channels']['yandex']['count'])->toBe(1)
|
||
|
|
->and($w['channels']['sms']['count'])->toBe(2)
|
||
|
|
->and($w['channels']['sms']['live'])->toBeFalse();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('неизвестный ИНН → пустой прогрев', function () {
|
||
|
|
$res = $this->postJson('/api/sales/integration/warming-state', ['inns' => ['9999999999']], ['X-Sales-Token' => 'TESTTOKEN'])
|
||
|
|
->assertOk();
|
||
|
|
|
||
|
|
expect($res->json('data.9999999999.active'))->toBeFalse()
|
||
|
|
->and($res->json('data.9999999999.channels'))->toBe([]);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('валидация: inns обязателен непустой массив → 422', function () {
|
||
|
|
$this->postJson('/api/sales/integration/warming-state', [], ['X-Sales-Token' => 'TESTTOKEN'])
|
||
|
|
->assertStatus(422);
|
||
|
|
});
|