billing admin account 1

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-05 08:01:55 +00:00
parent f91037b729
commit 1e718105f2
12 changed files with 378 additions and 85 deletions

View File

@@ -52,6 +52,8 @@ class InvoiceService:
billing_email=account.billing_email or account.users.filter(role='owner').first().email,
status='pending',
currency='USD',
invoice_date=timezone.now().date(),
due_date=billing_period_end.date(),
billing_period_start=billing_period_start,
billing_period_end=billing_period_end
)
@@ -83,7 +85,13 @@ class InvoiceService:
invoice_number=InvoiceService.generate_invoice_number(account),
billing_email=account.billing_email or account.users.filter(role='owner').first().email,
status='pending',
currency='USD'
currency='USD',
invoice_date=timezone.now().date(),
due_date=timezone.now().date(),
metadata={
'credit_package_id': credit_package.id,
'credit_amount': credit_package.credits,
},
)
# Add line item for credit package
@@ -125,6 +133,7 @@ class InvoiceService:
status='draft',
currency='USD',
notes=notes,
invoice_date=timezone.now().date(),
due_date=due_date or (timezone.now() + timedelta(days=30))
)

View File

@@ -77,6 +77,12 @@ class PaymentService:
if payment_method not in ['bank_transfer', 'local_wallet', 'manual']:
raise ValueError("Invalid manual payment method")
meta = metadata or {}
# propagate credit package metadata from invoice if present
if invoice.metadata.get('credit_package_id'):
meta.setdefault('credit_package_id', invoice.metadata.get('credit_package_id'))
meta.setdefault('credit_amount', invoice.metadata.get('credit_amount'))
payment = Payment.objects.create(
account=invoice.account,
invoice=invoice,
@@ -86,7 +92,7 @@ class PaymentService:
status='pending_approval',
transaction_reference=transaction_reference,
admin_notes=admin_notes,
metadata=metadata or {}
metadata=meta
)
return payment
@@ -102,7 +108,7 @@ class PaymentService:
"""
from .invoice_service import InvoiceService
payment.status = 'completed'
payment.status = 'succeeded'
payment.processed_at = timezone.now()
if transaction_id:
@@ -153,9 +159,10 @@ class PaymentService:
if payment.status != 'pending_approval':
raise ValueError("Payment is not pending approval")
payment.status = 'completed'
payment.status = 'succeeded'
payment.processed_at = timezone.now()
payment.approved_by_id = approved_by_user_id
payment.approved_at = timezone.now()
if admin_notes:
payment.admin_notes = f"{payment.admin_notes}\n\nApproval notes: {admin_notes}" if payment.admin_notes else admin_notes
@@ -212,6 +219,11 @@ class PaymentService:
except CreditPackage.DoesNotExist:
return
# Update account balance
account: Account = payment.account
account.credits = (account.credits or 0) + credit_package.credits
account.save(update_fields=['credits', 'updated_at'])
# Create credit transaction
CreditTransaction.objects.create(
account=payment.account,
@@ -244,14 +256,20 @@ class PaymentService:
return {
'methods': [
{
'id': 'stripe-default',
'type': 'stripe',
'name': 'Credit/Debit Card',
'instructions': 'Pay securely with your credit or debit card'
'display_name': 'Credit/Debit Card',
'instructions': 'Pay securely with your credit or debit card',
'is_enabled': True,
},
{
'id': 'paypal-default',
'type': 'paypal',
'name': 'PayPal',
'instructions': 'Pay with your PayPal account'
'display_name': 'PayPal',
'instructions': 'Pay with your PayPal account',
'is_enabled': True,
}
],
'stripe': True,
@@ -272,9 +290,12 @@ class PaymentService:
for config in configs:
method_flags[config.payment_method] = True
method_data = {
'id': f"{config.country_code}-{config.payment_method}-{config.id}",
'type': config.payment_method,
'name': config.display_name or config.get_payment_method_display(),
'instructions': config.instructions
'display_name': config.display_name or config.get_payment_method_display(),
'instructions': config.instructions,
'is_enabled': True,
}
# Add bank details if bank_transfer
@@ -323,8 +344,8 @@ class PaymentService:
TODO: Implement actual refund logic for Stripe/PayPal
For now, just mark as refunded
"""
if payment.status != 'completed':
raise ValueError("Can only refund completed payments")
if payment.status not in ['completed', 'succeeded']:
raise ValueError("Can only refund succeeded/complete payments")
refund_amount = amount or payment.amount
@@ -338,8 +359,9 @@ class PaymentService:
amount=-refund_amount, # Negative amount for refund
currency=payment.currency,
payment_method=payment.payment_method,
status='completed',
status='refunded',
processed_at=timezone.now(),
refunded_at=timezone.now(),
metadata={
'refund_for_payment_id': payment.id,
'refund_reason': reason,
@@ -348,10 +370,16 @@ class PaymentService:
)
# Update original payment metadata
payment.metadata['refunded'] = True
payment.metadata['refund_payment_id'] = refund.id
payment.metadata['refund_amount'] = str(refund_amount)
payment.save()
meta = payment.metadata or {}
meta['refunded'] = True
meta['refund_payment_id'] = refund.id
meta['refund_amount'] = str(refund_amount)
if reason:
meta['refund_reason'] = reason
payment.metadata = meta
payment.status = 'refunded'
payment.refunded_at = timezone.now()
payment.save(update_fields=['metadata', 'status', 'refunded_at', 'updated_at'])
return refund