This commit is contained in:
2026-03-23 02:09:14 +01:00
parent 705329d3c2
commit d8d46ed8e9
61 changed files with 6054 additions and 3116 deletions

104
server/routes/api/events.js Normal file
View File

@@ -0,0 +1,104 @@
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;
}
});
}