7.9 KiB
Payment Approval Workflow - Admin Guide
Date: December 9, 2025
Status: ✅ FULLY IMPLEMENTED
Overview
After a user signs up for a paid plan and submits payment confirmation, a manual admin approval step is required to activate their account. This is a single-step process for the admin.
Payment Status Flow
User Journey
- User signs up for paid plan (e.g., Starter - $139/month)
- User selects payment method (Bank Transfer)
- User confirms payment by submitting transaction reference
- Payment created with status:
pending_approval - ⏳ User waits for admin approval
- Admin approves payment (THIS IS THE ONLY ADMIN STEP)
- ✅ Account automatically activated with credits
Payment Statuses Explained
The system has 8 payment statuses, but only 2 are relevant for manual payment approval:
Statuses You'll See:
| Status | Meaning | What It Means |
|---|---|---|
| pending_approval | 🟡 Waiting for admin | User submitted payment proof, needs verification |
| succeeded | ✅ Approved & Completed | Admin approved, account activated, credits added |
| failed | ❌ Rejected | Admin rejected or payment failed |
| cancelled | ⚫ Cancelled | Payment was cancelled |
Statuses You Won't Use (Auto-handled):
| Status | Purpose | Used For |
|---|---|---|
| pending | Initial state | Stripe/PayPal automated payments |
| processing | Payment being processed | Stripe/PayPal automated payments |
| completed | Legacy alias | Same as "succeeded" (backward compatibility) |
| refunded | Money returned | Refund scenarios (rare) |
Admin Approval Process
Step 1: Find Pending Payment
In Django Admin:
- Go to Billing → Payments
- Filter by Status:
Pending Approval - You'll see payments with:
- Invoice number (e.g., INV-89-202512-0001)
- Amount (e.g., 139.00 USD)
- Manual reference (user's transaction ID: 22334445)
- Payment method (Bank Transfer)
Step 2: Verify Payment
Check the details:
- ✅ Manual reference matches bank statement
- ✅ Amount is correct
- ✅ Payment received in bank account
- ✅ User notes make sense
Step 3: Approve Payment
Option A: Django Admin (Current)
- Select the payment checkbox
- From "Actions" dropdown, choose "Approve selected manual payments"
- Click "Go"
- ✅ Done!
Option B: Change Status Dropdown (Your Screenshot)
- Open the payment edit page
- Change Status from
Pending ApprovaltoSucceeded - Add admin notes (optional)
- Save
- ✅ Done!
⚠️ IMPORTANT: Use Succeeded status, NOT Completed. Both work (they're aliases), but succeeded is the standard.
What Happens When You Approve?
The system automatically performs ALL these steps in a single atomic transaction:
Automatic Actions (All at Once):
1. ✅ Payment Status: pending_approval → succeeded
- Sets approved_by = admin user
- Sets approved_at = current timestamp
- Adds admin notes
2. ✅ Invoice Status: pending → paid
- Sets paid_at = current timestamp
3. ✅ Subscription Status: pending_payment → active
- Links payment reference to subscription
4. ✅ Account Status: pending_payment → active
- Account now fully activated
5. ✅ Credits Added: 0 → Plan Credits
- Starter Plan: +5,000 credits
- Growth Plan: +50,000 credits
- Scale Plan: +500,000 credits
- Creates CreditTransaction record
6. ✅ User Can Now:
- Create sites (up to plan limit)
- Use AI features
- Access all paid features
Backend Code Reference:
- File:
/backend/igny8_core/business/billing/views.py - Method:
BillingViewSet.approve_payment()(line 299-400) - All 6 steps execute atomically (all or nothing)
That's It! No Other Steps Required
❌ You DON'T Need To:
- Manually update the account status
- Manually add credits
- Manually activate subscription
- Send any emails (system does it)
- Do anything else
✅ You ONLY Need To:
- Verify payment is real
- Click "Approve" (or change status to Succeeded)
- Done!
Implementation Status
✅ FULLY IMPLEMENTED (Backend)
Backend APIs:
- ✅
POST /v1/billing/admin/payments/confirm/- User submits payment - ✅
POST /v1/billing/admin/payments/{id}/approve/- Admin approves - ✅
POST /v1/billing/admin/payments/{id}/reject/- Admin rejects
Django Admin Actions:
- ✅ Bulk approve payments
- ✅ Bulk reject payments
- ✅ Individual payment editing
Atomic Transaction:
- ✅ All 6 steps execute together
- ✅ Rollback if any step fails
- ✅ Credits added via CreditService
- ✅ Full audit trail (approved_by, approved_at)
Files:
- ✅
/backend/igny8_core/business/billing/views.py(lines 299-400) - ✅
/backend/igny8_core/modules/billing/admin.py(lines 96-161) - ✅
/backend/igny8_core/business/billing/models.py(Payment model)
✅ FULLY IMPLEMENTED (Frontend)
User Components:
- ✅ Signup form with payment method selection
- ✅ Payment confirmation modal
- ✅ Pending payment banner
- ✅ Invoice display
Files:
- ✅
/frontend/src/components/billing/PaymentConfirmationModal.tsx - ✅
/frontend/src/components/billing/PendingPaymentBanner.tsx - ✅
/frontend/src/components/auth/SignUpFormSimplified.tsx
Testing
Test Scenario:
-
User Signs Up:
Email: testuser@example.com Plan: Starter ($139/month) Payment: Bank Transfer Reference: BT-2025-12345 -
Admin Approves:
- Django Admin → Payments → Filter: Pending Approval
- Select payment → Approve selected manual payments
- Result: Payment #8 status = succeeded ✅
-
Verify Results:
-- Check payment SELECT id, status, approved_by_id, approved_at FROM igny8_payments WHERE id = 8; -- Result: succeeded, admin user, timestamp ✅ -- Check invoice SELECT id, status, paid_at FROM igny8_invoices WHERE invoice_number = 'INV-89-202512-0001'; -- Result: paid, timestamp ✅ -- Check account SELECT id, status, credits FROM igny8_tenants WHERE id = 89; -- Result: active, 5000 credits ✅ -- Check subscription SELECT id, status FROM igny8_subscriptions WHERE account_id = 89; -- Result: active ✅
Documentation References
Complete Documentation:
- ✅
/multi-tenancy/in-progress/IMPLEMENTATION-STATUS.md- Status & testing - ✅
/multi-tenancy/in-progress/PAYMENT-WORKFLOW-QUICK-START.md- Quick reference - ✅
/multi-tenancy/in-progress/FRONTEND-IMPLEMENTATION-SUMMARY.md- Frontend details - ✅
/multi-tenancy/IMPLEMENTATION-PLAN-SIGNUP-TO-PAYMENT-WORKFLOW.md- Original plan
API Documentation:
- ✅
/backend/api_integration_example.py- Python API examples - ✅
/backend/test_payment_workflow.py- Automated E2E tests
Common Questions
Q: Which status activates the account?
A: succeeded - This triggers all 6 automatic actions.
Q: What's the difference between succeeded and completed?
A: They're the same. completed is a legacy alias. Use succeeded.
Q: Do I need to manually add credits?
A: No! Credits are automatically added when you approve the payment.
Q: What if I accidentally approve the wrong payment?
A: You can change status to refunded or create a new payment reversal. Contact dev team for help.
Q: Can I approve multiple payments at once?
A: Yes! Use the bulk action "Approve selected manual payments" in Django Admin.
Q: How long does approval take?
A: Instant! All 6 steps execute in < 1 second atomically.
Summary
✅ Single Admin Action Required: Approve payment (change status to succeeded)
✅ All Else is Automatic: Account, subscription, invoice, credits all updated
✅ Fully Implemented: Backend + Frontend + Admin UI complete
✅ Production Ready: Tested and verified
You only need to verify the payment is real and click approve. Everything else happens automatically!