Hard-Coded Document Implementation Guide
This guide explains how to create and integrate a new hard-coded document into the document generation system.
Overview
Hard-coded documents are PDF templates with mostly static content and some dynamic fields (like borrower names, dates, etc.). They are used for standardized forms and disclosures.
Step-by-Step Implementation
1. Analyze the Source PDF
- Carefully review the PDF document to identify:
- Static content (disclosure text, headers, instructions)
- Dynamic fields (borrower names, dates, loan information)
- Page structure and breaks
- Footer information
- Tables and formatting requirements
2. Create the HTML Template
Create your HTML file in: documents/hard_coded_documents/html_templates/YOUR_DOCUMENT_NAME.html
Basic HTML Structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
@page {
size: Letter;
margin: 0.75in 0.44in;
font-family: Arial, Helvetica, sans-serif;
/* Footer configuration */
@bottom-left {
content: "Loan Officer Company NMLS #:\A{{ loan_officer_company_nmls }}\A...";
font-size: 8px;
white-space: pre;
}
@bottom-center {
content: "Page " counter(page) " of X";
font-size: 8px;
}
@bottom-right {
content: "{{ footer_text }}\APrinted:{{ printed_date }}";
font-size: 8px;
white-space: pre;
}
}
body {
font-family: Arial, Helvetica, sans-serif;
margin: 0;
padding: 0;
font-size: 11px;
}
/* Page break */
.break-before {
page-break-before: always;
}
/* Add other styles as needed */
</style>
</head>
<body>
<div class="page-content">
<!-- Your content here -->
{{ dynamic_field }}
</div>
</body>
</html>
Key HTML Elements:
-
Headers: Use company logo and QR code if needed
html <img src="{{ company_logo }}" alt="Company Logo" class="logo"> <img src="data:image/png;base64,{{ qr_code_base64 }}" alt="QR Code"> -
Dynamic Fields: Use Jinja2 template syntax
html {{ borrower_name }} {{ printed_date }} -
Signatures: Create empty fields for signatures ```html
{{ borrower.name }}
```
- Tables: Use standard HTML tables with borders
```html
Header {{ data }}
```
3. Create the Python Data Generator
Create your Python file in: documents/hard_coded_documents/input_jsons/YOUR_DOCUMENT_NAME.py
Basic Python Structure:
from datetime import datetime
def get_your_document_name_data(loan):
"""
Generate data for Your Document Name
"""
# Get current date
printed_date = datetime.now().strftime("%m/%d/%Y")
# Get borrower information
borrowers = []
youngest_borrower = loan.get_youngest_borrower()
if youngest_borrower:
borrowers.append({
"name": youngest_borrower.get_full_name(),
"signature": "", # Empty for signature
"date": "" # Empty for date
})
# Get loan officer information
loan_officer_nmls = loan.get_loan_officer_nmls_id() or "DEFAULT_VALUE"
loan_officer_company_nmls = loan.get_loan_officer_company_nmls_id() or "DEFAULT_VALUE"
# Return all data needed by the template
return {
# REQUIRED: URL for QR code generation
"url": f"https://example.com/loan/{loan.id}",
# Dynamic fields from loan object
"borrowers": borrowers,
"loan_officer_nmls": loan_officer_nmls,
"loan_officer_company_nmls": loan_officer_company_nmls,
"printed_date": printed_date,
# Static/hard-coded values
"footer_text": "YourDocumentFooter-2024",
"document_id": "12345",
# Any other fields your template needs
"custom_field": "value",
}
4. Register the Document in generator.py
Add your import at the top of documents/hard_coded_documents/generator.py:
from .input_jsons.YOUR_DOCUMENT_NAME import get_your_document_name_data
Add your case in the get_template_data function:
elif template_name == "YOUR_DOCUMENT_NAME":
return get_your_document_name_data(loan)
5. Add to Constants
In documents/hard_coded_documents/constants.py, add your document to HARD_CODED_DOCUMENT_TYPES:
{"name": "Your Document Display Name", "value": "YOUR_DOCUMENT_NAME"},
6. Test Your Document
- Restart your application
- The document should now appear in the UI document list
- Generate a test document to verify:
- All dynamic fields populate correctly
- Page breaks work as expected
- Footer appears on all pages
- Formatting matches the original PDF
Common Patterns
Multiple Borrowers
borrowers = []
for borrower in loan.borrowers.all():
borrowers.append({
"name": borrower.get_full_name(),
"signature": "",
"date": ""
})
Conditional Content
{% if condition %}
<p>Show this content</p>
{% endif %}
Loops in Templates
{% for item in items %}
<div>{{ item.name }}</div>
{% endfor %}
Page Numbers
The CSS @page rule handles automatic page numbering:
@bottom-center {
content: "Page " counter(page) " of " counter(pages);
}
Best Practices
- Keep Static Content Static: Don't make fields dynamic unless they actually change
- Use Consistent Naming: Match file names with the
valuein constants.py - Handle Missing Data: Provide defaults for optional fields
- Test Pagination: Ensure content doesn't overflow pages
- Match Original Formatting: Pay attention to fonts, sizes, and spacing
Troubleshooting
- Document doesn't appear in UI: Check that all 4 integration steps are complete
- Import errors: Verify file names match exactly
- Missing data: Check loan object methods and provide defaults
- Formatting issues: Use browser developer tools to inspect generated HTML
- QR code not showing: Ensure
urlfield is included in data dictionary
Example Documents
For reference, see these existing implementations:
- HECM_NOTE.html / HECM_NOTE.py
- HECM_DOT.html / HECM_DOT.py
- HECM_TIL_APPLICATION.html / HECM_TIL_APPLICATION.py