drtjh
This commit is contained in:
parent
596f60c1a4
commit
97ad1359e1
@ -342,5 +342,20 @@ router.get('/export/pdf/:invoiceId', requireAdmin, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// POST – Rechnung stornieren
|
||||
router.post('/invoices/:id/cancel', requireAdmin, async (req, res) => {
|
||||
const period = req.body.period || currentPeriod();
|
||||
try {
|
||||
await db.query(
|
||||
"UPDATE invoices SET status='cancelled' WHERE id=?",
|
||||
[req.params.id]
|
||||
);
|
||||
res.redirect(`/admin/billing?period=${period}&success=Rechnung+storniert`);
|
||||
} catch (err) {
|
||||
res.redirect(`/admin/billing?period=${period}&error=Fehler+beim+Stornieren`);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
module.exports.currentPeriod = currentPeriod;
|
||||
|
||||
@ -93,6 +93,16 @@ router.get('/', requireAdmin, async (req, res) => {
|
||||
ORDER BY m.effective_end ASC
|
||||
`);
|
||||
|
||||
// Stornierte Rechnungen
|
||||
const [cancelledInvoices] = await db.query(`
|
||||
SELECT i.*, m.first_name, m.last_name, m.email, t.name as tariff_name
|
||||
FROM invoices i
|
||||
JOIN memberships m ON i.membership_id = m.id
|
||||
LEFT JOIN tariffs t ON m.tariff_id = t.id
|
||||
WHERE i.status = 'cancelled'
|
||||
ORDER BY i.created_at DESC
|
||||
`);
|
||||
|
||||
// Alle Mitglieder für Dropdowns
|
||||
const [members] = await db.query(`
|
||||
SELECT m.id, m.first_name, m.last_name
|
||||
@ -121,6 +131,7 @@ router.get('/', requireAdmin, async (req, res) => {
|
||||
expiringContracts,
|
||||
members,
|
||||
openInvoicesDropdown,
|
||||
cancelledInvoices,
|
||||
success: req.query.success || null,
|
||||
error: req.query.error || null
|
||||
});
|
||||
|
||||
@ -74,6 +74,7 @@
|
||||
<button class="ftab" onclick="showTab('chargebacks', this)">↩️ Rückläufer</button>
|
||||
<button class="ftab" onclick="showTab('dunning', this)">📬 Mahngebühren</button>
|
||||
<button class="ftab" onclick="showTab('expiring', this)">⏳ Auslaufende Verträge</button>
|
||||
<button class="ftab" onclick="showTab('cancelled', this)">🚫 Storniert</button>
|
||||
<button class="ftab" onclick="showTab('settings', this)">⚙️ Einstellungen</button>
|
||||
</div>
|
||||
|
||||
@ -285,6 +286,55 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ===== TAB: STORNIERT ===== -->
|
||||
<div class="ftab-content" id="tab-cancelled">
|
||||
<div class="finance-card">
|
||||
<h3>Stornierte Rechnungen (<%= cancelledInvoices.length %>)</h3>
|
||||
<% if (cancelledInvoices.length === 0) { %>
|
||||
<p class="karte-empty">Keine stornierten Rechnungen vorhanden.</p>
|
||||
<% } else { %>
|
||||
<div class="table-wrap">
|
||||
<table class="admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nr.</th>
|
||||
<th>Mitglied</th>
|
||||
<th>Tarif</th>
|
||||
<th>Periode</th>
|
||||
<th>Betrag</th>
|
||||
<th>Storniert am</th>
|
||||
<th>Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% cancelledInvoices.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><%= inv.period %></td>
|
||||
<td><span style="text-decoration:line-through;color:var(--text-muted)">
|
||||
<%= Number(inv.amount).toFixed(2).replace('.', ',') %> €
|
||||
</span></td>
|
||||
<td><%= new Date(inv.created_at).toLocaleDateString('de-DE') %></td>
|
||||
<td>
|
||||
<a href="/admin/billing?period=<%= inv.period %>" class="btn btn-sm btn-outline">
|
||||
Zur Abrechnung
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===== TAB: EINSTELLUNGEN ===== -->
|
||||
<div class="ftab-content" id="tab-settings">
|
||||
<div class="finance-card" style="max-width:400px">
|
||||
@ -579,7 +629,7 @@ new Chart(ctx, {
|
||||
|
||||
// Tabs
|
||||
const tabMap = {
|
||||
chart: 0, open: 1, chargebacks: 2, dunning: 3, expiring: 4, settings: 5
|
||||
chart: 0, open: 1, chargebacks: 2, dunning: 3, expiring: 4, cancelled: 5, settings: 6
|
||||
};
|
||||
|
||||
function showTab(name, el) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user