-- ===================================================================== -- aether-medical / Modul: Behandlungsverwaltung -- -- Das System speichert AUSSCHLIESSLICH die Dokumentation. -- -- Es heilt nicht, es diagnostiziert nicht, es schlägt keine Diagnose -- vor und es leitet aus Symptomen nichts ab. Jedes Feld ist ein -- Freitext, den ein Mediziner schreibt. -- -- Auch die Medikamentengabe wird hier nur DOKUMENTIERT. Das System -- verabreicht nichts und verordnet nichts — es bucht den Bestand -- nach, weil ein Mensch etwas entnommen hat. -- ===================================================================== Kern.RegistriereModul({ id = 'behandlung', name = 'Behandlungen', icon = '📋', reihenfolge = 5, recht = 'behandlung.dokumentieren', beschreibung = 'Untersuchung, Diagnose, Maßnahmen und Medikamentengaben', }) -- --------------------------------------------------------------------- -- Grundbestand an Medikamenten -- -- Wird einmalig angelegt, damit sich eine Gabe überhaupt dokumentieren -- lässt. Die Pflege übernimmt später die Medikamentenverwaltung. -- Die Standarddosierung ist ein VORSCHLAG und nichts weiter. -- --------------------------------------------------------------------- local GRUNDMEDIKAMENTE = { -- kennung, name, wirkstoff, kategorie, dosierung, einheit, bestand, mindest, btm { 'ANA-01', 'Novalgin', 'Metamizol', 'analgetika', '1 g i.v.', 'Ampulle', 40, 10, 0 }, { 'ANA-02', 'Morphin 10 mg', 'Morphin', 'analgetika', '2–10 mg i.v.', 'Ampulle', 12, 4, 1 }, { 'ANA-03', 'Ibuprofen 600', 'Ibuprofen', 'analgetika', '600 mg p.o.', 'Tablette', 90, 20, 0 }, { 'ANT-01', 'Amoxicillin', 'Amoxicillin', 'antibiotika', '1 g p.o.', 'Tablette', 50, 15, 0 }, { 'ANT-02', 'Cefuroxim', 'Cefuroxim', 'antibiotika', '1,5 g i.v.', 'Ampulle', 20, 6, 0 }, { 'KRE-01', 'Adrenalin 1 mg', 'Epinephrin', 'kreislauf', '1 mg i.v.', 'Ampulle', 25, 8, 0 }, { 'KRE-02', 'Amiodaron', 'Amiodaron', 'kreislauf', '300 mg i.v.', 'Ampulle', 10, 3, 0 }, { 'KRE-03', 'Acetylsalicylsäure', 'ASS', 'kreislauf', '250 mg i.v.', 'Ampulle', 18, 6, 0 }, { 'NAR-01', 'Propofol', 'Propofol', 'narkose', 'nach Wirkung', 'Ampulle', 15, 5, 1 }, { 'NAR-02', 'Midazolam', 'Midazolam', 'narkose', '2–5 mg i.v.', 'Ampulle', 14, 5, 1 }, { 'NAR-03', 'Ketamin', 'Esketamin', 'narkose', 'nach Wirkung', 'Ampulle', 10, 4, 1 }, { 'INF-01', 'Ringer-Lactat', '—', 'infusion', '500–1000 ml', 'Beutel', 60, 20, 0 }, { 'INF-02', 'NaCl 0,9 %', 'Kochsalz', 'infusion', '500 ml', 'Beutel', 80, 25, 0 }, { 'VER-01', 'Kompressen steril', '—', 'verband', '—', 'Packung', 120, 30, 0 }, { 'VER-02', 'Verbandpäckchen', '—', 'verband', '—', 'Stück', 100, 25, 0 }, { 'VER-03', 'Druckverband', '—', 'verband', '—', 'Stück', 40, 12, 0 }, { 'SON-01', 'Sauerstoff', 'O₂', 'sonstiges', '2–15 l/min', 'Flasche', 16, 5, 0 }, } CreateThread(function() Wait(2000) local vorhanden = tonumber(MySQL.scalar.await('SELECT COUNT(*) FROM medical_medikament')) or 0 if vorhanden > 0 then return end for reihenfolge, eintrag in ipairs(GRUNDMEDIKAMENTE) do MySQL.insert.await([[ INSERT INTO medical_medikament (kennung, name, wirkstoff, kategorie, dosierung_standard, einheit, bestand, mindestbestand, betaeubungsmittel, lagerort, sortierung) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ]], { eintrag[1], eintrag[2], eintrag[3], eintrag[4], eintrag[5], eintrag[6], eintrag[7], eintrag[8], eintrag[9], eintrag[9] == 1 and 'BTM-Schrank' or 'Apotheke', reihenfolge, }) end Aether.Debug('Grundbestand an Medikamenten angelegt.') end) -- --------------------------------------------------------------------- -- Hilfsfunktionen -- --------------------------------------------------------------------- --- Begrenzt einen Text und liefert nil bei leerer Eingabe 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 --- Name eines Mitarbeiters für die Anzeige 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 end -- ===================================================================== -- ÜBERSICHT -- ===================================================================== Kern.RegistriereAktion('behandlung', 'uebersicht', nil, function(quelle, mitarbeiter, daten) local ordner = tostring(daten.ordner or 'laufend') local bedingungen, werte = {}, {} if ordner == 'meine' then bedingungen[#bedingungen + 1] = 'b.erstellt_von = ?' werte[#werte + 1] = mitarbeiter.charakterId elseif ordner == 'abgeschlossen' then bedingungen[#bedingungen + 1] = "b.status = 'abgeschlossen'" else bedingungen[#bedingungen + 1] = "b.status = 'laufend'" end if type(daten.begriff) == 'string' and #daten.begriff >= 2 then bedingungen[#bedingungen + 1] = '(b.kennung LIKE ? OR b.diagnose LIKE ? OR c.firstname LIKE ? OR c.lastname LIKE ?)' local muster = '%' .. daten.begriff .. '%' for _ = 1, 4 do werte[#werte + 1] = muster end end local liste = MySQL.query.await(([[ SELECT b.id, b.kennung, b.patient, b.aufnahme, b.einsatz, b.diagnose, b.massnahmen, b.status, b.erstellt_am, b.erstellt_von, b.abgeschlossen_am, TIMESTAMPDIFF(MINUTE, b.erstellt_am, NOW()) AS offenSeit, c.firstname, c.lastname, c.dob, m.allergien, m.hinweis, e.nummer AS einsatzNummer, (SELECT COUNT(*) FROM medical_behandlung_medikament g WHERE g.behandlung = b.id) AS gaben FROM medical_behandlung b JOIN aether_characters c ON c.id = b.patient LEFT JOIN medical_patient m ON m.`character` = b.patient LEFT JOIN medical_einsatz e ON e.id = b.einsatz WHERE %s ORDER BY b.id DESC LIMIT 120 ]]):format(table.concat(bedingungen, ' AND ')), werte) or {} for _, eintrag in ipairs(liste) do eintrag.patientName = eintrag.firstname .. ' ' .. eintrag.lastname eintrag.geburt = tostring(eintrag.dob):sub(1, 10) eintrag.autor = NameVon(eintrag.erstellt_von) eintrag.eigene = eintrag.erstellt_von == mitarbeiter.charakterId eintrag.gaben = tonumber(eintrag.gaben) or 0 eintrag.firstname, eintrag.lastname, eintrag.dob = nil, nil, nil eintrag.erstellt_von = nil end return { ordner = ordner, liste = liste, zaehler = { laufend = tonumber(MySQL.scalar.await( "SELECT COUNT(*) FROM medical_behandlung WHERE status = 'laufend'")) or 0, meine = tonumber(MySQL.scalar.await([[ SELECT COUNT(*) FROM medical_behandlung WHERE status = 'laufend' AND erstellt_von = ? ]], { mitarbeiter.charakterId })) or 0, heute = tonumber(MySQL.scalar.await([[ SELECT COUNT(*) FROM medical_behandlung WHERE status = 'abgeschlossen' AND DATE(abgeschlossen_am) = CURDATE() ]])) or 0, }, rechte = { dokumentieren = Rechte.Hat(mitarbeiter, 'behandlung.dokumentieren'), diagnose = Rechte.Hat(mitarbeiter, 'behandlung.diagnose'), abschliessen = Rechte.Hat(mitarbeiter, 'behandlung.abschliessen'), medikament = Rechte.Hat(mitarbeiter, 'medikament.ausgeben'), btm = Rechte.Hat(mitarbeiter, 'medikament.btm'), }, } end) Kern.RegistriereAktion('behandlung', 'oeffnen', nil, function(quelle, mitarbeiter, daten) local behandlungId = tonumber(daten.id) if not behandlungId then return nil, 'Ungültige Kennung.' end local zeilen = MySQL.query.await([[ SELECT b.*, c.firstname, c.lastname, c.dob, m.blutgruppe, m.allergien, m.vorerkrankungen, m.dauermedikation, m.hinweis, m.lichtbild, e.nummer AS einsatzNummer, e.titel AS einsatzTitel, a.grund AS aufnahmeGrund, a.status AS aufnahmeStatus FROM medical_behandlung b JOIN aether_characters c ON c.id = b.patient LEFT JOIN medical_patient m ON m.`character` = b.patient LEFT JOIN medical_einsatz e ON e.id = b.einsatz LEFT JOIN medical_aufnahme a ON a.id = b.aufnahme WHERE b.id = ? ]], { behandlungId }) if not zeilen or not zeilen[1] then return nil, 'Behandlung nicht gefunden.' end local b = zeilen[1] -- Dokumentierte Medikamentengaben local gaben = MySQL.query.await([[ SELECT g.id, g.dosierung, g.menge, g.gegeben_am, g.gegeben_von, g.hinweis, m.id AS medikamentId, m.name, m.wirkstoff, m.einheit, m.betaeubungsmittel FROM medical_behandlung_medikament g JOIN medical_medikament m ON m.id = g.medikament WHERE g.behandlung = ? ORDER BY g.id DESC ]], { behandlungId }) or {} for _, gabe in ipairs(gaben) do gabe.autor = NameVon(gabe.gegeben_von) gabe.eigene = gabe.gegeben_von == mitarbeiter.charakterId gabe.btm = gabe.betaeubungsmittel == 1 gabe.betaeubungsmittel, gabe.gegeben_von = nil, nil end -- Operationen zu diesem Patienten, damit die Doku vollständig wird local operationen = MySQL.query.await([[ SELECT id, kennung, art, status, beginn, ende FROM medical_operation WHERE patient = ? ORDER BY id DESC LIMIT 10 ]], { b.patient }) or {} -- Laborergebnisse zu diesem Patienten local labor = MySQL.query.await([[ SELECT id, kennung, art, status, ergebnis, befund, auftrag_am FROM medical_labor WHERE patient = ? ORDER BY id DESC LIMIT 10 ]], { b.patient }) or {} return { behandlung = { id = b.id, kennung = b.kennung, patient = b.patient, patientName = b.firstname .. ' ' .. b.lastname, geburt = tostring(b.dob):sub(1, 10), aufnahme = b.aufnahme, aufnahmeGrund = b.aufnahmeGrund, aufnahmeStatus = b.aufnahmeStatus, einsatz = b.einsatz, einsatzNummer = b.einsatzNummer, einsatzTitel = b.einsatzTitel, symptome = b.symptome, untersuchung = b.untersuchung, diagnose = b.diagnose, massnahmen = b.massnahmen, empfehlung = b.empfehlung, nachsorge = b.nachsorge, status = b.status, erstelltAm = b.erstellt_am, erstelltVon = NameVon(b.erstellt_von), istMeine = b.erstellt_von == mitarbeiter.charakterId, abgeschlossenAm = b.abgeschlossen_am, abgeschlossenVon = b.abgeschlossen_von and NameVon(b.abgeschlossen_von) or nil, }, stamm = { blutgruppe = b.blutgruppe, allergien = b.allergien, vorerkrankungen = b.vorerkrankungen, dauermedikation = b.dauermedikation, hinweis = b.hinweis, lichtbild = b.lichtbild, }, gaben = gaben, operationen = operationen, labor = labor, rechte = { dokumentieren = Rechte.Hat(mitarbeiter, 'behandlung.dokumentieren'), diagnose = Rechte.Hat(mitarbeiter, 'behandlung.diagnose'), abschliessen = Rechte.Hat(mitarbeiter, 'behandlung.abschliessen'), medikament = Rechte.Hat(mitarbeiter, 'medikament.ausgeben'), btm = Rechte.Hat(mitarbeiter, 'medikament.btm'), bestand = Rechte.Hat(mitarbeiter, 'medikament.bestand'), }, } end) -- ===================================================================== -- ANLEGEN -- ===================================================================== --- Patientensuche mit laufender Aufnahme, damit die Doku andocken kann Kern.RegistriereAktion('behandlung', 'patientSuche', 'behandlung.dokumentieren', function(quelle, mitarbeiter, daten) local begriff = type(daten.begriff) == 'string' and daten.begriff or '' if #begriff < 2 then return { treffer = {} } end local muster = '%' .. begriff .. '%' local treffer = MySQL.query.await([[ SELECT c.id, c.firstname, c.lastname, c.dob, m.blutgruppe, m.allergien, m.hinweis, (SELECT a.id FROM medical_aufnahme a WHERE a.patient = c.id AND a.status IN ('wartend', 'aufgenommen') ORDER BY a.id DESC LIMIT 1) AS aufnahme, (SELECT a.grund FROM medical_aufnahme a WHERE a.patient = c.id AND a.status IN ('wartend', 'aufgenommen') ORDER BY a.id DESC LIMIT 1) AS aufnahmeGrund FROM aether_characters c LEFT JOIN medical_patient m ON m.`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 ?) ORDER BY c.lastname, c.firstname LIMIT 20 ]], { muster, muster, muster, muster }) or {} for _, eintrag in ipairs(treffer) do eintrag.dob = tostring(eintrag.dob):sub(1, 10) end -- Laufende Einsätze, an denen der Mitarbeiter beteiligt ist local einsaetze = MySQL.query.await([[ SELECT e.id, e.nummer, e.titel FROM medical_einsatz e JOIN medical_einsatz_kraft k ON k.einsatz = e.id AND k.bis IS NULL WHERE k.`character` = ? AND e.status <> 'abgeschlossen' ORDER BY e.id DESC LIMIT 10 ]], { mitarbeiter.charakterId }) or {} return { treffer = treffer, einsaetze = einsaetze } end) Kern.RegistriereAktion('behandlung', 'anlegen', 'behandlung.dokumentieren', function(quelle, mitarbeiter, daten) local patientId = tonumber(daten.patient) if not patientId then return nil, 'Kein Patient gewählt.' end local person = MySQL.query.await( 'SELECT firstname, lastname FROM aether_characters WHERE id = ? AND deleted = 0', { patientId }) if not person or not person[1] then return nil, 'Diese Person ist nicht erfasst.' end -- Aufnahme und Einsatz sind freiwillig, müssen aber existieren local aufnahmeId = tonumber(daten.aufnahme) if aufnahmeId then local gueltig = MySQL.scalar.await( 'SELECT id FROM medical_aufnahme WHERE id = ? AND patient = ?', { aufnahmeId, patientId }) if not gueltig then return nil, 'Diese Aufnahme gehört nicht zu dem Patienten.' end end local einsatzId = tonumber(daten.einsatz) if einsatzId then local gueltig = MySQL.scalar.await( 'SELECT id FROM medical_einsatz WHERE id = ?', { einsatzId }) if not gueltig then return nil, 'Unbekannter Einsatz.' end end local kennung = Kern.ErzeugeKennung('BEH', 'medical_behandlung', 'kennung') local id = MySQL.insert.await([[ INSERT INTO medical_behandlung (kennung, patient, aufnahme, einsatz, symptome, untersuchung, status, erstellt_von) VALUES (?, ?, ?, ?, ?, ?, 'laufend', ?) ]], { kennung, patientId, aufnahmeId, einsatzId, Text(daten.symptome, 4000), Text(daten.untersuchung, 4000), mitarbeiter.charakterId, }) Protokoll.Schreibe(mitarbeiter, 'behandlung', 'Behandlung angelegt', { typ = 'behandlung', id = id }, { kennung = kennung, patient = patientId, aufnahme = aufnahmeId, einsatz = einsatzId }) Kern.Loese('behandlung.angelegt', id, mitarbeiter) return { id = id, kennung = kennung } end) -- ===================================================================== -- DOKUMENTIEREN -- -- Die Diagnose ist ein eigenes Recht. Wer sie nicht hat, kann alles -- andere schreiben — das Feld bleibt dann unverändert. -- ===================================================================== Kern.RegistriereAktion('behandlung', 'speichern', 'behandlung.dokumentieren', function(quelle, mitarbeiter, daten) local behandlungId = tonumber(daten.id) if not behandlungId then return nil, 'Ungültige Kennung.' end local zeilen = MySQL.query.await( 'SELECT id, kennung, status, diagnose FROM medical_behandlung WHERE id = ?', { behandlungId }) if not zeilen or not zeilen[1] then return nil, 'Behandlung nicht gefunden.' end local behandlung = zeilen[1] if behandlung.status == 'abgeschlossen' then return nil, 'Eine abgeschlossene Behandlung lässt sich nicht mehr ändern.' end -- Diagnose nur mit dem passenden Recht local darfDiagnose = Rechte.Hat(mitarbeiter, 'behandlung.diagnose') local neueDiagnose = darfDiagnose and Text(daten.diagnose, 4000) or behandlung.diagnose if not darfDiagnose and Text(daten.diagnose, 4000) ~= nil and Text(daten.diagnose, 4000) ~= behandlung.diagnose then return nil, 'Eine Diagnose darfst du nicht eintragen.' end MySQL.update.await([[ UPDATE medical_behandlung SET symptome = ?, untersuchung = ?, diagnose = ?, massnahmen = ?, empfehlung = ?, nachsorge = ? WHERE id = ? ]], { Text(daten.symptome, 4000), Text(daten.untersuchung, 4000), neueDiagnose, Text(daten.massnahmen, 4000), Text(daten.empfehlung, 4000), Text(daten.nachsorge, 4000), behandlungId, }) Protokoll.Schreibe(mitarbeiter, 'behandlung', 'Dokumentation gespeichert', { typ = 'behandlung', id = behandlungId }, { kennung = behandlung.kennung, diagnoseGeaendert = neueDiagnose ~= behandlung.diagnose }) return { ok = true } end) Kern.RegistriereAktion('behandlung', 'abschliessen', 'behandlung.abschliessen', function(quelle, mitarbeiter, daten) local behandlungId = tonumber(daten.id) if not behandlungId then return nil, 'Ungültige Kennung.' end local zeilen = MySQL.query.await([[ SELECT id, kennung, status, diagnose, massnahmen, untersuchung FROM medical_behandlung WHERE id = ? ]], { behandlungId }) if not zeilen or not zeilen[1] then return nil, 'Behandlung nicht gefunden.' end local behandlung = zeilen[1] if behandlung.status == 'abgeschlossen' then return nil, 'Diese Behandlung ist bereits abgeschlossen.' end -- Eine leere Dokumentation abzuschliessen ergibt keinen Sinn. -- Geprüft wird nur, DASS etwas dasteht — nicht, was. local leer = not behandlung.untersuchung and not behandlung.massnahmen and not behandlung.diagnose if leer then return nil, 'Die Dokumentation ist leer. Bitte zuerst etwas eintragen.' end MySQL.update.await([[ UPDATE medical_behandlung SET status = 'abgeschlossen', abgeschlossen_von = ?, abgeschlossen_am = NOW() WHERE id = ? ]], { mitarbeiter.charakterId, behandlungId }) Protokoll.Schreibe(mitarbeiter, 'behandlung', 'Behandlung abgeschlossen', { typ = 'behandlung', id = behandlungId }, { kennung = behandlung.kennung, ohneDiagnose = behandlung.diagnose == nil }, Text(daten.vermerk, 255)) Kern.Loese('behandlung.abgeschlossen', behandlungId, mitarbeiter) return { ok = true, ohneDiagnose = behandlung.diagnose == nil } end) --- Wieder öffnen, falls etwas nachzutragen ist — immer mit Begründung Kern.RegistriereAktion('behandlung', 'wiedereroeffnen', 'behandlung.abschliessen', function(quelle, mitarbeiter, daten) local behandlungId = tonumber(daten.id) if not behandlungId then return nil, 'Ungültige Kennung.' end local grund = Text(daten.grund, 255) if not grund then return nil, 'Bitte begründen, warum die Doku wieder geöffnet wird.' end local zeilen = MySQL.query.await( 'SELECT id, kennung, status FROM medical_behandlung WHERE id = ?', { behandlungId }) if not zeilen or not zeilen[1] then return nil, 'Behandlung nicht gefunden.' end if zeilen[1].status ~= 'abgeschlossen' then return nil, 'Diese Behandlung läuft bereits.' end MySQL.update.await([[ UPDATE medical_behandlung SET status = 'laufend', abgeschlossen_von = NULL, abgeschlossen_am = NULL WHERE id = ? ]], { behandlungId }) Protokoll.Schreibe(mitarbeiter, 'behandlung', 'Behandlung wieder geöffnet', { typ = 'behandlung', id = behandlungId }, { kennung = zeilen[1].kennung }, grund) return { ok = true } end) -- ===================================================================== -- MEDIKAMENTENGABE -- -- Dokumentation einer Gabe, die ein Mediziner vorgenommen hat. -- Das System gibt nichts aus und verordnet nichts. -- ===================================================================== --- Auswahlliste der Medikamente Kern.RegistriereAktion('behandlung', 'medikamente', 'medikament.ausgeben', function(quelle, mitarbeiter, daten) local medikamente = MySQL.query.await([[ SELECT id, kennung, name, wirkstoff, kategorie, dosierung_standard, einheit, bestand, mindestbestand, betaeubungsmittel, hinweis, lagerort, verfaellt_am, DATEDIFF(verfaellt_am, CURDATE()) AS tageBisVerfall FROM medical_medikament WHERE aktiv = 1 ORDER BY kategorie, sortierung, name ]]) or {} local darfBtm = Rechte.Hat(mitarbeiter, 'medikament.btm') for _, eintrag in ipairs(medikamente) do eintrag.btm = eintrag.betaeubungsmittel == 1 -- Betäubungsmittel bleiben sichtbar, sind aber ohne Recht nicht wählbar eintrag.waehlbar = not eintrag.btm or darfBtm -- Abgelaufene Praeparate werden markiert, aber nicht gesperrt: -- ob sie verwendbar sind, beurteilt ein Mensch. local tage = tonumber(eintrag.tageBisVerfall) eintrag.abgelaufen = tage ~= nil and tage < 0 eintrag.betaeubungsmittel = nil end return { medikamente = medikamente, kategorien = Medizin.Config.Medikamentkategorien, darfBtm = darfBtm, } end) Kern.RegistriereAktion('behandlung', 'medikamentGeben', 'medikament.ausgeben', function(quelle, mitarbeiter, daten) local behandlungId = tonumber(daten.id) local medikamentId = tonumber(daten.medikament) local menge = math.floor(tonumber(daten.menge) or 0) if not behandlungId or not medikamentId then return nil, 'Unvollständige Angaben.' end if menge < 1 or menge > 999 then return nil, 'Ungültige Menge.' end local behandlung = MySQL.query.await( 'SELECT id, kennung, patient, status FROM medical_behandlung WHERE id = ?', { behandlungId }) if not behandlung or not behandlung[1] then return nil, 'Behandlung nicht gefunden.' end if behandlung[1].status == 'abgeschlossen' then return nil, 'Die Behandlung ist abgeschlossen. Bitte zuerst wieder öffnen.' end local zeilen = MySQL.query.await([[ SELECT id, kennung, name, einheit, bestand, mindestbestand, betaeubungsmittel FROM medical_medikament WHERE id = ? AND aktiv = 1 ]], { medikamentId }) if not zeilen or not zeilen[1] then return nil, 'Unbekanntes Medikament.' end local medikament = zeilen[1] -- Betäubungsmittel erfordern ein eigenes Recht if medikament.betaeubungsmittel == 1 and not Rechte.Hat(mitarbeiter, 'medikament.btm') then return nil, 'Betäubungsmittel darfst du nicht dokumentieren.' end -- Reicht der Bestand? Falls nicht, wird die Gabe trotzdem dokumentiert, -- aber nur auf ausdrücklichen Wunsch und ohne Bestandsbuchung. -- Eine Dokumentation darf nie an einer Lagerzahl scheitern. local ohneBestand = daten.ohneBestand == true if medikament.bestand < menge and not ohneBestand then return nil, ('Im Bestand sind nur %d %s. Du kannst die Gabe trotzdem dokumentieren — dann ohne Bestandsbuchung.') :format(medikament.bestand, medikament.einheit) end local gabeId = MySQL.insert.await([[ INSERT INTO medical_behandlung_medikament (behandlung, medikament, dosierung, menge, gegeben_von, hinweis) VALUES (?, ?, ?, ?, ?, ?) ]], { behandlungId, medikamentId, Text(daten.dosierung, 64), menge, mitarbeiter.charakterId, ohneBestand and ((Text(daten.hinweis, 200) or '') .. ' [ohne Bestandsbuchung]') or Text(daten.hinweis, 255), }) -- Bestand nachführen, weil jemand etwas entnommen hat if not ohneBestand then local neuerBestand = medikament.bestand - menge MySQL.update.await('UPDATE medical_medikament SET bestand = ? WHERE id = ?', { neuerBestand, medikamentId }) MySQL.insert.await([[ INSERT INTO medical_medikament_buchung (medikament, art, menge, bestand_danach, patient, grund, gebucht_von) VALUES (?, 'ausgabe', ?, ?, ?, ?, ?) ]], { medikamentId, menge, neuerBestand, behandlung[1].patient, 'Gabe zu ' .. behandlung[1].kennung, mitarbeiter.charakterId, }) -- Mindestbestand erreicht? Erinnern, nicht nachbestellen. if neuerBestand <= medikament.mindestbestand then Hinweise.Erstelle(nil, { kategorie = 'medikament', prioritaet = neuerBestand <= 0 and 'hoch' or 'normal', titel = neuerBestand <= 0 and 'Medikament nicht mehr vorrätig' or 'Medikament fast leer', text = ('%s — noch %d %s.') :format(medikament.name, neuerBestand, medikament.einheit), zielTyp = 'medikament', zielId = medikamentId, }) end end Protokoll.Schreibe(mitarbeiter, 'behandlung', 'Medikamentengabe dokumentiert', { typ = 'behandlung', id = behandlungId }, { medikament = medikament.kennung, menge = menge, btm = medikament.betaeubungsmittel == 1, ohneBestand = ohneBestand }) Kern.Loese('medikament.gegeben', gabeId, medikamentId, mitarbeiter) return { id = gabeId } end) --- Fehleintrag zurücknehmen. Der Bestand wird als Korrektur zurückgebucht. Kern.RegistriereAktion('behandlung', 'medikamentZuruecknehmen', 'medikament.ausgeben', function(quelle, mitarbeiter, daten) local gabeId = tonumber(daten.gabe) if not gabeId then return nil, 'Ungültige Kennung.' end local grund = Text(daten.grund, 255) if not grund then return nil, 'Bitte begründen, warum der Eintrag zurückgenommen wird.' end local zeilen = MySQL.query.await([[ SELECT g.id, g.behandlung, g.medikament, g.menge, g.gegeben_von, g.hinweis, m.name, m.bestand, m.einheit, b.status FROM medical_behandlung_medikament g JOIN medical_medikament m ON m.id = g.medikament JOIN medical_behandlung b ON b.id = g.behandlung WHERE g.id = ? ]], { gabeId }) if not zeilen or not zeilen[1] then return nil, 'Eintrag nicht gefunden.' end local gabe = zeilen[1] if gabe.status == 'abgeschlossen' then return nil, 'Die Behandlung ist abgeschlossen. Bitte zuerst wieder öffnen.' end -- Nur der eigene Eintrag, ausser man verwaltet den Bestand if gabe.gegeben_von ~= mitarbeiter.charakterId and not Rechte.Hat(mitarbeiter, 'medikament.bestand') then return nil, 'Du kannst nur eigene Einträge zurücknehmen.' end MySQL.query.await('DELETE FROM medical_behandlung_medikament WHERE id = ?', { gabeId }) -- Nur zurückbuchen, wenn seinerzeit auch gebucht wurde local wurdeGebucht = not (gabe.hinweis and gabe.hinweis:find('ohne Bestandsbuchung', 1, true)) if wurdeGebucht then local neuerBestand = gabe.bestand + gabe.menge MySQL.update.await('UPDATE medical_medikament SET bestand = ? WHERE id = ?', { neuerBestand, gabe.medikament }) MySQL.insert.await([[ INSERT INTO medical_medikament_buchung (medikament, art, menge, bestand_danach, grund, gebucht_von) VALUES (?, 'korrektur', ?, ?, ?, ?) ]], { gabe.medikament, gabe.menge, neuerBestand, 'Rücknahme: ' .. grund, mitarbeiter.charakterId }) end Protokoll.Schreibe(mitarbeiter, 'behandlung', 'Medikamentengabe zurückgenommen', { typ = 'behandlung', id = gabe.behandlung }, { medikament = gabe.name, menge = gabe.menge, zurueckgebucht = wurdeGebucht }, grund) return { ok = true } end) -- --------------------------------------------------------------------- -- Schnittstelle für andere Ressourcen -- --------------------------------------------------------------------- --- Zählt offene Dokumentationen eines Mitarbeiters --- @param charakterId number Charakter --- @return number exports('OffeneDokumentationen', function(charakterId) if not tonumber(charakterId) then return 0 end return tonumber(MySQL.scalar.await([[ SELECT COUNT(*) FROM medical_behandlung WHERE status = 'laufend' AND erstellt_von = ? ]], { tonumber(charakterId) })) or 0 end)