from django.conf import settings from django.db import models from infrasynth.shared.enums import BillingInterval, InvoiceStatus, SubscriptionStatus class PaymentGateway(models.Model): slug = models.SlugField(max_length=100, primary_key=True) display_name = models.CharField(max_length=200) gateway_class = models.CharField(max_length=500) config = models.JSONField(default=dict) is_active = models.BooleanField(default=True) supported_currencies = models.JSONField(default=list) webhook_secret = models.CharField(max_length=500, blank=True) class Meta: db_table = "billing_gateway" def __str__(self): return self.display_name class BillingPlan(models.Model): slug = models.SlugField(max_length=100, unique=True) name = models.CharField(max_length=200) description = models.TextField(blank=True) price_amount = models.DecimalField(max_digits=12, decimal_places=2) price_currency = models.CharField(max_length=3, default="USD") interval = models.CharField(max_length=20, choices=BillingInterval.choices) trial_days = models.IntegerField(default=0) features = models.JSONField(default=list) is_active = models.BooleanField(default=True) gateway = models.ForeignKey( PaymentGateway, on_delete=models.SET_NULL, null=True, blank=True, related_name="+", ) external_id = models.CharField(max_length=255, blank=True) class Meta: db_table = "billing_plan" def __str__(self): return self.name class Subscription(models.Model): user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="+", ) plan = models.ForeignKey( BillingPlan, on_delete=models.SET_NULL, null=True, blank=True, related_name="+", ) gateway = models.ForeignKey( PaymentGateway, on_delete=models.SET_NULL, null=True, blank=True, related_name="+", ) external_id = models.CharField(max_length=255, blank=True) status = models.CharField(max_length=20, choices=SubscriptionStatus.choices) current_period_start = models.DateTimeField(null=True, blank=True) current_period_end = models.DateTimeField(null=True, blank=True) cancel_at_period_end = models.BooleanField(default=False) cancelled_at = models.DateTimeField(null=True, blank=True) trial_end = models.DateTimeField(null=True, blank=True) metadata = models.JSONField(default=dict) class Meta: db_table = "billing_subscription" def __str__(self): return f"{self.user}#{self.plan}" class Invoice(models.Model): subscription = models.ForeignKey( Subscription, on_delete=models.SET_NULL, null=True, blank=True, related_name="+", ) user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="+", ) gateway = models.ForeignKey( PaymentGateway, on_delete=models.SET_NULL, null=True, blank=True, related_name="+", ) external_id = models.CharField(max_length=255, blank=True) invoice_number = models.CharField(max_length=100, unique=True) amount = models.DecimalField(max_digits=12, decimal_places=2) currency = models.CharField(max_length=3, default="USD") tax_amount = models.DecimalField(max_digits=12, decimal_places=2, default=0) tax_name = models.CharField(max_length=100, blank=True) status = models.CharField(max_length=20, choices=InvoiceStatus.choices) due_date = models.DateTimeField(null=True, blank=True) paid_at = models.DateTimeField(null=True, blank=True) line_items = models.JSONField(default=list) pdf_file = models.ForeignKey( "infrasynth_files.StoredFile", on_delete=models.SET_NULL, null=True, blank=True, related_name="+", ) metadata = models.JSONField(default=dict) class Meta: db_table = "billing_invoice" def __str__(self): return self.invoice_number class PaymentTransaction(models.Model): invoice = models.ForeignKey( Invoice, on_delete=models.SET_NULL, null=True, blank=True, related_name="+", ) gateway = models.ForeignKey( PaymentGateway, on_delete=models.SET_NULL, null=True, blank=True, related_name="+", ) external_id = models.CharField(max_length=255, blank=True) amount = models.DecimalField(max_digits=12, decimal_places=2) currency = models.CharField(max_length=3, default="USD") status = models.CharField(max_length=50, blank=True) payment_method = models.CharField(max_length=100, blank=True) metadata = models.JSONField(default=dict) created_at = models.DateTimeField(auto_now_add=True) class Meta: db_table = "billing_transaction" def __str__(self): return f"txn_{self.pk}"