Company (return) address down 0.25in (to 0.8in) and customer address down 1.5in (to 3.0in) to line up with the #9 double-window envelope, per a printed proof. Push the body padding-top to clear the lower customer window. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
96 lines
3.4 KiB
HTML
96 lines
3.4 KiB
HTML
{# One customer account statement = one printed page.
|
||
Envelope geometry (window positions in _wrap_document) is field-tuned to the
|
||
#9 (9x4) double-window envelope. Rendered via frappe.render_template with
|
||
context key `s` (see ns_app.api.statements.get_statement_data). #}
|
||
{% set fmt = frappe.utils.fmt_money %}
|
||
<div class="statement-page">
|
||
|
||
<!-- Return address (top-left envelope window) -->
|
||
<div class="return-window">
|
||
<strong>{{ s.company_name }}</strong><br>
|
||
{{ s.return_address | safe }}
|
||
</div>
|
||
|
||
<!-- Document header (top-right) -->
|
||
<div class="doc-header">
|
||
<div class="doc-title">STATEMENT</div>
|
||
<div><strong>Date:</strong> {{ frappe.utils.formatdate(s.statement_date, "MM-dd-yyyy") }}</div>
|
||
<div><strong>Account:</strong> {{ s.customer }}</div>
|
||
</div>
|
||
|
||
<!-- Recipient address (lower envelope window) -->
|
||
<div class="recipient-window">
|
||
{{ s.customer_name }}<br>
|
||
{{ s.customer_address | safe }}
|
||
</div>
|
||
|
||
<!-- Statement body (starts below the address windows) -->
|
||
<div class="statement-body">
|
||
|
||
<div class="intro">
|
||
The following is a summary of your account as of
|
||
{{ frappe.utils.formatdate(s.statement_date, "MM-dd-yyyy") }}.
|
||
Please remit payment for any past-due balance at your earliest convenience.
|
||
</div>
|
||
|
||
<table class="items">
|
||
<thead>
|
||
<tr>
|
||
<th>Invoice</th>
|
||
<th class="c">Date</th>
|
||
<th class="c">Due Date</th>
|
||
<th class="c">Days Overdue</th>
|
||
<th class="c">Aging</th>
|
||
<th class="r">Outstanding</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for inv in s.invoices %}
|
||
<tr class="{{ 'overdue' if inv.is_overdue else '' }}">
|
||
<td>{{ inv.name }}{% if inv.is_late_fee %} <span class="tag">late fee</span>{% endif %}</td>
|
||
<td class="c">{{ frappe.utils.formatdate(inv.posting_date, "MM-dd-yyyy") }}</td>
|
||
<td class="c">{{ frappe.utils.formatdate(inv.due_date, "MM-dd-yyyy") }}</td>
|
||
<td class="c">{{ inv.days_overdue if inv.days_overdue else "—" }}</td>
|
||
<td class="c">{{ inv.aging_bucket }}</td>
|
||
<td class="r">{{ fmt(inv.outstanding_amount, currency=s.currency) }}</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
|
||
<!-- Totals -->
|
||
<div class="totals">
|
||
<p class="grand"><span>Total Due:</span><span>{{ fmt(s.total_due, currency=s.currency) }}</span></p>
|
||
</div>
|
||
|
||
<!-- Aging summary -->
|
||
<table class="aging">
|
||
<thead>
|
||
<tr>
|
||
<th class="c">Current</th>
|
||
<th class="c">1–30</th>
|
||
<th class="c">31–60</th>
|
||
<th class="c">61–90</th>
|
||
<th class="c">90+</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td class="c">{{ fmt(s.aging["Current"], currency=s.currency) }}</td>
|
||
<td class="c">{{ fmt(s.aging["1-30"], currency=s.currency) }}</td>
|
||
<td class="c">{{ fmt(s.aging["31-60"], currency=s.currency) }}</td>
|
||
<td class="c">{{ fmt(s.aging["61-90"], currency=s.currency) }}</td>
|
||
<td class="c">{{ fmt(s.aging["90+"], currency=s.currency) }}</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<div class="footer">
|
||
Prompt payment is always appreciated. We accept payments by check or over
|
||
the phone using a debit or credit card. Automatic payment setup is also
|
||
available upon request. Please contact us if payment has already been sent.
|
||
</div>
|
||
|
||
</div><!-- /statement-body -->
|
||
</div><!-- /statement-page -->
|