diff --git a/routes/finance.js b/routes/finance.js index 9689d53..261d13b 100644 --- a/routes/finance.js +++ b/routes/finance.js @@ -248,4 +248,103 @@ router.post('/dunning/:id/cancel', requireAdmin, async (req, res) => { } }); + +// ============================================ +// Alle offenen Rückläufer mahnen +// ============================================ +router.post('/chargebacks/dunning-all', requireAdmin, async (req, res) => { + const { amount, issued_date, reason } = req.body; + try { + const [openCBs] = await db.query( + "SELECT * FROM chargebacks WHERE status = 'open'", [] + ); + if (openCBs.length === 0) { + return res.redirect('/admin/finance?error=Keine+offenen+Rückläufer+vorhanden'); + } + let count = 0; + for (const cb of openCBs) { + await db.query( + 'INSERT INTO dunning_fees (membership_id, amount, reason, issued_date, notes) VALUES (?,?,?,?,?)', + [cb.membership_id, amount, reason || 'Mahngebühr Rücklastschrift', issued_date, + `Automatisch aus Rückläufer vom ${new Date(cb.chargeback_date).toLocaleDateString('de-DE')}`] + ); + count++; + } + res.redirect(`/admin/finance?success=${count}+Mahngebühren+eingetragen#chargebacks`); + } catch (err) { + console.error(err); + res.redirect('/admin/finance?error=Fehler+beim+Eintragen'); + } +}); + +// Einzelne Mahngebühr über Rückläufer-ID (membership_id wird aus chargeback geholt) +router.post('/dunning/add-from-chargeback', requireAdmin, async (req, res) => { + const { chargeback_id, amount, issued_date, reason, notes } = req.body; + try { + const [cbs] = await db.query('SELECT * FROM chargebacks WHERE id = ?', [chargeback_id]); + if (cbs.length === 0) return res.redirect('/admin/finance?error=Rückläufer+nicht+gefunden'); + await db.query( + 'INSERT INTO dunning_fees (membership_id, amount, reason, issued_date, notes) VALUES (?,?,?,?,?)', + [cbs[0].membership_id, amount, reason || 'Mahngebühr Rücklastschrift', issued_date, notes || null] + ); + res.redirect('/admin/finance?success=Mahngebühr+eingetragen'); + } catch (err) { + res.redirect('/admin/finance?error=Fehler'); + } +}); + +// ============================================ +// SEPA Nachforderung: offene Rückläufer + Mahngebühren +// ============================================ +router.get('/chargebacks/sepa-export', requireAdmin, async (req, res) => { + try { + // Offene Rückläufer + const [chargebacks] = await db.query(` + SELECT c.*, m.first_name, m.last_name, m.iban, m.account_holder + FROM chargebacks c + JOIN memberships m ON c.membership_id = m.id + WHERE c.status = 'open' + `); + + // Offene Mahngebühren + const [dunnings] = await db.query(` + SELECT d.*, m.first_name, m.last_name, m.iban, m.account_holder + FROM dunning_fees d + JOIN memberships m ON d.membership_id = m.id + WHERE d.status = 'open' + `); + + if (chargebacks.length === 0 && dunnings.length === 0) { + return res.redirect('/admin/finance?error=Keine+offenen+Rückläufer+oder+Mahngebühren'); + } + + const today = new Date().toISOString().split('T')[0]; + res.setHeader('Content-Type', 'text/csv; charset=utf-8'); + res.setHeader('Content-Disposition', `attachment; filename="SEPA_Nachforderung_${today}.csv"`); + res.write('\uFEFF'); + res.write('Name;IBAN;BIC;Betrag;Verwendungszweck;Mandatsreferenz;Mandatsdatum\n'); + + for (const c of chargebacks) { + const name = `${c.last_name} ${c.first_name}`.replace(/;/g, ' '); + const iban = (c.iban || '').replace(/\s/g, ''); + const amount = Number(c.amount).toFixed(2).replace('.', ','); + const ref = `PF24-RL-${String(c.id).padStart(5,'0')}`; + res.write(`${name};${iban};;${amount};Nachforderung Rücklastschrift ${c.period};${ref};${today}\n`); + } + + for (const d of dunnings) { + const name = `${d.last_name} ${d.first_name}`.replace(/;/g, ' '); + const iban = (d.iban || '').replace(/\s/g, ''); + const amount = Number(d.amount).toFixed(2).replace('.', ','); + const ref = `PF24-MG-${String(d.id).padStart(5,'0')}`; + res.write(`${name};${iban};;${amount};${d.reason};${ref};${today}\n`); + } + + res.end(); + } catch (err) { + console.error(err); + res.redirect('/admin/finance?error=SEPA+Export+Fehler'); + } +}); + module.exports = router; diff --git a/views/admin/finance.ejs b/views/admin/finance.ejs index 76323fe..f519a2e 100644 --- a/views/admin/finance.ejs +++ b/views/admin/finance.ejs @@ -146,9 +146,11 @@