Files
portal/app/tests/Unit/Dashboard/BalanceHealthTest.php
T
Дмитрий 88e816c576 feat(балансы): backend плитки балансов внешних сервисов
Ежедневный контроль баланса DaData/Поставщик/Yandex Cloud плиткой дашборда.

- Таблица external_service_balances (pgsql_supplier, BYPASSRLS, last-value upsert)
- BalanceHealth: чистая логика светофора (red <floor или <3д; amber <floor или <7д)
- BalanceProvider+DTO; провайдеры DaData(API)/YC(OAuth→IAM→billing)/Supplier(Playwright)
- RefreshExternalBalancesJob: изоляция провайдеров (try/catch), расписание 06:30 МСК
- AdminDashboardController::balances() + плитка в summary + topup_url (кнопка «Пополнить»)
- Тесты: BalanceHealth, 3 провайдера, джоба, endpoint (102 теста зелёные)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:12:14 +03:00

24 lines
1.5 KiB
PHP

<?php
declare(strict_types=1);
use App\Services\Dashboard\BalanceHealth;
it('красный при низком балансе ИЛИ малом числе дней', function () {
// balance 1000, spend 500/д → days=2 → red (дней<3)
expect(BalanceHealth::evaluate(1000, 500, 5000, 15000))->toMatchArray(['days_left' => 2, 'light' => 'red']);
// balance 4000 (< red_floor 5000), spend 100 → days 40, но баланс<red → red
expect(BalanceHealth::evaluate(4000, 100, 5000, 15000)['light'])->toBe('red');
// balance 12000 (< amber 15000), days большой → amber
expect(BalanceHealth::evaluate(12000, 100, 5000, 15000)['light'])->toBe('amber');
// balance 100000, spend 100 → days 1000, выше порогов → green
expect(BalanceHealth::evaluate(100000, 100, 5000, 15000)['light'])->toBe('green');
// нет данных о расходе → days_left null, светофор только по порогам
expect(BalanceHealth::evaluate(100000, null, 5000, 15000))->toMatchArray(['days_left' => null, 'light' => 'green']);
// граница: ровно 7 дней — НЕ amber (порог «< 7»); 6 дней — amber
expect(BalanceHealth::evaluate(700, 100, 0, 0)['light'])->toBe('green');
expect(BalanceHealth::evaluate(600, 100, 0, 0)['light'])->toBe('amber');
// отрицательный баланс (YC в минусе) → red
expect(BalanceHealth::evaluate(-540, null, 1000, 5000))->toMatchArray(['days_left' => null, 'light' => 'red']);
});