Coverage for apps/disclosures/models.py: 93%

29 statements  

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

1"""TRID disclosure packages (Loan Estimate, Closing Disclosure, Closing Package) and 

2their per-recipient e-sign tracking.""" 

3 

4from __future__ import annotations 

5 

6from django.db import models 

7 

8 

9class Disclosure(models.Model): 

10 """A generated (or generating) TRID disclosure package for a loan.""" 

11 

12 PACKAGE_TYPES = [ 

13 ("LoanEstimate", "Loan Estimate"), 

14 ("ClosingDisclosure", "Closing Disclosure"), 

15 ("ClosingPackage", "Closing Package"), 

16 ("ChangeOfCircumstance", "Change of Circumstance"), 

17 ] 

18 STATUSES = [ 

19 ("Draft", "Draft"), 

20 ("Generated", "Generated"), 

21 ("SentForEsign", "Sent for e-Sign"), 

22 ("Completed", "Completed"), 

23 ] 

24 

25 loan = models.ForeignKey( 

26 "core_los.Loan", on_delete=models.CASCADE, related_name="disclosures" 

27 ) 

28 package_type = models.CharField(max_length=30, choices=PACKAGE_TYPES) 

29 status = models.CharField(max_length=20, choices=STATUSES, default="Draft") 

30 audit_findings = models.JSONField(default=list, blank=True) 

31 generated_at = models.DateTimeField(null=True, blank=True) 

32 sent_at = models.DateTimeField(null=True, blank=True) 

33 completed_at = models.DateTimeField(null=True, blank=True) 

34 created_at = models.DateTimeField(auto_now_add=True) 

35 # Populated only for package_type="ChangeOfCircumstance" (design.md D1/D6). 

36 coc_reason = models.TextField(blank=True) 

37 coc_discovered_date = models.DateField(null=True, blank=True) 

38 

39 class Meta: 

40 db_table = "disclosures" 

41 

42 def __str__(self) -> str: 

43 return f"{self.package_type} ({self.status}) for loan {self.loan_id}" 

44 

45 

46class DisclosureRecipient(models.Model): 

47 """Per-recipient e-sign tracking on a sent disclosure package.""" 

48 

49 disclosure = models.ForeignKey( 

50 Disclosure, on_delete=models.CASCADE, related_name="recipients" 

51 ) 

52 borrower = models.ForeignKey( 

53 "application_1003.Borrower", on_delete=models.CASCADE, related_name="disclosure_recipients" 

54 ) 

55 # Snapshot, not a live read of Borrower.email (design.md D6) — the address the 

56 # package was actually sent to should not silently change if the borrower record 

57 # is edited afterward. 

58 email = models.EmailField() 

59 signed_at = models.DateTimeField(null=True, blank=True) 

60 created_at = models.DateTimeField(auto_now_add=True) 

61 

62 class Meta: 

63 db_table = "disclosure_recipients" 

64 

65 def __str__(self) -> str: 

66 return f"{self.email} on disclosure {self.disclosure_id}"