e1601e7862
Spec C §3.6/§6.2. Бэкенд: GET /api/billing/balance-status (frozen + capacity + required + дефицит ₽/leads), Pest 6. Фронт: BalanceFrozenBanner (в AppLayout, глобально), BalanceCapacityIndicator (в BillingView под балансом), ProjectLimitOverloadDialog (409-перехват в NewProjectDialog: save-blocked/set-zero), tenantStore + api getBalanceStatus. Vitest +18. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
44 lines
1.9 KiB
TypeScript
44 lines
1.9 KiB
TypeScript
import { defineStore } from 'pinia';
|
|
import { computed, ref } from 'vue';
|
|
import * as billingApi from '../api/billing';
|
|
import type { BalanceStatus } from '../api/billing';
|
|
|
|
/**
|
|
* Tenant-store: статус баланса текущего тенанта для UI префлайта (Billing v2
|
|
* Spec C Task 1.10). Единый источник для глобального баннера заморозки
|
|
* (BalanceFrozenBanner в AppLayout) и индикатора ёмкости (BalanceCapacityIndicator
|
|
* в BillingView) — чтобы не делать два запроса.
|
|
*
|
|
* Загружается глобально в AppLayout (load + polling). `load()` молча проглатывает
|
|
* ошибку: баннер/индикатор не критичны и не должны валить страницу.
|
|
*/
|
|
export const useTenantStore = defineStore('tenant', () => {
|
|
const status = ref<BalanceStatus | null>(null);
|
|
|
|
const frozen = computed(() => status.value?.frozen_by_balance_at != null);
|
|
const deficitRub = computed(() => status.value?.deficit_rub ?? '0.00');
|
|
const deficitLeads = computed(() => status.value?.deficit_leads ?? 0);
|
|
const balanceRub = computed(() => status.value?.balance_rub ?? '0.00');
|
|
const capacityLeads = computed(() => status.value?.capacity_leads ?? 0);
|
|
const requiredLeadsPerDay = computed(() => status.value?.required_leads_per_day ?? 0);
|
|
|
|
async function load(): Promise<void> {
|
|
try {
|
|
status.value = await billingApi.getBalanceStatus();
|
|
} catch {
|
|
// Не критично — оставляем прошлый статус (или null → баннер скрыт).
|
|
}
|
|
}
|
|
|
|
return {
|
|
status,
|
|
frozen,
|
|
deficitRub,
|
|
deficitLeads,
|
|
balanceRub,
|
|
capacityLeads,
|
|
requiredLeadsPerDay,
|
|
load,
|
|
};
|
|
});
|