final docs
This commit is contained in:
@@ -5,16 +5,16 @@
|
|||||||
|
|
||||||
## ✅ WORKING ENDPOINTS
|
## ✅ WORKING ENDPOINTS
|
||||||
|
|
||||||
### Billing V2 Endpoints (New)
|
### Billing API Endpoints
|
||||||
|
|
||||||
| Endpoint | Method | Status | Notes |
|
| Endpoint | Method | Status | Notes |
|
||||||
|----------|--------|--------|-------|
|
|----------|--------|--------|-------|
|
||||||
| `/api/v1/billing/v2/invoices/` | GET | ✅ 401 | Auth required (correct) |
|
| `/api/v1/billing/invoices/` | GET | ✅ 401 | Auth required (correct) |
|
||||||
| `/api/v1/billing/v2/payments/` | GET | ✅ 401 | Auth required (correct) |
|
| `/api/v1/billing/payments/` | GET | ✅ 401 | Auth required (correct) |
|
||||||
| `/api/v1/billing/v2/credit-packages/` | GET | ✅ 401 | Auth required (correct) |
|
| `/api/v1/billing/credit-packages/` | GET | ✅ 401 | Auth required (correct) |
|
||||||
| `/api/v1/billing/v2/transactions/` | GET | ✅ 401 | Auth required (correct) |
|
| `/api/v1/billing/transactions/` | GET | ✅ 401 | Auth required (correct) |
|
||||||
| `/api/v1/billing/v2/transactions/balance/` | GET | ✅ 401 | Auth required (correct) |
|
| `/api/v1/billing/transactions/balance/` | GET | ✅ 401 | Auth required (correct) |
|
||||||
| `/api/v1/billing/v2/admin/stats/` | GET | ✅ 401 | Auth required (correct) |
|
| `/api/v1/billing/admin/stats/` | GET | ✅ 401 | Auth required (correct) |
|
||||||
|
|
||||||
### Account Endpoints
|
### Account Endpoints
|
||||||
|
|
||||||
@@ -27,21 +27,19 @@
|
|||||||
|
|
||||||
## ❌ ISSUES FIXED
|
## ❌ ISSUES FIXED
|
||||||
|
|
||||||
### Frontend API Path Issues
|
### Frontend API Path Alignment
|
||||||
**Problem:** Frontend was calling `/api/billing/v2/...` instead of `/api/v1/billing/v2/...`
|
**Problem:** Frontend must always call the canonical `/api/v1/billing/...` endpoints (no `/v2` alias).
|
||||||
|
|
||||||
**Files Fixed:**
|
**Files Fixed:**
|
||||||
- `frontend/src/services/billing.api.ts` - Added `/v1/` prefix to all endpoints
|
- `frontend/src/services/billing.api.ts` – ensured all billing calls use `/v1/billing/...`
|
||||||
|
|
||||||
**Changes:**
|
**Changes:**
|
||||||
```typescript
|
```typescript
|
||||||
// Before:
|
// Before:
|
||||||
fetchAPI('/billing/v2/invoices/')
|
fetchAPI('/billing/invoices/')
|
||||||
fetchAPI('/account/settings/')
|
|
||||||
|
|
||||||
// After:
|
// After:
|
||||||
fetchAPI('/v1/billing/v2/invoices/')
|
fetchAPI('/v1/billing/invoices/')
|
||||||
fetchAPI('/v1/account/settings/')
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Component Export Issues
|
### Component Export Issues
|
||||||
@@ -84,33 +82,33 @@ await createManualPayment({...}) // ✅
|
|||||||
| Account Settings | `/account/settings` | ✅ Ready | `/v1/account/settings/` |
|
| Account Settings | `/account/settings` | ✅ Ready | `/v1/account/settings/` |
|
||||||
| Team Management | `/account/team` | ✅ Ready | `/v1/account/team/` |
|
| Team Management | `/account/team` | ✅ Ready | `/v1/account/team/` |
|
||||||
| Usage Analytics | `/account/usage` | ✅ Ready | `/v1/account/usage/analytics/` |
|
| Usage Analytics | `/account/usage` | ✅ Ready | `/v1/account/usage/analytics/` |
|
||||||
| Purchase Credits | `/account/purchase-credits` | ✅ Ready | `/v1/billing/v2/credit-packages/` |
|
| Purchase Credits | `/account/purchase-credits` | ✅ Ready | `/v1/billing/credit-packages/` |
|
||||||
|
|
||||||
### Billing Pages
|
### Billing Pages
|
||||||
| Page | Route | Status | Backend API |
|
| Page | Route | Status | Backend API |
|
||||||
|------|-------|--------|-------------|
|
|------|-------|--------|-------------|
|
||||||
| Credits Overview | `/billing/credits` | ✅ Ready | `/v1/billing/v2/transactions/balance/` |
|
| Credits Overview | `/billing/credits` | ✅ Ready | `/v1/billing/transactions/balance/` |
|
||||||
| Transactions | `/billing/transactions` | ✅ Ready | `/v1/billing/v2/transactions/` |
|
| Transactions | `/billing/transactions` | ✅ Ready | `/v1/billing/transactions/` |
|
||||||
| Usage | `/billing/usage` | ✅ Ready | `/v1/billing/v2/transactions/` |
|
| Usage | `/billing/usage` | ✅ Ready | `/v1/billing/transactions/` |
|
||||||
| Plans | `/settings/plans` | ✅ Ready | `/v1/auth/plans/` |
|
| Plans | `/settings/plans` | ✅ Ready | `/v1/auth/plans/` |
|
||||||
|
|
||||||
### Admin Pages
|
### Admin Pages
|
||||||
| Page | Route | Status | Backend API |
|
| Page | Route | Status | Backend API |
|
||||||
|------|-------|--------|-------------|
|
|------|-------|--------|-------------|
|
||||||
| Admin Dashboard | `/admin/billing` | ⏳ Partial | `/v1/billing/v2/admin/stats/` |
|
| Admin Dashboard | `/admin/billing` | ⏳ Partial | `/v1/billing/admin/stats/` |
|
||||||
| Billing Management | `/admin/billing` | ⏳ Partial | Multiple endpoints |
|
| Billing Management | `/admin/billing` | ⏳ Partial | Multiple endpoints |
|
||||||
|
|
||||||
## 🔧 URL STRUCTURE
|
## 🔧 URL STRUCTURE
|
||||||
|
|
||||||
### Correct URL Pattern
|
### Correct URL Pattern
|
||||||
```
|
```
|
||||||
Frontend calls: /v1/billing/v2/invoices/
|
Frontend calls: /v1/billing/invoices/
|
||||||
↓
|
↓
|
||||||
API Base URL: https://api.igny8.com/api
|
API Base URL: https://api.igny8.com/api
|
||||||
↓
|
↓
|
||||||
Full URL: https://api.igny8.com/api/v1/billing/v2/invoices/
|
Full URL: https://api.igny8.com/api/v1/billing/invoices/
|
||||||
↓
|
↓
|
||||||
Backend route: /api/v1/billing/v2/ → igny8_core.business.billing.urls
|
Backend route: /api/v1/billing/ → igny8_core.business.billing.urls
|
||||||
```
|
```
|
||||||
|
|
||||||
### API Base URL Detection
|
### API Base URL Detection
|
||||||
|
|||||||
@@ -584,3 +584,11 @@ LOGGING = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Billing / Payments configuration
|
||||||
|
STRIPE_PUBLIC_KEY = os.getenv('STRIPE_PUBLIC_KEY', '')
|
||||||
|
STRIPE_SECRET_KEY = os.getenv('STRIPE_SECRET_KEY', '')
|
||||||
|
STRIPE_WEBHOOK_SECRET = os.getenv('STRIPE_WEBHOOK_SECRET', '')
|
||||||
|
PAYPAL_CLIENT_ID = os.getenv('PAYPAL_CLIENT_ID', '')
|
||||||
|
PAYPAL_CLIENT_SECRET = os.getenv('PAYPAL_CLIENT_SECRET', '')
|
||||||
|
PAYPAL_API_BASE = os.getenv('PAYPAL_API_BASE', 'https://api-m.sandbox.paypal.com')
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ urlpatterns = [
|
|||||||
path('api/v1/planner/', include('igny8_core.modules.planner.urls')),
|
path('api/v1/planner/', include('igny8_core.modules.planner.urls')),
|
||||||
path('api/v1/writer/', include('igny8_core.modules.writer.urls')),
|
path('api/v1/writer/', include('igny8_core.modules.writer.urls')),
|
||||||
path('api/v1/system/', include('igny8_core.modules.system.urls')),
|
path('api/v1/system/', include('igny8_core.modules.system.urls')),
|
||||||
path('api/v1/billing/', include('igny8_core.modules.billing.urls')), # Basic billing endpoints (credits, usage)
|
path('api/v1/billing/', include('igny8_core.business.billing.urls')), # Billing (credits, invoices, payments, packages)
|
||||||
path('api/v1/billing/', include('igny8_core.business.billing.urls')), # Advanced billing (invoices, payments, packages)
|
|
||||||
path('api/v1/admin/', include('igny8_core.modules.billing.admin_urls')), # Admin billing
|
path('api/v1/admin/', include('igny8_core.modules.billing.admin_urls')), # Admin billing
|
||||||
path('api/v1/automation/', include('igny8_core.business.automation.urls')), # Automation endpoints
|
path('api/v1/automation/', include('igny8_core.business.automation.urls')), # Automation endpoints
|
||||||
path('api/v1/linker/', include('igny8_core.modules.linker.urls')), # Linker endpoints
|
path('api/v1/linker/', include('igny8_core.modules.linker.urls')), # Linker endpoints
|
||||||
|
|||||||
@@ -13,3 +13,4 @@ beautifulsoup4>=4.12.0
|
|||||||
psutil>=5.9.0
|
psutil>=5.9.0
|
||||||
docker>=7.0.0
|
docker>=7.0.0
|
||||||
drf-spectacular>=0.27.0
|
drf-spectacular>=0.27.0
|
||||||
|
stripe>=7.10.0
|
||||||
|
|||||||
@@ -1,287 +0,0 @@
|
|||||||
# CORRECT API Endpoints Reference
|
|
||||||
**Date:** December 5, 2025
|
|
||||||
**Purpose:** Document ACTUAL working backend endpoints for frontend integration
|
|
||||||
|
|
||||||
## ✅ WORKING BILLING ENDPOINTS
|
|
||||||
|
|
||||||
### Credit Balance
|
|
||||||
**Endpoint:** `GET /v1/billing/credits/balance/balance/`
|
|
||||||
**Returns:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"data": {
|
|
||||||
"credits": 100,
|
|
||||||
"plan_credits_per_month": 100,
|
|
||||||
"credits_used_this_month": 0,
|
|
||||||
"credits_remaining": 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Credit Transactions
|
|
||||||
**Endpoint:** `GET /v1/billing/transactions/`
|
|
||||||
**Returns:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"data": {
|
|
||||||
"results": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"amount": 100,
|
|
||||||
"transaction_type": "grant",
|
|
||||||
"description": "Initial credits",
|
|
||||||
"created_at": "2025-12-05T10:00:00Z",
|
|
||||||
"balance_after": 100
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Credit Usage Logs
|
|
||||||
**Endpoint:** `GET /v1/billing/credits/usage/`
|
|
||||||
**Returns:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"data": {
|
|
||||||
"results": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"operation_type": "clustering",
|
|
||||||
"credits_used": 10,
|
|
||||||
"cost_usd": "0.10",
|
|
||||||
"created_at": "2025-12-05T10:00:00Z"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Invoices
|
|
||||||
**Endpoint:** `GET /v1/billing/invoices/`
|
|
||||||
**Returns:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"results": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"invoice_number": "INV-2025-001",
|
|
||||||
"status": "paid",
|
|
||||||
"total_amount": "29.00",
|
|
||||||
"created_at": "2025-12-05T10:00:00Z"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Payments
|
|
||||||
**Endpoint:** `GET /v1/billing/payments/`
|
|
||||||
**Returns:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"results": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"amount": "29.00",
|
|
||||||
"status": "succeeded",
|
|
||||||
"payment_method": "stripe",
|
|
||||||
"created_at": "2025-12-05T10:00:00Z"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Payment Methods
|
|
||||||
**Endpoint:** `GET /v1/billing/payment-methods/`
|
|
||||||
**Returns:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"results": [
|
|
||||||
{
|
|
||||||
"payment_method": "stripe",
|
|
||||||
"display_name": "Credit/Debit Card",
|
|
||||||
"is_enabled": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Credit Packages
|
|
||||||
**Endpoint:** `GET /v1/billing/credit-packages/`
|
|
||||||
**Returns:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"results": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"name": "Starter Pack",
|
|
||||||
"credits": 500,
|
|
||||||
"price": "9.00",
|
|
||||||
"is_active": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## ✅ WORKING ACCOUNT ENDPOINTS
|
|
||||||
|
|
||||||
### Account Settings
|
|
||||||
**Endpoint:** `GET /v1/account/settings/`
|
|
||||||
**Returns:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"name": "My Account",
|
|
||||||
"slug": "my-account",
|
|
||||||
"billing_address_line1": "123 Main St",
|
|
||||||
"billing_city": "New York",
|
|
||||||
"credit_balance": 100,
|
|
||||||
"created_at": "2025-01-01T00:00:00Z"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Update Account Settings
|
|
||||||
**Endpoint:** `PATCH /v1/account/settings/`
|
|
||||||
**Body:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "Updated Account Name",
|
|
||||||
"billing_address_line1": "456 New St"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Team Members
|
|
||||||
**Endpoint:** `GET /v1/account/team/`
|
|
||||||
**Returns:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"results": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"email": "user@example.com",
|
|
||||||
"first_name": "John",
|
|
||||||
"last_name": "Doe",
|
|
||||||
"is_active": true,
|
|
||||||
"is_staff": false,
|
|
||||||
"date_joined": "2025-01-01T00:00:00Z"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Usage Analytics
|
|
||||||
**Endpoint:** `GET /v1/account/usage/analytics/`
|
|
||||||
**Query Params:** `?days=30`
|
|
||||||
**Returns:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"period_days": 30,
|
|
||||||
"current_balance": 100,
|
|
||||||
"usage_by_type": [
|
|
||||||
{
|
|
||||||
"transaction_type": "deduction",
|
|
||||||
"total": -50,
|
|
||||||
"count": 5
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"daily_usage": [
|
|
||||||
{
|
|
||||||
"date": "2025-12-05",
|
|
||||||
"usage": 10,
|
|
||||||
"purchases": 0,
|
|
||||||
"net": -10
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"total_usage": 50,
|
|
||||||
"total_purchases": 0
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## ⚠️ CORRECT DATA STRUCTURE FOR PAGES
|
|
||||||
|
|
||||||
### AccountBillingPage.tsx
|
|
||||||
**Should use:**
|
|
||||||
- `getCreditBalance()` → `/v1/billing/credits/balance/balance/`
|
|
||||||
- `getInvoices()` → `/v1/billing/invoices/`
|
|
||||||
- `getPayments()` → `/v1/billing/payments/`
|
|
||||||
|
|
||||||
**Data fields to use:**
|
|
||||||
```typescript
|
|
||||||
creditBalance.credits // NOT balance
|
|
||||||
creditBalance.plan_credits_per_month // NOT monthly_credits
|
|
||||||
creditBalance.credits_used_this_month // NEW field
|
|
||||||
```
|
|
||||||
|
|
||||||
### AccountSettingsPage.tsx
|
|
||||||
**Should use:**
|
|
||||||
- `getAccountSettings()` → `/v1/account/settings/`
|
|
||||||
- `updateAccountSettings(data)` → `PATCH /v1/account/settings/`
|
|
||||||
|
|
||||||
### TeamManagementPage.tsx
|
|
||||||
**Should use:**
|
|
||||||
- `getTeamMembers()` → `/v1/account/team/`
|
|
||||||
- `inviteTeamMember(email)` → `POST /v1/account/team/`
|
|
||||||
- `removeTeamMember(id)` → `DELETE /v1/account/team/{id}/`
|
|
||||||
|
|
||||||
### UsageAnalyticsPage.tsx
|
|
||||||
**Should use:**
|
|
||||||
- `getUsageAnalytics(days)` → `/v1/account/usage/analytics/?days=30`
|
|
||||||
|
|
||||||
**Data fields to use:**
|
|
||||||
```typescript
|
|
||||||
analytics.current_balance
|
|
||||||
analytics.usage_by_type // Array with transaction_type, total, count
|
|
||||||
analytics.daily_usage // Array with date, usage, purchases, net
|
|
||||||
analytics.total_usage
|
|
||||||
analytics.total_purchases
|
|
||||||
```
|
|
||||||
|
|
||||||
### PurchaseCreditsPage.tsx
|
|
||||||
**Should use:**
|
|
||||||
- `getCreditPackages()` → `/v1/billing/credit-packages/`
|
|
||||||
- `getPaymentMethods()` → `/v1/billing/payment-methods/`
|
|
||||||
- `purchaseCreditPackage(data)` → `POST /v1/billing/credit-packages/{id}/purchase/`
|
|
||||||
|
|
||||||
## 🔑 KEY POINTS
|
|
||||||
|
|
||||||
1. **Account Relationship:** All endpoints automatically filter by the logged-in user's account. The backend middleware sets `request.account` from the JWT token.
|
|
||||||
|
|
||||||
2. **Unified Response Format:** All endpoints return data in the format:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"data": { ... }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
The `fetchAPI` function in `services/api.ts` automatically extracts the `data` field.
|
|
||||||
|
|
||||||
3. **Field Names:** Backend uses specific field names that MUST match in frontend:
|
|
||||||
- `credits` (NOT `balance`)
|
|
||||||
- `plan_credits_per_month` (NOT `monthly_credits`)
|
|
||||||
- `credits_used_this_month` (NEW)
|
|
||||||
- `credits_remaining` (NEW)
|
|
||||||
|
|
||||||
4. **No Fake Data:** Pages must load real data from these endpoints. NO placeholder data.
|
|
||||||
|
|
||||||
5. **Error Handling:** If endpoint returns 404, the backend route is not registered. Check `backend/igny8_core/urls.py` and restart backend container.
|
|
||||||
|
|
||||||
## 🛠️ FRONTEND FIX CHECKLIST
|
|
||||||
|
|
||||||
- [ ] Update `billing.api.ts` to use correct endpoints
|
|
||||||
- [ ] Update type interfaces to match backend response
|
|
||||||
- [ ] Fix AccountBillingPage to use `credits`, `plan_credits_per_month`, `credits_used_this_month`
|
|
||||||
- [ ] Fix UsageAnalyticsPage to use `usage_by_type`, `daily_usage` structure
|
|
||||||
- [ ] Fix PurchaseCreditsPage to call correct payment-methods endpoint
|
|
||||||
- [ ] Fix TeamManagementPage to handle optional `date_joined` field
|
|
||||||
- [ ] Fix AccountSettingsPage to load from `/v1/account/settings/`
|
|
||||||
- [ ] Remove all placeholder/fake data
|
|
||||||
- [ ] Test all pages with real backend data
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,384 +0,0 @@
|
|||||||
# SaaS Platform Implementation - Status Summary
|
|
||||||
|
|
||||||
**Date:** December 4, 2025
|
|
||||||
**Session Status:** ✅ PHASE 1 COMPLETE - Models Created
|
|
||||||
**Ready For:** Database migrations and service implementation
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 WHAT WAS ACCOMPLISHED
|
|
||||||
|
|
||||||
### ✅ Complete Backend Models (Ready for Migration)
|
|
||||||
|
|
||||||
I've created all necessary database models with support for:
|
|
||||||
|
|
||||||
1. **Multi-Payment Gateway Support**
|
|
||||||
- ✅ Stripe integration
|
|
||||||
- ✅ PayPal integration
|
|
||||||
- ✅ Manual payments (bank transfer, local wallets)
|
|
||||||
- ✅ Per-country payment method configuration
|
|
||||||
|
|
||||||
2. **Invoice System**
|
|
||||||
- ✅ Full invoice tracking
|
|
||||||
- ✅ Line items support
|
|
||||||
- ✅ Status management (draft, pending, paid, void)
|
|
||||||
- ✅ Stripe integration fields
|
|
||||||
|
|
||||||
3. **Payment Tracking**
|
|
||||||
- ✅ Multi-gateway payment records
|
|
||||||
- ✅ Manual payment approval workflow
|
|
||||||
- ✅ Refund tracking
|
|
||||||
- ✅ Comprehensive timestamps and status
|
|
||||||
|
|
||||||
4. **Credit Packages**
|
|
||||||
- ✅ Purchasable credit bundles
|
|
||||||
- ✅ Featured packages support
|
|
||||||
- ✅ Stripe & PayPal product IDs
|
|
||||||
- ✅ Discount percentage tracking
|
|
||||||
|
|
||||||
5. **Payment Method Configuration**
|
|
||||||
- ✅ Per-country method enabling/disabling
|
|
||||||
- ✅ Bank details for manual payments
|
|
||||||
- ✅ Local wallet information
|
|
||||||
- ✅ Custom instructions per country
|
|
||||||
|
|
||||||
6. **Account Billing Information**
|
|
||||||
- ✅ Billing address fields
|
|
||||||
- ✅ Tax ID support
|
|
||||||
- ✅ Billing email
|
|
||||||
- ✅ Country tracking for payment methods
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📄 DOCUMENTS CREATED
|
|
||||||
|
|
||||||
### 1. **SAAS-STANDARDIZATION-PLAN-DEC-4-2025.md**
|
|
||||||
- Comprehensive architecture overview
|
|
||||||
- All entity relationships
|
|
||||||
- Complete UI/UX restructuring plan
|
|
||||||
- Payment integration requirements
|
|
||||||
- 32-task implementation roadmap
|
|
||||||
|
|
||||||
### 2. **IMPLEMENTATION-GUIDE-DEC-4-2025.md** (NEW)
|
|
||||||
- Step-by-step implementation guide
|
|
||||||
- All 32 tasks detailed with code examples
|
|
||||||
- Service implementation templates
|
|
||||||
- API endpoint specifications
|
|
||||||
- Frontend page requirements with components
|
|
||||||
- Quick start guide for immediate next steps
|
|
||||||
- Recommended 12-week implementation timeline
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 IMMEDIATE NEXT STEPS
|
|
||||||
|
|
||||||
### Step 1: Apply Database Migrations (5 minutes)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /data/app/igny8/backend
|
|
||||||
|
|
||||||
# Create migrations
|
|
||||||
python manage.py makemigrations billing --name add_invoice_payment_models
|
|
||||||
python manage.py makemigrations auth --name add_billing_address_fields
|
|
||||||
|
|
||||||
# Review what will be created
|
|
||||||
python manage.py sqlmigrate billing <migration_number>
|
|
||||||
python manage.py sqlmigrate auth <migration_number>
|
|
||||||
|
|
||||||
# Apply migrations
|
|
||||||
python manage.py migrate billing
|
|
||||||
python manage.py migrate auth
|
|
||||||
|
|
||||||
# Verify tables created
|
|
||||||
python manage.py dbshell
|
|
||||||
\dt igny8_invoices
|
|
||||||
\dt igny8_payments
|
|
||||||
\dt igny8_credit_packages
|
|
||||||
\dt igny8_payment_method_config
|
|
||||||
\dt igny8_tenants # Check new billing fields
|
|
||||||
\q
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Create Sample Data (10 minutes)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python manage.py shell
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
from igny8_core.business.billing.models import CreditPackage, PaymentMethodConfig
|
|
||||||
|
|
||||||
# Create credit packages
|
|
||||||
packages = [
|
|
||||||
{"name": "Starter Pack", "slug": "starter", "credits": 500, "price": 9.00, "sort_order": 1},
|
|
||||||
{"name": "Pro Pack", "slug": "pro", "credits": 2000, "price": 29.00, "discount_percentage": 10, "sort_order": 2, "is_featured": True},
|
|
||||||
{"name": "Business Pack", "slug": "business", "credits": 5000, "price": 69.00, "discount_percentage": 15, "sort_order": 3},
|
|
||||||
{"name": "Enterprise Pack", "slug": "enterprise", "credits": 20000, "price": 249.00, "discount_percentage": 20, "sort_order": 4},
|
|
||||||
]
|
|
||||||
|
|
||||||
for pkg in packages:
|
|
||||||
CreditPackage.objects.create(**pkg, is_active=True)
|
|
||||||
|
|
||||||
# Configure payment methods for US
|
|
||||||
methods = [
|
|
||||||
{"country_code": "US", "payment_method": "stripe", "display_name": "Credit/Debit Card", "sort_order": 1},
|
|
||||||
{"country_code": "US", "payment_method": "paypal", "display_name": "PayPal", "sort_order": 2},
|
|
||||||
]
|
|
||||||
|
|
||||||
for method in methods:
|
|
||||||
PaymentMethodConfig.objects.create(**method, is_enabled=True)
|
|
||||||
|
|
||||||
print("✅ Sample data created!")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Start Implementing Services (Week 1)
|
|
||||||
|
|
||||||
**Recommended Order:**
|
|
||||||
|
|
||||||
1. **InvoiceService** (Simplest - Start here)
|
|
||||||
- File: `backend/igny8_core/business/billing/services/invoice_service.py`
|
|
||||||
- Refer to IMPLEMENTATION-GUIDE-DEC-4-2025.md for full code
|
|
||||||
|
|
||||||
2. **PaymentService** (Manual payments only)
|
|
||||||
- File: `backend/igny8_core/business/billing/services/payment_service.py`
|
|
||||||
- Start with manual payment creation and approval
|
|
||||||
|
|
||||||
3. **Basic API Endpoints**
|
|
||||||
- File: `backend/igny8_core/business/billing/views.py`
|
|
||||||
- Implement `/v1/billing/invoices/` GET endpoint
|
|
||||||
- Implement `/v1/billing/credits/packages/` GET endpoint
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 IMPLEMENTATION PROGRESS
|
|
||||||
|
|
||||||
### Completed ✅
|
|
||||||
|
|
||||||
- [x] Backend models design
|
|
||||||
- [x] Multi-payment gateway support (Stripe, PayPal, Manual)
|
|
||||||
- [x] Invoice and Payment models
|
|
||||||
- [x] Credit Packages model
|
|
||||||
- [x] Payment Method Configuration model
|
|
||||||
- [x] Account billing fields
|
|
||||||
- [x] Comprehensive documentation (2 detailed guides)
|
|
||||||
- [x] 32-task implementation roadmap
|
|
||||||
- [x] All model code written and ready
|
|
||||||
|
|
||||||
### In Progress 🔄
|
|
||||||
|
|
||||||
- [ ] Database migrations (ready to run)
|
|
||||||
- [ ] Sample data creation
|
|
||||||
|
|
||||||
### Not Started ⏳
|
|
||||||
|
|
||||||
- [ ] Backend services (6 services needed)
|
|
||||||
- [ ] Stripe webhook handlers
|
|
||||||
- [ ] PayPal webhook handlers
|
|
||||||
- [ ] API endpoints (30+ endpoints)
|
|
||||||
- [ ] Frontend pages (9 pages)
|
|
||||||
- [ ] Navigation updates
|
|
||||||
- [ ] Email templates
|
|
||||||
- [ ] PDF invoice generation
|
|
||||||
- [ ] Testing
|
|
||||||
- [ ] Documentation
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📈 ESTIMATED TIMELINE
|
|
||||||
|
|
||||||
Based on the implementation guide:
|
|
||||||
|
|
||||||
| Phase | Duration | Tasks | Status |
|
|
||||||
|-------|----------|-------|--------|
|
|
||||||
| **Phase 1: Backend Foundation** | Week 1-2 | Models, Migrations, Services, Webhooks | ✅ 25% Done (Models) |
|
|
||||||
| **Phase 2: Backend APIs** | Week 3-4 | 30+ REST API endpoints | ⏳ Not Started |
|
|
||||||
| **Phase 3: Frontend Pages** | Week 5-8 | 9 user + admin pages | ⏳ Not Started |
|
|
||||||
| **Phase 4: Navigation & UI** | Week 9 | Menu restructuring | ⏳ Not Started |
|
|
||||||
| **Phase 5: Supporting Features** | Week 10-12 | Email, PDF, polish | ⏳ Not Started |
|
|
||||||
| **Phase 6: Testing & Docs** | Week 13-14 | QA, documentation | ⏳ Not Started |
|
|
||||||
|
|
||||||
**Total Estimated Time:** 12-14 weeks with 2-3 developers
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 RECOMMENDED APPROACH
|
|
||||||
|
|
||||||
### Option A: Full Implementation (12-14 weeks)
|
|
||||||
- Follow IMPLEMENTATION-GUIDE-DEC-4-2025.md step by step
|
|
||||||
- Implement all 32 tasks in order
|
|
||||||
- Result: Complete, professional SaaS billing system
|
|
||||||
|
|
||||||
### Option B: MVP Approach (4-6 weeks)
|
|
||||||
Focus on essentials first:
|
|
||||||
|
|
||||||
**Week 1-2:**
|
|
||||||
- ✅ Migrations
|
|
||||||
- ✅ InvoiceService
|
|
||||||
- ✅ PaymentService (manual only)
|
|
||||||
- ✅ Basic Invoice API
|
|
||||||
|
|
||||||
**Week 3-4:**
|
|
||||||
- ✅ Account Settings page
|
|
||||||
- ✅ Simple billing page (invoices list)
|
|
||||||
- ✅ Manual payment request flow
|
|
||||||
|
|
||||||
**Week 5-6:**
|
|
||||||
- ✅ Stripe integration (one-time payments)
|
|
||||||
- ✅ Purchase Credits page
|
|
||||||
- ✅ Payment confirmation
|
|
||||||
|
|
||||||
**Result:** Basic functional billing with manual + Stripe payments
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💡 KEY FEATURES IMPLEMENTED
|
|
||||||
|
|
||||||
### 1. **Real Payment Pages**
|
|
||||||
All pages in the implementation guide include:
|
|
||||||
- ✅ Actual data loading from APIs
|
|
||||||
- ✅ Real forms with validation
|
|
||||||
- ✅ Proper error handling
|
|
||||||
- ✅ Loading states
|
|
||||||
- ✅ Success/failure feedback
|
|
||||||
- ✅ No placeholder/mock content
|
|
||||||
|
|
||||||
### 2. **Multi-Gateway Support**
|
|
||||||
- ✅ Stripe (credit/debit cards)
|
|
||||||
- ✅ PayPal
|
|
||||||
- ✅ Bank Transfer (manual approval)
|
|
||||||
- ✅ Local Wallets (manual approval)
|
|
||||||
- ✅ Per-country configuration
|
|
||||||
|
|
||||||
### 3. **Admin Controls**
|
|
||||||
- ✅ Approve/reject manual payments
|
|
||||||
- ✅ Configure payment methods per country
|
|
||||||
- ✅ View all accounts, invoices, payments
|
|
||||||
- ✅ Create manual invoices
|
|
||||||
- ✅ System-wide analytics
|
|
||||||
|
|
||||||
### 4. **Verification & Testing**
|
|
||||||
The implementation guide includes:
|
|
||||||
- ✅ Unit test templates
|
|
||||||
- ✅ Integration test scenarios
|
|
||||||
- ✅ Stripe test mode setup
|
|
||||||
- ✅ PayPal sandbox testing
|
|
||||||
- ✅ Manual payment workflow testing
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📚 DOCUMENTATION FILES
|
|
||||||
|
|
||||||
1. **SAAS-STANDARDIZATION-PLAN-DEC-4-2025.md** (1,371 lines)
|
|
||||||
- Architecture overview
|
|
||||||
- Complete model specifications
|
|
||||||
- UI/UX redesign
|
|
||||||
- All requirements
|
|
||||||
|
|
||||||
2. **IMPLEMENTATION-GUIDE-DEC-4-2025.md** (800+ lines)
|
|
||||||
- Step-by-step tasks
|
|
||||||
- Code templates
|
|
||||||
- API specifications
|
|
||||||
- Quick start guide
|
|
||||||
- Testing procedures
|
|
||||||
|
|
||||||
3. **IMPLEMENTATION_COMPLETE-DEC-4-2025.md** (Existing)
|
|
||||||
- Previous implementations
|
|
||||||
- Credits system details
|
|
||||||
|
|
||||||
4. **BILLING-ADMIN-IMPLEMENTATION.md** (Existing)
|
|
||||||
- Current billing pages
|
|
||||||
- Admin features
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚠️ IMPORTANT REMINDERS
|
|
||||||
|
|
||||||
### Before You Start Implementation:
|
|
||||||
|
|
||||||
1. **Install Required Packages**
|
|
||||||
```bash
|
|
||||||
# Backend
|
|
||||||
pip install stripe paypalrestsdk reportlab
|
|
||||||
|
|
||||||
# Frontend
|
|
||||||
npm install @stripe/stripe-js @stripe/react-stripe-js
|
|
||||||
npm install @paypal/react-paypal-js
|
|
||||||
npm install recharts
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Set Up Environment Variables**
|
|
||||||
```python
|
|
||||||
# .env
|
|
||||||
STRIPE_PUBLIC_KEY=pk_test_...
|
|
||||||
STRIPE_SECRET_KEY=sk_test_...
|
|
||||||
STRIPE_WEBHOOK_SECRET=whsec_...
|
|
||||||
|
|
||||||
PAYPAL_CLIENT_ID=...
|
|
||||||
PAYPAL_CLIENT_SECRET=...
|
|
||||||
PAYPAL_MODE=sandbox
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Create Stripe Products**
|
|
||||||
- Log into Stripe Dashboard
|
|
||||||
- Create products for each credit package
|
|
||||||
- Create products for subscription plans
|
|
||||||
- Copy product/price IDs to database
|
|
||||||
|
|
||||||
4. **Set Up Webhooks**
|
|
||||||
- Stripe: Create webhook endpoint
|
|
||||||
- PayPal: Configure IPN/webhooks
|
|
||||||
- Test with CLI tools first
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎉 WHAT YOU HAVE NOW
|
|
||||||
|
|
||||||
✅ **Complete Backend Models** - All database tables designed and coded
|
|
||||||
✅ **Comprehensive Plan** - 1,371 lines of detailed specifications
|
|
||||||
✅ **Implementation Guide** - 800+ lines of step-by-step instructions
|
|
||||||
✅ **32 Detailed Tasks** - Each with code examples and requirements
|
|
||||||
✅ **Multi-Payment Support** - Stripe, PayPal, and manual methods
|
|
||||||
✅ **Per-Country Config** - Enable/disable payment methods by region
|
|
||||||
✅ **Real Pages Spec** - No mock content, all functional requirements
|
|
||||||
✅ **Testing Strategy** - Unit, integration, and E2E test plans
|
|
||||||
✅ **Timeline** - 12-14 week roadmap with milestones
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📞 NEXT SESSION RECOMMENDATIONS
|
|
||||||
|
|
||||||
### If continuing implementation:
|
|
||||||
|
|
||||||
**Session 1 (Next):**
|
|
||||||
- Run migrations
|
|
||||||
- Create InvoiceService
|
|
||||||
- Create basic Invoice API endpoint
|
|
||||||
- Test invoice creation
|
|
||||||
|
|
||||||
**Session 2:**
|
|
||||||
- Create PaymentService (manual payments)
|
|
||||||
- Create manual payment approval API
|
|
||||||
- Test manual payment flow
|
|
||||||
|
|
||||||
**Session 3:**
|
|
||||||
- Account Settings frontend page
|
|
||||||
- Connect to account API
|
|
||||||
- Test account updates
|
|
||||||
|
|
||||||
**Session 4:**
|
|
||||||
- Purchase Credits page
|
|
||||||
- Credit packages API
|
|
||||||
- Manual payment request form
|
|
||||||
|
|
||||||
Continue following IMPLEMENTATION-GUIDE-DEC-4-2025.md for subsequent sessions.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Status:** ✅ **FOUNDATION COMPLETE - READY FOR IMPLEMENTATION**
|
|
||||||
|
|
||||||
**Your next command should be:**
|
|
||||||
```bash
|
|
||||||
cd /data/app/igny8/backend
|
|
||||||
python manage.py makemigrations billing --name add_invoice_payment_models
|
|
||||||
```
|
|
||||||
|
|
||||||
143
docs/working-docs/billing-account-final-plan-2025-12-05.md
Normal file
143
docs/working-docs/billing-account-final-plan-2025-12-05.md
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
# IGNY8 Billing & Account Platform — Final Plan
|
||||||
|
**Date:** 2025-12-05
|
||||||
|
**Status:** Canonical (supersedes all prior billing/account docs)
|
||||||
|
**Scope:** Tenant + Admin experience across Billing, Account, Credits, Payment Methods, and Payment Gateways. Frontend + Backend must use the IGNY8 standard API system.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1) Purpose & Principles
|
||||||
|
- Single source of truth for billing/account flows.
|
||||||
|
- One canonical API namespace per audience (tenant vs admin).
|
||||||
|
- Align models ↔ services ↔ serializers ↔ frontend calls; remove drift.
|
||||||
|
- Keep manual payment path healthy while Stripe/PayPal mature.
|
||||||
|
- Favor incremental rollout with feature-flagged transitions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2) Canonical Namespaces
|
||||||
|
- Tenant: `/api/v1/billing/...`
|
||||||
|
- Admin: `/api/v1/admin/billing/...`
|
||||||
|
- Deprecate legacy `/api/v1/admin/...` (modules/billing) and duplicated routers. Optionally dual-serve for one release behind a feature flag.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3) Reality Snapshot (current code)
|
||||||
|
- Tenant billing viewsets live in `backend/igny8_core/business/billing/views.py` (invoices, payments, credit packages, transactions).
|
||||||
|
- Admin billing viewset also exists there (`pending_payments`, approvals, stats) but mounted at `/api/v1/billing/admin/...`.
|
||||||
|
- Legacy admin stack in `backend/igny8_core/modules/billing/views.py` exposes stats/users/credit-costs only; no invoices/payments.
|
||||||
|
- Model drift: `InvoiceService` expects `currency`, `tax_amount`, `total_amount` that are absent on `Invoice`. `PaymentService` uses `pending_approval`/`completed` statuses not present in `Payment.STATUS_CHOICES`.
|
||||||
|
- Frontend admin pages are wired but call nonexistent or legacy routes (e.g., `/v1/admin/payments/`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4) Backend Plan
|
||||||
|
### 4.1 Models & Migrations (billing app)
|
||||||
|
- Invoice: add `currency`, `subtotal_amount`, `tax_amount`, `total_amount`, `line_items` (JSON list), `payment_method` (string), `stripe_invoice_id`/`paypal_invoice_id` (nullable), `metadata`. Keep existing dates/status. Add index on `status, created_at`.
|
||||||
|
- Payment: extend `STATUS_CHOICES` to include `pending_approval`, `processing`, `completed`, `failed`, `refunded`, `cancelled`. Add `payment_method` enum (stripe, paypal, bank_transfer, local_wallet, manual), gateway intent/charge ids, `manual_reference`, `failure_reason`, `approved_by/at`, `metadata`.
|
||||||
|
- CreditPackage: ensure `slug`, `price`, `credits`, `stripe_price_id` exist and `is_active`, `is_featured`. Add `sort_order` for admin ordering.
|
||||||
|
- PaymentMethodConfig: keep as source for country-level enablement; ensure uniqueness `(country_code, payment_method)`.
|
||||||
|
- Write forward/backward-safe migrations; backfill currency and totals with sensible defaults (e.g., `USD`, recompute `total_amount=subtotal_amount+tax_amount` where possible).
|
||||||
|
|
||||||
|
### 4.2 Services
|
||||||
|
- `InvoiceService`: align fields; generate invoice numbers, compute subtotal/tax/total, store line items, mark paid/void/uncollectible, emit events, optionally render PDF stub.
|
||||||
|
- `PaymentService`:
|
||||||
|
- Stripe/PayPal: create intents/orders, store ids, update status on success/failure, attach to invoice, and trigger credit application when relevant.
|
||||||
|
- Manual: create `pending_approval`, allow approve/reject endpoints to flip status and apply credits.
|
||||||
|
- Sync helpers from webhooks/intents; emit structured logs.
|
||||||
|
- `SubscriptionService` (existing): ensure plan ↔ subscription sync; use Stripe subscription id; update invoice/payment when Stripe posts events.
|
||||||
|
- `CreditPackageService`: list active packages, create invoice + payment intent, on success add credits (`CreditTransaction`) and recalc balance.
|
||||||
|
|
||||||
|
### 4.3 Webhooks
|
||||||
|
- Add `/api/v1/billing/webhooks/stripe/` and `/api/v1/billing/webhooks/paypal/` with signature verification.
|
||||||
|
- Handle events: `invoice.paid`, `invoice.payment_failed`, `customer.subscription.updated/deleted`, `payment_intent.succeeded/failed`, PayPal equivalents.
|
||||||
|
- Idempotent processing; log and surface dead-letter queue for failures.
|
||||||
|
|
||||||
|
### 4.4 APIs (Tenant)
|
||||||
|
- `GET /api/v1/billing/account_balance/` – balance + monthly included.
|
||||||
|
- `GET /api/v1/billing/transactions/` – credit transactions (paginated).
|
||||||
|
- `GET /api/v1/billing/usage/` – usage logs with filters.
|
||||||
|
- `GET /api/v1/billing/invoices/` | `GET /api/v1/billing/invoices/:id/` | `GET /api/v1/billing/invoices/:id/pdf/`.
|
||||||
|
- `GET /api/v1/billing/payments/` | `GET /api/v1/billing/payments/:id/`.
|
||||||
|
- `GET /api/v1/billing/credit-packages/`.
|
||||||
|
- `POST /api/v1/billing/credits/purchase/` – create intent; returns client secret + invoice id.
|
||||||
|
- `POST /api/v1/billing/subscriptions/create|upgrade|cancel/`.
|
||||||
|
- `GET /api/v1/billing/subscriptions/` – current subscription status.
|
||||||
|
- `GET/POST /api/v1/billing/payment-methods/` – list/add; store tokens/ids, not card data.
|
||||||
|
|
||||||
|
### 4.5 APIs (Admin)
|
||||||
|
- `GET /api/v1/admin/billing/invoices/` | `GET /:id/` – all accounts, filters (status, account, method, date), pagination, export.
|
||||||
|
- `GET /api/v1/admin/billing/payments/` | `GET /:id/` – all accounts, filters (status, method, gateway).
|
||||||
|
- `POST /api/v1/admin/billing/payments/:id/approve/` | `/reject/` – manual payments only.
|
||||||
|
- `GET/POST/PATCH/DELETE /api/v1/admin/billing/credit-packages/` – CRUD with `is_featured`, `sort_order`.
|
||||||
|
- `GET /api/v1/admin/billing/stats/` – totals, MRR, pending approvals, failed webhooks.
|
||||||
|
- `GET /api/v1/admin/billing/pending_payments/` – for approvals (same payload frontend expects).
|
||||||
|
- AuthZ: developer/superuser only; enforce tenant scoping for non-admin routes.
|
||||||
|
|
||||||
|
### 4.6 Settings & Config
|
||||||
|
- Add `STRIPE_PUBLIC_KEY`, `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`, `PAYPAL_CLIENT_ID`, `PAYPAL_CLIENT_SECRET`, `PAYPAL_WEBHOOK_ID` to settings/env; feature-flag gateways.
|
||||||
|
- Rate-limit payment endpoints; CSRF exempt webhooks only.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5) Frontend Plan
|
||||||
|
### 5.1 Service Layer (`frontend/src/services/billing.api.ts`)
|
||||||
|
- Point all admin calls to `/api/v1/admin/billing/...`; remove dead `/v1/admin/...` routes.
|
||||||
|
- Reuse tenant calls for user-facing pages; ensure response shapes match new serializers (`InvoiceSerializer`, `PaymentSerializer`, `CreditPackageSerializer`).
|
||||||
|
- Add helpers for manual approval actions and credit-package CRUD.
|
||||||
|
|
||||||
|
### 5.2 Tenant Pages
|
||||||
|
- Plans & Billing (`/account/billing`): tabs for Plan, Credits, Billing History (invoices), Payment Methods. Uses balance, subscription, invoices, payment-methods, credit-packages, purchase intent.
|
||||||
|
- Purchase Credits (`/account/credits/purchase`): list packages → create purchase intent → confirm via Stripe/PayPal/manual upload → poll payment.
|
||||||
|
- Invoices (`/account/invoices`): paginated table, filters, PDF download.
|
||||||
|
- Payment Methods: list/add/remove default (via tokens).
|
||||||
|
|
||||||
|
### 5.3 Admin Pages
|
||||||
|
- Billing Overview (`/admin/billing`): stats from `/admin/billing/stats/`, pending approvals summary.
|
||||||
|
- Invoices (`/admin/invoices`): uses `/admin/billing/invoices/`; add filters (account, status, method, date) and CSV/PDF export.
|
||||||
|
- Payments (`/admin/payments`): uses `/admin/billing/payments/`; add filters and status badges.
|
||||||
|
- Credit Packages (`/admin/credit-packages`): CRUD via admin endpoints; show `is_active`, `is_featured`, `sort_order`, Stripe price id.
|
||||||
|
- Payment Approvals (`/admin/payments/approvals`): call `pending_payments`, approve/reject endpoints; show invoice link and manual references.
|
||||||
|
- Sidebar links already present—only fix data wiring.
|
||||||
|
|
||||||
|
### 5.4 UX/Consistency
|
||||||
|
- Standard empty/error/loading states across billing pages.
|
||||||
|
- Currency display from invoice/payment `currency`.
|
||||||
|
- Role-guard tenant routes (owner/admin only for purchases; read-only for others where applicable).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6) Sequenced Action Plan
|
||||||
|
- **Day 0 (alignment):** Merge this doc; add “retired” note to older docs; choose namespace flag (`USE_NEW_ADMIN_BILLING_API=true`).
|
||||||
|
- **Phase 1 (backend, 2-3 days):** Migrate models; update services; add admin list endpoints; webhook stubs; tests for serializers and viewsets.
|
||||||
|
- **Phase 2 (gateways + frontend wiring, 3-4 days):** Implement Stripe/PayPal intent paths, hook webhooks, wire `billing.api.ts` to new endpoints, fix admin pages, enable manual approvals end-to-end.
|
||||||
|
- **Phase 3 (polish, 2 days):** Add exports, filters, pagination polish; observability (structured logs, alerts); finalize docs and remove legacy router.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7) Deliverables & DoD
|
||||||
|
- Schema migration applied and reversible; services match models.
|
||||||
|
- Canonical endpoints live and documented; legacy admin endpoints removed/flagged off.
|
||||||
|
- Tenant billing pages load without 404s; purchases and subscriptions succeed (manual + Stripe at minimum).
|
||||||
|
- Admin pages show data, support approvals, and package CRUD.
|
||||||
|
- Tests: unit (services), API (tenant/admin billing), integration (purchase + manual approval flow), webhook idempotency.
|
||||||
|
- Docs: this file referenced from legacy docs; endpoint matrix embedded in `billing.api.ts` JSDoc or a short `/docs/billing/api-map.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8) Quick Endpoint Matrix (canonical)
|
||||||
|
- Tenant: invoices (`/api/v1/billing/invoices`), payments (`/api/v1/billing/payments`), credit packages + purchase (`/api/v1/billing/credit-packages`, `/credits/purchase`), subscription create/upgrade/cancel (`/subscriptions/...`), payment methods (`/payment-methods`), usage/transactions/balance.
|
||||||
|
- Admin: invoices (`/api/v1/admin/billing/invoices`), payments (`/api/v1/admin/billing/payments`), pending approvals (`/api/v1/admin/billing/pending_payments`), approve/reject (`/api/v1/admin/billing/payments/:id/approve|reject`), credit packages CRUD (`/api/v1/admin/billing/credit-packages`), stats (`/api/v1/admin/billing/stats`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9) Rollout & Migration Notes
|
||||||
|
- Run migrations during maintenance window; backfill currency/totals.
|
||||||
|
- If dual-stack needed, proxy legacy admin routes to new handlers temporarily.
|
||||||
|
- Communicate new admin endpoints to frontend before flipping flags.
|
||||||
|
- Validate webhook secrets in non-prod before enabling in prod.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10) Retirement Notice
|
||||||
|
This document supersedes `docs/working-docs/Original-plan-may-have-wrong-logic.md` and `docs/working-docs/admin-billing-plan-2025-12-05.md`. Treat those as retired; keep only for historical reference.
|
||||||
|
|
||||||
@@ -1,634 +0,0 @@
|
|||||||
/**
|
|
||||||
* Billing API Service
|
|
||||||
* Uses STANDARD existing billing endpoints from /v1/billing/ and /v1/system/
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { fetchAPI } from './api';
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// TYPES
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export interface CreditBalance {
|
|
||||||
balance: number;
|
|
||||||
credits: number;
|
|
||||||
plan_credits_per_month: number;
|
|
||||||
credits_used_this_month: number;
|
|
||||||
credits_remaining: number;
|
|
||||||
subscription_plan?: string;
|
|
||||||
monthly_credits?: number;
|
|
||||||
subscription_status?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CreditTransaction {
|
|
||||||
id: number;
|
|
||||||
amount: number;
|
|
||||||
transaction_type: 'purchase' | 'subscription' | 'refund' | 'deduction' | 'adjustment' | 'grant';
|
|
||||||
description: string;
|
|
||||||
created_at: string;
|
|
||||||
reference_id?: string;
|
|
||||||
metadata?: Record<string, any>;
|
|
||||||
balance_after?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CreditUsageLog {
|
|
||||||
id: number;
|
|
||||||
operation_type: string;
|
|
||||||
credits_used: number;
|
|
||||||
cost_usd: string;
|
|
||||||
model_used?: string;
|
|
||||||
tokens_input?: number;
|
|
||||||
tokens_output?: number;
|
|
||||||
created_at: string;
|
|
||||||
metadata?: Record<string, any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminBillingStats {
|
|
||||||
total_accounts: number;
|
|
||||||
active_subscriptions: number;
|
|
||||||
total_revenue: string;
|
|
||||||
revenue_this_month?: string;
|
|
||||||
new_accounts_this_month?: number;
|
|
||||||
active_accounts?: number;
|
|
||||||
credits_issued_30d?: number;
|
|
||||||
credits_used_30d?: number;
|
|
||||||
pending_approvals?: number;
|
|
||||||
invoices_pending?: number;
|
|
||||||
invoices_overdue?: number;
|
|
||||||
system_health?: {
|
|
||||||
status: string;
|
|
||||||
last_check: string;
|
|
||||||
};
|
|
||||||
recent_activity?: Array<{
|
|
||||||
id: number;
|
|
||||||
type: string;
|
|
||||||
account_name: string;
|
|
||||||
amount: string;
|
|
||||||
currency: string;
|
|
||||||
timestamp: string;
|
|
||||||
description: string;
|
|
||||||
}>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CreditCostConfig {
|
|
||||||
id: number;
|
|
||||||
operation_type: string;
|
|
||||||
credits_cost: number;
|
|
||||||
unit: string;
|
|
||||||
display_name: string;
|
|
||||||
description: string;
|
|
||||||
is_active: boolean;
|
|
||||||
updated_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminUser {
|
|
||||||
id: number;
|
|
||||||
email: string;
|
|
||||||
account_name: string;
|
|
||||||
account_id: number;
|
|
||||||
role: string;
|
|
||||||
is_active: boolean;
|
|
||||||
credit_balance: number;
|
|
||||||
plan_name?: string;
|
|
||||||
created_at: string;
|
|
||||||
last_login?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// CREDIT BALANCE & TRANSACTIONS
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export async function getCreditBalance(): Promise<CreditBalance> {
|
|
||||||
return fetchAPI('/v1/billing/credits/balance/balance/');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getCreditTransactions(): Promise<{
|
|
||||||
results: CreditTransaction[];
|
|
||||||
count: number;
|
|
||||||
current_balance?: number;
|
|
||||||
}> {
|
|
||||||
return fetchAPI('/v1/billing/credits/transactions/');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// CREDIT USAGE LOGS
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export async function getCreditUsage(params?: {
|
|
||||||
operation_type?: string;
|
|
||||||
start_date?: string;
|
|
||||||
end_date?: string;
|
|
||||||
}): Promise<{
|
|
||||||
results: CreditUsageLog[];
|
|
||||||
count: number;
|
|
||||||
}> {
|
|
||||||
const queryParams = new URLSearchParams();
|
|
||||||
if (params?.operation_type) queryParams.append('operation_type', params.operation_type);
|
|
||||||
if (params?.start_date) queryParams.append('start_date', params.start_date);
|
|
||||||
if (params?.end_date) queryParams.append('end_date', params.end_date);
|
|
||||||
|
|
||||||
const url = `/v1/billing/credits/usage/${queryParams.toString() ? '?' + queryParams.toString() : ''}`;
|
|
||||||
return fetchAPI(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getCreditUsageSummary(params?: {
|
|
||||||
start_date?: string;
|
|
||||||
end_date?: string;
|
|
||||||
}): Promise<{
|
|
||||||
total_credits_used: number;
|
|
||||||
total_cost_usd: string;
|
|
||||||
by_operation: Record<string, {
|
|
||||||
credits: number;
|
|
||||||
cost: number;
|
|
||||||
count: number;
|
|
||||||
}>;
|
|
||||||
by_model: Record<string, {
|
|
||||||
credits: number;
|
|
||||||
cost: number;
|
|
||||||
count: number;
|
|
||||||
}>;
|
|
||||||
}> {
|
|
||||||
const queryParams = new URLSearchParams();
|
|
||||||
if (params?.start_date) queryParams.append('start_date', params.start_date);
|
|
||||||
if (params?.end_date) queryParams.append('end_date', params.end_date);
|
|
||||||
|
|
||||||
const url = `/v1/billing/credits/usage/summary/${queryParams.toString() ? '?' + queryParams.toString() : ''}`;
|
|
||||||
return fetchAPI(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getCreditUsageLimits(): Promise<{
|
|
||||||
plan_name: string;
|
|
||||||
plan_credits_per_month: number;
|
|
||||||
credits_used_this_month: number;
|
|
||||||
credits_remaining: number;
|
|
||||||
percentage_used: number;
|
|
||||||
approaching_limit: boolean;
|
|
||||||
}> {
|
|
||||||
return fetchAPI('/v1/billing/credits/usage/limits/');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ADMIN - BILLING STATS & MANAGEMENT
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export async function getAdminBillingStats(): Promise<AdminBillingStats> {
|
|
||||||
return fetchAPI('/v1/admin/billing/stats/');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAdminUsers(params?: {
|
|
||||||
search?: string;
|
|
||||||
role?: string;
|
|
||||||
is_active?: boolean;
|
|
||||||
}): Promise<{
|
|
||||||
results: AdminUser[];
|
|
||||||
count: number;
|
|
||||||
}> {
|
|
||||||
const queryParams = new URLSearchParams();
|
|
||||||
if (params?.search) queryParams.append('search', params.search);
|
|
||||||
if (params?.role) queryParams.append('role', params.role);
|
|
||||||
if (params?.is_active !== undefined) queryParams.append('is_active', String(params.is_active));
|
|
||||||
|
|
||||||
const url = `/v1/admin/users/${queryParams.toString() ? '?' + queryParams.toString() : ''}`;
|
|
||||||
return fetchAPI(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function adjustUserCredits(
|
|
||||||
userId: number,
|
|
||||||
data: {
|
|
||||||
amount: number;
|
|
||||||
reason: string;
|
|
||||||
}
|
|
||||||
): Promise<{
|
|
||||||
message: string;
|
|
||||||
new_balance: number;
|
|
||||||
}> {
|
|
||||||
return fetchAPI(`/v1/admin/users/${userId}/adjust-credits/`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ADMIN - CREDIT COSTS CONFIGURATION
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export async function getCreditCosts(): Promise<{
|
|
||||||
results: CreditCostConfig[];
|
|
||||||
count: number;
|
|
||||||
}> {
|
|
||||||
return fetchAPI('/v1/admin/credit-costs/');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function updateCreditCosts(
|
|
||||||
costs: Array<{
|
|
||||||
operation_type: string;
|
|
||||||
credits_cost: number;
|
|
||||||
}>
|
|
||||||
): Promise<{
|
|
||||||
message: string;
|
|
||||||
updated_count: number;
|
|
||||||
}> {
|
|
||||||
return fetchAPI('/v1/admin/credit-costs/', {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({ costs }),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ACCOUNT SETTINGS (from /v1/system/)
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export interface AccountSettings {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
slug: string;
|
|
||||||
billing_address_line1?: string;
|
|
||||||
billing_address_line2?: string;
|
|
||||||
billing_city?: string;
|
|
||||||
billing_state?: string;
|
|
||||||
billing_postal_code?: string;
|
|
||||||
billing_country?: string;
|
|
||||||
tax_id?: string;
|
|
||||||
billing_email?: string;
|
|
||||||
credit_balance: number;
|
|
||||||
plan_name?: string;
|
|
||||||
created_at: string;
|
|
||||||
updated_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAccountSettings(): Promise<AccountSettings> {
|
|
||||||
return fetchAPI('/v1/system/settings/account/');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function updateAccountSettings(
|
|
||||||
settings: Partial<AccountSettings>
|
|
||||||
): Promise<{
|
|
||||||
message: string;
|
|
||||||
account: Partial<AccountSettings>;
|
|
||||||
}> {
|
|
||||||
return fetchAPI('/v1/system/settings/account/', {
|
|
||||||
method: 'PATCH',
|
|
||||||
body: JSON.stringify(settings),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// TYPES
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export interface CreditPackage {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
slug: string;
|
|
||||||
credits: number;
|
|
||||||
price: string;
|
|
||||||
discount_percentage: number;
|
|
||||||
is_featured: boolean;
|
|
||||||
description: string;
|
|
||||||
display_order: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Invoice {
|
|
||||||
id: number;
|
|
||||||
invoice_number: string;
|
|
||||||
status: 'draft' | 'pending' | 'paid' | 'void';
|
|
||||||
total_amount: string;
|
|
||||||
subtotal: string;
|
|
||||||
tax_amount: string;
|
|
||||||
currency: string;
|
|
||||||
created_at: string;
|
|
||||||
paid_at: string | null;
|
|
||||||
due_date: string | null;
|
|
||||||
line_items: Array<{
|
|
||||||
description: string;
|
|
||||||
amount: string;
|
|
||||||
quantity: number;
|
|
||||||
}>;
|
|
||||||
billing_period_start: string | null;
|
|
||||||
billing_period_end: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Payment {
|
|
||||||
id: number;
|
|
||||||
amount: string;
|
|
||||||
currency: string;
|
|
||||||
payment_method: 'stripe' | 'paypal' | 'bank_transfer' | 'local_wallet' | 'manual';
|
|
||||||
status: 'pending' | 'completed' | 'failed' | 'pending_approval';
|
|
||||||
created_at: string;
|
|
||||||
processed_at: string | null;
|
|
||||||
invoice_id: number;
|
|
||||||
invoice_number: string | null;
|
|
||||||
transaction_reference: string;
|
|
||||||
failure_reason: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PaymentMethod {
|
|
||||||
type: string;
|
|
||||||
name: string;
|
|
||||||
instructions: string;
|
|
||||||
bank_details?: {
|
|
||||||
bank_name: string;
|
|
||||||
account_number: string;
|
|
||||||
routing_number: string;
|
|
||||||
swift_code: string;
|
|
||||||
};
|
|
||||||
wallet_details?: {
|
|
||||||
wallet_type: string;
|
|
||||||
wallet_id: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CreditTransaction {
|
|
||||||
id: number;
|
|
||||||
amount: number;
|
|
||||||
transaction_type: string;
|
|
||||||
description: string;
|
|
||||||
created_at: string;
|
|
||||||
reference_id: string;
|
|
||||||
metadata: Record<string, any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CreditBalance {
|
|
||||||
balance: number;
|
|
||||||
subscription_plan: string;
|
|
||||||
monthly_credits: number;
|
|
||||||
subscription_status: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PendingPayment {
|
|
||||||
id: number;
|
|
||||||
account_name: string;
|
|
||||||
amount: string;
|
|
||||||
currency: string;
|
|
||||||
payment_method: string;
|
|
||||||
transaction_reference: string;
|
|
||||||
created_at: string;
|
|
||||||
invoice_number: string | null;
|
|
||||||
admin_notes: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// CREDIT PACKAGES
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export async function getCreditPackages(): Promise<{ results: CreditPackage[]; count: number }> {
|
|
||||||
return fetchAPI('/billing/v2/credit-packages/');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function purchaseCreditPackage(
|
|
||||||
packageId: number,
|
|
||||||
paymentMethod: string
|
|
||||||
): Promise<{
|
|
||||||
invoice_id: number;
|
|
||||||
invoice_number: string;
|
|
||||||
total_amount: string;
|
|
||||||
message: string;
|
|
||||||
next_action: string;
|
|
||||||
}> {
|
|
||||||
return fetchAPI(`/billing/v2/credit-packages/${packageId}/purchase/`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({ payment_method: paymentMethod }),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// INVOICES
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export async function getInvoices(status?: string): Promise<{ results: Invoice[]; count: number }> {
|
|
||||||
const params = status ? `?status=${status}` : '';
|
|
||||||
return fetchAPI(`/billing/v2/invoices/${params}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getInvoice(invoiceId: number): Promise<Invoice> {
|
|
||||||
return fetchAPI(`/v1/billing/invoices/${invoiceId}/`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function downloadInvoicePDF(invoiceId: number): Promise<Blob> {
|
|
||||||
const response = await fetch(`/api/v1/billing/invoices/${invoiceId}/download_pdf/`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${localStorage.getItem('access_token')}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to download invoice');
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.blob();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// PAYMENTS
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export async function getPayments(status?: string): Promise<{ results: Payment[]; count: number }> {
|
|
||||||
const params = status ? `?status=${status}` : '';
|
|
||||||
return fetchAPI(`/v1/billing/payments/${params}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAvailablePaymentMethods(): Promise<{
|
|
||||||
methods: PaymentMethod[];
|
|
||||||
stripe: boolean;
|
|
||||||
paypal: boolean;
|
|
||||||
bank_transfer: boolean;
|
|
||||||
local_wallet: boolean;
|
|
||||||
}> {
|
|
||||||
return fetchAPI('/v1/billing/payments/available_methods/');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createManualPayment(data: {
|
|
||||||
invoice_id: number;
|
|
||||||
payment_method: 'bank_transfer' | 'local_wallet';
|
|
||||||
transaction_reference: string;
|
|
||||||
notes?: string;
|
|
||||||
}): Promise<{
|
|
||||||
id: number;
|
|
||||||
status: string;
|
|
||||||
message: string;
|
|
||||||
}> {
|
|
||||||
return fetchAPI('/v1/billing/payments/create_manual_payment/', {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// CREDIT TRANSACTIONS
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export async function getCreditTransactions(): Promise<{
|
|
||||||
results: CreditTransaction[];
|
|
||||||
count: number;
|
|
||||||
current_balance: number;
|
|
||||||
}> {
|
|
||||||
return fetchAPI('/v1/billing/credits/transactions/');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getCreditBalance(): Promise<CreditBalance> {
|
|
||||||
return fetchAPI('/v1/billing/credits/balance/balance/');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ADMIN - PAYMENT APPROVALS
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export async function getPendingPayments(): Promise<{
|
|
||||||
results: PendingPayment[];
|
|
||||||
count: number;
|
|
||||||
}> {
|
|
||||||
return fetchAPI('/v1/billing/admin/pending_payments/');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function approvePayment(
|
|
||||||
paymentId: number,
|
|
||||||
notes?: string
|
|
||||||
): Promise<{
|
|
||||||
id: number;
|
|
||||||
status: string;
|
|
||||||
message: string;
|
|
||||||
}> {
|
|
||||||
return fetchAPI(`/v1/billing/admin/${paymentId}/approve_payment/`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({ notes }),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function rejectPayment(
|
|
||||||
paymentId: number,
|
|
||||||
reason: string
|
|
||||||
): Promise<{
|
|
||||||
id: number;
|
|
||||||
status: string;
|
|
||||||
message: string;
|
|
||||||
}> {
|
|
||||||
return fetchAPI(`/v1/billing/admin/${paymentId}/reject_payment/`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({ reason }),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAdminBillingStats(): Promise<{
|
|
||||||
total_accounts: number;
|
|
||||||
active_subscriptions: number;
|
|
||||||
total_revenue: string;
|
|
||||||
pending_approvals: number;
|
|
||||||
invoices_pending: number;
|
|
||||||
invoices_paid: number;
|
|
||||||
}> {
|
|
||||||
return fetchAPI('/v1/billing/v2/admin/stats/');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// ACCOUNT SETTINGS
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export interface AccountSettings {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
slug: string;
|
|
||||||
billing_address_line1: string;
|
|
||||||
billing_address_line2: string;
|
|
||||||
billing_city: string;
|
|
||||||
billing_state: string;
|
|
||||||
billing_postal_code: string;
|
|
||||||
billing_country: string;
|
|
||||||
tax_id: string;
|
|
||||||
billing_email: string;
|
|
||||||
credit_balance: number;
|
|
||||||
created_at: string;
|
|
||||||
updated_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAccountSettings(): Promise<AccountSettings> {
|
|
||||||
return fetchAPI('/v1/system/settings/account/');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function updateAccountSettings(
|
|
||||||
settings: Partial<AccountSettings>
|
|
||||||
): Promise<{
|
|
||||||
message: string;
|
|
||||||
account: Partial<AccountSettings>;
|
|
||||||
}> {
|
|
||||||
return fetchAPI('/v1/account/settings/', {
|
|
||||||
method: 'PATCH',
|
|
||||||
body: JSON.stringify(settings),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// TEAM MANAGEMENT
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export interface TeamMember {
|
|
||||||
id: number;
|
|
||||||
email: string;
|
|
||||||
first_name: string;
|
|
||||||
last_name: string;
|
|
||||||
is_active: boolean;
|
|
||||||
is_staff: boolean;
|
|
||||||
date_joined: string;
|
|
||||||
last_login: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getTeamMembers(): Promise<{
|
|
||||||
results: TeamMember[];
|
|
||||||
count: number;
|
|
||||||
}> {
|
|
||||||
return fetchAPI('/v1/account/team/');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function inviteTeamMember(data: {
|
|
||||||
email: string;
|
|
||||||
first_name?: string;
|
|
||||||
last_name?: string;
|
|
||||||
}): Promise<{
|
|
||||||
message: string;
|
|
||||||
user: Partial<TeamMember>;
|
|
||||||
}> {
|
|
||||||
return fetchAPI('/v1/account/team/', {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function removeTeamMember(userId: number): Promise<{
|
|
||||||
message: string;
|
|
||||||
}> {
|
|
||||||
return fetchAPI(`/v1/account/team/${userId}/`, {
|
|
||||||
method: 'DELETE',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// USAGE ANALYTICS
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
export interface UsageAnalytics {
|
|
||||||
period_days: number;
|
|
||||||
start_date: string;
|
|
||||||
end_date: string;
|
|
||||||
current_balance: number;
|
|
||||||
usage_by_type: Array<{
|
|
||||||
transaction_type: string;
|
|
||||||
total: number;
|
|
||||||
count: number;
|
|
||||||
}>;
|
|
||||||
purchases_by_type: Array<{
|
|
||||||
transaction_type: string;
|
|
||||||
total: number;
|
|
||||||
count: number;
|
|
||||||
}>;
|
|
||||||
daily_usage: Array<{
|
|
||||||
date: string;
|
|
||||||
usage: number;
|
|
||||||
purchases: number;
|
|
||||||
net: number;
|
|
||||||
}>;
|
|
||||||
total_usage: number;
|
|
||||||
total_purchases: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getUsageAnalytics(days: number = 30): Promise<UsageAnalytics> {
|
|
||||||
return fetchAPI(`/v1/account/usage/analytics/?days=${days}`);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user