DealDocumentScreening/tests/unit/test_refund_calculator.py

99 lines
3.5 KiB
Python

"""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