diff --git a/package.json b/package.json index a652886..b41b51d 100644 --- a/package.json +++ b/package.json @@ -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" diff --git a/public/css/style.css b/public/css/style.css index aaac667..29bc200 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -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); +} diff --git a/routes/finance.js b/routes/finance.js index db58ec6..9689d53 100644 --- a/routes/finance.js +++ b/routes/finance.js @@ -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, '')); diff --git a/views/admin/finance.ejs b/views/admin/finance.ejs index eced953..76323fe 100644 --- a/views/admin/finance.ejs +++ b/views/admin/finance.ejs @@ -365,16 +365,34 @@