Дмитрий
|
4532b95d64
|
phase2(admin-billing): GET /api/admin/billing + AdminBillingView API (этап 3/5)
Aggregates пополнений/списаний за текущий месяц по balance_transactions
+ summary с MRR/revenue/overdue/refunds_30d.
Backend (AdminBillingController::index):
- GET /api/admin/billing?search=. Per-tenant SUM с CASE WHEN type IN
('topup','lead_charge') GROUP BY tenant_id; ABS для charges.
- Row: id/subdomain/organization_name/contact_email/status/balance_rub/
tariff_id/tariff_name/mrr_rub (=tariff.price_monthly если не-trial)/
monthly_topups_rub/monthly_charges_rub/last_payment_at/
chargeback_unrecovered_rub.
- summary: total_mrr_rub (SUM не-trial), monthly_revenue_rub (SUM topup),
overdue_count (balance<0 || chargeback>0), refunds_count_30d.
- Quirk: schema-колонка tariff_plans.price_monthly (НЕ price_rub_monthly)
— обнаружено первым прогоном Pest, исправлено сразу.
Pest +9 (AdminBillingIndexTest):
- пустой / поля+tariff JOIN / aggregates за месяц / прошлый месяц не
попадает / overdue / refunds_30d (старые исключены) / total_mrr_rub
(trial исключаются) / search ILIKE / soft-deleted скрыт.
Frontend:
- api/admin.ts::listAdminBilling — типизированный helper.
- AdminBillingView: reactive rowsState+summary default = MOCK,
loadBilling() async на onMounted парсит API-строки → numbers + derive
status (suspended/balance<0||chargeback>0→overdue/active). На fail —
fetchError + warning alert + MOCK fallback. Reload-btn.
- tariffLabel/statusInfo обобщены с fallback'ами на новые slug'и.
Vitest +4:
- listAdminBilling на mount / replace rowsState+summary + string→number
+ status derive / reject → fetchError+alert+fallback / reload-btn x2.
PHPStan baseline регенерирован.
Регресс:
- Lint+type-check+format passed.
- Vitest 300/300 за 18.41 сек (+4 от 296).
- Vite build 925 ms.
- Pint + PHPStan passed.
- Pest 237/237 за 27.69 сек (+9 от 228, 926 assertions).
Реестр v1.66→v1.67 / CLAUDE.md v1.57→v1.58.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-09 09:28:49 +03:00 |
|