11 KiB
Payment Workflow Quick Start Guide
Date: December 8, 2025
Backend Port: 8011
🚀 Quick Test Commands
1. Test Payment Methods API
# Get payment methods for Pakistan
curl "http://localhost:8011/api/v1/billing/admin/payment-methods/?country=PK" | jq
# Get payment methods for USA
curl "http://localhost:8011/api/v1/billing/admin/payment-methods/?country=US" | jq
# Get all global payment methods
curl "http://localhost:8011/api/v1/billing/admin/payment-methods/" | jq
2. Register Free Trial User
curl -X POST http://localhost:8011/api/v1/auth/register/ \
-H "Content-Type: application/json" \
-d '{
"email": "freetrial@test.com",
"password": "TestPass123!",
"password_confirm": "TestPass123!",
"first_name": "Free",
"last_name": "Trial"
}' | jq
Expected Result:
- Account created with status='trial'
- 1000 credits allocated
- Free plan assigned
- No subscription/invoice created
3. Register Paid User with Billing Info
curl -X POST http://localhost:8011/api/v1/auth/register/ \
-H "Content-Type: application/json" \
-d '{
"email": "paiduser@test.com",
"password": "TestPass123!",
"password_confirm": "TestPass123!",
"first_name": "Paid",
"last_name": "User",
"plan_slug": "starter",
"billing_email": "billing@test.com",
"billing_country": "PK",
"billing_city": "Karachi",
"billing_address_line1": "123 Main Street",
"payment_method": "bank_transfer"
}' | jq
Expected Result:
- Account created with status='pending_payment'
- 0 credits (awaiting payment)
- Subscription created with status='pending_payment'
- Invoice created with status='pending'
- AccountPaymentMethod created (type='bank_transfer')
- Billing info saved in account AND snapshotted in invoice metadata
🔄 Complete Manual Payment Workflow
Step 1: User Registers with Paid Plan
# User fills signup form with billing info
# Backend creates: Account, Subscription, Invoice, AccountPaymentMethod
Step 2: User Sees Payment Instructions
# Frontend displays invoice details and payment instructions
# For bank_transfer: Bank account details
# For local_wallet: Mobile wallet number
Step 3: User Makes External Payment
User transfers money via bank or mobile wallet
User keeps transaction reference: "BT-20251208-12345"
Step 4: User Confirms Payment
# Get auth token first
TOKEN=$(curl -X POST http://localhost:8011/api/v1/auth/login/ \
-H "Content-Type: application/json" \
-d '{"email": "paiduser@test.com", "password": "TestPass123!"}' | jq -r '.data.token')
# Submit payment confirmation
curl -X POST http://localhost:8011/api/v1/billing/admin/payments/confirm/ \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"invoice_id": 1,
"payment_method": "bank_transfer",
"manual_reference": "BT-20251208-12345",
"manual_notes": "Transferred via ABC Bank on Dec 8, 2025",
"amount": "89.00"
}' | jq
Expected Response:
{
"success": true,
"message": "Payment confirmation submitted for review. You will be notified once approved.",
"data": {
"payment_id": 1,
"invoice_id": 1,
"invoice_number": "INV-2-202512-0001",
"status": "pending_approval",
"amount": "89.00",
"currency": "USD",
"manual_reference": "BT-20251208-12345"
}
}
Step 5: Admin Approves Payment
Option A: Via Django Admin Panel
1. Go to: http://localhost:8011/admin/billing/payment/
2. Filter by status: "pending_approval"
3. Select payment(s)
4. Actions dropdown: "Approve selected manual payments"
5. Click "Go"
Option B: Via API (Admin Token Required)
# Get admin token
ADMIN_TOKEN=$(curl -X POST http://localhost:8011/api/v1/auth/login/ \
-H "Content-Type: application/json" \
-d '{"email": "admin@example.com", "password": "adminpass"}' | jq -r '.data.token')
# Approve payment
curl -X POST http://localhost:8011/api/v1/billing/admin/payments/1/approve/ \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"admin_notes": "Verified payment in bank statement on Dec 8, 2025"
}' | jq
Expected Response:
{
"success": true,
"message": "Payment approved successfully. Account activated.",
"data": {
"payment_id": 1,
"invoice_id": 1,
"invoice_number": "INV-2-202512-0001",
"account_id": 2,
"account_status": "active",
"subscription_status": "active",
"credits_added": 1000,
"total_credits": 1000,
"approved_by": "admin@example.com",
"approved_at": "2025-12-08T15:30:00Z"
}
}
What Happens Atomically:
- ✅ Payment.status → 'succeeded'
- ✅ Invoice.status → 'paid'
- ✅ Subscription.status → 'active'
- ✅ Account.status → 'active'
- ✅ Credits added: 1000 (plan.included_credits)
- ✅ CreditTransaction logged
🔍 Verification Queries
Check Account Status
docker compose -f docker-compose.app.yml exec -T igny8_backend python manage.py shell <<'EOF'
from igny8_core.auth.models import Account
account = Account.objects.get(id=2) # Replace with actual ID
print(f'Account: {account.name}')
print(f'Status: {account.status}')
print(f'Credits: {account.credits}')
print(f'Plan: {account.plan.name}')
print(f'Billing Email: {account.billing_email}')
EOF
Check Subscription & Invoice
docker compose -f docker-compose.app.yml exec -T igny8_backend python manage.py shell <<'EOF'
from igny8_core.auth.models import Subscription
from igny8_core.business.billing.models import Invoice, Payment
# Check subscription
sub = Subscription.objects.filter(account_id=2).first()
if sub:
print(f'Subscription Status: {sub.status}')
print(f'Plan: {sub.plan.name if sub.plan else "None"}')
# Check invoice
invoice = Invoice.objects.filter(account_id=2).first()
if invoice:
print(f'\nInvoice: {invoice.invoice_number}')
print(f'Status: {invoice.status}')
print(f'Total: ${invoice.total}')
print(f'Has billing snapshot: {"billing_snapshot" in invoice.metadata}')
# Check payment
payment = Payment.objects.filter(invoice=invoice).first()
if payment:
print(f'\nPayment Status: {payment.status}')
print(f'Reference: {payment.manual_reference}')
print(f'Approved by: {payment.approved_by}')
EOF
Check Credit Transactions
docker compose -f docker-compose.app.yml exec -T igny8_backend python manage.py shell <<'EOF'
from igny8_core.business.billing.models import CreditTransaction
transactions = CreditTransaction.objects.filter(account_id=2).order_by('-created_at')
print(f'Credit Transactions: {transactions.count()}\n')
for t in transactions:
print(f'{t.created_at.strftime("%Y-%m-%d %H:%M")} | {t.transaction_type:15} | {t.amount:6} credits | Balance: {t.balance_after}')
print(f' {t.description}')
EOF
📋 Payment Method Configurations
| Country | Method | Display Name | Instructions |
|---|---|---|---|
| * (Global) | stripe | Credit/Debit Card (Stripe) | - |
| * (Global) | paypal | PayPal | - |
| * (Global) | bank_transfer | Bank Transfer | Bank: ABC Bank, Account: 1234567890, SWIFT: ABCPKKA |
| PK | local_wallet | JazzCash / Easypaisa | JazzCash: 03001234567 |
🧪 Test Scenarios
Scenario 1: Free Trial User Journey
1. Register without plan_slug → Free plan assigned
2. Account status: 'trial'
3. Credits: 1000
4. Create 1 site (max_sites=1)
5. Site requires industry selection
6. SiteUserAccess auto-created
7. Use AI features with 1000 credits
Scenario 2: Paid User Journey (Happy Path)
1. Register with plan_slug='starter'
2. Fill billing form
3. Select payment_method='bank_transfer'
4. Account status: 'pending_payment', Credits: 0
5. Subscription status: 'pending_payment'
6. Invoice created (status='pending')
7. User transfers money externally
8. User submits payment confirmation with reference
9. Payment created (status='pending_approval')
10. Admin approves payment
11. Account status: 'active', Credits: 1000
12. Subscription status: 'active'
13. Invoice status: 'paid'
14. User can create 1 site and use features
Scenario 3: Rejected Payment
1-9. Same as Scenario 2
10. Admin rejects payment (reference not found)
11. Payment status: 'failed'
12. Account remains: status='pending_payment'
13. User notified (email - when implemented)
14. User can re-submit with correct reference
🔐 Admin Panel Access
Access Payment Management
URL: http://localhost:8011/admin/billing/payment/
Login: Use superuser credentials
Features:
- Filter by status (pending_approval, succeeded, failed)
- Search by manual_reference, invoice_number, account_name
- Bulk approve payments action
- Bulk reject payments action
- View payment details (reference, notes, proof)
Approve Multiple Payments
1. Go to Payments admin
2. Filter: status = "pending_approval"
3. Select multiple payments (checkboxes)
4. Action: "Approve selected manual payments"
5. Click "Go"
6. All selected payments processed atomically
📊 Database Schema Changes
New/Modified Tables
igny8_subscriptions:
- Added:
plan_id(FK to igny8_plans) - Removed:
payment_method(now property from Account)
igny8_sites:
- Modified:
industry_id(now NOT NULL, required)
igny8_payment_method_config:
- 14 records created for global + country-specific methods
igny8_invoices:
billing_period_start,billing_period_end,billing_email→ properties onlymetadatanow contains billing_snapshot
igny8_payments:
transaction_referenceremoved (duplicate of manual_reference)
🐛 Troubleshooting
Issue: "Invoice not found"
Cause: Wrong invoice_id or invoice doesn't belong to user's account
Fix: Query invoices: Invoice.objects.filter(account=request.account)
Issue: "Amount mismatch"
Cause: Submitted amount doesn't match invoice.total
Fix: Ensure exact amount from invoice (including decimals)
Issue: "Payment not pending approval"
Cause: Trying to approve already processed payment
Fix: Check payment.status before approval
Issue: "Site creation fails - industry required"
Cause: Industry field is now required
Fix: Always include industry_id when creating sites
Issue: "No credits after approval"
Cause: Plan might not have included_credits
Fix: Check plan.included_credits in database
📝 Next Steps
For Frontend Development:
- Implement billing form step in signup flow
- Create PaymentMethodSelect component
- Build payment confirmation modal
- Add pending payment status banner to dashboard
For Testing:
- Write E2E tests for free trial flow
- Write E2E tests for paid signup flow
- Test payment approval workflow
- Test payment rejection workflow
For Enhancement:
- Add email notifications (payment submitted, approved, rejected)
- Implement S3 upload for payment proof
- Add Stripe/PayPal webhook handlers for automation
- Create payment analytics dashboard
Last Updated: December 8, 2025
Backend Version: Phase 2 & 3 Complete
API Base URL: http://localhost:8011/api/v1/