feat(billing): add missing payment methods and configurations

- Added migration to include global payment method configurations for Stripe and PayPal (both disabled).
- Ensured existing payment methods like bank transfer and manual payment are correctly configured.
- Added database constraints and indexes for improved data integrity in billing models.
- Introduced foreign key relationship between CreditTransaction and Payment models.
- Added webhook configuration fields to PaymentMethodConfig for future payment gateway integrations.
- Updated SignUpFormUnified component to handle payment method selection based on user country and plan.
- Implemented PaymentHistory component to display user's payment history with status indicators.
This commit is contained in:
IGNY8 VPS (Salman)
2025-12-09 06:14:44 +00:00
parent 72d0b6b0fd
commit 4d13a57068
36 changed files with 4159 additions and 253 deletions

View File

@@ -15,7 +15,8 @@ import PaymentConfirmationModal from './PaymentConfirmationModal';
interface Invoice {
id: number;
invoice_number: string;
total_amount: string; // Backend returns 'total_amount' in serialized response
total?: string; // For backward compatibility
total_amount?: string; // Backend returns 'total_amount'
currency: string;
status: string;
due_date?: string;
@@ -65,9 +66,9 @@ export default function PendingPaymentBanner({ className = '' }: PendingPaymentB
if (response.ok && data.success && data.results?.length > 0) {
setInvoice(data.results[0]);
// Load payment method if available
// Load payment method if available - use public endpoint
const country = (user?.account as any)?.billing_country || 'US';
const pmResponse = await fetch(`${API_BASE_URL}/v1/billing/admin/payment-methods/?country=${country}`, {
const pmResponse = await fetch(`${API_BASE_URL}/v1/billing/payment-configs/payment-methods/?country=${country}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
@@ -75,8 +76,10 @@ export default function PendingPaymentBanner({ className = '' }: PendingPaymentB
});
const pmData = await pmResponse.json();
// API returns array directly from DRF Response
if (pmResponse.ok && Array.isArray(pmData) && pmData.length > 0) {
// Use public endpoint response format
if (pmResponse.ok && pmData.success && pmData.results?.length > 0) {
setPaymentMethod(pmData.results[0]);
} else if (pmResponse.ok && Array.isArray(pmData) && pmData.length > 0) {
setPaymentMethod(pmData[0]);
}
}
@@ -123,10 +126,15 @@ export default function PendingPaymentBanner({ className = '' }: PendingPaymentB
<p className="mt-1 text-sm text-amber-800 dark:text-amber-200">
Your account is pending payment. Please complete your payment to activate your subscription.
</p>
<div className="mt-3">
<div className="mt-3 flex gap-2">
<Link to="/account/plans">
<Button variant="primary" size="sm">
View Billing Details
Complete Payment
</Button>
</Link>
<Link to="/dashboard">
<Button variant="outline" size="sm">
Go to Dashboard
</Button>
</Link>
</div>
@@ -251,13 +259,17 @@ export default function PendingPaymentBanner({ className = '' }: PendingPaymentB
</div>
{/* Payment Confirmation Modal */}
{showPaymentModal && invoice && paymentMethod && (
{showPaymentModal && invoice && (
<PaymentConfirmationModal
isOpen={showPaymentModal}
onClose={() => setShowPaymentModal(false)}
onSuccess={handlePaymentSuccess}
invoice={invoice}
paymentMethod={paymentMethod}
paymentMethod={paymentMethod || {
payment_method: 'bank_transfer',
display_name: 'Bank Transfer',
country_code: 'US'
}}
/>
)}
</>