678 lines
21 KiB
Markdown
678 lines
21 KiB
Markdown
# Payment System Documentation
|
|
|
|
> **Version:** 1.6.0
|
|
> **Last Updated:** January 8, 2026
|
|
> **Status:** Production Ready
|
|
|
|
This document provides comprehensive documentation of the IGNY8 payment system architecture, implementation, and flows.
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [System Overview](#system-overview)
|
|
2. [Payment Entry Points](#payment-entry-points)
|
|
3. [Backend Architecture](#backend-architecture)
|
|
4. [Frontend Architecture](#frontend-architecture)
|
|
5. [Payment Flows](#payment-flows)
|
|
6. [Country-Based Payment Rules](#country-based-payment-rules)
|
|
7. [Webhook Processing](#webhook-processing)
|
|
8. [Models Reference](#models-reference)
|
|
9. [Security Features](#security-features)
|
|
|
|
---
|
|
|
|
## System Overview
|
|
|
|
### Supported Payment Methods
|
|
|
|
| Method | Type | Regions | Use Cases |
|
|
|--------|------|---------|-----------|
|
|
| **Stripe** | Credit/Debit Card | Global | Subscriptions, Credit packages |
|
|
| **PayPal** | PayPal account | Global (except PK) | Subscriptions, Credit packages |
|
|
| **Bank Transfer** | Manual | Pakistan (PK) | Subscriptions, Credit packages |
|
|
|
|
### Payment Method Selection Logic
|
|
|
|
```
|
|
┌────────────────────────────────────────────────────────┐
|
|
│ Country-Based Payment Rules │
|
|
├────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ Global Users (non-PK): │
|
|
│ ✅ Stripe (Credit/Debit Card) │
|
|
│ ✅ PayPal │
|
|
│ ❌ Bank Transfer (not available) │
|
|
│ │
|
|
│ Pakistan Users (PK): │
|
|
│ ✅ Stripe (Credit/Debit Card) │
|
|
│ ❌ PayPal (not available in PK) │
|
|
│ ✅ Bank Transfer (manual) │
|
|
│ │
|
|
└────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Architecture Overview
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ PAYMENT SYSTEM FLOW │
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌──────────────┐ ┌──────────────┐ │
|
|
│ │ Signup │───────▶ │ /account/ │ │
|
|
│ │ (no pay) │ │ plans │ │
|
|
│ └──────────────┘ └──────┬───────┘ │
|
|
│ │ │
|
|
│ ┌─────────────┴─────────────┐ │
|
|
│ │ │ │
|
|
│ New User? Existing User? │
|
|
│ │ │ │
|
|
│ ▼ ▼ │
|
|
│ ┌──────────────┐ ┌──────────────┐ │
|
|
│ │ PendingPay- │ │ Plans/Billing│ │
|
|
│ │ mentView │ │ Dashboard │ │
|
|
│ └──────┬───────┘ └──────┬───────┘ │
|
|
│ │ │ │
|
|
│ ┌─────────┼─────────┐ ┌────────┼────────┐ │
|
|
│ │ │ │ │ │ │ │
|
|
│ ▼ ▼ ▼ ▼ ▼ ▼ │
|
|
│ Stripe PayPal Bank Upgrade Credits Manage │
|
|
│ Transfer │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Payment Entry Points
|
|
|
|
### 1. Signup Flow
|
|
|
|
**File:** `frontend/src/components/auth/SignUpFormUnified.tsx`
|
|
|
|
**Simplified Signup (No Payment on Signup):**
|
|
- User selects plan and provides details
|
|
- Account created with `status='pending_payment'` for paid plans
|
|
- User redirected to `/account/plans` to complete payment
|
|
- No payment gateway redirect from signup page
|
|
|
|
```typescript
|
|
// Signup flow creates account only, no checkout
|
|
const handleSignup = async (data) => {
|
|
const result = await register({
|
|
email, password, plan_slug, billing_country
|
|
});
|
|
// Redirect to plans page for payment
|
|
navigate('/account/plans');
|
|
};
|
|
```
|
|
|
|
### 2. Plans & Billing Page
|
|
|
|
**File:** `frontend/src/pages/account/PlansAndBillingPage.tsx`
|
|
|
|
Central hub for all payment-related actions:
|
|
|
|
**For New Users (pending_payment):**
|
|
- Shows `PendingPaymentView` component
|
|
- Full-page payment interface
|
|
- Invoice details and payment method selection
|
|
|
|
**For Existing Users:**
|
|
- Current plan and subscription status
|
|
- Credit balance and purchase
|
|
- Invoice history and downloads
|
|
- Subscription management
|
|
|
|
### 3. PendingPaymentView Component
|
|
|
|
**File:** `frontend/src/components/billing/PendingPaymentView.tsx`
|
|
|
|
Full-page payment interface for new users:
|
|
- Displays invoice details and plan info
|
|
- Payment method selection based on country
|
|
- Stripe/PayPal redirect or Bank Transfer form
|
|
- Status checking for bank transfer submissions
|
|
|
|
### 4. Bank Transfer Form
|
|
|
|
**File:** `frontend/src/components/billing/BankTransferForm.tsx`
|
|
|
|
Manual payment submission for Pakistan users:
|
|
- Bank account details display
|
|
- Transaction reference input
|
|
- File upload for payment proof
|
|
- Submission and status tracking
|
|
|
|
---
|
|
|
|
## Backend Architecture
|
|
|
|
### Service Layer
|
|
|
|
#### StripeService
|
|
|
|
**File:** `backend/igny8_core/business/billing/services/stripe_service.py`
|
|
|
|
| Method | Description |
|
|
|--------|-------------|
|
|
| `create_checkout_session()` | Create subscription checkout |
|
|
| `create_credit_checkout_session()` | Create credit package checkout |
|
|
| `create_billing_portal_session()` | Customer billing portal |
|
|
| `get_or_create_customer()` | Stripe customer management |
|
|
| `construct_webhook_event()` | Verify webhook signatures |
|
|
|
|
#### PayPalService
|
|
|
|
**File:** `backend/igny8_core/business/billing/services/paypal_service.py`
|
|
|
|
| Method | Description |
|
|
|--------|-------------|
|
|
| `create_order()` | Create one-time payment order |
|
|
| `create_subscription_order()` | Create subscription order |
|
|
| `capture_order()` | Capture approved payment |
|
|
| `verify_webhook_signature()` | Webhook verification |
|
|
|
|
#### InvoiceService
|
|
|
|
**File:** `backend/igny8_core/business/billing/services/invoice_service.py`
|
|
|
|
| Method | Description |
|
|
|--------|-------------|
|
|
| `create_subscription_invoice()` | Invoice for plan subscription |
|
|
| `create_credit_package_invoice()` | Invoice for credit purchase |
|
|
| `mark_paid()` | Mark invoice as paid |
|
|
| `generate_pdf()` | Generate PDF invoice |
|
|
|
|
#### PaymentService
|
|
|
|
**File:** `backend/igny8_core/business/billing/services/payment_service.py`
|
|
|
|
| Method | Description |
|
|
|--------|-------------|
|
|
| `create_stripe_payment()` | Record Stripe payment |
|
|
| `create_paypal_payment()` | Record PayPal payment |
|
|
| `create_manual_payment()` | Record bank transfer |
|
|
| `approve_manual_payment()` | Admin approval |
|
|
|
|
### API Endpoints
|
|
|
|
#### Stripe Endpoints
|
|
|
|
| Endpoint | Method | Description |
|
|
|----------|--------|-------------|
|
|
| `/v1/billing/stripe/config/` | GET | Publishable key |
|
|
| `/v1/billing/stripe/checkout/` | POST | Create checkout session |
|
|
| `/v1/billing/stripe/credit-checkout/` | POST | Credit package checkout |
|
|
| `/v1/billing/stripe/billing-portal/` | POST | Billing portal |
|
|
| `/v1/billing/webhooks/stripe/` | POST | Webhook handler |
|
|
|
|
#### PayPal Endpoints
|
|
|
|
| Endpoint | Method | Description |
|
|
|----------|--------|-------------|
|
|
| `/v1/billing/paypal/config/` | GET | Client ID |
|
|
| `/v1/billing/paypal/create-order/` | POST | Credit package order |
|
|
| `/v1/billing/paypal/create-subscription-order/` | POST | Subscription order |
|
|
| `/v1/billing/paypal/capture-order/` | POST | Capture payment |
|
|
| `/v1/billing/webhooks/paypal/` | POST | Webhook handler |
|
|
|
|
#### Invoice Endpoints
|
|
|
|
| Endpoint | Method | Description |
|
|
|----------|--------|-------------|
|
|
| `/v1/billing/invoices/` | GET | List invoices |
|
|
| `/v1/billing/invoices/{id}/` | GET | Invoice detail |
|
|
| `/v1/billing/invoices/{id}/download_pdf/` | GET | Download PDF |
|
|
|
|
#### Payment Endpoints
|
|
|
|
| Endpoint | Method | Description |
|
|
|----------|--------|-------------|
|
|
| `/v1/billing/payments/` | GET | List payments |
|
|
| `/v1/billing/payments/manual/` | POST | Submit bank transfer |
|
|
| `/v1/billing/admin/payments/confirm/` | POST | Admin approve/reject |
|
|
|
|
---
|
|
|
|
## Frontend Architecture
|
|
|
|
### Services
|
|
|
|
**File:** `frontend/src/services/billing.api.ts`
|
|
|
|
Key functions:
|
|
|
|
```typescript
|
|
// Gateway availability (country-based)
|
|
getAvailablePaymentGateways(userCountry?: string)
|
|
|
|
// Subscription helpers
|
|
subscribeToPlan(planId, gateway, options)
|
|
purchaseCredits(packageId, gateway, options)
|
|
|
|
// Stripe functions
|
|
createStripeCheckout(planId, options)
|
|
createStripeCreditCheckout(packageId, options)
|
|
openStripeBillingPortal(returnUrl)
|
|
|
|
// PayPal functions
|
|
createPayPalSubscriptionOrder(planId, options)
|
|
createPayPalCreditOrder(packageId, options)
|
|
capturePayPalOrder(orderId, metadata)
|
|
|
|
// Manual payment
|
|
submitManualPayment(invoiceId, data)
|
|
```
|
|
|
|
### Components
|
|
|
|
| Component | File | Purpose |
|
|
|-----------|------|---------|
|
|
| `PendingPaymentView` | `/components/billing/PendingPaymentView.tsx` | New user payment |
|
|
| `BankTransferForm` | `/components/billing/BankTransferForm.tsx` | Bank transfer submission |
|
|
| `PendingPaymentBanner` | `/components/billing/PendingPaymentBanner.tsx` | Alert for pending payments |
|
|
| `PaymentGatewaySelector` | `/components/billing/PaymentGatewaySelector.tsx` | Gateway selection UI |
|
|
| `PayInvoiceModal` | `/components/billing/PayInvoiceModal.tsx` | Pay invoice modal |
|
|
|
|
---
|
|
|
|
## Payment Flows
|
|
|
|
### Flow 1: New User Signup with Stripe
|
|
|
|
```
|
|
1. User submits signup form with plan
|
|
2. Backend creates:
|
|
- User account
|
|
- Account (status='pending_payment')
|
|
- Subscription (status='pending_payment')
|
|
- Invoice (status='pending')
|
|
3. User redirected to /account/plans
|
|
4. PendingPaymentView displays
|
|
5. User selects Stripe, clicks Pay
|
|
6. Redirect to Stripe Checkout
|
|
7. User completes payment
|
|
8. Stripe webhook received:
|
|
- Payment recorded
|
|
- Invoice marked paid
|
|
- Account activated
|
|
- Credits added
|
|
9. User redirected back to /account/plans
|
|
10. Success message, dashboard displays
|
|
```
|
|
|
|
### Flow 2: New User with PayPal (Non-PK)
|
|
|
|
```
|
|
1. Same as Stripe steps 1-4
|
|
5. User selects PayPal, clicks Pay
|
|
6. PayPal order created
|
|
7. Redirect to PayPal approval
|
|
8. User approves on PayPal
|
|
9. Redirect back with order_id
|
|
10. Frontend calls capture-order
|
|
11. Backend processes:
|
|
- Payment captured
|
|
- Payment recorded
|
|
- Invoice marked paid
|
|
- Account activated
|
|
- Credits added
|
|
12. Success displayed
|
|
```
|
|
|
|
### Flow 3: Pakistan User with Bank Transfer
|
|
|
|
```
|
|
1. Same as signup steps 1-4
|
|
5. User sees Stripe + Bank Transfer options
|
|
6. User selects Bank Transfer
|
|
7. BankTransferForm displays:
|
|
- Bank details (SCB Pakistan)
|
|
- Reference input
|
|
- Proof upload option
|
|
8. User makes transfer, submits form
|
|
9. Backend creates:
|
|
- Payment (status='pending_approval')
|
|
10. User sees "Awaiting Approval" status
|
|
11. Admin reviews in Django Admin
|
|
12. Admin approves:
|
|
- Payment marked succeeded
|
|
- Invoice marked paid
|
|
- Account activated
|
|
- Credits added
|
|
13. User receives email confirmation
|
|
```
|
|
|
|
### Flow 4: Existing User Buys Credits
|
|
|
|
```
|
|
1. User on /account/plans clicks "Buy Credits"
|
|
2. Credit package selection modal
|
|
3. User selects package and gateway
|
|
4. For Stripe/PayPal: redirect flow
|
|
5. For Bank Transfer: form submission
|
|
6. On success: credits added to account
|
|
```
|
|
|
|
---
|
|
|
|
## Country-Based Payment Rules
|
|
|
|
### Implementation in Frontend
|
|
|
|
```typescript
|
|
// billing.api.ts
|
|
export async function getAvailablePaymentGateways(userCountry?: string) {
|
|
const [stripeAvailable, paypalAvailable] = await Promise.all([
|
|
isStripeConfigured(),
|
|
isPayPalConfigured(),
|
|
]);
|
|
|
|
const isPakistan = userCountry?.toUpperCase() === 'PK';
|
|
|
|
return {
|
|
stripe: stripeAvailable,
|
|
// PayPal: NOT available for Pakistan
|
|
paypal: !isPakistan && paypalAvailable,
|
|
// Bank Transfer: ONLY for Pakistan
|
|
manual: isPakistan,
|
|
};
|
|
}
|
|
```
|
|
|
|
### Usage in Components
|
|
|
|
```typescript
|
|
// PendingPaymentView.tsx
|
|
const isPakistan = userCountry === 'PK';
|
|
|
|
// Load gateways with country filter
|
|
const gateways = await getAvailablePaymentGateways(userCountry);
|
|
|
|
// Show appropriate options
|
|
const paymentOptions = [
|
|
{ type: 'stripe', ... }, // Always shown if configured
|
|
isPakistan ? { type: 'manual', ... } : { type: 'paypal', ... },
|
|
];
|
|
```
|
|
|
|
---
|
|
|
|
## Webhook Processing
|
|
|
|
### Stripe Webhooks
|
|
|
|
**Endpoint:** `POST /v1/billing/webhooks/stripe/`
|
|
|
|
| Event | Handler Action |
|
|
|-------|----------------|
|
|
| `checkout.session.completed` | Activate subscription, add credits |
|
|
| `invoice.paid` | Add renewal credits |
|
|
| `invoice.payment_failed` | Send notification |
|
|
| `customer.subscription.updated` | Sync changes |
|
|
| `customer.subscription.deleted` | Cancel subscription |
|
|
|
|
**Idempotency:** Checks `WebhookEvent` model before processing:
|
|
```python
|
|
# Check if already processed
|
|
if WebhookEvent.objects.filter(
|
|
provider='stripe',
|
|
event_id=event_id,
|
|
status='processed'
|
|
).exists():
|
|
return # Already handled
|
|
```
|
|
|
|
### PayPal Webhooks
|
|
|
|
**Endpoint:** `POST /v1/billing/webhooks/paypal/`
|
|
|
|
| Event | Handler Action |
|
|
|-------|----------------|
|
|
| `CHECKOUT.ORDER.APPROVED` | Auto-capture if configured |
|
|
| `PAYMENT.CAPTURE.COMPLETED` | Mark succeeded, add credits |
|
|
| `PAYMENT.CAPTURE.DENIED` | Mark failed |
|
|
| `BILLING.SUBSCRIPTION.ACTIVATED` | Activate subscription |
|
|
|
|
**Signature Verification:** Enabled and enforced:
|
|
```python
|
|
is_valid = service.verify_webhook_signature(...)
|
|
if not is_valid:
|
|
return Response({'error': 'Invalid signature'}, status=400)
|
|
```
|
|
|
|
---
|
|
|
|
## Models Reference
|
|
|
|
### Invoice Model
|
|
|
|
```python
|
|
class Invoice(AccountBaseModel):
|
|
STATUS_CHOICES = [
|
|
('draft', 'Draft'),
|
|
('pending', 'Pending'),
|
|
('paid', 'Paid'),
|
|
('void', 'Void'),
|
|
('uncollectible', 'Uncollectible'),
|
|
]
|
|
|
|
invoice_number = models.CharField(max_length=50, unique=True)
|
|
subscription = models.ForeignKey('auth.Subscription', ...)
|
|
status = models.CharField(max_length=20, choices=STATUS_CHOICES)
|
|
subtotal = models.DecimalField(...)
|
|
tax = models.DecimalField(...)
|
|
total = models.DecimalField(...)
|
|
currency = models.CharField(max_length=3, default='USD')
|
|
due_date = models.DateField()
|
|
line_items = models.JSONField(default=list)
|
|
```
|
|
|
|
### Payment Model
|
|
|
|
```python
|
|
class Payment(AccountBaseModel):
|
|
STATUS_CHOICES = [
|
|
('pending', 'Pending'),
|
|
('pending_approval', 'Pending Approval'),
|
|
('succeeded', 'Succeeded'),
|
|
('failed', 'Failed'),
|
|
('refunded', 'Refunded'),
|
|
]
|
|
|
|
PAYMENT_METHOD_CHOICES = [
|
|
('stripe', 'Stripe'),
|
|
('paypal', 'PayPal'),
|
|
('bank_transfer', 'Bank Transfer'),
|
|
('manual', 'Manual'),
|
|
]
|
|
|
|
invoice = models.ForeignKey('Invoice', ...)
|
|
amount = models.DecimalField(...)
|
|
currency = models.CharField(max_length=3)
|
|
payment_method = models.CharField(choices=PAYMENT_METHOD_CHOICES)
|
|
status = models.CharField(choices=STATUS_CHOICES)
|
|
stripe_payment_intent_id = models.CharField(...)
|
|
paypal_order_id = models.CharField(...)
|
|
manual_reference = models.CharField(..., unique=True)
|
|
```
|
|
|
|
### WebhookEvent Model
|
|
|
|
```python
|
|
class WebhookEvent(models.Model):
|
|
"""Audit trail for webhook processing"""
|
|
PROVIDER_CHOICES = [
|
|
('stripe', 'Stripe'),
|
|
('paypal', 'PayPal'),
|
|
]
|
|
|
|
provider = models.CharField(choices=PROVIDER_CHOICES)
|
|
event_id = models.CharField(max_length=255)
|
|
event_type = models.CharField(max_length=100)
|
|
payload = models.JSONField()
|
|
status = models.CharField() # 'pending', 'processed', 'failed'
|
|
processed_at = models.DateTimeField(null=True)
|
|
error_message = models.TextField(blank=True)
|
|
```
|
|
|
|
---
|
|
|
|
## Security Features
|
|
|
|
### Implemented Security Measures
|
|
|
|
1. **Webhook Signature Verification**
|
|
- Stripe: `stripe.Webhook.construct_event()` with signing secret
|
|
- PayPal: `verify_webhook_signature()` API call
|
|
|
|
2. **Idempotency**
|
|
- `WebhookEvent` model tracks processed events
|
|
- Duplicate detection before processing
|
|
|
|
3. **Amount Validation**
|
|
- PayPal capture validates amount matches expected
|
|
- Prevents manipulation attacks
|
|
|
|
4. **Manual Reference Uniqueness**
|
|
- Database constraint prevents duplicate bank transfer references
|
|
- Prevents double submission
|
|
|
|
5. **CSRF Protection**
|
|
- Webhook endpoints exempt (external callers)
|
|
- All other endpoints protected
|
|
|
|
6. **Authentication**
|
|
- Payment endpoints require `IsAuthenticatedAndActive`
|
|
- Config endpoints allow `AllowAny` (public keys only)
|
|
|
|
---
|
|
|
|
## Admin Operations
|
|
|
|
### Django Admin Features
|
|
|
|
**Location:** Django Admin > Billing
|
|
|
|
- **Invoices:** View, filter, download PDF
|
|
- **Payments:** View, approve/reject manual payments
|
|
- **Credit Transactions:** Audit trail
|
|
- **Credit Packages:** Manage packages
|
|
|
|
### Manual Payment Approval
|
|
|
|
```
|
|
1. Admin navigates to Payments in Django Admin
|
|
2. Filter by status='pending_approval'
|
|
3. Review payment details and proof
|
|
4. Click "Approve" or "Reject" action
|
|
5. System automatically:
|
|
- Updates payment status
|
|
- Marks invoice paid (if approved)
|
|
- Activates account (if approved)
|
|
- Adds credits (if approved)
|
|
- Sends email notification
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
### Environment Variables
|
|
|
|
```bash
|
|
# Stripe
|
|
STRIPE_SECRET_KEY=sk_...
|
|
STRIPE_PUBLISHABLE_KEY=pk_...
|
|
STRIPE_WEBHOOK_SECRET=whsec_...
|
|
|
|
# PayPal
|
|
PAYPAL_CLIENT_ID=...
|
|
PAYPAL_CLIENT_SECRET=...
|
|
PAYPAL_WEBHOOK_ID=...
|
|
PAYPAL_MODE=sandbox|live
|
|
|
|
# General
|
|
DEFAULT_CURRENCY=USD
|
|
```
|
|
|
|
### IntegrationProvider Setup
|
|
|
|
Payment gateways configured via `IntegrationProvider` model in Django Admin:
|
|
|
|
1. **Stripe Provider:**
|
|
- Name: "Stripe"
|
|
- Provider Type: "stripe"
|
|
- Credentials: `{"secret_key": "...", "publishable_key": "...", "webhook_secret": "..."}`
|
|
|
|
2. **PayPal Provider:**
|
|
- Name: "PayPal"
|
|
- Provider Type: "paypal"
|
|
- Credentials: `{"client_id": "...", "client_secret": "...", "webhook_id": "..."}`
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
| Issue | Cause | Solution |
|
|
|-------|-------|----------|
|
|
| "Stripe not configured" | Missing IntegrationProvider | Add Stripe provider in admin |
|
|
| "PayPal not configured" | Missing IntegrationProvider | Add PayPal provider in admin |
|
|
| PayPal shown for PK users | Country not passed correctly | Ensure `billing_country` saved on account |
|
|
| Duplicate payments | Webhook retry without idempotency | Check `WebhookEvent` for duplicates |
|
|
| PDF download fails | Missing `reportlab` | Run `pip install reportlab` |
|
|
|
|
### Debug Logging
|
|
|
|
Enable billing debug logs:
|
|
```python
|
|
# settings.py
|
|
LOGGING = {
|
|
'loggers': {
|
|
'igny8_core.business.billing': {
|
|
'level': 'DEBUG',
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## File Reference
|
|
|
|
### Backend Files
|
|
|
|
| File | Description |
|
|
|------|-------------|
|
|
| `billing/views/stripe_views.py` | Stripe API endpoints |
|
|
| `billing/views/paypal_views.py` | PayPal API endpoints |
|
|
| `billing/views/refund_views.py` | Refund processing |
|
|
| `billing/services/stripe_service.py` | Stripe service layer |
|
|
| `billing/services/paypal_service.py` | PayPal service layer |
|
|
| `billing/services/invoice_service.py` | Invoice operations |
|
|
| `billing/services/payment_service.py` | Payment operations |
|
|
| `billing/services/pdf_service.py` | PDF generation |
|
|
| `billing/services/email_service.py` | Email notifications |
|
|
| `billing/models.py` | Billing models |
|
|
| `billing/urls.py` | URL routing |
|
|
|
|
### Frontend Files
|
|
|
|
| File | Description |
|
|
|------|-------------|
|
|
| `services/billing.api.ts` | API client functions |
|
|
| `pages/account/PlansAndBillingPage.tsx` | Main billing page |
|
|
| `components/billing/PendingPaymentView.tsx` | New user payment |
|
|
| `components/billing/BankTransferForm.tsx` | Bank transfer form |
|
|
| `components/billing/PayInvoiceModal.tsx` | Invoice payment modal |
|
|
| `components/billing/PaymentGatewaySelector.tsx` | Gateway selection |
|
|
| `components/billing/PendingPaymentBanner.tsx` | Payment alert banner |
|
|
|
|
---
|
|
|
|
*Document generated from production codebase - January 8, 2026*
|