Initial version of the E-Invoice solution of JR IT Services

This commit is contained in:
2026-02-16 17:02:03 +01:00
commit e0c15fc7f2
36 changed files with 1407 additions and 0 deletions

111
templates/invoice.html.j2 Normal file
View File

@@ -0,0 +1,111 @@
<!doctype html>
<html lang="{{ meta.language or 'de' }}">
<head>
<meta charset="utf-8">
<title>Rechnung {{ meta.invoice_number }}</title>
<style>
body { font-family: sans-serif; font-size: 12px; }
.row { display: flex; justify-content: space-between; gap: 12px; }
.muted { color: #555; }
h1 { font-size: 22px; margin: 0 0 8px 0; }
.box { border: 1px solid #ddd; padding: 10px; border-radius: 6px; }
table { width: 100%; border-collapse: collapse; margin-top: 14px; }
th, td { border-bottom: 1px solid #eee; padding: 6px 6px; text-align: left; }
th { background: #fafafa; }
.right { text-align: right; }
.totals { margin-top: 12px; width: 44%; margin-left: auto; }
.totals td { border: none; padding: 4px 6px; }
.footer { margin-top: 18px; font-size: 11px; }
</style>
</head>
<body>
<div style="margin-bottom: 12px;">
<img src="assets/logo.svg" alt="Logo" style="height: 42px;" />
</div>
<div class="row">
<div style="flex: 1;">
<h1>Rechnung</h1>
<div class="muted">Rechnungsnummer: <strong>{{ meta.invoice_number }}</strong></div>
<div class="muted">Rechnungsdatum: {{ meta.invoice_date }}</div>
<div class="muted">Leistungsdatum: {{ meta.service_date }}</div>
</div>
<div class="box" style="min-width: 260px;">
<div><strong>{{ seller.name }}</strong></div>
<div>{{ seller.address.street }}</div>
<div>{{ seller.address.postal_code }} {{ seller.address.city }}</div>
<div>{{ seller.address.country }}</div>
{% if seller.vat_id %}<div>USt-IdNr: {{ seller.vat_id }}</div>{% endif %}
{% if seller.tax_number %}<div>Steuernr: {{ seller.tax_number }}</div>{% endif %}
{% if seller.email %}<div>{{ seller.email }}</div>{% endif %}
</div>
</div>
<div class="row" style="margin-top: 16px;">
<div class="box" style="flex: 1;">
<div class="muted">Rechnung an</div>
<div><strong>{{ buyer.name }}</strong></div>
<div>{{ buyer.address.street }}</div>
<div>{{ buyer.address.postal_code }} {{ buyer.address.city }}</div>
<div>{{ buyer.address.country }}</div>
{% if buyer.vat_id %}<div>USt-IdNr: {{ buyer.vat_id }}</div>{% endif %}
</div>
<div class="box" style="flex: 1;">
<div class="muted">Zahlungsinformationen</div>
<div>Fällig am: {{ payment.due_date }}</div>
<div>Verwendungszweck: {{ payment.reference }}</div>
{% if payment.iban %}<div>IBAN: {{ payment.iban }}</div>{% endif %}
{% if payment.bic %}<div>BIC: {{ payment.bic }}</div>{% endif %}
{% if payment.bank_name %}<div>Bank: {{ payment.bank_name }}</div>{% endif %}
</div>
</div>
<table>
<thead>
<tr>
<th>Pos.</th>
<th>Beschreibung</th>
<th class="right">Menge</th>
<th>Einheit</th>
<th class="right">Einzelpreis (netto)</th>
<th class="right">Steuer</th>
<th class="right">Summe (netto)</th>
</tr>
</thead>
<tbody>
{% for it in items %}
<tr>
<td>{{ loop.index }}</td>
<td>
<strong>{{ it.name }}</strong><br>
{% if it.description %}<span class="muted">{{ it.description }}</span>{% endif %}
</td>
<td class="right">{{ "%.2f"|format(it.quantity) }}</td>
<td>{{ it.unit }}</td>
<td class="right">{{ money(it.unit_price_net) }}</td>
<td class="right">{{ "%.2f"|format(it.tax_rate) }}%</td>
<td class="right">{{ money(it.line_total_net) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<table class="totals">
<tr><td class="right">Zwischensumme (netto):</td><td class="right"><strong>{{ money(totals.net_total) }}</strong></td></tr>
<tr><td class="right">USt gesamt:</td><td class="right"><strong>{{ money(totals.tax_total) }}</strong></td></tr>
<tr><td class="right">Gesamt (brutto):</td><td class="right"><strong>{{ money(totals.gross_total) }}</strong></td></tr>
</table>
{% if meta.notes %}
<div class="footer">
<strong>Hinweise</strong><br>
{{ meta.notes }}
</div>
{% endif %}
<div class="footer muted">
Hinweis: Bei Nutzung von --combine wird ein Factur-X/ZUGFeRD XML-Datensatz in das PDF eingebettet.
</div>
</body>
</html>