import { apiClient, ensureCsrfCookie } from './client'; /** * API-модуль биллинга (Sprint 2 Plan C). * * Эндпоинты под [auth:sanctum, tenant]: GET wallet/transactions/invoices * (E3), POST topup (E1 — добавляется в Task 5). GET'ы не требуют CSRF-cookie. */ /** Тариф в составе ответа GET /api/billing/wallet (Billing v2 Spec A). */ export interface WalletTariff { code: string; name: string; features: string[]; } /** Один уровень tier-сетки в tiers_preview. */ export interface WalletTierPreview { tier_no: number; leads_in_tier: number | null; price_rub: string; } /** Ответ GET /api/billing/wallet — кошелёк тенанта (Billing v2 Spec A). */ export interface Wallet { balance_rub: string; affordable_leads: number; current_tier: { no: number; price_rub: string; leads_left_in_tier: number } | null; next_tier: { no: number; price_rub: string; leads_in_tier: number } | null; delivered_in_month: number; runway_days: number | null; tiers_preview: WalletTierPreview[]; tariff: WalletTariff | null; } /** GET /api/billing/wallet — балансы + текущий тариф + runway. */ export async function getWallet(): Promise { const { data } = await apiClient.get('/api/billing/wallet'); return data; } /** Строка истории транзакций (GET /api/billing/transactions, Billing v2 Spec A). */ export interface BillingTransaction { id: number; code: string; type: | 'topup' | 'lead_charge' | 'migration' | 'trial_bonus' | 'manual_adjustment' | 'historical_import' | 'chargeback_writedown' | 'chargeback_repayment'; description: string | null; amount_rub: string; amount_leads: number | null; balance_rub_after: string; display_amount_rub: string; created_at: string; } /** Пагинированный ответ GET /api/billing/transactions. */ export interface TransactionsPage { data: BillingTransaction[]; meta: { current_page: number; last_page: number; total: number; per_page: number }; } /** Счёт тенанта (GET /api/billing/invoices). */ export interface BillingInvoice { id: number; invoice_number: string; amount_total: string; status: string; issued_at: string; has_pdf: boolean; } /** GET /api/billing/transactions — пагинированная история транзакций. */ export async function getTransactions(params: { page?: number; type?: string }): Promise { const { data } = await apiClient.get('/api/billing/transactions', { params }); return data; } /** GET /api/billing/invoices — счета тенанта (real-but-empty до Б-1). */ export async function getInvoices(): Promise<{ data: BillingInvoice[] }> { const { data } = await apiClient.get<{ data: BillingInvoice[] }>('/api/billing/invoices'); return data; } /** Результат POST /api/billing/topup. */ export interface TopupResult { transaction: { id: number; type: string; amount_rub: string; balance_rub_after: string | null; created_at: string; }; balance_rub: string; } /** POST /api/billing/topup — пополнить рублёвый баланс (MVP-stub). */ export async function topup(amountRub: number): Promise { await ensureCsrfCookie(); const { data } = await apiClient.post('/api/billing/topup', { amount_rub: amountRub }); return data; } /** * Ответ GET /api/billing/balance-status — лёгкий статус баланса для UI префлайта * (Billing v2 Spec C §3.6): питает баннер заморозки + индикатор ёмкости. */ export interface BalanceStatus { /** ISO-дата заморозки или null (не заморожен). */ frozen_by_balance_at: string | null; balance_rub: string; /** Сколько лидов покрывает баланс по текущему тарифу. */ capacity_leads: number; /** Суммарный дневной заказ активных не-заблокированных проектов. */ required_leads_per_day: number; /** На сколько лидов заказ превышает ёмкость (0 если хватает). */ deficit_leads: number; /** Сколько ₽ не хватает, чтобы покрыть дефицит (scale 2, "0.00" если хватает). */ deficit_rub: string; } /** GET /api/billing/balance-status — статус для баннера заморозки и индикатора ёмкости. */ export async function getBalanceStatus(): Promise { const { data } = await apiClient.get('/api/billing/balance-status'); return data; }