- aether-medical: Stationen/Belegung, Intensivstation, Blutbank, Fuhrpark, Nachrichten/Aushänge, Berichte und Textbausteine (server + NUI) - aether-admin: vollständiges Server-Admin-Panel als echtes FiveM-Resource, an aether-core gekoppelt (Rechte über aether_users.admin_group), mit WebRTC-Live-Kameras (Bildschirmfreigabe) und separatem Media-Server (SFU) - Prototypen admin/ vervollständigt - SQL-Schema aether_admin.sql - Docker-Compose mit MariaDB und idempotenter Auto-Migration (schema_migrations) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
583 lines
22 KiB
Lua
583 lines
22 KiB
Lua
-- =====================================================================
|
|
-- aether-police / Modul: Berichtswesen
|
|
--
|
|
-- Ein Bericht durchläuft drei Stufen: Entwurf → Eingereicht → Freigegeben.
|
|
-- Keine davon wird automatisch erreicht. Auch die Freigabe ist eine
|
|
-- bewusste Handlung eines berechtigten Beamten und wird mit Namen
|
|
-- festgehalten. Unterschriften sind verbindlich und nicht widerrufbar.
|
|
-- =====================================================================
|
|
|
|
Kern.RegistriereModul({
|
|
id = 'bericht', name = 'Berichte', icon = '📄',
|
|
reihenfolge = 8, recht = 'bericht.erstellen',
|
|
beschreibung = 'Einsatzberichte verfassen und freigeben',
|
|
})
|
|
|
|
-- ---------------------------------------------------------------------
|
|
-- Hilfsfunktionen
|
|
-- ---------------------------------------------------------------------
|
|
|
|
--- Entschlüsselt ein JSON-Feld sicher zu einer Liste
|
|
--- @param roh string|nil
|
|
--- @return table
|
|
local function ZuListe(roh)
|
|
if not roh then return {} end
|
|
local erfolg, liste = pcall(json.decode, roh)
|
|
return (erfolg and type(liste) == 'table') and liste or {}
|
|
end
|
|
|
|
--- Lädt einen Bericht samt aufbereiteter Felder
|
|
--- @param berichtId number
|
|
--- @return table|nil
|
|
local function LadeBericht(berichtId)
|
|
local zeilen = MySQL.query.await([[
|
|
SELECT b.*, c.firstname, c.lastname, p.dienstnummer,
|
|
e.nummer AS einsatz_nummer, e.titel AS einsatz_titel,
|
|
a.aktenzeichen, a.titel AS akte_titel
|
|
FROM police_bericht b
|
|
LEFT JOIN aether_characters c ON c.id = b.erstellt_von
|
|
LEFT JOIN police_personal p ON p.`character` = b.erstellt_von
|
|
LEFT JOIN police_einsatz e ON e.id = b.einsatz
|
|
LEFT JOIN police_akte a ON a.id = b.akte
|
|
WHERE b.id = ?
|
|
]], { berichtId })
|
|
|
|
if not zeilen or not zeilen[1] then return nil end
|
|
|
|
local bericht = zeilen[1]
|
|
bericht.beteiligte = ZuListe(bericht.beteiligte)
|
|
bericht.anlagen = ZuListe(bericht.anlagen)
|
|
bericht.unterschriften = ZuListe(bericht.unterschriften)
|
|
|
|
return bericht
|
|
end
|
|
|
|
--- Darf der Beamte diesen Bericht inhaltlich ändern?
|
|
--- @param bericht table
|
|
--- @param beamter table
|
|
--- @return boolean
|
|
local function DarfBearbeiten(bericht, beamter)
|
|
-- Freigegebene Berichte sind gesperrt — auch für den Verfasser
|
|
if bericht.status == 'freigegeben' then return false end
|
|
if bericht.erstellt_von == beamter.charakterId then return true end
|
|
-- Fremde Berichte darf nur bearbeiten, wer auch freigeben darf
|
|
return Rechte.Hat(beamter, 'bericht.freigeben')
|
|
end
|
|
|
|
-- =====================================================================
|
|
-- ÜBERSICHT
|
|
-- =====================================================================
|
|
|
|
Kern.RegistriereAktion('bericht', 'liste', nil, function(quelle, beamter, daten)
|
|
local bedingungen, werte = { '1=1' }, {}
|
|
|
|
if daten.status and daten.status ~= '' then
|
|
bedingungen[#bedingungen + 1] = 'b.status = ?'
|
|
werte[#werte + 1] = daten.status
|
|
end
|
|
if daten.nurEigene then
|
|
bedingungen[#bedingungen + 1] = 'b.erstellt_von = ?'
|
|
werte[#werte + 1] = beamter.charakterId
|
|
end
|
|
if type(daten.begriff) == 'string' and #daten.begriff >= 2 then
|
|
bedingungen[#bedingungen + 1] = '(b.titel LIKE ? OR b.nummer LIKE ?)'
|
|
local muster = '%' .. daten.begriff .. '%'
|
|
werte[#werte + 1] = muster
|
|
werte[#werte + 1] = muster
|
|
end
|
|
|
|
local berichte = MySQL.query.await(([[
|
|
SELECT b.id, b.nummer, b.titel, b.status, b.erstellt_am, b.erstellt_von,
|
|
b.unterschriften, b.einsatz, b.akte,
|
|
c.firstname, c.lastname, p.dienstnummer,
|
|
e.nummer AS einsatz_nummer
|
|
FROM police_bericht b
|
|
LEFT JOIN aether_characters c ON c.id = b.erstellt_von
|
|
LEFT JOIN police_personal p ON p.`character` = b.erstellt_von
|
|
LEFT JOIN police_einsatz e ON e.id = b.einsatz
|
|
WHERE %s
|
|
ORDER BY
|
|
CASE b.status WHEN 'entwurf' THEN 0 WHEN 'eingereicht' THEN 1 ELSE 2 END,
|
|
b.id DESC
|
|
LIMIT 80
|
|
]]):format(table.concat(bedingungen, ' AND ')), werte) or {}
|
|
|
|
for _, bericht in ipairs(berichte) do
|
|
bericht.unterschriften = ZuListe(bericht.unterschriften)
|
|
bericht.eigener = bericht.erstellt_von == beamter.charakterId
|
|
end
|
|
|
|
-- Zahlen für die Übersicht
|
|
local offen = MySQL.scalar.await(
|
|
"SELECT COUNT(*) FROM police_bericht WHERE status = 'entwurf' AND erstellt_von = ?",
|
|
{ beamter.charakterId }) or 0
|
|
local zurPruefung = MySQL.scalar.await(
|
|
"SELECT COUNT(*) FROM police_bericht WHERE status = 'eingereicht'") or 0
|
|
|
|
return {
|
|
berichte = berichte,
|
|
eigeneOffen = offen,
|
|
zurPruefung = zurPruefung,
|
|
rechte = {
|
|
erstellen = Rechte.Hat(beamter, 'bericht.erstellen'),
|
|
freigeben = Rechte.Hat(beamter, 'bericht.freigeben'),
|
|
},
|
|
}
|
|
end)
|
|
|
|
Kern.RegistriereAktion('bericht', 'oeffnen', nil, function(quelle, beamter, daten)
|
|
local berichtId = tonumber(daten.id)
|
|
if not berichtId then return nil, 'Ungültige Kennung.' end
|
|
|
|
local bericht = LadeBericht(berichtId)
|
|
if not bericht then return nil, 'Bericht nicht gefunden.' end
|
|
|
|
-- Habe ich bereits unterschrieben?
|
|
local habeUnterschrieben = false
|
|
for _, unterschrift in ipairs(bericht.unterschriften) do
|
|
if unterschrift.charakterId == beamter.charakterId then
|
|
habeUnterschrieben = true
|
|
break
|
|
end
|
|
end
|
|
|
|
return {
|
|
bericht = bericht,
|
|
habeUnterschrieben = habeUnterschrieben,
|
|
rechte = {
|
|
bearbeiten = DarfBearbeiten(bericht, beamter),
|
|
freigeben = Rechte.Hat(beamter, 'bericht.freigeben'),
|
|
},
|
|
}
|
|
end)
|
|
|
|
-- =====================================================================
|
|
-- ANLEGEN
|
|
-- =====================================================================
|
|
|
|
Kern.RegistriereAktion('bericht', 'erstellen', 'bericht.erstellen', function(quelle, beamter, daten)
|
|
local titel = type(daten.titel) == 'string'
|
|
and daten.titel:gsub('^%s+', ''):gsub('%s+$', '') or ''
|
|
if #titel < 3 or #titel > 160 then
|
|
return nil, 'Der Titel muss 3 bis 160 Zeichen lang sein.'
|
|
end
|
|
|
|
-- Bezüge prüfen, falls angegeben
|
|
local einsatzId = tonumber(daten.einsatz)
|
|
if einsatzId then
|
|
local vorhanden = MySQL.scalar.await('SELECT id FROM police_einsatz WHERE id = ?', { einsatzId })
|
|
if not vorhanden then return nil, 'Der angegebene Einsatz existiert nicht.' end
|
|
end
|
|
|
|
local akteId = tonumber(daten.akte)
|
|
if akteId then
|
|
local vorhanden = MySQL.scalar.await('SELECT id FROM police_akte WHERE id = ?', { akteId })
|
|
if not vorhanden then return nil, 'Die angegebene Akte existiert nicht.' end
|
|
end
|
|
|
|
local nummer = Kern.ErzeugeKennung('BER', 'police_bericht', 'nummer')
|
|
|
|
-- Der Verfasser ist von Beginn an als beteiligter Beamter geführt
|
|
local beteiligte = { {
|
|
typ = 'beamter', charakterId = beamter.charakterId,
|
|
name = beamter.name, dienstnummer = beamter.dienstnummer,
|
|
rolle = 'Verfasser',
|
|
} }
|
|
|
|
local berichtId = MySQL.insert.await([[
|
|
INSERT INTO police_bericht
|
|
(nummer, einsatz, akte, titel, beschreibung, massnahmen, beteiligte,
|
|
anlagen, unterschriften, status, erstellt_von)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, '[]', '[]', 'entwurf', ?)
|
|
]], {
|
|
nummer, einsatzId, akteId, titel,
|
|
type(daten.beschreibung) == 'string' and daten.beschreibung or nil,
|
|
type(daten.massnahmen) == 'string' and daten.massnahmen or nil,
|
|
json.encode(beteiligte), beamter.charakterId,
|
|
})
|
|
|
|
Protokoll.Schreibe(beamter, 'bericht', 'Bericht angelegt',
|
|
{ typ = 'bericht', id = berichtId }, { nummer = nummer })
|
|
|
|
Kern.Loese('bericht.erstellt', berichtId, beamter)
|
|
|
|
return { id = berichtId, nummer = nummer }
|
|
end)
|
|
|
|
-- =====================================================================
|
|
-- BEARBEITEN
|
|
--
|
|
-- Freigegebene Berichte sind gesperrt — auch für den Verfasser.
|
|
-- =====================================================================
|
|
|
|
Kern.RegistriereAktion('bericht', 'speichern', 'bericht.erstellen', function(quelle, beamter, daten)
|
|
local berichtId = tonumber(daten.id)
|
|
if not berichtId then return nil, 'Ungültige Kennung.' end
|
|
|
|
local bericht = LadeBericht(berichtId)
|
|
if not bericht then return nil, 'Bericht nicht gefunden.' end
|
|
|
|
if not DarfBearbeiten(bericht, beamter) then
|
|
return nil, bericht.status == 'freigegeben'
|
|
and 'Freigegebene Berichte können nicht mehr geändert werden.'
|
|
or 'Du kannst nur eigene Berichte bearbeiten.'
|
|
end
|
|
|
|
-- Liegen bereits Unterschriften vor, ist eine Änderung heikel
|
|
if #bericht.unterschriften > 0 then
|
|
local grund = type(daten.grund) == 'string' and daten.grund or ''
|
|
if #grund < 5 then
|
|
return nil, 'Der Bericht wurde bereits unterschrieben. Eine Änderung erfordert eine Begründung.'
|
|
end
|
|
end
|
|
|
|
MySQL.update.await([[
|
|
UPDATE police_bericht SET titel = ?, beschreibung = ?, massnahmen = ? WHERE id = ?
|
|
]], {
|
|
type(daten.titel) == 'string' and daten.titel:sub(1, 160) or bericht.titel,
|
|
type(daten.beschreibung) == 'string' and daten.beschreibung or nil,
|
|
type(daten.massnahmen) == 'string' and daten.massnahmen or nil,
|
|
berichtId,
|
|
})
|
|
|
|
Protokoll.Schreibe(beamter, 'bericht', 'Bericht bearbeitet',
|
|
{ typ = 'bericht', id = berichtId },
|
|
{ unterschriften = #bericht.unterschriften },
|
|
type(daten.grund) == 'string' and daten.grund or nil)
|
|
|
|
return { ok = true }
|
|
end)
|
|
|
|
-- ---------------------------------------------------------------------
|
|
-- Beteiligte
|
|
-- ---------------------------------------------------------------------
|
|
|
|
Kern.RegistriereAktion('bericht', 'beteiligtHinzu', 'bericht.erstellen', function(quelle, beamter, daten)
|
|
local berichtId = tonumber(daten.id)
|
|
if not berichtId then return nil, 'Ungültige Kennung.' end
|
|
|
|
local bericht = LadeBericht(berichtId)
|
|
if not bericht then return nil, 'Bericht nicht gefunden.' end
|
|
if not DarfBearbeiten(bericht, beamter) then return nil, 'Keine Berechtigung.' end
|
|
|
|
local typ = (daten.typ == 'beamter') and 'beamter' or 'person'
|
|
local name = type(daten.name) == 'string'
|
|
and daten.name:gsub('^%s+', ''):gsub('%s+$', '') or ''
|
|
if #name < 2 then return nil, 'Bitte einen Namen angeben.' end
|
|
|
|
local charakterId = tonumber(daten.charakterId)
|
|
|
|
-- Doppelte Einträge vermeiden
|
|
for _, eintrag in ipairs(bericht.beteiligte) do
|
|
if charakterId and eintrag.charakterId == charakterId then
|
|
return nil, 'Diese Person ist bereits aufgeführt.'
|
|
end
|
|
end
|
|
|
|
table.insert(bericht.beteiligte, {
|
|
typ = typ, charakterId = charakterId, name = name:sub(1, 64),
|
|
rolle = type(daten.rolle) == 'string' and daten.rolle:sub(1, 48) or nil,
|
|
dienstnummer = type(daten.dienstnummer) == 'string' and daten.dienstnummer:sub(1, 16) or nil,
|
|
})
|
|
|
|
MySQL.update.await('UPDATE police_bericht SET beteiligte = ? WHERE id = ?',
|
|
{ json.encode(bericht.beteiligte), berichtId })
|
|
|
|
Protokoll.Schreibe(beamter, 'bericht', 'Beteiligten ergänzt',
|
|
{ typ = 'bericht', id = berichtId }, { name = name, rolle = daten.rolle })
|
|
|
|
return { ok = true }
|
|
end)
|
|
|
|
Kern.RegistriereAktion('bericht', 'beteiligtEntfernen', 'bericht.erstellen', function(quelle, beamter, daten)
|
|
local berichtId = tonumber(daten.id)
|
|
local index = tonumber(daten.index)
|
|
if not berichtId or not index then return nil, 'Unvollständige Angaben.' end
|
|
|
|
local bericht = LadeBericht(berichtId)
|
|
if not bericht then return nil, 'Bericht nicht gefunden.' end
|
|
if not DarfBearbeiten(bericht, beamter) then return nil, 'Keine Berechtigung.' end
|
|
|
|
local eintrag = bericht.beteiligte[index]
|
|
if not eintrag then return nil, 'Eintrag nicht gefunden.' end
|
|
|
|
-- Der Verfasser bleibt immer aufgeführt
|
|
if eintrag.charakterId == bericht.erstellt_von then
|
|
return nil, 'Der Verfasser kann nicht entfernt werden.'
|
|
end
|
|
|
|
table.remove(bericht.beteiligte, index)
|
|
|
|
MySQL.update.await('UPDATE police_bericht SET beteiligte = ? WHERE id = ?',
|
|
{ json.encode(bericht.beteiligte), berichtId })
|
|
|
|
Protokoll.Schreibe(beamter, 'bericht', 'Beteiligten entfernt',
|
|
{ typ = 'bericht', id = berichtId }, { name = eintrag.name })
|
|
|
|
return { ok = true }
|
|
end)
|
|
|
|
-- ---------------------------------------------------------------------
|
|
-- Anlagen (Dateien und Beweisbezüge)
|
|
-- ---------------------------------------------------------------------
|
|
|
|
Kern.RegistriereAktion('bericht', 'anlageHinzu', 'bericht.erstellen', function(quelle, beamter, daten)
|
|
local berichtId = tonumber(daten.id)
|
|
if not berichtId then return nil, 'Ungültige Kennung.' end
|
|
|
|
local bericht = LadeBericht(berichtId)
|
|
if not bericht then return nil, 'Bericht nicht gefunden.' end
|
|
if not DarfBearbeiten(bericht, beamter) then return nil, 'Keine Berechtigung.' end
|
|
|
|
local eintrag
|
|
|
|
if daten.typ == 'beweis' then
|
|
local beweisId = tonumber(daten.beweisId)
|
|
if not beweisId then return nil, 'Kein Beweismittel gewählt.' end
|
|
|
|
local beweis = MySQL.query.await(
|
|
'SELECT kennung, bezeichnung, art FROM police_beweis WHERE id = ?', { beweisId })
|
|
if not beweis or not beweis[1] then return nil, 'Beweismittel nicht gefunden.' end
|
|
|
|
for _, vorhanden in ipairs(bericht.anlagen) do
|
|
if vorhanden.typ == 'beweis' and vorhanden.beweisId == beweisId then
|
|
return nil, 'Dieses Beweismittel ist bereits aufgeführt.'
|
|
end
|
|
end
|
|
|
|
eintrag = {
|
|
typ = 'beweis', beweisId = beweisId,
|
|
kennung = beweis[1].kennung, titel = beweis[1].bezeichnung, art = beweis[1].art,
|
|
}
|
|
else
|
|
local titel = type(daten.titel) == 'string'
|
|
and daten.titel:gsub('^%s+', ''):gsub('%s+$', '') or ''
|
|
if #titel < 2 then return nil, 'Bitte eine Bezeichnung angeben.' end
|
|
|
|
eintrag = {
|
|
typ = 'datei', titel = titel:sub(1, 120),
|
|
adresse = type(daten.adresse) == 'string' and daten.adresse:sub(1, 2000) or nil,
|
|
}
|
|
end
|
|
|
|
table.insert(bericht.anlagen, eintrag)
|
|
|
|
MySQL.update.await('UPDATE police_bericht SET anlagen = ? WHERE id = ?',
|
|
{ json.encode(bericht.anlagen), berichtId })
|
|
|
|
Protokoll.Schreibe(beamter, 'bericht', 'Anlage ergänzt',
|
|
{ typ = 'bericht', id = berichtId }, eintrag)
|
|
|
|
return { ok = true }
|
|
end)
|
|
|
|
Kern.RegistriereAktion('bericht', 'anlageEntfernen', 'bericht.erstellen', function(quelle, beamter, daten)
|
|
local berichtId = tonumber(daten.id)
|
|
local index = tonumber(daten.index)
|
|
if not berichtId or not index then return nil, 'Unvollständige Angaben.' end
|
|
|
|
local bericht = LadeBericht(berichtId)
|
|
if not bericht then return nil, 'Bericht nicht gefunden.' end
|
|
if not DarfBearbeiten(bericht, beamter) then return nil, 'Keine Berechtigung.' end
|
|
|
|
local eintrag = bericht.anlagen[index]
|
|
if not eintrag then return nil, 'Anlage nicht gefunden.' end
|
|
|
|
table.remove(bericht.anlagen, index)
|
|
|
|
MySQL.update.await('UPDATE police_bericht SET anlagen = ? WHERE id = ?',
|
|
{ json.encode(bericht.anlagen), berichtId })
|
|
|
|
Protokoll.Schreibe(beamter, 'bericht', 'Anlage entfernt',
|
|
{ typ = 'bericht', id = berichtId }, { titel = eintrag.titel })
|
|
|
|
return { ok = true }
|
|
end)
|
|
|
|
-- =====================================================================
|
|
-- UNTERSCHREIBEN
|
|
--
|
|
-- Eine Unterschrift ist verbindlich und wird nicht zurückgenommen.
|
|
-- =====================================================================
|
|
|
|
Kern.RegistriereAktion('bericht', 'unterschreiben', nil, function(quelle, beamter, daten)
|
|
local berichtId = tonumber(daten.id)
|
|
if not berichtId then return nil, 'Ungültige Kennung.' end
|
|
|
|
local bericht = LadeBericht(berichtId)
|
|
if not bericht then return nil, 'Bericht nicht gefunden.' end
|
|
|
|
if bericht.status == 'freigegeben' then
|
|
return nil, 'Der Bericht ist bereits freigegeben.'
|
|
end
|
|
|
|
for _, unterschrift in ipairs(bericht.unterschriften) do
|
|
if unterschrift.charakterId == beamter.charakterId then
|
|
return nil, 'Du hast bereits unterschrieben.'
|
|
end
|
|
end
|
|
|
|
table.insert(bericht.unterschriften, {
|
|
charakterId = beamter.charakterId,
|
|
name = beamter.name,
|
|
dienstnummer = beamter.dienstnummer,
|
|
rolle = beamter.rolleName,
|
|
am = os.date('%Y-%m-%d %H:%M:%S'),
|
|
})
|
|
|
|
MySQL.update.await('UPDATE police_bericht SET unterschriften = ? WHERE id = ?',
|
|
{ json.encode(bericht.unterschriften), berichtId })
|
|
|
|
Protokoll.Schreibe(beamter, 'bericht', 'Bericht unterschrieben',
|
|
{ typ = 'bericht', id = berichtId }, { nummer = bericht.nummer })
|
|
|
|
return { ok = true }
|
|
end)
|
|
|
|
-- =====================================================================
|
|
-- EINREICHEN UND FREIGEBEN
|
|
-- =====================================================================
|
|
|
|
Kern.RegistriereAktion('bericht', 'einreichen', 'bericht.erstellen', function(quelle, beamter, daten)
|
|
local berichtId = tonumber(daten.id)
|
|
if not berichtId then return nil, 'Ungültige Kennung.' end
|
|
|
|
local bericht = LadeBericht(berichtId)
|
|
if not bericht then return nil, 'Bericht nicht gefunden.' end
|
|
|
|
if bericht.status ~= 'entwurf' then
|
|
return nil, 'Nur Entwürfe können eingereicht werden.'
|
|
end
|
|
if bericht.erstellt_von ~= beamter.charakterId
|
|
and not Rechte.Hat(beamter, 'bericht.freigeben') then
|
|
return nil, 'Nur der Verfasser kann seinen Bericht einreichen.'
|
|
end
|
|
if not bericht.beschreibung or #bericht.beschreibung < 20 then
|
|
return nil, 'Der Bericht enthält noch keine ausreichende Beschreibung.'
|
|
end
|
|
if #bericht.unterschriften == 0 then
|
|
return nil, 'Bitte unterschreibe den Bericht, bevor du ihn einreichst.'
|
|
end
|
|
|
|
MySQL.update.await("UPDATE police_bericht SET status = 'eingereicht' WHERE id = ?", { berichtId })
|
|
|
|
Protokoll.Schreibe(beamter, 'bericht', 'Bericht eingereicht',
|
|
{ typ = 'bericht', id = berichtId }, { nummer = bericht.nummer })
|
|
|
|
-- Die Führung darüber informieren, dass eine Prüfung ansteht
|
|
Hinweise.Erstelle(nil, {
|
|
kategorie = 'bericht', prioritaet = 'normal',
|
|
titel = 'Bericht zur Prüfung eingereicht',
|
|
text = ('%s „%s" von %s wartet auf Freigabe.')
|
|
:format(bericht.nummer, bericht.titel, beamter.dienstnummer),
|
|
zielTyp = 'bericht', zielId = berichtId,
|
|
})
|
|
|
|
return { ok = true }
|
|
end)
|
|
|
|
Kern.RegistriereAktion('bericht', 'freigeben', 'bericht.freigeben', function(quelle, beamter, daten)
|
|
local berichtId = tonumber(daten.id)
|
|
if not berichtId then return nil, 'Ungültige Kennung.' end
|
|
|
|
local bericht = LadeBericht(berichtId)
|
|
if not bericht then return nil, 'Bericht nicht gefunden.' end
|
|
|
|
if bericht.status == 'freigegeben' then
|
|
return nil, 'Der Bericht ist bereits freigegeben.'
|
|
end
|
|
if bericht.status ~= 'eingereicht' then
|
|
return nil, 'Nur eingereichte Berichte können freigegeben werden.'
|
|
end
|
|
|
|
-- Mit der Freigabe unterschreibt der Freigebende zugleich
|
|
local schonDrin = false
|
|
for _, unterschrift in ipairs(bericht.unterschriften) do
|
|
if unterschrift.charakterId == beamter.charakterId then schonDrin = true break end
|
|
end
|
|
if not schonDrin then
|
|
table.insert(bericht.unterschriften, {
|
|
charakterId = beamter.charakterId, name = beamter.name,
|
|
dienstnummer = beamter.dienstnummer, rolle = beamter.rolleName,
|
|
am = os.date('%Y-%m-%d %H:%M:%S'), freigabe = true,
|
|
})
|
|
end
|
|
|
|
MySQL.update.await(
|
|
"UPDATE police_bericht SET status = 'freigegeben', unterschriften = ? WHERE id = ?",
|
|
{ json.encode(bericht.unterschriften), berichtId })
|
|
|
|
Protokoll.Schreibe(beamter, 'bericht', 'Bericht freigegeben',
|
|
{ typ = 'bericht', id = berichtId }, { nummer = bericht.nummer }, daten.vermerk)
|
|
|
|
Hinweise.Erstelle({ charakterId = bericht.erstellt_von }, {
|
|
kategorie = 'bericht', prioritaet = 'normal',
|
|
titel = 'Bericht freigegeben',
|
|
text = ('%s wurde von %s freigegeben.'):format(bericht.nummer, beamter.dienstnummer),
|
|
zielTyp = 'bericht', zielId = berichtId,
|
|
})
|
|
|
|
Kern.Loese('bericht.freigegeben', berichtId, beamter)
|
|
|
|
return { ok = true }
|
|
end)
|
|
|
|
--- Zurück in den Entwurf (Nachbesserung anfordern)
|
|
Kern.RegistriereAktion('bericht', 'zurueckweisen', 'bericht.freigeben', function(quelle, beamter, daten)
|
|
local berichtId = tonumber(daten.id)
|
|
if not berichtId then return nil, 'Ungültige Kennung.' end
|
|
|
|
local grund = type(daten.grund) == 'string' and daten.grund:sub(1, 255) or ''
|
|
if #grund < 5 then return nil, 'Bitte gib an, was nachgebessert werden soll.' end
|
|
|
|
local bericht = LadeBericht(berichtId)
|
|
if not bericht then return nil, 'Bericht nicht gefunden.' end
|
|
if bericht.status ~= 'eingereicht' then
|
|
return nil, 'Nur eingereichte Berichte können zurückgewiesen werden.'
|
|
end
|
|
|
|
MySQL.update.await("UPDATE police_bericht SET status = 'entwurf' WHERE id = ?", { berichtId })
|
|
|
|
Protokoll.Schreibe(beamter, 'bericht', 'Bericht zurückgewiesen',
|
|
{ typ = 'bericht', id = berichtId }, { nummer = bericht.nummer }, grund)
|
|
|
|
Hinweise.Erstelle({ charakterId = bericht.erstellt_von }, {
|
|
kategorie = 'bericht', prioritaet = 'hoch',
|
|
titel = 'Bericht zur Nachbesserung',
|
|
text = ('%s wurde zurückgewiesen: %s'):format(bericht.nummer, grund),
|
|
zielTyp = 'bericht', zielId = berichtId,
|
|
})
|
|
|
|
return { ok = true }
|
|
end)
|
|
|
|
-- =====================================================================
|
|
-- HILFSABFRAGEN FÜR DIE OBERFLÄCHE
|
|
-- =====================================================================
|
|
|
|
--- Offene Einsätze und Akten zur Auswahl beim Anlegen
|
|
Kern.RegistriereAktion('bericht', 'bezuege', nil, function(quelle, beamter, daten)
|
|
local einsaetze = MySQL.query.await([[
|
|
SELECT id, nummer, titel FROM police_einsatz
|
|
ORDER BY id DESC LIMIT 30
|
|
]]) or {}
|
|
|
|
return { einsaetze = einsaetze }
|
|
end)
|
|
|
|
--- Beweismittel zur Auswahl als Anlage
|
|
Kern.RegistriereAktion('bericht', 'beweisSuche', 'bericht.erstellen', function(quelle, beamter, daten)
|
|
local begriff = type(daten.begriff) == 'string' and daten.begriff or ''
|
|
if #begriff < 2 then return { beweise = {} } end
|
|
|
|
local muster = '%' .. begriff .. '%'
|
|
local beweise = MySQL.query.await([[
|
|
SELECT id, kennung, art, bezeichnung, fundort
|
|
FROM police_beweis
|
|
WHERE kennung LIKE ? OR bezeichnung LIKE ?
|
|
ORDER BY id DESC LIMIT 20
|
|
]], { muster, muster }) or {}
|
|
|
|
return { beweise = beweise }
|
|
end)
|