New Club.legal_address/legal_zip_code/legal_city, editable from the identity page (management:club_settings). Official document headers (the dues invoice, the referee payment form) previously borrowed the club's home Location for this -- conflating "where we play" with "our registered address", which aren't always the same place. New club.services.invoicing.resolve_document_address(club) picks the club's own legal address when set, falling back to the home Location exactly as before when it isn't, so nothing breaks for a club that hasn't set one yet. Location.is_home now means only what it always should have: telling a home game from an away one. Renamed the shared "home_location" template/context variable to "document_address" on both PDFs to match -- it was never accurate once a legal address could win instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
101 lines
4.8 KiB
HTML
101 lines
4.8 KiB
HTML
{% load i18n %}
|
|
|
|
{% comment %}
|
|
Rendered by WeasyPrint, not a browser -- same convention as billing/templates/billing/invoice.html
|
|
and management/templates/management/membership_list_pdf.html: a standalone document with its
|
|
own print stylesheet, no app.css. Branded off the club's own colours (falling back to the same
|
|
shades club.templatetags.club_email's HTML emails use) rather than a fixed accent, since this
|
|
is the club's invoice to its own member, not RosterChief's to the club.
|
|
{% endcomment %}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>{{ invoice.number }}</title>
|
|
<style>
|
|
@page {
|
|
size: A4;
|
|
margin: 20mm;
|
|
@bottom-center {
|
|
content: "{{ club.name }} — {% trans "invoice" %} {{ invoice.number }} — " counter(page) " / " counter(pages);
|
|
font-size: 8pt;
|
|
color: #666;
|
|
}
|
|
}
|
|
body { font-family: sans-serif; font-size: 10pt; color: #111; }
|
|
h1 { font-size: 20pt; margin: 0 0 2mm; }
|
|
.muted { color: #666; }
|
|
.header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12mm; }
|
|
.accent { color: {{ club.primary_color|default:"#4f46e5" }}; }
|
|
.parties { display: flex; justify-content: space-between; margin-bottom: 10mm; }
|
|
.parties h2 { font-size: 9pt; text-transform: uppercase; letter-spacing: 0.5pt; color: #666; margin: 0 0 2mm; }
|
|
table { width: 100%; border-collapse: collapse; margin-bottom: 6mm; }
|
|
th { text-align: left; font-size: 9pt; text-transform: uppercase; letter-spacing: 0.5pt; color: #666; border-bottom: 1px solid #ccc; padding: 2mm 0; }
|
|
td { padding: 2mm 0; border-bottom: 1px solid #eee; }
|
|
.right { text-align: right; }
|
|
.total td { font-weight: bold; border-bottom: 2px solid #111; border-top: 1px solid #111; }
|
|
.balance { font-size: 12pt; font-weight: bold; }
|
|
.paid { color: #15803d; }
|
|
.owed { color: #b91c1c; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="header">
|
|
<div>
|
|
<h1>{{ club.official_name }}</h1>
|
|
{% if document_address %}
|
|
<div class="muted">{{ document_address.address }}</div>
|
|
<div class="muted">{{ document_address.zip_code }} {{ document_address.city }}</div>
|
|
{% endif %}
|
|
{% if club.contact_email %}<div class="muted">{{ club.contact_email }}</div>{% endif %}
|
|
</div>
|
|
<div class="right">
|
|
<h1 class="accent">{% trans "Invoice" %}</h1>
|
|
<div><strong>{{ invoice.number }}</strong></div>
|
|
{% if invoice.sent_at %}<div class="muted">{% blocktrans with date=invoice.sent_at|date:"j F Y" %}Issued {{ date }}{% endblocktrans %}</div>{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="parties">
|
|
<div>
|
|
<h2>{% trans "Billed to" %}</h2>
|
|
<div><strong>{{ member }}</strong></div>
|
|
{% if invoice.sent_to_email %}<div class="muted">{{ invoice.sent_to_email }}{% if invoice.sent_to_guardian %} ({% trans "parent/guardian" %}){% endif %}</div>{% endif %}
|
|
</div>
|
|
<div class="right">
|
|
<h2>{% trans "Season" %}</h2>
|
|
<div>{{ membership.season }}</div>
|
|
<div class="muted">{% blocktrans with date=invoice.due_date|date:"j F Y" %}Due {{ date }}{% endblocktrans %}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>{% trans "Description" %}</th>
|
|
<th class="right">{% trans "Amount" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>
|
|
<strong>{% trans "Membership fee" %}</strong>
|
|
<div class="muted">{{ club.name }} — {{ membership.season }}</div>
|
|
</td>
|
|
<td class="right">€{{ invoice.amount }}</td>
|
|
</tr>
|
|
<tr class="total">
|
|
<td>{% trans "Balance due" %}</td>
|
|
<td class="right balance {% if invoice.is_paid %}paid{% else %}owed{% endif %}">€{{ invoice.amount }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
{% if invoice.is_paid %}
|
|
<p class="paid"><strong>{% trans "Paid in full." %}</strong> {% trans "Thank you." %}</p>
|
|
{% else %}
|
|
<p class="muted">{% blocktrans with date=invoice.due_date|date:"j F Y" %}Payable by {{ date }}.{% endblocktrans %}</p>
|
|
{% endif %}
|
|
</body>
|
|
</html>
|