2026-06-28 14:20:54 +03:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
2026-07-01 15:45:37 +03:00
|
|
|
use App\Exceptions\Autopodbor\RunInFlightException;
|
|
|
|
|
use App\Exceptions\Billing\InsufficientBalanceException;
|
|
|
|
|
use App\Jobs\Autopodbor\RunAutopodborResolveJob;
|
|
|
|
|
use App\Jobs\Autopodbor\RunAutopodborSearchJob;
|
2026-07-05 06:08:12 +03:00
|
|
|
use App\Jobs\Autopodbor\RunAutopodborStudyJob;
|
|
|
|
|
use App\Models\AutopodborCompetitor;
|
|
|
|
|
use App\Models\AutopodborRun;
|
2026-06-28 14:20:54 +03:00
|
|
|
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;
|
2026-07-01 15:45:37 +03:00
|
|
|
use Tests\Concerns\SharesSupplierPdo;
|
2026-06-28 14:20:54 +03:00
|
|
|
|
2026-07-01 15:45:37 +03:00
|
|
|
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
|
2026-06-28 14:20:54 +03:00
|
|
|
|
|
|
|
|
it('стартует search, создаёт queued-прогон и ставит джобу', function () {
|
|
|
|
|
Queue::fake();
|
|
|
|
|
$tenant = Tenant::factory()->create(['balance_rub' => '100000.00']);
|
2026-07-01 15:45:37 +03:00
|
|
|
DB::statement('SET app.current_tenant_id = '.$tenant->id);
|
2026-06-28 14:20:54 +03:00
|
|
|
SystemSetting::updateOrCreate(['key' => 'autopodbor_price_search_rub'], ['value' => '500', 'type' => 'decimal']);
|
|
|
|
|
|
|
|
|
|
$run = app(AutopodborRunService::class)->startSearch($tenant->id, 16, ['okna.ru'], [], true);
|
|
|
|
|
|
|
|
|
|
expect($run->kind)->toBe('search')->and($run->status)->toBe('queued');
|
|
|
|
|
Queue::assertPushed(RunAutopodborSearchJob::class);
|
|
|
|
|
});
|
|
|
|
|
|
2026-07-05 06:08:12 +03:00
|
|
|
it('startStudy на уже изученном конкуренте создаёт НОВЫЙ прогон (повторный сбор источников)', 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']);
|
|
|
|
|
|
|
|
|
|
$oldRun = AutopodborRun::create(['tenant_id' => $tenant->id, 'kind' => 'study', 'status' => 'done', 'region_code' => 16, 'params' => []]);
|
|
|
|
|
$comp = AutopodborCompetitor::create([
|
|
|
|
|
'tenant_id' => $tenant->id, 'name' => 'Окна', 'dedup_key' => 'okna', 'box' => 'field',
|
|
|
|
|
'studied_at' => now(), 'study_run_id' => $oldRun->id,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$run = app(AutopodborRunService::class)->startStudy($tenant->id, $comp->id);
|
|
|
|
|
|
|
|
|
|
// Раньше был жёсткий стоп «уже изучали → вернуть старый прогон». Теперь повтор разрешён.
|
|
|
|
|
expect($run->id)->not->toBe($oldRun->id)
|
|
|
|
|
->and($run->kind)->toBe('study')
|
|
|
|
|
->and($run->status)->toBe('queued')
|
|
|
|
|
->and($run->competitor_id)->toBe($comp->id);
|
|
|
|
|
Queue::assertPushed(RunAutopodborStudyJob::class);
|
|
|
|
|
});
|
|
|
|
|
|
2026-06-28 14:20:54 +03:00
|
|
|
it('не стартует второй in-flight search того же tenant', function () {
|
|
|
|
|
Queue::fake();
|
|
|
|
|
$tenant = Tenant::factory()->create(['balance_rub' => '100000.00']);
|
2026-07-01 15:45:37 +03:00
|
|
|
DB::statement('SET app.current_tenant_id = '.$tenant->id);
|
2026-06-28 14:20:54 +03:00
|
|
|
SystemSetting::updateOrCreate(['key' => 'autopodbor_price_search_rub'], ['value' => '500', 'type' => 'decimal']);
|
|
|
|
|
$svc = app(AutopodborRunService::class);
|
|
|
|
|
$svc->startSearch($tenant->id, 16, ['okna.ru'], [], true);
|
|
|
|
|
|
|
|
|
|
expect(fn () => $svc->startSearch($tenant->id, 16, ['okna.ru'], [], true))
|
2026-07-01 15:45:37 +03:00
|
|
|
->toThrow(RunInFlightException::class);
|
2026-06-28 14:20:54 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('гейтит по балансу: нехватка на цену search → InsufficientBalanceException', function () {
|
|
|
|
|
Queue::fake();
|
|
|
|
|
$tenant = Tenant::factory()->create(['balance_rub' => '100.00']);
|
2026-07-01 15:45:37 +03:00
|
|
|
DB::statement('SET app.current_tenant_id = '.$tenant->id);
|
2026-06-28 14:20:54 +03:00
|
|
|
SystemSetting::updateOrCreate(['key' => 'autopodbor_price_search_rub'], ['value' => '500', 'type' => 'decimal']);
|
|
|
|
|
|
|
|
|
|
expect(fn () => app(AutopodborRunService::class)->startSearch($tenant->id, 16, ['okna.ru'], [], true))
|
2026-07-01 15:45:37 +03:00
|
|
|
->toThrow(InsufficientBalanceException::class);
|
2026-06-28 14:20:54 +03:00
|
|
|
Queue::assertNotPushed(RunAutopodborSearchJob::class);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('startResolve бесплатный: стартует даже при нулевом балансе, ставит resolve-джобу', function () {
|
|
|
|
|
Queue::fake();
|
|
|
|
|
$tenant = Tenant::factory()->create(['balance_rub' => '0.00']);
|
2026-07-01 15:45:37 +03:00
|
|
|
DB::statement('SET app.current_tenant_id = '.$tenant->id);
|
2026-06-28 14:20:54 +03:00
|
|
|
|
|
|
|
|
$run = app(AutopodborRunService::class)->startResolve($tenant->id, 'Окна Комфорт', 16);
|
|
|
|
|
|
|
|
|
|
expect($run->kind)->toBe('resolve')->and($run->status)->toBe('queued');
|
|
|
|
|
Queue::assertPushed(RunAutopodborResolveJob::class);
|
|
|
|
|
});
|