2026-06-28 07:11:02 +03:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
|
|
|
|
|
|
uses(DatabaseTransactions::class);
|
|
|
|
|
|
|
|
|
|
beforeEach(function () {
|
|
|
|
|
DB::table('external_service_balances')->delete();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('GET /api/admin/dashboard/balances возвращает строки сервисов + topup_url', function () {
|
|
|
|
|
config()->set('services.yandex_cloud.console_billing_url', 'https://console.yandex.cloud/billing/accounts');
|
|
|
|
|
config()->set('services.yandex_cloud.billing_account_id', 'dn2w7fcvynjxe6elljct');
|
|
|
|
|
|
|
|
|
|
DB::table('external_service_balances')->insert([
|
|
|
|
|
['service_key' => 'dadata', 'balance_amount' => 4500, 'currency' => 'RUB', 'daily_spend_estimate' => 100,
|
|
|
|
|
'days_left' => 9, 'light' => 'green', 'ok' => true, 'checked_at' => now(), 'created_at' => now(), 'updated_at' => now()],
|
|
|
|
|
['service_key' => 'yandex_cloud', 'balance_amount' => -540.48, 'currency' => 'RUB', 'daily_spend_estimate' => 600,
|
|
|
|
|
'days_left' => 0, 'light' => 'red', 'ok' => true, 'checked_at' => now(), 'created_at' => now(), 'updated_at' => now()],
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$res = $this->getJson('/api/admin/dashboard/balances');
|
|
|
|
|
|
|
|
|
|
$res->assertOk();
|
|
|
|
|
$res->assertJsonStructure([
|
|
|
|
|
'light',
|
|
|
|
|
'services' => [['service_key', 'balance_amount', 'currency', 'days_left', 'light', 'ok', 'checked_at', 'topup_url']],
|
|
|
|
|
]);
|
|
|
|
|
expect($res->json('light'))->toBe('red'); // худший из сервисов
|
|
|
|
|
$yc = collect($res->json('services'))->firstWhere('service_key', 'yandex_cloud');
|
|
|
|
|
expect($yc['topup_url'])->toBe('https://console.yandex.cloud/billing/accounts/dn2w7fcvynjxe6elljct/payments');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('неуспешный сервис показывается серым (grey), не красным', function () {
|
|
|
|
|
DB::table('external_service_balances')->insert([
|
|
|
|
|
'service_key' => 'supplier', 'balance_amount' => 12000, 'currency' => 'RUB',
|
|
|
|
|
'light' => 'red', 'ok' => false, 'error' => 'кабинет недоступен',
|
|
|
|
|
'checked_at' => now(), 'created_at' => now(), 'updated_at' => now(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$res = $this->getJson('/api/admin/dashboard/balances');
|
|
|
|
|
$res->assertOk();
|
|
|
|
|
$svc = collect($res->json('services'))->firstWhere('service_key', 'supplier');
|
|
|
|
|
expect($svc['light'])->toBe('grey');
|
|
|
|
|
expect($svc['ok'])->toBeFalse();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('summary включает плитку balances', function () {
|
|
|
|
|
$res = $this->getJson('/api/admin/dashboard?period=30d');
|
|
|
|
|
$res->assertOk();
|
|
|
|
|
$res->assertJsonStructure(['balances' => ['light', 'count', 'red']]);
|
|
|
|
|
});
|
2026-07-16 14:27:25 +03:00
|
|
|
|
2026-07-16 19:06:39 +03:00
|
|
|
it('платные сервисы отдают ссылку «Пополнить» (topup_url)', function () {
|
2026-07-16 18:45:06 +03:00
|
|
|
config()->set('services.aitunnel.topup_url', 'https://aitunnel.ru/');
|
|
|
|
|
config()->set('services.exa.topup_url', 'https://dashboard.exa.ai/');
|
2026-07-16 19:06:39 +03:00
|
|
|
config()->set('services.xfetch.topup_url', 'https://xf4.ru/');
|
|
|
|
|
config()->set('services.keyso.topup_url', 'https://www.keys.so/ru/tarif');
|
|
|
|
|
config()->set('services.exa.tunnel_topup_url', 'https://happ-proxy.com/');
|
|
|
|
|
DB::table('external_service_balances')->insert(
|
|
|
|
|
collect(['aitunnel', 'exa', 'xfetch', 'keyso', 'exa_tunnel'])->map(fn ($k) => [
|
|
|
|
|
'service_key' => $k, 'balance_amount' => null, 'currency' => 'RUB', 'light' => 'green', 'ok' => true,
|
|
|
|
|
'checked_at' => now(), 'created_at' => now(), 'updated_at' => now(),
|
|
|
|
|
])->all()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$svc = collect($this->getJson('/api/admin/dashboard/balances')->assertOk()->json('services'))
|
|
|
|
|
->keyBy('service_key');
|
|
|
|
|
expect($svc['aitunnel']['topup_url'])->toBe('https://aitunnel.ru/');
|
|
|
|
|
expect($svc['exa']['topup_url'])->toBe('https://dashboard.exa.ai/');
|
|
|
|
|
expect($svc['xfetch']['topup_url'])->toBe('https://xf4.ru/');
|
|
|
|
|
expect($svc['keyso']['topup_url'])->toBe('https://www.keys.so/ru/tarif');
|
|
|
|
|
expect($svc['exa_tunnel']['topup_url'])->toBe('https://happ-proxy.com/');
|
2026-07-16 18:45:06 +03:00
|
|
|
});
|
|
|
|
|
|
2026-07-16 14:27:25 +03:00
|
|
|
it('GET /balances не отдаёт неизвестные ключи (осиротевший jivosite)', function () {
|
|
|
|
|
DB::table('external_service_balances')->insert([
|
|
|
|
|
'service_key' => 'jivosite', 'light' => 'red', 'ok' => false, 'error' => 'старое',
|
|
|
|
|
'currency' => 'RUB', 'checked_at' => now(), 'created_at' => now(), 'updated_at' => now(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$res = $this->getJson('/api/admin/dashboard/balances');
|
|
|
|
|
|
|
|
|
|
$res->assertOk();
|
|
|
|
|
$keys = collect($res->json('services'))->pluck('service_key');
|
|
|
|
|
expect($keys)->not->toContain('jivosite');
|
|
|
|
|
});
|