import pytest from infrasynth.billing.models import ( App, Entitlement, Invoice, PaymentGateway, Plan, Subscription, ) from infrasynth.shared.enums import EntitlementStatus, InvoiceStatus, MonetizationModel, SubscriptionStatus pytestmark = pytest.mark.django_db @pytest.fixture def gateway(): return PaymentGateway.objects.create( slug="stripe", display_name="Stripe", gateway_class="infrasynth.billing.gateways.stripe.StripeGateway", supported_currencies=["USD"], ) @pytest.fixture def app(): return App.objects.create(slug="messenger", name="Messenger", monetization=MonetizationModel.SUBSCRIPTION) @pytest.fixture def plan(app, gateway): return Plan.objects.create( app=app, slug="pro", name="Pro", price_amount=4900, price_currency="USD", interval="monthly", gateway=gateway, ) class TestPaymentGateway: def test_create(self): gateway = PaymentGateway.objects.create( slug="fake", display_name="Fake", gateway_class="tests.helpers.FakeGateway", ) assert gateway.is_active is True assert str(gateway) == "Fake" assert gateway.supported_currencies == [] assert gateway.config == {} def test_pk_is_slug(self, gateway): assert gateway.pk == "stripe" class TestApp: def test_create(self): app = App.objects.create(slug="invoicer", name="Invoicer", monetization=MonetizationModel.ONE_TIME) assert app.is_active is True assert str(app) == "Invoicer" def test_unique_slug(self): App.objects.create(slug="x", name="X", monetization="one_time") with pytest.raises(Exception): App.objects.create(slug="x", name="Y", monetization="one_time") class TestPlan: def test_create(self, app, gateway): plan = Plan.objects.create( app=app, slug="pro", name="Pro", price_amount=4900, price_currency="USD", interval="monthly", gateway=gateway, ) assert plan.is_active is True assert plan.trial_days == 0 assert plan.features == {} assert plan.limits == {} assert str(plan) == "messenger:pro" def test_slug_unique_per_app(self, app): Plan.objects.create(app=app, slug="pro", name="A", price_amount=1, interval="monthly") with pytest.raises(Exception): Plan.objects.create(app=app, slug="pro", name="B", price_amount=1, interval="monthly") def test_same_slug_allowed_across_apps(self, app): other = App.objects.create(slug="other", name="Other", monetization="one_time") Plan.objects.create(app=app, slug="pro", name="A", price_amount=1, interval="monthly") Plan.objects.create(app=other, slug="pro", name="B", price_amount=1, interval="one_time") class TestEntitlement: def test_create(self, tenant, app, plan): ent = Entitlement.all_objects.create(tenant=tenant, app=app, plan=plan) assert ent.status == EntitlementStatus.ACTIVE assert ent.metadata == {} def test_unique_per_tenant_app(self, tenant, app): Entitlement.all_objects.create(tenant=tenant, app=app) with pytest.raises(Exception): Entitlement.all_objects.create(tenant=tenant, app=app) class TestSubscription: def test_create(self, tenant, plan, gateway): subscription = Subscription.all_objects.create( tenant=tenant, plan=plan, gateway=gateway, status=SubscriptionStatus.ACTIVE, ) assert subscription.cancel_at_period_end is False assert subscription.metadata == {} def test_status_choices(self, tenant, plan, gateway): subscription = Subscription.all_objects.create( tenant=tenant, plan=plan, gateway=gateway, status=SubscriptionStatus.TRIALING, ) assert subscription.status == "trialing" class TestInvoice: def test_create(self, tenant, gateway): invoice = Invoice.all_objects.create( tenant=tenant, gateway=gateway, invoice_number="INV-2026-000001", amount=4900, currency="USD", status=InvoiceStatus.DRAFT, ) assert invoice.tax_amount == 0 assert invoice.tax_name == "" assert invoice.line_items == [] assert invoice.metadata == {} assert invoice.pdf_file_id is None assert str(invoice) == "INV-2026-000001" def test_unique_invoice_number_per_tenant(self, tenant, gateway): Invoice.all_objects.create(tenant=tenant, invoice_number="INV-1", amount=1, currency="USD", status="open") with pytest.raises(Exception): Invoice.all_objects.create(tenant=tenant, invoice_number="INV-1", amount=1, currency="USD", status="open")