import { randomUUID } from 'crypto'; import db from '../../db.js'; import { badRequest } from '../../lib/http.js'; import { mapEvent } from '../../lib/mappers.js'; import { computeRemoteDurationSeconds } from '../../teamviewer.js'; const EVENT_TYPES_USER = new Set(['NOTE', 'CALL', 'REMOTE', 'PART']); export function registerEventRoutes(api) { api.post('/events', (req, res) => { const b = req.body || {}; const ticketId = b.ticketId; const type = b.type; if (!ticketId || !type || !EVENT_TYPES_USER.has(type)) { return badRequest(res, 'Pflichtfelder fehlen oder ungültiger Typ.'); } const t = db .prepare('SELECT 1 AS ok FROM tickets WHERE id = ?') .get(ticketId); if (!t) return res.status(404).json({ message: 'Nicht gefunden' }); const desc = b.description != null ? String(b.description).trim() : ''; const callbackNumber = b.callbackNumber != null ? String(b.callbackNumber).trim() : ''; const teamviewerId = b.teamviewerId != null ? String(b.teamviewerId).trim() : ''; const articleNumber = b.articleNumber != null ? String(b.articleNumber).trim() : ''; let description = desc; let cb = callbackNumber || null; let tv = teamviewerId || null; let art = articleNumber || null; if (type === 'NOTE') { if (!description) return badRequest(res, 'Beschreibung fehlt.'); cb = null; tv = null; art = null; } else if (type === 'CALL') { // Rückrufnummer optional; nur Beschreibung ist Pflicht. if (!description) return badRequest(res, 'Beschreibung fehlt.'); tv = null; art = null; } else if (type === 'REMOTE') { if (!description?.trim() && !tv) { return badRequest(res, 'Beschreibung oder TeamViewer-Gerät erforderlich.'); } cb = null; art = null; } else if (type === 'PART') { if (!articleNumber) return badRequest(res, 'Artikelnummer fehlt.'); description = desc; cb = null; tv = null; } let remoteDurationSeconds = null; let teamviewerNotes = null; if (type === 'REMOTE') { remoteDurationSeconds = computeRemoteDurationSeconds( b.teamviewerStartDate, b.teamviewerEndDate, ); const tn = b.teamviewerNotes != null ? String(b.teamviewerNotes).trim() : ''; teamviewerNotes = tn || null; } const eid = randomUUID(); db.exec('BEGIN'); try { const row = db .prepare( `INSERT INTO events (id, ticket_id, type, description, callback_number, teamviewer_id, article_number, remote_duration_seconds, teamviewer_notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`, ) .get( eid, ticketId, type, description, cb, tv, art, remoteDurationSeconds, teamviewerNotes, ); db.prepare( `UPDATE tickets SET updated_at = datetime('now'), sla_anchor_at = CASE WHEN status IN ('OPEN', 'WAITING') THEN datetime('now') ELSE sla_anchor_at END WHERE id = ?`, ).run(ticketId); db.exec('COMMIT'); res.status(201).json(mapEvent(row)); } catch (e) { db.exec('ROLLBACK'); throw e; } }); }