import pytest from infrasynth.billing.invoice_generator import _build_invoice_pdf from infrasynth.billing.models import BillingPlan, Invoice, PaymentGateway from infrasynth.billing.services import BillingService pytestmark = pytest.mark.django_db @pytest.fixture def gateway(): return PaymentGateway.objects.create( slug="fake", display_name="Fake", gateway_class="tests.helpers.FakeGateway", is_active=True, ) @pytest.fixture def plan(gateway): return BillingPlan.objects.create( slug="pro", name="Pro", price_amount="49.00", price_currency="USD", interval="monthly", gateway=gateway, ) class TestBuildInvoicePdf: def test_generates_pdf_bytes(self, user, gateway, plan): subscription = BillingService().create_subscription(plan, user, gateway) invoice = Invoice.objects.create( subscription=subscription, user=user, gateway=gateway, invoice_number="INV-2026-000001", amount=49, currency="USD", status="open", line_items=[{"description": "Pro", "amount": 49.0, "quantity": 1}], ) pdf_bytes = _build_invoice_pdf(invoice) assert pdf_bytes.startswith(b"%PDF") assert len(pdf_bytes) > 100 def test_pdf_includes_tax(self, user, gateway, plan): subscription = BillingService().create_subscription(plan, user, gateway) invoice = Invoice.objects.create( subscription=subscription, user=user, gateway=gateway, invoice_number="INV-2026-000002", amount=100, tax_amount=19, tax_name="IVA", currency="USD", status="open", line_items=[{"description": "Plan", "amount": 100.0, "quantity": 1}], ) pdf_bytes = _build_invoice_pdf(invoice) assert pdf_bytes.startswith(b"%PDF") class TestGenerateInvoicePdfTask: def test_task_generates_and_attaches_pdf(self, user, gateway, plan, media_root): subscription = BillingService().create_subscription(plan, user, gateway) invoice = BillingService().generate_invoice(subscription) invoice.refresh_from_db() assert invoice.pdf_file_id is not None assert invoice.pdf_file.original_filename.startswith("invoice_") assert invoice.pdf_file.mime_type == "application/pdf" assert invoice.pdf_file.size_bytes > 100 def test_task_missing_invoice_returns_none(self): from infrasynth.billing.invoice_generator import generate_invoice_pdf assert generate_invoice_pdf.run(999999) is None