-- ===================================================================== -- aether-medical / Modul: Medizinisches MDT -- -- Das Herzstück: Patientensuche, Stammdaten und Patientenakte. -- -- Das MDT zeigt an und verknüpft. Es stellt keine Diagnose, es leitet -- aus Allergien oder Vorerkrankungen keine Warnung her, die eine -- Behandlung verhindert, und es bewertet keinen Befund. Ein roter -- Hinweis bedeutet hier immer: ein Mediziner hat ihn eingetragen. -- ===================================================================== Kern.RegistriereModul({ id = 'mdt', name = 'MDT', icon = '🩺', reihenfolge = 2, recht = 'patient.suchen', beschreibung = 'Patientensuche, Stammdaten und Akten', }) -- Zulässige Angaben zum Organspendeausweis local ORGANSTATUS = { ja = 'Spender', nein = 'Kein Spender', unbekannt = 'Unbekannt' } -- --------------------------------------------------------------------- -- Hilfsfunktionen -- --------------------------------------------------------------------- --- Prüft einen Suchbegriff --- @param begriff any Eingabe der Oberfläche --- @return boolean local function SuchbegriffGueltig(begriff) return type(begriff) == 'string' and #begriff >= 2 end --- Begrenzt einen Text und liefert nil bei leerer Eingabe --- @param wert any Eingabe --- @param laenge number Höchstlänge --- @return string|nil local function Text(wert, laenge) if type(wert) ~= 'string' then return nil end local sauber = wert:gsub('^%s+', ''):gsub('%s+$', '') if sauber == '' then return nil end return sauber:sub(1, laenge) end --- Lädt den Namen eines Mitarbeiters für die Anzeige --- @param charakterId number|nil Charakter --- @return string local function NameVon(charakterId) if not charakterId then return 'unbekannt' end local zeilen = MySQL.query.await([[ SELECT c.firstname, c.lastname, p.personalnummer FROM aether_characters c LEFT JOIN medical_personal p ON p.`character` = c.id WHERE c.id = ? ]], { charakterId }) if not zeilen or not zeilen[1] then return 'unbekannt' end return zeilen[1].firstname .. ' ' .. zeilen[1].lastname .. (zeilen[1].personalnummer and (' (' .. zeilen[1].personalnummer .. ')') or '') end -- ===================================================================== -- PATIENTENSUCHE -- ===================================================================== Kern.RegistriereAktion('mdt', 'suche', 'patient.suchen', function(quelle, mitarbeiter, daten) if not SuchbegriffGueltig(daten.begriff) then return nil, 'Bitte mindestens zwei Zeichen eingeben.' end local muster = '%' .. daten.begriff .. '%' -- Sucht über Name, Geburtsdatum und Telefonnummer local treffer = MySQL.query.await([[ SELECT c.id, c.firstname, c.lastname, c.dob, c.gender, m.blutgruppe, m.allergien, m.hinweis, m.lichtbild, t.number AS telefon, (SELECT COUNT(*) FROM medical_aufnahme a WHERE a.patient = c.id AND a.status = 'aufgenommen') AS imHaus, (SELECT COUNT(*) FROM medical_aufnahme a WHERE a.patient = c.id AND a.status = 'wartend') AS wartet FROM aether_characters c LEFT JOIN medical_patient m ON m.`character` = c.id LEFT JOIN aether_phone t ON t.`character` = c.id WHERE c.deleted = 0 AND (c.firstname LIKE ? OR c.lastname LIKE ? OR CONCAT(c.firstname, ' ', c.lastname) LIKE ? OR c.dob LIKE ? OR t.number LIKE ?) ORDER BY c.lastname, c.firstname LIMIT 40 ]], { muster, muster, muster, muster, muster }) or {} for _, eintrag in ipairs(treffer) do eintrag.dob = tostring(eintrag.dob):sub(1, 10) eintrag.imHaus = tonumber(eintrag.imHaus) > 0 eintrag.wartet = tonumber(eintrag.wartet) > 0 end return { treffer = treffer } end) -- ===================================================================== -- PATIENTENAKTE -- ===================================================================== Kern.RegistriereAktion('mdt', 'oeffnen', 'patient.suchen', function(quelle, mitarbeiter, daten) local patientId = tonumber(daten.patient) if not patientId then return nil, 'Ungültige Kennung.' end local zeilen = MySQL.query.await([[ SELECT c.id, c.firstname, c.lastname, c.dob, c.gender, c.nationality, c.job, c.is_dead FROM aether_characters c WHERE c.id = ? AND c.deleted = 0 ]], { patientId }) if not zeilen or not zeilen[1] then return nil, 'Diese Person ist nicht erfasst.' end local person = zeilen[1] -- --- Medizinische Stammdaten --- local stamm = MySQL.query.await( 'SELECT * FROM medical_patient WHERE `character` = ?', { patientId }) stamm = stamm and stamm[1] or {} -- --- Telefonnummer --- local telefon = MySQL.scalar.await( 'SELECT number FROM aether_phone WHERE `character` = ?', { patientId }) -- --- Aktuelle Aufnahme, falls vorhanden --- local aufnahme = MySQL.query.await([[ SELECT a.id, a.grund, a.prioritaet, a.station, a.status, a.aufgenommen_am, a.aufgenommen_von, z.kennung AS zimmer FROM medical_aufnahme a LEFT JOIN medical_zimmer z ON z.id = a.zimmer WHERE a.patient = ? AND a.status IN ('wartend', 'aufgenommen') ORDER BY a.id DESC LIMIT 1 ]], { patientId }) aufnahme = aufnahme and aufnahme[1] or nil if aufnahme then aufnahme.aufgenommenVon = NameVon(aufnahme.aufgenommen_von) aufnahme.aufgenommen_von = nil end -- --- Liegt der Patient auf Intensiv? --- local intensiv = MySQL.query.await([[ SELECT i.id, i.zustand, i.geraete, i.verantwortlich, i.aufgenommen_am FROM medical_intensiv i WHERE i.patient = ? AND i.beendet_am IS NULL ORDER BY i.id DESC LIMIT 1 ]], { patientId }) intensiv = intensiv and intensiv[1] or nil if intensiv then intensiv.verantwortlichName = NameVon(intensiv.verantwortlich) intensiv.verantwortlich = nil end -- --- Zählwerte für die Reiter --- local zaehler = { behandlungen = tonumber(MySQL.scalar.await( 'SELECT COUNT(*) FROM medical_behandlung WHERE patient = ?', { patientId })) or 0, operationen = tonumber(MySQL.scalar.await( 'SELECT COUNT(*) FROM medical_operation WHERE patient = ?', { patientId })) or 0, labor = tonumber(MySQL.scalar.await( 'SELECT COUNT(*) FROM medical_labor WHERE patient = ?', { patientId })) or 0, akten = tonumber(MySQL.scalar.await( 'SELECT COUNT(*) FROM medical_akte WHERE patient = ?', { patientId })) or 0, aufnahmen = tonumber(MySQL.scalar.await( 'SELECT COUNT(*) FROM medical_aufnahme WHERE patient = ?', { patientId })) or 0, notizen = tonumber(MySQL.scalar.await( 'SELECT COUNT(*) FROM medical_patient_notiz WHERE patient = ?', { patientId })) or 0, } return { patient = { id = person.id, name = person.firstname .. ' ' .. person.lastname, vorname = person.firstname, nachname = person.lastname, geburt = tostring(person.dob):sub(1, 10), geschlecht = person.gender, herkunft = person.nationality, beruf = person.job, telefon = telefon, -- Nur die Tatsache, dass der Charakter verletzt am Boden liegt. -- Das System leitet daraus nichts ab und stellt nichts fest. verletzt = person.is_dead == 1, }, stamm = { blutgruppe = stamm.blutgruppe, allergien = stamm.allergien, vorerkrankungen = stamm.vorerkrankungen, dauermedikation = stamm.dauermedikation, implantate = stamm.implantate, organspender = stamm.organspender or 'unbekannt', organspenderName = ORGANSTATUS[stamm.organspender or 'unbekannt'], notfallkontakt = stamm.notfallkontakt, hinweis = stamm.hinweis, lichtbild = stamm.lichtbild, gepflegtVon = stamm.aktualisiert_von and NameVon(stamm.aktualisiert_von) or nil, gepflegtAm = stamm.aktualisiert_am, }, aufnahme = aufnahme, intensiv = intensiv, zaehler = zaehler, stationen = Medizin.Config.Stationen, blutgruppen = Medizin.Config.Blutgruppen, organstatus = ORGANSTATUS, rechte = { stammdaten = Rechte.Hat(mitarbeiter, 'patient.stammdaten'), hinweis = Rechte.Hat(mitarbeiter, 'patient.hinweis'), akteLesen = Rechte.Hat(mitarbeiter, 'akte.lesen'), akteErstellen = Rechte.Hat(mitarbeiter, 'akte.erstellen'), akteBearbeiten = Rechte.Hat(mitarbeiter, 'akte.bearbeiten'), akteFreigeben = Rechte.Hat(mitarbeiter, 'akte.freigeben'), akteSchliessen = Rechte.Hat(mitarbeiter, 'akte.schliessen'), }, } end) -- ===================================================================== -- VERLAUF -- -- Alle Vorgänge eines Patienten in einer Zeitleiste. Reine Anzeige — -- aus der Abfolge wird nichts abgeleitet. -- ===================================================================== Kern.RegistriereAktion('mdt', 'verlauf', 'akte.lesen', function(quelle, mitarbeiter, daten) local patientId = tonumber(daten.patient) if not patientId then return nil, 'Ungültige Kennung.' end local eintraege = {} --- Hängt einen Eintrag an die Zeitleiste local function Anfuegen(art, zeitpunkt, titel, text, ziel, zielId, marker) if not zeitpunkt then return end eintraege[#eintraege + 1] = { art = art, am = zeitpunkt, titel = titel, text = text, ziel = ziel, zielId = zielId, marker = marker, } end -- --- Aufnahmen und Entlassungen --- local aufnahmen = MySQL.query.await([[ SELECT id, grund, station, status, aufgenommen_am, aufgenommen_von, entlassen_am, entlassen_von, entlass_grund FROM medical_aufnahme WHERE patient = ? ORDER BY id DESC LIMIT 40 ]], { patientId }) or {} for _, eintrag in ipairs(aufnahmen) do Anfuegen('aufnahme', eintrag.aufgenommen_am, 'Aufnahme', eintrag.grund, 'aufnahme', eintrag.id, 'aufgenommen von ' .. NameVon(eintrag.aufgenommen_von)) if eintrag.entlassen_am then Anfuegen('entlassung', eintrag.entlassen_am, 'Entlassung', eintrag.entlass_grund, 'aufnahme', eintrag.id, 'entlassen von ' .. NameVon(eintrag.entlassen_von)) end end -- --- Behandlungen --- local behandlungen = MySQL.query.await([[ SELECT id, kennung, diagnose, massnahmen, status, erstellt_am, erstellt_von FROM medical_behandlung WHERE patient = ? ORDER BY id DESC LIMIT 40 ]], { patientId }) or {} for _, eintrag in ipairs(behandlungen) do Anfuegen('behandlung', eintrag.erstellt_am, 'Behandlung ' .. eintrag.kennung, eintrag.diagnose or eintrag.massnahmen or 'Noch keine Diagnose eingetragen', 'behandlung', eintrag.id, (eintrag.status == 'laufend' and 'läuft · ' or '') .. NameVon(eintrag.erstellt_von)) end -- --- Operationen --- local operationen = MySQL.query.await([[ SELECT id, kennung, art, status, geplant_fuer, beginn, ende, erstellt_von FROM medical_operation WHERE patient = ? ORDER BY id DESC LIMIT 20 ]], { patientId }) or {} for _, eintrag in ipairs(operationen) do Anfuegen('operation', eintrag.beginn or eintrag.geplant_fuer, 'Operation ' .. eintrag.kennung, eintrag.art, 'operation', eintrag.id, eintrag.status .. ' · ' .. NameVon(eintrag.erstellt_von)) end -- --- Laboraufträge --- local labor = MySQL.query.await([[ SELECT id, kennung, art, status, fragestellung, auftrag_am, auftrag_von, befund FROM medical_labor WHERE patient = ? ORDER BY id DESC LIMIT 30 ]], { patientId }) or {} for _, eintrag in ipairs(labor) do Anfuegen('labor', eintrag.auftrag_am, 'Labor ' .. eintrag.kennung .. ' · ' .. eintrag.art, eintrag.befund or eintrag.fragestellung or 'Ohne Fragestellung', 'labor', eintrag.id, eintrag.status .. ' · ' .. NameVon(eintrag.auftrag_von)) end -- --- Verabreichte Medikamente --- local gaben = MySQL.query.await([[ SELECT g.id, g.dosierung, g.menge, g.gegeben_am, g.gegeben_von, g.hinweis, m.name, m.einheit FROM medical_behandlung_medikament g JOIN medical_behandlung b ON b.id = g.behandlung JOIN medical_medikament m ON m.id = g.medikament WHERE b.patient = ? ORDER BY g.id DESC LIMIT 40 ]], { patientId }) or {} for _, eintrag in ipairs(gaben) do Anfuegen('medikament', eintrag.gegeben_am, 'Medikamentengabe: ' .. eintrag.name, ('%s %s%s'):format(eintrag.menge, eintrag.einheit, eintrag.dosierung and (' · ' .. eintrag.dosierung) or ''), nil, nil, 'gegeben von ' .. NameVon(eintrag.gegeben_von)) end -- --- Vermerke --- local notizen = MySQL.query.await([[ SELECT id, text, von, am FROM medical_patient_notiz WHERE patient = ? ORDER BY id DESC LIMIT 30 ]], { patientId }) or {} for _, eintrag in ipairs(notizen) do Anfuegen('notiz', eintrag.am, 'Vermerk', eintrag.text, nil, nil, NameVon(eintrag.von)) end -- Jüngstes zuerst table.sort(eintraege, function(a, b) return tostring(a.am) > tostring(b.am) end) -- Nur die letzten 60 Einträge übertragen local gekuerzt = {} for i = 1, math.min(#eintraege, 60) do gekuerzt[i] = eintraege[i] end return { eintraege = gekuerzt, gesamt = #eintraege } end) -- ===================================================================== -- STAMMDATEN PFLEGEN -- -- Alles hier trägt ein Mediziner von Hand ein. Die Blutgruppe ist -- bewusst ein Freitextfeld aus einer Liste — sie wird NICHT aus einem -- Laborergebnis übernommen, denn das wäre eine Feststellung, die -- jemand verantworten muss. -- ===================================================================== Kern.RegistriereAktion('mdt', 'stammdaten', 'patient.stammdaten', function(quelle, mitarbeiter, daten) local patientId = tonumber(daten.patient) if not patientId then return nil, 'Ungültige Kennung.' end local vorhanden = MySQL.scalar.await( 'SELECT id FROM aether_characters WHERE id = ? AND deleted = 0', { patientId }) if not vorhanden then return nil, 'Diese Person ist nicht erfasst.' end -- Blutgruppe nur aus der bekannten Liste local blutgruppe = nil if daten.blutgruppe and daten.blutgruppe ~= '' then for _, gruppe in ipairs(Medizin.Config.Blutgruppen) do if gruppe == daten.blutgruppe then blutgruppe = gruppe break end end if not blutgruppe then return nil, 'Unbekannte Blutgruppe.' end end local organspender = ORGANSTATUS[daten.organspender] and daten.organspender or 'unbekannt' -- Alten Stand für das Protokoll festhalten local alt = MySQL.query.await( 'SELECT blutgruppe, allergien, hinweis FROM medical_patient WHERE `character` = ?', { patientId }) alt = alt and alt[1] or {} MySQL.query.await([[ INSERT INTO medical_patient (`character`, blutgruppe, allergien, vorerkrankungen, dauermedikation, implantate, organspender, notfallkontakt, lichtbild, aktualisiert_von, aktualisiert_am) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW()) ON DUPLICATE KEY UPDATE blutgruppe = VALUES(blutgruppe), allergien = VALUES(allergien), vorerkrankungen = VALUES(vorerkrankungen), dauermedikation = VALUES(dauermedikation), implantate = VALUES(implantate), organspender = VALUES(organspender), notfallkontakt = VALUES(notfallkontakt), lichtbild = VALUES(lichtbild), aktualisiert_von = VALUES(aktualisiert_von), aktualisiert_am = NOW() ]], { patientId, blutgruppe, Text(daten.allergien, 512), Text(daten.vorerkrankungen, 1000), Text(daten.dauermedikation, 1000), Text(daten.implantate, 512), organspender, Text(daten.notfallkontakt, 160), Text(daten.lichtbild, 512), mitarbeiter.charakterId, }) Protokoll.Schreibe(mitarbeiter, 'mdt', 'Stammdaten gepflegt', { typ = 'patient', id = patientId }, { blutgruppeAlt = alt.blutgruppe, blutgruppeNeu = blutgruppe }) Kern.Loese('patient.stammdaten', patientId, mitarbeiter) return { ok = true } end) --- Warnhinweis setzen oder entfernen — immer mit Begründung Kern.RegistriereAktion('mdt', 'hinweisSetzen', 'patient.hinweis', function(quelle, mitarbeiter, daten) local patientId = tonumber(daten.patient) if not patientId then return nil, 'Ungültige Kennung.' end local hinweis = Text(daten.hinweis, 512) local grund = Text(daten.grund, 255) if hinweis and not grund then return nil, 'Bitte begründen, warum der Warnhinweis gesetzt wird.' end MySQL.query.await([[ INSERT INTO medical_patient (`character`, hinweis, aktualisiert_von, aktualisiert_am) VALUES (?, ?, ?, NOW()) ON DUPLICATE KEY UPDATE hinweis = VALUES(hinweis), aktualisiert_von = VALUES(aktualisiert_von), aktualisiert_am = NOW() ]], { patientId, hinweis, mitarbeiter.charakterId }) Protokoll.Schreibe(mitarbeiter, 'mdt', hinweis and 'Warnhinweis gesetzt' or 'Warnhinweis entfernt', { typ = 'patient', id = patientId }, { hinweis = hinweis }, grund) return { ok = true } end) -- ===================================================================== -- VERMERKE -- ===================================================================== Kern.RegistriereAktion('mdt', 'notizen', 'akte.lesen', function(quelle, mitarbeiter, daten) local patientId = tonumber(daten.patient) if not patientId then return nil, 'Ungültige Kennung.' end local notizen = MySQL.query.await([[ SELECT n.id, n.text, n.am, n.von, c.firstname, c.lastname, p.personalnummer FROM medical_patient_notiz n LEFT JOIN aether_characters c ON c.id = n.von LEFT JOIN medical_personal p ON p.`character` = n.von WHERE n.patient = ? ORDER BY n.id DESC LIMIT 60 ]], { patientId }) or {} for _, eintrag in ipairs(notizen) do eintrag.autor = (eintrag.firstname or 'Unbekannt') .. ' ' .. (eintrag.lastname or '') eintrag.firstname, eintrag.lastname = nil, nil eintrag.eigene = eintrag.von == mitarbeiter.charakterId end return { notizen = notizen } end) Kern.RegistriereAktion('mdt', 'notizAnlegen', 'akte.lesen', function(quelle, mitarbeiter, daten) local patientId = tonumber(daten.patient) local text = Text(daten.text, 1000) if not patientId then return nil, 'Ungültige Kennung.' end if not text or #text < 3 then return nil, 'Der Vermerk ist zu kurz.' end local id = MySQL.insert.await( 'INSERT INTO medical_patient_notiz (patient, text, von) VALUES (?, ?, ?)', { patientId, text, mitarbeiter.charakterId }) Protokoll.Schreibe(mitarbeiter, 'mdt', 'Vermerk angelegt', { typ = 'patient', id = patientId }) return { id = id } end) -- ===================================================================== -- AKTEN -- -- Jede Änderung erzeugt eine neue Version. Nichts wird überschrieben, -- die Historie bleibt vollständig einsehbar. -- ===================================================================== Kern.RegistriereAktion('mdt', 'akten', 'akte.lesen', function(quelle, mitarbeiter, daten) local patientId = tonumber(daten.patient) if not patientId then return nil, 'Ungültige Kennung.' end local akten = MySQL.query.await([[ SELECT a.id, a.aktenzeichen, a.typ, a.titel, a.status, a.version, a.erstellt_am, a.erstellt_von, a.freigabe_am, c.firstname, c.lastname FROM medical_akte a LEFT JOIN aether_characters c ON c.id = a.erstellt_von WHERE a.patient = ? ORDER BY a.id DESC LIMIT 60 ]], { patientId }) or {} local artNamen = {} for _, eintrag in ipairs(Medizin.Config.Aktenarten) do artNamen[eintrag.id] = eintrag.name end for _, akte in ipairs(akten) do akte.typName = artNamen[akte.typ] or akte.typ akte.autor = (akte.firstname or 'Unbekannt') .. ' ' .. (akte.lastname or '') akte.firstname, akte.lastname = nil, nil end return { akten = akten, aktenarten = Medizin.Config.Aktenarten } end) Kern.RegistriereAktion('mdt', 'akteOeffnen', 'akte.lesen', function(quelle, mitarbeiter, daten) local akteId = tonumber(daten.id) if not akteId then return nil, 'Ungültige Kennung.' end local zeilen = MySQL.query.await([[ SELECT a.*, c.firstname, c.lastname FROM medical_akte a LEFT JOIN aether_characters c ON c.id = a.erstellt_von WHERE a.id = ? ]], { akteId }) if not zeilen or not zeilen[1] then return nil, 'Akte nicht gefunden.' end local akte = zeilen[1] -- Vollständige Versionshistorie local versionen = MySQL.query.await([[ SELECT v.version, v.geaendert_am, v.geaendert_von, v.kommentar, c.firstname, c.lastname FROM medical_akte_version v LEFT JOIN aether_characters c ON c.id = v.geaendert_von WHERE v.akte = ? ORDER BY v.version DESC ]], { akteId }) or {} for _, version in ipairs(versionen) do version.autor = (version.firstname or 'Unbekannt') .. ' ' .. (version.lastname or '') version.firstname, version.lastname = nil, nil end return { akte = { id = akte.id, aktenzeichen = akte.aktenzeichen, patient = akte.patient, typ = akte.typ, titel = akte.titel, status = akte.status, inhalt = akte.inhalt, version = akte.version, erstelltAm = akte.erstellt_am, autor = (akte.firstname or 'Unbekannt') .. ' ' .. (akte.lastname or ''), freigabeAm = akte.freigabe_am, freigabeVon = akte.freigabe_von and NameVon(akte.freigabe_von) or nil, }, versionen = versionen, aktenarten = Medizin.Config.Aktenarten, rechte = { bearbeiten = Rechte.Hat(mitarbeiter, 'akte.bearbeiten'), freigeben = Rechte.Hat(mitarbeiter, 'akte.freigeben'), schliessen = Rechte.Hat(mitarbeiter, 'akte.schliessen'), }, } end) --- Liefert den Inhalt einer bestimmten Version Kern.RegistriereAktion('mdt', 'akteVersion', 'akte.lesen', function(quelle, mitarbeiter, daten) local akteId = tonumber(daten.id) local version = tonumber(daten.version) if not akteId or not version then return nil, 'Ungültige Kennung.' end local zeilen = MySQL.query.await([[ SELECT v.version, v.inhalt, v.geaendert_am, v.geaendert_von, v.kommentar FROM medical_akte_version v WHERE v.akte = ? AND v.version = ? ]], { akteId, version }) if not zeilen or not zeilen[1] then return nil, 'Diese Version gibt es nicht.' end local eintrag = zeilen[1] eintrag.autor = NameVon(eintrag.geaendert_von) eintrag.geaendert_von = nil return eintrag end) Kern.RegistriereAktion('mdt', 'akteAnlegen', 'akte.erstellen', function(quelle, mitarbeiter, daten) local patientId = tonumber(daten.patient) local titel = Text(daten.titel, 160) if not patientId then return nil, 'Kein Patient gewählt.' end if not titel or #titel < 3 then return nil, 'Bitte einen Titel angeben.' end -- Aktenart prüfen local typ = nil for _, eintrag in ipairs(Medizin.Config.Aktenarten) do if eintrag.id == daten.typ then typ = eintrag.id break end end if not typ then return nil, 'Unbekannte Aktenart.' end local inhalt = type(daten.inhalt) == 'string' and daten.inhalt:sub(1, 20000) or nil local aktenzeichen = Kern.ErzeugeKennung('AKT', 'medical_akte', 'aktenzeichen') local id = MySQL.insert.await([[ INSERT INTO medical_akte (aktenzeichen, patient, typ, titel, status, inhalt, erstellt_von, version) VALUES (?, ?, ?, ?, 'entwurf', ?, ?, 1) ]], { aktenzeichen, patientId, typ, titel, inhalt, mitarbeiter.charakterId }) -- Erste Version festhalten MySQL.insert.await([[ INSERT INTO medical_akte_version (akte, version, inhalt, geaendert_von, kommentar) VALUES (?, 1, ?, ?, 'Anlage') ]], { id, inhalt, mitarbeiter.charakterId }) Protokoll.Schreibe(mitarbeiter, 'mdt', 'Akte angelegt', { typ = 'akte', id = id }, { aktenzeichen = aktenzeichen, patient = patientId }) Kern.Loese('akte.angelegt', id, mitarbeiter) return { id = id, aktenzeichen = aktenzeichen } end) Kern.RegistriereAktion('mdt', 'akteSpeichern', 'akte.bearbeiten', function(quelle, mitarbeiter, daten) local akteId = tonumber(daten.id) if not akteId then return nil, 'Ungültige Kennung.' end local zeilen = MySQL.query.await( 'SELECT id, aktenzeichen, status, version FROM medical_akte WHERE id = ?', { akteId }) if not zeilen or not zeilen[1] then return nil, 'Akte nicht gefunden.' end local akte = zeilen[1] if akte.status == 'geschlossen' then return nil, 'Eine geschlossene Akte lässt sich nicht mehr ändern.' end local titel = Text(daten.titel, 160) if not titel or #titel < 3 then return nil, 'Bitte einen Titel angeben.' end local inhalt = type(daten.inhalt) == 'string' and daten.inhalt:sub(1, 20000) or nil local kommentar = Text(daten.kommentar, 255) if not kommentar then return nil, 'Bitte kurz angeben, was geändert wurde.' end local neueVersion = akte.version + 1 MySQL.update.await([[ UPDATE medical_akte SET titel = ?, inhalt = ?, version = ? WHERE id = ? ]], { titel, inhalt, neueVersion, akteId }) -- Neue Version anhängen — die alte bleibt unangetastet MySQL.insert.await([[ INSERT INTO medical_akte_version (akte, version, inhalt, geaendert_von, kommentar) VALUES (?, ?, ?, ?, ?) ]], { akteId, neueVersion, inhalt, mitarbeiter.charakterId, kommentar }) Protokoll.Schreibe(mitarbeiter, 'mdt', 'Akte bearbeitet', { typ = 'akte', id = akteId }, { aktenzeichen = akte.aktenzeichen, version = neueVersion }, kommentar) return { version = neueVersion } end) Kern.RegistriereAktion('mdt', 'akteStatus', nil, function(quelle, mitarbeiter, daten) local akteId = tonumber(daten.id) local status = tostring(daten.status or '') if not akteId then return nil, 'Ungültige Kennung.' end -- Welches Recht der Statuswechsel verlangt local benoetigt = { offen = 'akte.bearbeiten', freigegeben = 'akte.freigeben', geschlossen = 'akte.schliessen', } if not benoetigt[status] then return nil, 'Unbekannter Status.' end if not Rechte.Hat(mitarbeiter, benoetigt[status]) then return nil, 'Dir fehlt die Berechtigung für diesen Schritt.' end local zeilen = MySQL.query.await( 'SELECT id, aktenzeichen, status FROM medical_akte WHERE id = ?', { akteId }) if not zeilen or not zeilen[1] then return nil, 'Akte nicht gefunden.' end if zeilen[1].status == 'geschlossen' then return nil, 'Diese Akte ist bereits geschlossen.' end local grund = Text(daten.grund, 255) if status == 'freigegeben' then MySQL.update.await([[ UPDATE medical_akte SET status = ?, freigabe_von = ?, freigabe_am = NOW() WHERE id = ? ]], { status, mitarbeiter.charakterId, akteId }) else MySQL.update.await('UPDATE medical_akte SET status = ? WHERE id = ?', { status, akteId }) end Protokoll.Schreibe(mitarbeiter, 'mdt', 'Aktenstatus geändert', { typ = 'akte', id = akteId }, { aktenzeichen = zeilen[1].aktenzeichen, von = zeilen[1].status, nach = status }, grund) Kern.Loese('akte.status', akteId, status, mitarbeiter) return { ok = true } end) -- --------------------------------------------------------------------- -- Schnittstelle für andere Module -- --------------------------------------------------------------------- --- Liefert die Stammdaten eines Patienten, so wie sie eingetragen sind. --- Ausdrücklich ohne Bewertung: was hier steht, hat ein Mediziner --- eingetragen, und was fehlt, ist schlicht nicht erhoben. --- @param patientId number Charakter --- @return table|nil exports('HolePatientenStammdaten', function(patientId) if not tonumber(patientId) then return nil end local zeilen = MySQL.query.await([[ SELECT blutgruppe, allergien, vorerkrankungen, dauermedikation, implantate, organspender, notfallkontakt, hinweis FROM medical_patient WHERE `character` = ? ]], { tonumber(patientId) }) return zeilen and zeilen[1] or nil end)