Coverage for apps/core_los/dashboard_schemas.py: 100%

66 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-11-04 14:06 +0000

1"""Ninja schemas for GET /api/dashboard. 

2 

3These shapes aren't 1:1 with any single model instance — they're pre-aggregated 

4dicts/lists built by the view (design.md D6) — so they're plain ``Schema``, not 

5``ModelSchema``. 

6""" 

7 

8from __future__ import annotations 

9 

10from datetime import date, datetime 

11from decimal import Decimal 

12 

13from ninja import Schema 

14 

15 

16class LoanRef(Schema): 

17 loan_guid: str 

18 loan_number: str 

19 borrower_name: str 

20 

21 

22class LockItem(LoanRef): 

23 expires_at: datetime 

24 rate: Decimal 

25 

26 

27class PipelineBuckets(Schema): 

28 prospect: int 

29 processing: int 

30 closing: int 

31 funded: int 

32 

33 

34class FundedYtd(Schema): 

35 purchase_count: int 

36 purchase_volume: Decimal 

37 refinance_count: int 

38 refinance_volume: Decimal 

39 

40 

41class LenderSpreadItem(Schema): 

42 lender_id: str 

43 count: int 

44 volume: Decimal 

45 

46 

47class RateAlertItem(LoanRef): 

48 rate: Decimal 

49 

50 

51class BirthdayItem(LoanRef): 

52 date: date 

53 

54 

55class AnniversaryItem(LoanRef): 

56 date: date 

57 

58 

59class MiDropItem(LoanRef): 

60 ltv: Decimal 

61 

62 

63class UpcomingEvents(Schema): 

64 birthdays: list[BirthdayItem] 

65 loan_anniversaries: list[AnniversaryItem] 

66 early_payoffs: list[RateAlertItem] 

67 mi_drop_eligible: list[MiDropItem] 

68 

69 

70class RecentLoan(LoanRef): 

71 stage: str 

72 updated_at: datetime 

73 

74 

75class DashboardCounts(Schema): 

76 loan: int 

77 appraisal: int 

78 closing: int 

79 

80 

81class DashboardWidgets(Schema): 

82 locks_expiring: list[LockItem] 

83 locks_expired: list[LockItem] 

84 conditions_pending: int 

85 needs_pending: int 

86 leads_new: int 

87 funded_ytd: FundedYtd 

88 lender_spread: list[LenderSpreadItem] 

89 upcoming_events: UpcomingEvents 

90 recent_loans: list[RecentLoan] 

91 counts: DashboardCounts 

92 contingencies: int 

93 rate_alerts: list[RateAlertItem] 

94 

95 

96class DashboardResponseOut(Schema): 

97 scope: str 

98 pipeline_volume: Decimal 

99 in_process: int 

100 funded: int 

101 tasks_due: int 

102 by_pipeline: PipelineBuckets 

103 widgets: DashboardWidgets