Vertragsverwaltung_Plusfit24/views/admin/billing.ejs
2026-03-28 10:36:08 +00:00

267 lines
11 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/contracts" class="nav-link">📑 Verträge</a>
<a href="/admin/billing" class="nav-link active">💶 Abrechnung</a>
<a href="/admin/finance" class="nav-link">📊 Finanzen</a>
<a href="/admin/mailing" class="nav-link">📧 Mailing</a>
<a href="/dokumentation/handbuch.docx" class="nav-link" target="_blank">❓ Hilfe</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">
<% if (inv.status !== 'cancelled') { %>
<!-- Normale Rechnung PDF -->
<a href="/admin/billing/export/pdf/<%= inv.id %>"
class="btn btn-sm btn-outline" target="_blank">
📄 Rechnung
</a>
<% } else { %>
<!-- Storno PDF -->
<a href="/admin/billing/export/storno-pdf/<%= inv.id %>"
class="btn btn-sm btn-storno" target="_blank">
🚫 Storno-PDF
</a>
<!-- Neue Rechnung ausstellen -->
<form method="POST" action="/admin/billing/invoices/<%= inv.id %>/reissue" style="display:inline"
onsubmit="return confirm('Neue Rechnung für diesen Posten ausstellen?')">
<button type="submit" class="btn btn-sm btn-primary">🔄 Neue Rechnung</button>
</form>
<% } %>
<% 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">✅ Bezahlt</button>
</form>
<% } %>
<% if (inv.status !== 'cancelled') { %>
<form method="POST" action="/admin/billing/invoices/<%= inv.id %>/cancel" style="display:inline"
onsubmit="return confirm('Rechnung PF24-<%= String(inv.id).padStart(6,'0') %> wirklich stornieren?')">
<input type="hidden" name="period" value="<%= period %>">
<button type="submit" class="btn btn-sm btn-danger">🚫 Stornieren</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.agreed_price || m.price_monthly).toFixed(2).replace('.', ',') %> €</strong>
<% if (m.agreed_price && Number(m.agreed_price) !== Number(m.price_monthly)) { %>
<br><small class="text-muted" title="Aktueller Tarif-Preis">Tarif: <%= Number(m.price_monthly).toFixed(2).replace('.', ',') %> €</small>
<% } %>
</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>
<div class="runs-scroll-wrap">
<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>
</div>
<% } %>
</main>
</div>
</body>
</html>