fixes fixes fixes tenaancy
This commit is contained in:
@@ -240,12 +240,16 @@ class Invoice(AccountBaseModel):
|
||||
@property
|
||||
def billing_period_start(self):
|
||||
"""Get from subscription - single source of truth"""
|
||||
return self.subscription.current_period_start if self.subscription else None
|
||||
if self.account and hasattr(self.account, 'subscription'):
|
||||
return self.account.subscription.current_period_start
|
||||
return None
|
||||
|
||||
@property
|
||||
def billing_period_end(self):
|
||||
"""Get from subscription - single source of truth"""
|
||||
return self.subscription.current_period_end if self.subscription else None
|
||||
if self.account and hasattr(self.account, 'subscription'):
|
||||
return self.account.subscription.current_period_end
|
||||
return None
|
||||
|
||||
@property
|
||||
def billing_email(self):
|
||||
@@ -285,14 +289,10 @@ class Payment(AccountBaseModel):
|
||||
Supports: Stripe, PayPal, Manual (Bank Transfer, Local Wallet)
|
||||
"""
|
||||
STATUS_CHOICES = [
|
||||
('pending', 'Pending'),
|
||||
('pending_approval', 'Pending Approval'),
|
||||
('processing', 'Processing'),
|
||||
('succeeded', 'Succeeded'),
|
||||
('completed', 'Completed'), # Legacy alias for succeeded
|
||||
('failed', 'Failed'),
|
||||
('refunded', 'Refunded'),
|
||||
('cancelled', 'Cancelled'),
|
||||
('pending_approval', 'Pending Approval'), # Manual payment submitted by user
|
||||
('succeeded', 'Succeeded'), # Payment approved and processed
|
||||
('failed', 'Failed'), # Payment rejected or failed
|
||||
('refunded', 'Refunded'), # Payment refunded (rare)
|
||||
]
|
||||
|
||||
PAYMENT_METHOD_CHOICES = [
|
||||
@@ -366,6 +366,85 @@ class Payment(AccountBaseModel):
|
||||
|
||||
def __str__(self):
|
||||
return f"Payment {self.id} - {self.get_payment_method_display()} - {self.amount} {self.currency}"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""
|
||||
Override save to automatically update related objects when payment is approved.
|
||||
When status changes to 'succeeded', automatically:
|
||||
1. Mark invoice as paid
|
||||
2. Activate subscription
|
||||
3. Activate account
|
||||
4. Add credits
|
||||
"""
|
||||
# Check if status is changing to succeeded
|
||||
is_new = self.pk is None
|
||||
old_status = None
|
||||
|
||||
if not is_new:
|
||||
try:
|
||||
old_payment = Payment.objects.get(pk=self.pk)
|
||||
old_status = old_payment.status
|
||||
except Payment.DoesNotExist:
|
||||
pass
|
||||
|
||||
# If status is changing to succeeded, trigger approval workflow
|
||||
if self.status == 'succeeded' and old_status != 'succeeded':
|
||||
from django.utils import timezone
|
||||
from django.db import transaction
|
||||
from igny8_core.business.billing.services.credit_service import CreditService
|
||||
|
||||
# Set approval timestamp if not set
|
||||
if not self.processed_at:
|
||||
self.processed_at = timezone.now()
|
||||
if not self.approved_at:
|
||||
self.approved_at = timezone.now()
|
||||
|
||||
# Save payment first
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
# Then update related objects in transaction
|
||||
with transaction.atomic():
|
||||
# 1. Update Invoice
|
||||
if self.invoice:
|
||||
self.invoice.status = 'paid'
|
||||
self.invoice.paid_at = timezone.now()
|
||||
self.invoice.save(update_fields=['status', 'paid_at'])
|
||||
|
||||
# 2. Update Account (MUST be before subscription check)
|
||||
if self.account:
|
||||
self.account.status = 'active'
|
||||
self.account.save(update_fields=['status'])
|
||||
|
||||
# 3. Update Subscription via account.subscription (one-to-one relationship)
|
||||
try:
|
||||
if hasattr(self.account, 'subscription'):
|
||||
subscription = self.account.subscription
|
||||
subscription.status = 'active'
|
||||
subscription.external_payment_id = self.manual_reference or f'payment-{self.id}'
|
||||
subscription.save(update_fields=['status', 'external_payment_id'])
|
||||
|
||||
# 4. Add Credits from subscription plan
|
||||
if subscription.plan and subscription.plan.included_credits > 0:
|
||||
CreditService.add_credits(
|
||||
account=self.account,
|
||||
amount=subscription.plan.included_credits,
|
||||
transaction_type='subscription',
|
||||
description=f'{subscription.plan.name} - Invoice {self.invoice.invoice_number}',
|
||||
metadata={
|
||||
'subscription_id': subscription.id,
|
||||
'invoice_id': self.invoice.id,
|
||||
'payment_id': self.id,
|
||||
'auto_approved': True
|
||||
}
|
||||
)
|
||||
except Exception as e:
|
||||
# Log error but don't fail payment save
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.error(f'Error updating subscription/credits for payment {self.id}: {e}', exc_info=True)
|
||||
else:
|
||||
# Normal save
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class CreditPackage(models.Model):
|
||||
|
||||
Reference in New Issue
Block a user