const express = require('express'); const db = require('../db'); const asyncHandler = require('../middleware/asyncHandler'); const router = express.Router(); // Helper: find or insert a tarifoptionen row matching the new structure's option. // Used by the /multi endpoints to keep the old tarifoptionen table in sync. async function syncLegacyOption(anbieter_id, tarif_id, name, code, provision_euro, beschreibung) { try { await db.run( `INSERT OR IGNORE INTO tarifoptionen (anbieter_id, tarif_id, name, code, provision_euro, beschreibung) VALUES (?, ?, ?, ?, ?, ?)`, [anbieter_id, tarif_id, name, code || null, provision_euro || 0, beschreibung || null] ); } catch (err) { console.error('Legacy tarifoption sync failed:', err.message); } } // --- Legacy single-tariff API (per-(anbieter,tarif) options) --- router.get('/', asyncHandler(async (req, res) => { const rows = await db.all( `SELECT t.*, a.name AS anbieter_name, ta.name AS tarif_name FROM tarifoptionen t JOIN anbieter a ON t.anbieter_id = a.id LEFT JOIN tarife ta ON t.tarif_id = ta.id WHERE t.aktiv = 1 ORDER BY a.name, t.tarif_id IS NULL DESC, COALESCE(ta.name, ''), t.name` ); res.json(rows); })); router.post('/', asyncHandler(async (req, res) => { const { anbieter_id, tarif_id, name, code, provision_euro, beschreibung } = req.body || {}; if (!anbieter_id && !tarif_id) { return res.status(400).json({ error: 'Entweder Anbieter oder Tarif muss angegeben werden' }); } if (!name || !name.trim()) { return res.status(400).json({ error: 'Name ist erforderlich' }); } let resolvedAnbieterId = anbieter_id; if (tarif_id && !resolvedAnbieterId) { const tarif = await db.get('SELECT anbieter_id FROM tarife WHERE id = ?', [tarif_id]); if (!tarif) return res.status(404).json({ error: 'Tarif nicht gefunden' }); resolvedAnbieterId = tarif.anbieter_id; } try { const result = await db.run( `INSERT INTO tarifoptionen (anbieter_id, tarif_id, name, code, provision_euro, beschreibung) VALUES (?, ?, ?, ?, ?, ?)`, [resolvedAnbieterId, tarif_id || null, name.trim(), code || null, provision_euro || 0, beschreibung || null] ); res.json({ id: result.lastID, message: 'Tarifoption erfolgreich erstellt' }); } catch (err) { if (/UNIQUE/.test(err.message)) { const scope = tarif_id ? 'für diesen Tarif' : 'für diesen Anbieter'; return res.status(400).json({ error: `Eine Tarifoption mit diesem Namen existiert bereits ${scope}` }); } throw err; } })); router.put('/:id', asyncHandler(async (req, res) => { const { id } = req.params; const { name, provision_euro } = req.body || {}; if (!name) return res.status(400).json({ error: 'Tarifoption-Name ist erforderlich' }); const result = await db.run( 'UPDATE tarifoptionen SET name = ?, provision_euro = ? WHERE id = ?', [name, provision_euro || 0, id] ); if (result.changes === 0) return res.status(404).json({ error: 'Tarifoption nicht gefunden' }); res.json({ message: 'Tarifoption erfolgreich aktualisiert' }); })); router.delete('/:id', asyncHandler(async (req, res) => { const { id } = req.params; const result = await db.run('DELETE FROM tarifoptionen WHERE id = ?', [id]); if (result.changes === 0) return res.status(404).json({ error: 'Tarifoption nicht gefunden' }); res.json({ message: 'Tarifoption erfolgreich gelöscht' }); })); // --- Multi-tariff API (tarifoptionen_new + tarifoptionen_tarife) --- router.get('/multi', asyncHandler(async (req, res) => { const rows = await db.all( `SELECT tn.id, tn.name, tn.code, tn.provision_euro, tn.beschreibung, tn.aktiv, tn.created_at, GROUP_CONCAT(t.name || ' (' || a.name || ')') AS tarif_names, GROUP_CONCAT(t.id) AS tarif_ids FROM tarifoptionen_new tn LEFT JOIN tarifoptionen_tarife tt ON tn.id = tt.tarifoption_id LEFT JOIN tarife t ON tt.tarif_id = t.id LEFT JOIN anbieter a ON t.anbieter_id = a.id WHERE tn.aktiv = 1 GROUP BY tn.id, tn.name, tn.code, tn.provision_euro, tn.beschreibung, tn.aktiv, tn.created_at ORDER BY tn.created_at DESC` ); res.json(rows); })); router.post('/multi', asyncHandler(async (req, res) => { const { anbieter_id, tarif_ids = [], is_anbieter_weit = false, name, code, provision_euro, beschreibung } = req.body || {}; if (!anbieter_id || !name) return res.status(400).json({ error: 'Anbieter und Name sind erforderlich' }); if (!is_anbieter_weit && (!tarif_ids || tarif_ids.length === 0)) { return res.status(400).json({ error: 'Bei tarif-spezifischen Optionen müssen Tarife ausgewählt werden' }); } const newId = await db.transaction(async () => { const inserted = await db.run( 'INSERT INTO tarifoptionen_new (name, code, provision_euro, beschreibung) VALUES (?, ?, ?, ?)', [name, code || null, provision_euro || 0, beschreibung || null] ); const tarifoptionId = inserted.lastID; let targetTarifIds = tarif_ids; if (is_anbieter_weit) { const tarifs = await db.all('SELECT id FROM tarife WHERE anbieter_id = ?', [anbieter_id]); targetTarifIds = tarifs.map(t => t.id); } for (const tarifId of targetTarifIds) { await db.run( 'INSERT INTO tarifoptionen_tarife (tarifoption_id, tarif_id) VALUES (?, ?)', [tarifoptionId, tarifId] ); await syncLegacyOption(anbieter_id, tarifId, name, code, provision_euro, beschreibung); } return { id: tarifoptionId, count: targetTarifIds.length }; }); res.json({ id: newId.id, message: 'Tarifoption erfolgreich erstellt', assignments: newId.count }); })); router.put('/multi/:id', asyncHandler(async (req, res) => { const { id } = req.params; const { name, code, provision_euro, beschreibung, anbieter_id, is_anbieter_weit, tarif_ids } = req.body || {}; if (!name) return res.status(400).json({ error: 'Tarifoption-Name ist erforderlich' }); await db.transaction(async () => { const upd = await db.run( 'UPDATE tarifoptionen_new SET name = ?, code = ?, provision_euro = ?, beschreibung = ? WHERE id = ?', [name, code || null, provision_euro || 0, beschreibung || null, id] ); if (upd.changes === 0) { const e = new Error('Tarifoption nicht gefunden'); e.status = 404; throw e; } await db.run('DELETE FROM tarifoptionen_tarife WHERE tarifoption_id = ?', [id]); // Best-effort cleanup of legacy rows that may have been synced under this name/code. await db.run( 'DELETE FROM tarifoptionen WHERE name = ? AND (code = ? OR (code IS NULL AND ? IS NULL))', [name, code || null, code || null] ); let targetTarifIds = tarif_ids || []; if (is_anbieter_weit && anbieter_id) { const tarifs = await db.all('SELECT id FROM tarife WHERE anbieter_id = ?', [anbieter_id]); targetTarifIds = tarifs.map(t => t.id); } for (const tarifId of targetTarifIds) { await db.run( 'INSERT INTO tarifoptionen_tarife (tarifoption_id, tarif_id) VALUES (?, ?)', [id, tarifId] ); const tarif = await db.get('SELECT anbieter_id FROM tarife WHERE id = ?', [tarifId]); if (tarif) { await syncLegacyOption(tarif.anbieter_id, tarifId, name, code, provision_euro, beschreibung); } } }); res.json({ message: 'Tarifoption erfolgreich aktualisiert' }); })); router.delete('/multi/:id', asyncHandler(async (req, res) => { const { id } = req.params; const option = await db.get('SELECT name, code FROM tarifoptionen_new WHERE id = ?', [id]); if (!option) return res.status(404).json({ error: 'Tarifoption nicht gefunden' }); await db.transaction(async () => { await db.run('DELETE FROM tarifoptionen_tarife WHERE tarifoption_id = ?', [id]); await db.run( 'DELETE FROM tarifoptionen WHERE name = ? AND (code = ? OR (code IS NULL AND ? IS NULL))', [option.name, option.code, option.code] ); await db.run('DELETE FROM tarifoptionen_new WHERE id = ?', [id]); }); res.json({ message: 'Tarifoption erfolgreich gelöscht' }); })); // Tariff-specific tarifoption list (used by frontend when adding options to a schaltung) router.get('/tarif/:tarif_id', asyncHandler(async (req, res) => { const { tarif_id } = req.params; const rows = await db.all( 'SELECT * FROM tarifoptionen WHERE tarif_id = ? AND aktiv = 1 ORDER BY name', [tarif_id] ); res.json(rows); })); module.exports = router;