Referee PDF: the info-card background used CSS color-mix(), which WeasyPrint doesn't support -- the rule was silently dropped, leaving the card with no background at all. Computed in Python instead (management/pdf.py) and baked into the template as a plain hex value; the tint is based on the club's primary_color, falling back to secondary_color when primary is itself (near) black or white, where a straight tint would be invisible or too harsh. Event forms: the location picker now shows "Name — City" (plus the country when it isn't Belgium) and is searchable by name or city, reusing the existing single-select searchable-select.js widget. Games API: GameOut now carries `end` (explicit, or start + 2h when a GAME was saved without one -- Event.save() sets this, never overwriting an explicit end; other event kinds are untouched). /games/upcoming/ now includes anything not yet finished rather than only things that haven't started, so a game already in progress keeps showing up until its window closes; `status` was adjusted to match so a game returned there never calls itself "finished". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
156 lines
8.0 KiB
HTML
156 lines
8.0 KiB
HTML
{% load i18n %}
|
|
|
|
{% comment %}
|
|
Rendered by WeasyPrint -- modeled on the club's existing paper referee
|
|
payment form ("Leeg Document RefereesCompetitie25-26.pdf"): club header,
|
|
match details, referee names, a payment sentence, a fee+km breakdown per
|
|
referee, and blank signature lines. Header uses club.official_name
|
|
(legal_name if set, else name); the payment sentence uses the plain club
|
|
name -- the original document does the same, using a longer legal form up
|
|
top and a shorter one in the body text.
|
|
{% endcomment %}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>{% trans "Referee form" %}</title>
|
|
<style>
|
|
@page {
|
|
size: A4;
|
|
margin: 20mm 18mm;
|
|
@bottom-center {
|
|
content: "{{ club.name }} — {% trans "referee form" %} — " counter(page) " / " counter(pages);
|
|
font-size: 8pt;
|
|
color: #8a8a8a;
|
|
}
|
|
}
|
|
:root {
|
|
--accent: {{ accent_color }};
|
|
--info-card-bg: {{ info_card_color }};
|
|
--ink: #16181d; --muted: #6b7280; --line: #d8dae0;
|
|
}
|
|
* { box-sizing: border-box; }
|
|
body { font-family: sans-serif; font-size: 10pt; color: var(--ink); line-height: 1.45; }
|
|
|
|
.header { display: flex; justify-content: space-between; align-items: flex-start; padding-bottom: 5mm; border-bottom: 2.5pt solid var(--accent); margin-bottom: 8mm; }
|
|
.header .club-name { font-size: 16pt; font-weight: 700; color: var(--accent); margin: 0 0 1mm; }
|
|
.header .club-address { font-size: 9pt; color: var(--muted); }
|
|
.header .doc-title { text-align: right; }
|
|
.header .doc-title .kicker { font-size: 8pt; letter-spacing: 1pt; text-transform: uppercase; color: var(--muted); }
|
|
.header .doc-title .title { font-size: 14pt; font-weight: 700; margin-top: 1mm; }
|
|
|
|
.info-card { background: var(--info-card-bg); border-radius: 3mm; padding: 5mm 6mm; margin-bottom: 7mm; }
|
|
.info-grid { display: flex; flex-wrap: wrap; gap: 4mm 10mm; }
|
|
.info-grid .item { min-width: 45mm; }
|
|
.info-grid .item.wide { flex: 1 1 100%; min-width: 100%; }
|
|
.info-label { font-size: 7.5pt; letter-spacing: 0.5pt; text-transform: uppercase; color: var(--muted); margin-bottom: 0.5mm; }
|
|
.info-value { font-size: 10.5pt; font-weight: 600; }
|
|
|
|
.note { font-size: 9.5pt; color: var(--muted); margin: 0 0 7mm; }
|
|
|
|
.section-title { font-size: 8pt; letter-spacing: 0.5pt; text-transform: uppercase; color: var(--accent); font-weight: 700; margin: 0 0 2mm; }
|
|
|
|
table.fees { width: 100%; border-collapse: collapse; margin-bottom: 9mm; }
|
|
table.fees th { text-align: left; font-size: 7.5pt; letter-spacing: 0.5pt; text-transform: uppercase; color: var(--muted); border-bottom: 1pt solid var(--line); padding: 2mm 2mm 1.5mm 0; }
|
|
table.fees td { padding: 2.5mm 2mm 2.5mm 0; border-bottom: 0.75pt solid var(--line); vertical-align: top; }
|
|
table.fees td.amount, table.fees th.amount { text-align: right; }
|
|
table.fees tr.empty td { color: var(--muted); font-style: italic; }
|
|
table.fees tr.total td { border-bottom: none; border-top: 1.5pt solid var(--accent); font-weight: 700; padding-top: 3mm; }
|
|
|
|
.signatures { display: flex; gap: 8mm; margin-top: 4mm; }
|
|
.sign-box { flex: 1; }
|
|
.sign-box .info-label { margin-bottom: 2mm; }
|
|
.sign-box .box { border: 0.75pt solid var(--line); border-radius: 2mm; min-height: 24mm; }
|
|
.collected-line { margin-top: 8mm; font-size: 9.5pt; }
|
|
.collected-line .fill { display: inline-block; border-bottom: 0.75pt solid var(--line); min-width: 90mm; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="header">
|
|
<div>
|
|
<div class="club-name">{{ club.official_name }}</div>
|
|
{% if home_location %}
|
|
<div class="club-address">{{ home_location.address }}</div>
|
|
<div class="club-address">{{ home_location.zip_code }} {{ home_location.city }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="doc-title">
|
|
<div class="kicker">{% trans "Referee payment form" %}</div>
|
|
<div class="title">{{ event.start|date:"j F Y" }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="info-card">
|
|
<div class="info-grid">
|
|
<div class="item wide">
|
|
<div class="info-label">{% trans "Game" %}</div>
|
|
<div class="info-value">
|
|
{% for team in event.teams.all %}{{ team.short_name }}{% if not forloop.last %}, {% endif %}{% endfor %}
|
|
{% if event.opponent %}{% trans "vs" %} {{ event.opponent }}{% endif %}
|
|
{% if event.external_game_id %}<span style="color: var(--muted); font-weight: 400;">({% trans "ID" %}: {{ event.external_game_id }})</span>{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="item">
|
|
<div class="info-label">{% trans "Date" %}</div>
|
|
<div class="info-value">{{ event.start|date:"j F Y" }}</div>
|
|
</div>
|
|
<div class="item">
|
|
<div class="info-label">{% trans "Time" %}</div>
|
|
<div class="info-value">{{ event.start|date:"H:i" }}</div>
|
|
</div>
|
|
<div class="item wide">
|
|
<div class="info-label">{% trans "Referee names" %}</div>
|
|
<div class="info-value">
|
|
{% for referee in referees %}{{ referee.display_name }}{% if not forloop.last %}, {% endif %}{% empty %}—{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<p class="note">{% blocktrans with name=club.name %}{{ name }} pays the fee to the referee(s) for officiating the game mentioned above.{% endblocktrans %}</p>
|
|
|
|
<div class="section-title">{% trans "Referees and fee, plus any kilometers" %}</div>
|
|
<table class="fees">
|
|
<thead>
|
|
<tr>
|
|
<th>{% trans "Referee" %}</th>
|
|
<th class="amount">{% trans "Fee" %}</th>
|
|
<th class="amount">{% trans "Kilometers" %}</th>
|
|
<th class="amount">{% trans "Rate" %}</th>
|
|
<th class="amount">{% trans "Total" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for referee in referees %}
|
|
<tr>
|
|
<td>{{ referee.display_name }}</td>
|
|
<td class="amount">€{{ referee.fee|floatformat:2 }}</td>
|
|
<td class="amount">{% if referee.km %}{{ referee.km }} km{% else %}—{% endif %}</td>
|
|
<td class="amount">{% if referee.km %}€{{ referee.km_rate }}{% else %}—{% endif %}</td>
|
|
<td class="amount">€{{ referee.total_payable|floatformat:2 }}</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr class="empty"><td colspan="5">{% trans "No referees assigned yet." %}</td></tr>
|
|
{% endfor %}
|
|
{% if referees %}
|
|
<tr class="total">
|
|
<td colspan="4">{% trans "Total to pay" %}</td>
|
|
<td class="amount">€{{ grand_total|floatformat:2 }}</td>
|
|
</tr>
|
|
{% endif %}
|
|
</tbody>
|
|
</table>
|
|
|
|
<div class="signatures">
|
|
<div class="sign-box">
|
|
<div class="info-label">{% trans "Referee signature" %}</div>
|
|
<div class="box"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="collected-line">
|
|
{% trans "Collected by team manager" %}: <span class="fill"> </span>
|
|
</div>
|
|
</body>
|
|
</html>
|