Files
portal/app/tests/Feature/Autopodbor/StudyBatchEnqueueTest.php
T

109 lines
4.9 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
use App\Exceptions\Autopodbor\BatchBudgetException;
use App\Jobs\Autopodbor\RunAutopodborStudyJob;
use App\Models\AutopodborCompetitor;
use App\Models\AutopodborRun;
use App\Models\PricingTier;
use App\Models\Project;
use App\Models\SystemSetting;
use App\Models\Tenant;
use App\Services\Autopodbor\AutopodborRunService;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Str;
use Tests\Concerns\SharesSupplierPdo;
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
function batchCompetitor(int $tenantId, string $name): AutopodborCompetitor
{
return AutopodborCompetitor::create([
'tenant_id' => $tenantId,
'name' => $name,
'origin' => 'manual',
'dedup_key' => Str::slug($name).'-'.Str::random(6),
'box' => 'field',
]);
}
it('ставит пакет: N queued-прогонов с общим batch_id, распорядитель стартует ровно первого', function () {
Queue::fake();
$tenant = Tenant::factory()->create(['balance_rub' => '100000.00']);
DB::statement('SET app.current_tenant_id = '.$tenant->id);
SystemSetting::updateOrCreate(['key' => 'autopodbor_price_study_rub'], ['value' => '300', 'type' => 'decimal']);
$c1 = batchCompetitor($tenant->id, 'Окна А');
$c2 = batchCompetitor($tenant->id, 'Окна Б');
$c3 = batchCompetitor($tenant->id, 'Окна В');
$result = app(AutopodborRunService::class)->startStudyBatch($tenant->id, [$c1->id, $c2->id, $c3->id]);
expect($result->queued)->toBe(3)
->and($result->batch_id)->not->toBeNull();
$runs = AutopodborRun::where('batch_id', $result->batch_id)->get();
expect($runs)->toHaveCount(3)
->and($runs->pluck('status')->unique()->values()->all())->toBe(['queued'])
->and($runs->pluck('kind')->unique()->values()->all())->toBe(['study']);
// Джобы не диспатчатся напрямую из сервиса — распорядитель стартует РОВНО первого.
Queue::assertPushed(RunAutopodborStudyJob::class, 1);
});
it('нормализация: дубли, чужие конкуренты и уже-в-очереди отсеиваются', function () {
Queue::fake();
$tenant = Tenant::factory()->create(['balance_rub' => '100000.00']);
$other = Tenant::factory()->create(['balance_rub' => '100000.00']);
DB::statement('SET app.current_tenant_id = '.$tenant->id);
SystemSetting::updateOrCreate(['key' => 'autopodbor_price_study_rub'], ['value' => '300', 'type' => 'decimal']);
$c1 = batchCompetitor($tenant->id, 'Окна А');
$c2 = batchCompetitor($tenant->id, 'Окна Б');
$foreign = batchCompetitor($other->id, 'Чужой');
$busy = batchCompetitor($tenant->id, 'Занятый');
// У «занятого» уже есть queued study-прогон → должен быть отсеян.
AutopodborRun::create([
'tenant_id' => $tenant->id, 'kind' => 'study', 'status' => 'queued',
'competitor_id' => $busy->id, 'region_code' => 1, 'params' => [],
]);
$result = app(AutopodborRunService::class)->startStudyBatch(
$tenant->id,
[$c1->id, $c1->id, $c2->id, $foreign->id, $busy->id],
);
expect($result->queued)->toBe(2);
$runs = AutopodborRun::where('batch_id', $result->batch_id)->get();
expect($runs)->toHaveCount(2)
->and($runs->pluck('competitor_id')->sort()->values()->all())
->toBe(collect([$c1->id, $c2->id])->sort()->values()->all());
});
it('нет баланса на весь пакет → BatchBudgetException, ни одного прогона не создано', function () {
Queue::fake();
$tenant = Tenant::factory()->create(['balance_rub' => '100.00', 'delivered_in_month' => 0]);
DB::statement('SET app.current_tenant_id = '.$tenant->id);
SystemSetting::updateOrCreate(['key' => 'autopodbor_price_study_rub'], ['value' => '300', 'type' => 'decimal']);
// Активный проект-обязательство + сетка тарифов — гейт учитывает резерв проектов.
Project::factory()->create(['tenant_id' => $tenant->id, 'is_active' => true, 'daily_limit_target' => 10]);
PricingTier::factory()->create([
'tier_no' => 1, 'leads_in_tier' => null, 'price_per_lead_kopecks' => 3000,
'is_active' => true, 'effective_from' => now()->toDateString(),
]);
$c1 = batchCompetitor($tenant->id, 'Окна А');
$c2 = batchCompetitor($tenant->id, 'Окна Б');
expect(fn () => app(AutopodborRunService::class)->startStudyBatch($tenant->id, [$c1->id, $c2->id]))
->toThrow(BatchBudgetException::class);
expect(AutopodborRun::where('tenant_id', $tenant->id)->where('kind', 'study')->count())->toBe(0);
Queue::assertNotPushed(RunAutopodborStudyJob::class);
});