"""Refund calculator unit tests (ticket 017). Table-driven tests for the pure ``calculate_refund`` function. """ from __future__ import annotations import datetime as dt import uuid import pytest from contract_check.core.billing.refunds import RefundCalc, calculate_refund pytestmark = pytest.mark.unit def _invoice( *, status: str = "succeeded", kind: str = "topup", amount: int = 19900, credits_purchased: int = 1, paid_at: dt.datetime | None = None, ) -> dict: return { "id": uuid.uuid4(), "status": status, "kind": kind, "amount": amount, "credits_purchased": credits_purchased, "paid_at": paid_at or dt.datetime.now(tz=dt.UTC), "user_id": uuid.uuid4(), } @pytest.mark.parametrize( "purchased, used, amount, price, expected", [ (20, 0, 398000, 19900, RefundCalc(398000, "full", "within full-refund usage window", 0)), (20, 3, 398000, 19900, RefundCalc(398000, "full", "within full-refund usage window", 3)), (20, 5, 398000, 19900, RefundCalc(298500, "proportional", "used 5 of 20", 5)), (20, 20, 398000, 19900, RefundCalc(0, "zero", "usage exceeds paid value", 20)), (20, 25, 398000, 19900, RefundCalc(0, "zero", "usage exceeds paid value", 25)), (1, 0, 19900, 19900, RefundCalc(19900, "full", "within full-refund usage window", 0)), ], ) def test_calculate_refund_full_and_proportional( purchased: int, used: int, amount: int, price: int, expected: RefundCalc ) -> None: invoice = _invoice(amount=amount, credits_purchased=purchased) result = calculate_refund( invoice, used, purchased_documents=purchased, price_per_doc_kopecks=price ) assert result.amount_kopecks == expected.amount_kopecks assert result.kind == expected.kind assert result.used_documents == used def test_calculate_refund_already_refunded() -> None: invoice = _invoice(status="refunded", credits_purchased=20) result = calculate_refund(invoice, 0, purchased_documents=20, price_per_doc_kopecks=19900) assert result.amount_kopecks == 0 assert result.kind == "zero" def test_calculate_refund_not_succeeded() -> None: invoice = _invoice(status="pending", credits_purchased=20) result = calculate_refund(invoice, 0, purchased_documents=20, price_per_doc_kopecks=19900) assert result.kind == "zero" def test_calculate_refund_outside_window() -> None: invoice = _invoice( credits_purchased=20, paid_at=dt.datetime.now(tz=dt.UTC) - dt.timedelta(days=15), ) result = calculate_refund(invoice, 0, purchased_documents=20, price_per_doc_kopecks=19900) assert result.kind == "zero" assert "window" in result.reason def test_calculate_refund_zero_usage_full() -> None: invoice = _invoice(credits_purchased=5) result = calculate_refund(invoice, 0, purchased_documents=5, price_per_doc_kopecks=19900) assert result.kind == "full" def test_calculate_refund_subscription_proportional() -> None: invoice = _invoice(kind="subscription", amount=49000, credits_purchased=None) result = calculate_refund(invoice, 4, purchased_documents=5, price_per_doc_kopecks=19900) assert result.kind == "zero" # 4*19900 = 79600 > 49000 def test_calculate_refund_subscription_full() -> None: invoice = _invoice(kind="subscription", amount=49000, credits_purchased=None) result = calculate_refund(invoice, 0, purchased_documents=5, price_per_doc_kopecks=19900) assert result.kind == "full" assert result.amount_kopecks == 49000