finanzen hinzugefügt.

This commit is contained in:
cay 2026-03-27 13:25:38 +00:00
parent 95f4d9f271
commit 6927d0be3e
4 changed files with 86 additions and 13 deletions

View File

@ -16,7 +16,8 @@
"dotenv": "^16.3.1",
"dns": "^0.2.2",
"pdfkit": "^0.14.0",
"node-cron": "^3.0.3"
"node-cron": "^3.0.3",
"multer": "^1.4.5-lts.1"
},
"devDependencies": {
"nodemon": "^3.0.1"

View File

@ -1248,3 +1248,44 @@ body:not(.admin-body) > * {
.expiry-urgent { background:#fee2e2; color:var(--error); }
.expiry-warning { background:#fffbeb; color:var(--warning); }
.expiry-normal { background:#f0fdf4; color:var(--success); }
/* ---- CSV File Upload ---- */
.file-upload-wrap { position: relative; }
.file-upload-wrap input[type="file"] {
position: absolute; width: 1px; height: 1px; opacity: 0;
}
.file-upload-label {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 16px;
border: 1.5px dashed var(--border);
border-radius: 8px;
cursor: pointer;
font-size: 0.9rem;
color: var(--text-muted);
transition: all 0.2s;
background: var(--bg);
}
.file-upload-label:hover {
border-color: var(--primary);
color: var(--primary);
background: #f0f0ff;
}
.file-upload-label::before { content: '📁'; font-size: 1.1rem; }
.import-divider {
display: flex;
align-items: center;
gap: 12px;
margin: 16px 0;
color: var(--text-muted);
font-size: 0.85rem;
}
.import-divider::before,
.import-divider::after {
content: '';
flex: 1;
height: 1px;
background: var(--border);
}

View File

@ -1,4 +1,6 @@
const express = require('express');
const multer = require('multer');
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 1024*1024 } });
const router = express.Router();
const db = require('../config/database');
const { requireAdmin } = require('../middleware/auth');
@ -175,11 +177,17 @@ router.post('/chargebacks/:id/resolve', requireAdmin, async (req, res) => {
});
// CSV Import Rückläufer
router.post('/chargebacks/import', requireAdmin, async (req, res) => {
const { csv_data } = req.body;
if (!csv_data || !csv_data.trim()) return res.redirect('/admin/finance?error=Keine+Daten+eingegeben');
router.post('/chargebacks/import', requireAdmin, upload.single('csv_file'), async (req, res) => {
// Datei hat Vorrang, sonst Textfeld
let rawData = '';
if (req.file && req.file.buffer.length > 0) {
rawData = req.file.buffer.toString('utf-8').replace(/\r/g, '');
} else if (req.body.csv_data && req.body.csv_data.trim()) {
rawData = req.body.csv_data.trim();
}
if (!rawData) return res.redirect('/admin/finance?error=Keine+Daten+eingegeben');
try {
const lines = csv_data.trim().split('\n').filter(l => l.trim());
const lines = rawData.trim().split('\n').filter(l => l.trim());
let imported = 0;
for (const line of lines) {
const cols = line.split(';').map(c => c.trim().replace(/"/g, ''));

View File

@ -365,16 +365,34 @@
<h3>Rückläufer CSV Import</h3>
<button onclick="toggleModal('importChargebackModal')" class="modal-close">✕</button>
</div>
<form method="POST" action="/admin/finance/chargebacks/import">
<form method="POST" action="/admin/finance/chargebacks/import"
enctype="multipart/form-data">
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:16px">
Format pro Zeile: <code>IBAN;Betrag;Datum;Grund</code><br>
Beispiel: <code>DE89370400440532013000;29,95;2026-04-05;Rücklastschrift</code>
</p>
<!-- Option 1: Datei -->
<div class="form-group">
<label>CSV-Daten einfügen</label>
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:8px">
Format pro Zeile: <code>IBAN;Betrag;Datum;Grund</code><br>
Beispiel: <code>DE89370400440532013000;29,95;2026-04-05;Rücklastschrift</code>
</p>
<textarea name="csv_data" class="form-control" rows="6"
placeholder="IBAN;Betrag;Datum;Grund"></textarea>
<label>📁 CSV-Datei hochladen</label>
<div class="file-upload-wrap">
<input type="file" name="csv_file" id="csvFile" accept=".csv,.txt"
onchange="showFileName(this)">
<label for="csvFile" class="file-upload-label">
<span id="fileNameDisplay">Datei auswählen...</span>
</label>
</div>
</div>
<div class="import-divider"><span>oder</span></div>
<!-- Option 2: Textfeld -->
<div class="form-group">
<label>📋 Daten einfügen</label>
<textarea name="csv_data" class="form-control" rows="5"
placeholder="IBAN;Betrag;Datum;Grund&#10;DE89370400440532013000;29,95;2026-04-05;Rücklastschrift"></textarea>
</div>
<div class="modal-footer">
<button type="button" onclick="toggleModal('importChargebackModal')" class="btn btn-outline">Abbrechen</button>
<button type="submit" class="btn btn-primary">📥 Importieren</button>
@ -480,6 +498,11 @@ function showTab(name) {
function toggleModal(id) {
document.getElementById(id).classList.toggle('hidden');
}
function showFileName(input) {
const display = document.getElementById('fileNameDisplay');
display.textContent = input.files.length > 0 ? input.files[0].name : 'Datei auswählen...';
}
</script>
</body>
</html>