Vertragsverwaltung_Plusfit24/views/admin/billing.ejs
2026-03-27 12:37:34 +00:00

235 lines
9.2 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PlusFit24 Abrechnung</title>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/style.css">
</head>
<body class="admin-body">
<div class="admin-layout">
<aside class="admin-sidebar">
<div class="logo admin-logo">Plusfit<span>24</span></div>
<nav class="admin-nav">
<a href="/admin" class="nav-link">📋 Tarife</a>
<a href="/admin#kategorien" class="nav-link">🏷️ Kategorien</a>
<a href="/admin#mitglieder" class="nav-link">👥 Mitglieder</a>
<a href="/admin/billing" class="nav-link active">💶 Abrechnung</a>
<a href="/admin#einstellungen" class="nav-link">⚙️ Einstellungen</a>
</nav>
<div class="sidebar-footer">
<span>👤 <%= admin %></span>
<a href="/admin/logout" class="logout-link">Abmelden</a>
</div>
</aside>
<main class="admin-main">
<!-- Kopfzeile mit Perioden-Auswahl -->
<div class="billing-header">
<h1>💶 Abrechnung</h1>
<form method="GET" action="/admin/billing" class="period-form">
<input type="month" name="period" value="<%= period %>" class="form-control period-input">
<button type="submit" class="btn btn-outline">Anzeigen</button>
</form>
</div>
<% if (success) { %><div class="alert alert-success"><%= success %></div><% } %>
<% if (error) { %><div class="alert alert-error"><%= error %></div><% } %>
<!-- Monatsüberschrift -->
<h2 class="billing-period-title"><%= periodLabel %></h2>
<!-- Stats -->
<div class="stats-row">
<div class="stat-card">
<div class="stat-number"><%= summary.total || 0 %></div>
<div class="stat-label">Rechnungen gesamt</div>
</div>
<div class="stat-card">
<div class="stat-number" style="color:var(--error)"><%= summary.open_count || 0 %></div>
<div class="stat-label">Offen</div>
</div>
<div class="stat-card">
<div class="stat-number" style="color:var(--success)"><%= summary.paid_count || 0 %></div>
<div class="stat-label">Bezahlt</div>
</div>
<div class="stat-card">
<div class="stat-number"><%= summary.total_amount ? Number(summary.total_amount).toFixed(2).replace('.', ',') + ' €' : '0,00 €' %></div>
<div class="stat-label">Gesamtbetrag</div>
</div>
<div class="stat-card">
<div class="stat-number" style="color:var(--error)"><%= summary.open_amount ? Number(summary.open_amount).toFixed(2).replace('.', ',') + ' €' : '0,00 €' %></div>
<div class="stat-label">Noch offen</div>
</div>
<div class="stat-card">
<div class="stat-number" style="color:var(--success)"><%= summary.paid_amount ? Number(summary.paid_amount).toFixed(2).replace('.', ',') + ' €' : '0,00 €' %></div>
<div class="stat-label">Bereits bezahlt</div>
</div>
</div>
<!-- Aktionen -->
<div class="billing-actions">
<% if (invoices.length === 0) { %>
<!-- Noch kein Lauf → Vorschau + Lauf starten -->
<div class="billing-preview-box">
<div class="preview-info">
<strong>Bereit für Abrechnungslauf <%= periodLabel %></strong>
<span><%= eligible.length %> Mitglieder · Voraussichtlich <%= Number(preview_total).toFixed(2).replace('.', ',') %> €</span>
</div>
<form method="POST" action="/admin/billing/run"
onsubmit="return confirm('Abrechnungslauf für <%= periodLabel %> starten? Dieser Vorgang kann nicht rückgängig gemacht werden.')">
<input type="hidden" name="period" value="<%= period %>">
<button type="submit" class="btn btn-primary">▶ Abrechnungslauf starten</button>
</form>
</div>
<% } else { %>
<!-- Lauf bereits durchgeführt → Export & Aktionen -->
<div class="billing-run-done">
<div class="billing-action-btns">
<a href="/admin/billing/export/csv?period=<%= period %>" class="btn btn-outline">
📥 SEPA CSV exportieren
</a>
<% if (summary.open_count > 0) { %>
<form method="POST" action="/admin/billing/mark-all-paid"
onsubmit="return confirm('Alle offenen Rechnungen als bezahlt markieren?')">
<input type="hidden" name="period" value="<%= period %>">
<button type="submit" class="btn btn-success">✅ Alle als bezahlt markieren</button>
</form>
<% } %>
</div>
</div>
<% } %>
</div>
<!-- Rechnungsliste -->
<% if (invoices.length > 0) { %>
<div class="table-wrap">
<table class="admin-table">
<thead>
<tr>
<th>Nr.</th>
<th>Mitglied</th>
<th>Tarif</th>
<th>Betrag</th>
<th>IBAN</th>
<th>Status</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
<% invoices.forEach(inv => { %>
<tr>
<td class="invoice-nr">PF24-<%= String(inv.id).padStart(6, '0') %></td>
<td>
<strong><%= inv.last_name %>, <%= inv.first_name %></strong><br>
<small class="text-muted"><%= inv.email %></small>
</td>
<td><%= inv.tariff_name || '' %></td>
<td class="amount-cell">
<strong><%= Number(inv.amount).toFixed(2).replace('.', ',') %> €</strong>
</td>
<td class="iban-cell">
<%= inv.iban ? inv.iban.replace(/(.{4})/g, '$1 ').trim() : '' %>
</td>
<td>
<span class="invoice-status <%= inv.status %>">
<%= inv.status === 'paid' ? '✅ Bezahlt' : inv.status === 'open' ? '🔴 Offen' : '❌ Storniert' %>
</span>
<% if (inv.paid_at) { %>
<br><small class="text-muted"><%= new Date(inv.paid_at).toLocaleDateString('de-DE') %></small>
<% } %>
</td>
<td>
<div class="invoice-actions">
<a href="/admin/billing/export/pdf/<%= inv.id %>"
class="btn btn-sm btn-outline" target="_blank" title="PDF herunterladen">
📄 PDF
</a>
<% if (inv.status === 'open') { %>
<form method="POST" action="/admin/billing/invoices/<%= inv.id %>/paid" style="display:inline">
<input type="hidden" name="period" value="<%= period %>">
<button type="submit" class="btn btn-sm btn-success" title="Als bezahlt markieren">✅</button>
</form>
<% } %>
</div>
</td>
</tr>
<% }) %>
</tbody>
</table>
</div>
<% } else if (eligible.length > 0) { %>
<!-- Vorschau der Mitglieder -->
<div class="preview-table-wrap">
<h3 class="preview-title">Vorschau wird abgerechnet</h3>
<table class="admin-table">
<thead>
<tr>
<th>Mitglied</th>
<th>Tarif</th>
<th>Voraussichtlicher Betrag</th>
</tr>
</thead>
<tbody>
<% eligible.forEach(m => { %>
<tr>
<td><%= m.last_name %>, <%= m.first_name %></td>
<td><%= m.tariff_name %></td>
<td><strong><%= Number(m.price_monthly).toFixed(2).replace('.', ',') %> €</strong></td>
</tr>
<% }) %>
</tbody>
</table>
</div>
<% } else { %>
<div class="no-data-card">Keine Mitglieder für diesen Zeitraum.</div>
<% } %>
<!-- Letzte Abrechnungsläufe -->
<% if (runs.length > 0) { %>
<div class="runs-section">
<h3>Letzte Abrechnungsläufe</h3>
<table class="admin-table">
<thead>
<tr>
<th>Periode</th>
<th>Datum</th>
<th>Rechnungen</th>
<th>Gesamtbetrag</th>
<th>Erstellt von</th>
<th>Aktion</th>
</tr>
</thead>
<tbody>
<% runs.forEach(run => { %>
<tr>
<td><strong><%= run.period %></strong></td>
<td><%= new Date(run.created_at).toLocaleDateString('de-DE') %></td>
<td><%= run.invoice_count %></td>
<td><%= Number(run.total_amount).toFixed(2).replace('.', ',') %> €</td>
<td><%= run.created_by || '' %></td>
<td>
<div style="display:flex;gap:6px">
<a href="/admin/billing?period=<%= run.period %>" class="btn btn-sm btn-outline">
Anzeigen
</a>
<a href="/admin/billing/export/csv?period=<%= run.period %>" class="btn btn-sm btn-outline" title="SEPA CSV">
📥 CSV
</a>
</div>
</td>
</tr>
<% }) %>
</tbody>
</table>
</div>
<% } %>
</main>
</div>
</body>
</html>