v1.19: Schadensmeldungen mit Kommunikation verknuepft
This commit is contained in:
@@ -72,6 +72,9 @@ CREATE TABLE IF NOT EXISTS threads (
|
||||
unread_by_tenant BOOLEAN NOT NULL DEFAULT FALSE
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_threads_unit ON threads(unit_id);
|
||||
-- Verknüpfung Unterhaltung ↔ Schadensmeldung (v1.19)
|
||||
ALTER TABLE threads ADD COLUMN IF NOT EXISTS ticket_id TEXT REFERENCES tickets(id);
|
||||
CREATE INDEX IF NOT EXISTS idx_threads_ticket ON threads(ticket_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS messages (
|
||||
id TEXT PRIMARY KEY,
|
||||
|
||||
+39
-4
@@ -169,6 +169,7 @@ const mapMessage = (m) => ({ id: m.id, from: m.from_role, author: m.author, text
|
||||
const mapThread = (t) => ({
|
||||
id: t.id, unitId: t.unit_id, tenant: t.tenant, subject: t.subject,
|
||||
unreadByAdmin: t.unread_by_admin, unreadByTenant: t.unread_by_tenant,
|
||||
ticketId: t.ticket_id ?? null,
|
||||
})
|
||||
const mapCode = (c) => ({ code: c.code, einheitId: c.einheit_id, erstelltAm: c.erstellt_am, verwendetAm: c.verwendet_am ?? undefined })
|
||||
const mapAnnouncement = (a) => ({ id: a.id, title: a.title, text: a.text, date: a.date, tag: a.tag })
|
||||
@@ -390,10 +391,10 @@ app.post('/api/tickets', auth, async (req, res, next) => {
|
||||
`Priorität: ${['niedrig', 'mittel', 'hoch'].includes(priority) ? priority : 'mittel'}.\n\n` +
|
||||
`${String(title).trim()}\n${String(description || '–').trim()}`
|
||||
await pool.query(
|
||||
`INSERT INTO threads (id, unit_id, tenant, subject, unread_by_admin, unread_by_tenant)
|
||||
VALUES ($1,$2,$3,$4,$5,$6)`,
|
||||
`INSERT INTO threads (id, unit_id, tenant, subject, unread_by_admin, unread_by_tenant, ticket_id)
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7)`,
|
||||
[threadId, unitId, mieterName, threadBetreff,
|
||||
vonRolle === 'tenant', vonRolle === 'admin'],
|
||||
vonRolle === 'tenant', vonRolle === 'admin', id],
|
||||
)
|
||||
await pool.query(
|
||||
`INSERT INTO messages (id, thread_id, from_role, author, text, at) VALUES ($1,$2,$3,$4,$5,$6)`,
|
||||
@@ -466,10 +467,44 @@ app.patch('/api/tickets/:id', auth, adminOnly, async (req, res, next) => {
|
||||
const status = String((req.body || {}).status || '')
|
||||
if (!['offen', 'in Bearbeitung', 'erledigt'].includes(status))
|
||||
return res.status(400).json({ fehler: 'Ungültiger Status.' })
|
||||
const { rows: altRows } = await pool.query('SELECT status FROM tickets WHERE id = $1', [req.params.id])
|
||||
if (!altRows.length) return res.status(404).json({ fehler: 'Ticket nicht gefunden.' })
|
||||
const alterStatus = altRows[0].status
|
||||
const { rows } = await pool.query(
|
||||
'UPDATE tickets SET status = $1 WHERE id = $2 RETURNING *', [status, req.params.id],
|
||||
)
|
||||
if (!rows.length) return res.status(404).json({ fehler: 'Ticket nicht gefunden.' })
|
||||
// Statuswechsel als Systemnachricht in die verknüpfte Unterhaltung schreiben,
|
||||
// damit der gesamte Verlauf der Schadensmeldung an einem Ort bleibt (v1.19).
|
||||
const { rows: threadRows } = await pool.query(
|
||||
'SELECT * FROM threads WHERE ticket_id = $1', [req.params.id],
|
||||
)
|
||||
if (threadRows.length && alterStatus !== status) {
|
||||
const th = threadRows[0]
|
||||
const systemText = `Status der Schadensmeldung geändert: ${alterStatus} → ${status}`
|
||||
await pool.query(
|
||||
`INSERT INTO messages (id, thread_id, from_role, author, text, at) VALUES ($1,$2,'admin',$3,$4,$5)`,
|
||||
[`${th.id}-${Date.now()}`, th.id, req.user.name, systemText, deutschesDatumZeit()],
|
||||
)
|
||||
await pool.query('UPDATE threads SET unread_by_tenant = TRUE WHERE id = $1', [th.id])
|
||||
const { rows: einheitRows } = await pool.query('SELECT * FROM units WHERE id = $1', [th.unit_id])
|
||||
const label = mail.einheitLabel(mapUnit(einheitRows[0]))
|
||||
const textVersion =
|
||||
`Der Status der Schadensmeldung „${rows[0].title}“ wurde geändert:\n\n` +
|
||||
`${alterStatus} → ${status}\n\nWohnung: ${label}`
|
||||
const html = mail.baueHtmlMail({
|
||||
titel: 'Status aktualisiert',
|
||||
untertitel: th.subject,
|
||||
einleitung: `Der Status Ihrer Schadensmeldung „${rows[0].title}“ wurde von der Verwaltung geändert.`,
|
||||
zeilen: [
|
||||
['Wohnung', label],
|
||||
['Vorher', alterStatus],
|
||||
['Neu', status],
|
||||
],
|
||||
statusBox: { hintergrund: '#f0fdfa', farbe: '#0f766e', text: `Status: ${status}` },
|
||||
aktionenHtml: mail.buttonHtml('Zum Mieterportal', `${process.env.PORTAL_URL || 'https://mieterportal.hocks.eu'}/nachrichten`),
|
||||
})
|
||||
mail.benachrichtigeMieter(th.unit_id, `Status: ${status} – ${rows[0].title}`, textVersion, html)
|
||||
}
|
||||
res.json({ ticket: mapTicket(rows[0]) })
|
||||
} catch (e) { next(e) }
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user