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
« 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."""
4from __future__ import annotations
6from django.db import models
9class Disclosure(models.Model):
10 """A generated (or generating) TRID disclosure package for a loan."""
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 ]
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)
39 class Meta:
40 db_table = "disclosures"
42 def __str__(self) -> str:
43 return f"{self.package_type} ({self.status}) for loan {self.loan_id}"
46class DisclosureRecipient(models.Model):
47 """Per-recipient e-sign tracking on a sent disclosure package."""
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)
62 class Meta:
63 db_table = "disclosure_recipients"
65 def __str__(self) -> str:
66 return f"{self.email} on disclosure {self.disclosure_id}"