c2cb3af4c6
TopupDialog (сумма + пресеты + min 100 ₽ валидация) → POST /api/billing/topup. Кнопки «Пополнить баланс» (шапка) и «Пополнить» (BalanceCard) открывают диалог; при успехе — refresh кошелька + транзакций + snackbar. Sprint 2 Plan C, audit E1 (frontend). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
91 lines
2.9 KiB
TypeScript
91 lines
2.9 KiB
TypeScript
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. */
|
|
export interface WalletTariff {
|
|
code: string;
|
|
name: string;
|
|
price_monthly: string | null;
|
|
billing_model: string;
|
|
features: string[];
|
|
}
|
|
|
|
/** Ответ GET /api/billing/wallet — кошелёк тенанта. */
|
|
export interface Wallet {
|
|
balance_rub: string;
|
|
balance_leads: number;
|
|
runway_days: number | null;
|
|
tariff: WalletTariff | null;
|
|
}
|
|
|
|
/** GET /api/billing/wallet — балансы + текущий тариф + runway. */
|
|
export async function getWallet(): Promise<Wallet> {
|
|
const { data } = await apiClient.get<Wallet>('/api/billing/wallet');
|
|
return data;
|
|
}
|
|
|
|
/** Строка истории транзакций (GET /api/billing/transactions). */
|
|
export interface BillingTransaction {
|
|
id: number;
|
|
code: string;
|
|
type: string;
|
|
description: string | null;
|
|
amount_rub: string;
|
|
amount_leads: number;
|
|
balance_rub_after: string | null;
|
|
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<TransactionsPage> {
|
|
const { data } = await apiClient.get<TransactionsPage>('/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<TopupResult> {
|
|
await ensureCsrfCookie();
|
|
const { data } = await apiClient.post<TopupResult>('/api/billing/topup', { amount_rub: amountRub });
|
|
return data;
|
|
}
|