PricingTier::create([ 'tier_no' => 1, 'leads_in_tier' => null, 'price_per_lead_kopecks' => 10000, 'is_active' => true, 'effective_from' => now()->toDateString(), ])); it('resumes when balance fits', function () { Queue::fake(); $t = Tenant::factory()->create(['balance_rub' => '1000.00', 'delivered_in_month' => 0]); $p = Project::factory()->for($t)->create([ 'is_active' => false, 'daily_limit_target' => 5, 'paused_at' => now(), 'preflight_blocked_at' => null, ]); $r = app(ProjectService::class)->setActive($p, true); expect($r->is_active)->toBeTrue(); expect($r->activate_deferred)->toBeFalse(); Queue::assertPushed(SyncSupplierProjectJob::class); }); it('refuses resume when balance insufficient, stays paused, no sync', function () { Queue::fake(); $t = Tenant::factory()->create(['balance_rub' => '100.00', 'delivered_in_month' => 0]); // 1 лид $p = Project::factory()->for($t)->create([ 'is_active' => false, 'daily_limit_target' => 5, 'paused_at' => now(), 'preflight_blocked_at' => null, ]); $r = app(ProjectService::class)->setActive($p, true); expect($r->is_active)->toBeFalse(); expect($r->preflight_blocked_at)->not->toBeNull(); expect($r->activate_deferred)->toBeTrue(); expect($r->gate_payload['deficit_leads'])->toBe(4); Queue::assertNotPushed(SyncSupplierProjectJob::class); }); it('pauses without gate', function () { Queue::fake(); $t = Tenant::factory()->create(['balance_rub' => '0.00']); $p = Project::factory()->for($t)->create(['is_active' => true, 'daily_limit_target' => 5]); $r = app(ProjectService::class)->setActive($p, false); expect($r->is_active)->toBeFalse(); expect($r->paused_at)->not->toBeNull(); Queue::assertPushed(SyncSupplierProjectJob::class); // пауза тоже синкается (снять заказ) });