Coverage for domain/reports.py: 100%
12 statements
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-04 14:06 +0000
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-04 14:06 +0000
1"""Pure domain logic for the Reports & MCR dashboard (add-reports-mcr-api).
3Pure, side-effect-free. Zero dependencies on Django or external databases.
4"""
6from __future__ import annotations
8import datetime
9from decimal import ROUND_HALF_UP, Decimal
11_CENTS = Decimal("0.01")
12_BROKER_COMP_BPS = Decimal("200")
14# A loan not in ADVERSE counts as "active" everywhere in Reports & MCR (design.md):
15# the one concrete signal is the frontend mock's single ADVERSE-stage seed loan,
16# excluded uniformly from pipeline, revenue, and call-report figures. SUSPENDED
17# stays active — it is resumable (LOAN_TRANSITIONS), unlike ADVERSE, a dead end.
18_INACTIVE_STAGES = frozenset({"ADVERSE"})
21def is_active_loan(stage: str) -> bool:
22 return stage not in _INACTIVE_STAGES
25def broker_compensation(base_loan_amt: Decimal) -> Decimal:
26 """Flat 200bps of the base loan amount (reports.types.ts `est_comp_amt`/`broker_comp`)."""
27 return (base_loan_amt * _BROKER_COMP_BPS / Decimal("10000")).quantize(
28 _CENTS, rounding=ROUND_HALF_UP
29 )
32def quarter_of(dt: datetime.date | datetime.datetime) -> int:
33 """The calendar quarter (1-4) a date falls in."""
34 return (dt.month - 1) // 3 + 1