Files
portal/app/tests/Feature/RunwayCalculatorTest.php
T

77 lines
3.5 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
use App\Models\Project;
use App\Models\Tenant;
use App\Services\Billing\RunwayCalculator;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
/**
* B1-fix (24.06.2026): runway считается от ДНЕВНОГО ЗАКАЗА активных проектов
* (sum daily_limit_target), а не от прошлого расхода. Так дашборд перестаёт врать
* на новых аккаунтах («0 дней» при полном балансе) и совпадает с витриной биллинга.
* daysLeft(tenantId, affordableLeads):
* affordable<=0 → 0; нет активных проектов (заказ=0) → null;
* иначе floor(affordable / дневной_заказ).
*/
uses(DatabaseTransactions::class);
/** Создаёт активный проект тенанта с заданным дневным лимитом. */
function makeActiveProject(int $tenantId, int $dailyLimit): void
{
DB::statement('SET app.current_tenant_id = '.$tenantId);
Project::factory()->create([
'tenant_id' => $tenantId,
'is_active' => true,
'daily_limit_target' => $dailyLimit,
]);
}
test('daysLeft = 0 если affordableLeads <= 0', function () {
$tenant = Tenant::factory()->create();
makeActiveProject($tenant->id, 50);
expect(app(RunwayCalculator::class)->daysLeft($tenant->id, 0))->toBe(0);
expect(app(RunwayCalculator::class)->daysLeft($tenant->id, -5))->toBe(0);
});
test('daysLeft = null если нет активных проектов (нечего заказывать)', function () {
$tenant = Tenant::factory()->create();
expect(app(RunwayCalculator::class)->daysLeft($tenant->id, 100))->toBeNull();
});
test('daysLeft = floor(affordable / дневной заказ активных проектов)', function () {
$tenant = Tenant::factory()->create();
makeActiveProject($tenant->id, 50);
// 223 лида по карману, заказ 50/день → 4 полных дня (не «0» как раньше).
expect(app(RunwayCalculator::class)->daysLeft($tenant->id, 223))->toBe(4);
});
test('мало денег при большом заказе → 0 дней, а не раздутое число', function () {
$tenant = Tenant::factory()->create();
makeActiveProject($tenant->id, 50);
// 1 лид по карману, заказ 50/день → 0 дней (раньше выдавало «10 из 7»).
expect(app(RunwayCalculator::class)->daysLeft($tenant->id, 1))->toBe(0);
});
test('daysLeft суммирует лимиты нескольких активных проектов', function () {
$tenant = Tenant::factory()->create();
makeActiveProject($tenant->id, 30);
makeActiveProject($tenant->id, 20); // суммарный заказ 50/день
expect(app(RunwayCalculator::class)->daysLeft($tenant->id, 100))->toBe(2);
});
test('daysLeft игнорирует неактивные проекты', function () {
$tenant = Tenant::factory()->create();
makeActiveProject($tenant->id, 50);
DB::statement('SET app.current_tenant_id = '.$tenant->id);
Project::factory()->create([
'tenant_id' => $tenant->id,
'is_active' => false,
'daily_limit_target' => 1000,
]);
// считаем только активный (223/50=4), неактивный 1000 не учитывается.
expect(app(RunwayCalculator::class)->daysLeft($tenant->id, 223))->toBe(4);
});