summaryrefslogtreecommitdiff
path: root/src/main/java/dev/dnpm/analyzer
diff options
context:
space:
mode:
authorPaul-Christian Volkmer2024-09-21 22:10:24 +0200
committerPaul-Christian Volkmer2024-09-21 22:10:24 +0200
commitcc27edc544cec1b892e7c224aec9e6e42342aa39 (patch)
tree3036b92f84a707d769782d63c2b018166623abf5 /src/main/java/dev/dnpm/analyzer
parent93215825f5c8aec0912d562b544f370cffe9cda7 (diff)
refactor: use package name following Java guidelines
Diffstat (limited to 'src/main/java/dev/dnpm/analyzer')
-rw-r--r--src/main/java/dev/dnpm/analyzer/Analyzer.java12
-rw-r--r--src/main/java/dev/dnpm/analyzer/AnalyzerUtils.java145
-rw-r--r--src/main/java/dev/dnpm/analyzer/BackendService.java25
-rw-r--r--src/main/java/dev/dnpm/analyzer/ConsentManager.java63
-rw-r--r--src/main/java/dev/dnpm/analyzer/DNPMHelper.java260
-rw-r--r--src/main/java/dev/dnpm/analyzer/EinzelempfehlungAnalyzer.java134
-rw-r--r--src/main/java/dev/dnpm/analyzer/FollowUpAnalyzer.java103
-rw-r--r--src/main/java/dev/dnpm/analyzer/IPluginPart.java19
-rw-r--r--src/main/java/dev/dnpm/analyzer/Merkmalskatalog.java97
-rw-r--r--src/main/java/dev/dnpm/analyzer/TherapieMitEcogAnalyzer.java168
-rw-r--r--src/main/java/dev/dnpm/analyzer/TherapieplanAnalyzer.java127
11 files changed, 1153 insertions, 0 deletions
diff --git a/src/main/java/dev/dnpm/analyzer/Analyzer.java b/src/main/java/dev/dnpm/analyzer/Analyzer.java
new file mode 100644
index 0000000..7868f32
--- /dev/null
+++ b/src/main/java/dev/dnpm/analyzer/Analyzer.java
@@ -0,0 +1,12 @@
+package dev.dnpm.analyzer;
+
+import de.itc.onkostar.api.analysis.OnkostarPluginType;
+
+public abstract class Analyzer implements IPluginPart {
+
+ @Override
+ public final OnkostarPluginType getType() {
+ return OnkostarPluginType.ANALYZER;
+ }
+
+}
diff --git a/src/main/java/dev/dnpm/analyzer/AnalyzerUtils.java b/src/main/java/dev/dnpm/analyzer/AnalyzerUtils.java
new file mode 100644
index 0000000..937cc74
--- /dev/null
+++ b/src/main/java/dev/dnpm/analyzer/AnalyzerUtils.java
@@ -0,0 +1,145 @@
+package dev.dnpm.analyzer;
+
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Klasse mit Hilfsfunktionen für Analyzer
+ *
+ * @since 0.1.0
+ */
+public class AnalyzerUtils {
+
+ private AnalyzerUtils() {}
+
+ /**
+ * Prüft, ob in InputMap einen Eintrag mit key <code>key</code> und Typ <code>type</code>
+ * gefunden wurde.
+ *
+ * @param input InputMap
+ * @param key Key des Werts
+ * @param type Typ des Werts
+ * @return <code>true</code>>, wenn ein Wert von dem Typ gefunden wurde
+ */
+ public static boolean requiredValuePresent(final Map<String, Object> input, final String key, final Class<?> type) {
+ var value = input.get(key);
+
+ if (null == value) {
+ return false;
+ }
+
+ return type.isInstance(value);
+ }
+
+ /**
+ * Übergibt ein Optional mit Wert, wenn in InputMap ein Eintrag mit key <code>key</code> und Typ <code>type</code>
+ * gefunden wurde. Anderenfalls ein leeres Optional
+ *
+ * <p><b>Beispiel</b>
+ * <pre>
+ * var id = AnalyzerUtils.getRequiredValue(input, "id", Integer.class);
+ * if (id.isEmpty()) {
+ * logger.error("Keine ID angegeben!");
+ * return false;
+ * }
+ *
+ * var idNummer = id.get();
+ * ...
+ * </pre>
+ *
+ * @param input InputMap
+ * @param key Key des Werts
+ * @param type Typ des Werts
+ * @return Optional mit entsprechendem Wert oder leeres Optional
+ */
+ public static <T> Optional<T> getRequiredValue(final Map<String, Object> input, final String key, final Class<T> type) {
+ if (! requiredValuePresent(input, key, type)) {
+ return Optional.empty();
+ }
+
+ @SuppressWarnings("unchecked")
+ var result = Optional.of((T)input.get(key));
+
+ return result;
+ }
+
+ /**
+ * Prüft, ob ein Wert in der InputMap als Zeichenkette dem angegebenen RegExp entspricht
+ *
+ * @param input InputMap
+ * @param key Key des Werts
+ * @param regexp Der zu prüfende reguläre Ausdruck
+ * @return <code>true</code>>, wenn ein Wert gefunden wurde, der dem RegExp entspricht
+ */
+ public static boolean requiredValueMatches(final Map<String, Object> input, final String key, final String regexp) {
+ var value = input.get(key);
+
+ if (null == value) {
+ return false;
+ }
+
+ return value.toString().matches(regexp);
+ }
+
+ /**
+ * Übergibt ein Optional mit dem Wert als Zeichenkette, wenn er dem angegebenen RegExp entspricht.
+ * Hierzu wird die Methode <code>toString()</code> auf den Wert angewendet.
+ *
+ * @param input InputMap
+ * @param key Key des Werts
+ * @param regexp Der zu prüfende reguläre Ausdruck
+ * @return Optional mit entsprechendem Wert als Zeichenkette oder leeres Optional
+ */
+ public static Optional<String> getRequiredValueMatching(final Map<String, Object> input, final String key, final String regexp) {
+ if (! requiredValueMatches(input, key, regexp)) {
+ return Optional.empty();
+ }
+
+ return Optional.of(input.get(key).toString());
+ }
+
+ /**
+ * Prüft, ob ein Wert in der InputMap eine ID ist und damit eine Zahl größer Null ist.
+ *
+ * @param input InputMap
+ * @param key Key des Werts
+ * @return <code>true</code>>, wenn ein Wert gefunden wurde, der dem RegExp entspricht
+ */
+ public static boolean requiredValueIsId(final Map<String, Object> input, final String key) {
+ return requiredValuePresent(input, key, Integer.class) && Integer.parseInt(input.get(key).toString()) > 0;
+ }
+
+ /**
+ * Übergibt ein Optional, wenn der Wert eine ID ist und damit eine Zahl größer Null ist.
+ * <p><b>Beispiel</b>
+ * <pre>
+ * var id = AnalyzerUtils.getRequiredId(input, "id");
+ * if (id.isEmpty()) {
+ * logger.error("Keine gültige ID angegeben!");
+ * return false;
+ * }
+ *
+ * // Ist hier immer größer als Null
+ * var idNummer = id.get();
+ * ...
+ * </pre>
+ *
+ * @param input InputMap
+ * @param key Key des Werts
+ * @return Optional mit entsprechendem Wert oder leeres Optional
+ */
+ public static Optional<Integer> getRequiredId(final Map<String, Object> input, final String key) {
+ if (! requiredValuePresent(input, key, Integer.class)) {
+ return Optional.empty();
+ }
+
+ var id = (int)input.get(key);
+
+ if (id > 0) {
+ return Optional.of(id);
+ }
+
+ return Optional.empty();
+ }
+
+}
diff --git a/src/main/java/dev/dnpm/analyzer/BackendService.java b/src/main/java/dev/dnpm/analyzer/BackendService.java
new file mode 100644
index 0000000..c5fca5c
--- /dev/null
+++ b/src/main/java/dev/dnpm/analyzer/BackendService.java
@@ -0,0 +1,25 @@
+package dev.dnpm.analyzer;
+
+import de.itc.onkostar.api.Disease;
+import de.itc.onkostar.api.Procedure;
+import de.itc.onkostar.api.analysis.OnkostarPluginType;
+
+public abstract class BackendService implements IPluginPart {
+
+ @Override
+ public final OnkostarPluginType getType() {
+ return OnkostarPluginType.BACKEND_SERVICE;
+ }
+
+ /**
+ * Ein Backend-Service verwendet die Methode nicht, daher wird hier eine final Stub-Implementierung
+ * verwendet, die ein Überschreiben verhindert.
+ * @param procedure
+ * @param disease
+ */
+ @Override
+ public final void analyze(Procedure procedure, Disease disease) {
+ // No op
+ }
+
+}
diff --git a/src/main/java/dev/dnpm/analyzer/ConsentManager.java b/src/main/java/dev/dnpm/analyzer/ConsentManager.java
new file mode 100644
index 0000000..601399d
--- /dev/null
+++ b/src/main/java/dev/dnpm/analyzer/ConsentManager.java
@@ -0,0 +1,63 @@
+package dev.dnpm.analyzer;
+
+import dev.dnpm.services.consent.ConsentManagerServiceFactory;
+import de.itc.onkostar.api.Disease;
+import de.itc.onkostar.api.IOnkostarApi;
+import de.itc.onkostar.api.Procedure;
+import de.itc.onkostar.api.analysis.AnalyzerRequirement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConsentManager extends Analyzer {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private final IOnkostarApi onkostarApi;
+
+ private final ConsentManagerServiceFactory consentManagerServiceFactory;
+
+ public ConsentManager(
+ final IOnkostarApi onkostarApi,
+ final ConsentManagerServiceFactory consentManagerServiceFactory
+ ) {
+ this.onkostarApi = onkostarApi;
+ this.consentManagerServiceFactory = consentManagerServiceFactory;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Aktualisiert Consent Daten in verknüpften Formularen";
+ }
+
+ @Override
+ public AnalyzerRequirement getRequirement() {
+ return AnalyzerRequirement.PROCEDURE;
+ }
+
+ @Override
+ public boolean isRelevantForAnalyzer(Procedure prozedur, Disease erkrankung) {
+ return prozedur.getFormName().equals(onkostarApi.getGlobalSetting("consentform"));
+ }
+
+ @Override
+ public boolean isRelevantForDeletedProcedure() {
+ // TODO is relevant for deleted procedure = true
+ return false;
+ }
+
+ @Override
+ public boolean isSynchronous() {
+ return true;
+ }
+
+ @Override
+ public void analyze(Procedure prozedur, Disease erkrankung) {
+ var consentManagerService = consentManagerServiceFactory.currentUsableInstance();
+ if (! consentManagerService.canApply(prozedur)) {
+ logger.error("Fehler im ConsentManagement: Kann Prozedur mit Formularnamen '{}' nicht anwenden", prozedur.getFormName());
+ return;
+ }
+ consentManagerService.applyConsent(prozedur);
+ }
+
+}
diff --git a/src/main/java/dev/dnpm/analyzer/DNPMHelper.java b/src/main/java/dev/dnpm/analyzer/DNPMHelper.java
new file mode 100644
index 0000000..211b3bd
--- /dev/null
+++ b/src/main/java/dev/dnpm/analyzer/DNPMHelper.java
@@ -0,0 +1,260 @@
+package dev.dnpm.analyzer;
+
+import dev.dnpm.dto.EcogStatusWithDate;
+import dev.dnpm.VerweisVon;
+import dev.dnpm.security.DelegatingDataBasedPermissionEvaluator;
+import dev.dnpm.security.IllegalSecuredObjectAccessException;
+import dev.dnpm.security.PermissionType;
+import dev.dnpm.services.systemtherapie.SystemtherapieService;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.itc.onkostar.api.Disease;
+import de.itc.onkostar.api.IOnkostarApi;
+import de.itc.onkostar.api.Procedure;
+import de.itc.onkostar.api.analysis.AnalyzerRequirement;
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.transform.Transformers;
+import org.hibernate.type.StandardBasicTypes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class DNPMHelper extends BackendService {
+
+ private static final Logger logger = LoggerFactory.getLogger(DNPMHelper.class);
+
+ private final IOnkostarApi onkostarApi;
+
+ private final SystemtherapieService systemtherapieService;
+
+ private final DelegatingDataBasedPermissionEvaluator delegatingDataBasedPermissionEvaluator;
+
+ public DNPMHelper(
+ final IOnkostarApi onkostarApi,
+ final SystemtherapieService systemtherapieService,
+ final DelegatingDataBasedPermissionEvaluator permissionEvaluator
+ ) {
+ this.onkostarApi = onkostarApi;
+ this.systemtherapieService = systemtherapieService;
+ this.delegatingDataBasedPermissionEvaluator = permissionEvaluator;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Methoden für DNPM-Formulare";
+ }
+
+ @Override
+ public boolean isRelevantForDeletedProcedure() {
+ return false;
+ }
+
+ @Override
+ public boolean isSynchronous() {
+ return true;
+ }
+
+ @Override
+ public AnalyzerRequirement getRequirement() {
+ return AnalyzerRequirement.PROCEDURE;
+ }
+
+ @Override
+ public boolean isRelevantForAnalyzer(Procedure entry, Disease currentDisease) {
+ // Plugin enthält nur Methoden für Formulare und soll nicht ausgeführt werden
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<Map<String, String>> getVerweise(final Map<String, Object> input) {
+ var procedureId = AnalyzerUtils.getRequiredId(input, "ProcedureId");
+ var patientId = AnalyzerUtils.getRequiredId(input, "PatientId");
+
+ if (procedureId.isEmpty() || patientId.isEmpty()) {
+ return null;
+ }
+
+ var verbundeneFormulare = new ArrayList<Map<String, String>>();
+
+ try {
+ SessionFactory sessionFactory = onkostarApi.getSessionFactory();
+ Session session = sessionFactory.getCurrentSession();
+
+ String sql = "SELECT prozedur.id AS procedure_id, prozedur.data_form_id, data_catalogue.name AS data_catalogue, data_catalogue_entry.name AS data_catalogue_entry, data_form.description AS formname, prozedur.beginndatum AS datum " +
+ "FROM prozedur " +
+ "LEFT JOIN data_form_data_catalogue ON data_form_data_catalogue.data_form_id = prozedur.data_form_id " +
+ "LEFT JOIN data_catalogue_entry ON data_catalogue_entry.data_catalogue_id = data_form_data_catalogue.data_catalogue_id " +
+ "LEFT JOIN data_catalogue ON data_catalogue.id = data_catalogue_entry.data_catalogue_id " +
+ "LEFT JOIN data_form ON data_form.id = prozedur.data_form_id " +
+ "WHERE patient_id = " + patientId.get() + " " +
+ "AND geloescht = 0 " +
+ "AND data_catalogue_entry.type = 'formReference' " +
+ "GROUP BY prozedur.id, prozedur.data_form_id, data_catalogue.name, data_catalogue_entry.name";
+
+ SQLQuery query = session.createSQLQuery(sql)
+ .addScalar("procedure_id", StandardBasicTypes.INTEGER)
+ .addScalar("data_form_id", StandardBasicTypes.INTEGER)
+ .addScalar("data_catalogue", StandardBasicTypes.STRING)
+ .addScalar("data_catalogue_entry", StandardBasicTypes.STRING)
+ .addScalar("formname", StandardBasicTypes.STRING)
+ .addScalar("datum", StandardBasicTypes.DATE);
+
+ query.setResultTransformer(Transformers.aliasToBean(VerweisVon.class));
+ List<VerweisVon> result = query.list();
+ try {
+ int value = 0;
+ for (VerweisVon verweisVon : result) {
+ sql = verweisVon.getSQL();
+ query = session.createSQLQuery(sql)
+ .addScalar("value", StandardBasicTypes.INTEGER);
+ if (query.uniqueResult() != null) {
+ value = (Integer) query.uniqueResult();
+ }
+ if (value == procedureId.get()) {
+ verbundeneFormulare.add(Map.of("formular", verweisVon.getVerbundenesFormular()));
+ value = 0;
+ }
+ }
+ } catch (Exception e) {
+ logger.warn("Fehler beim Hinzufügen eines Formularverweises", e);
+ }
+ } catch (Exception e) {
+ logger.error("Fehler beim Ermitteln der Formularverweise", e);
+ return null;
+ }
+ return verbundeneFormulare;
+ }
+
+ public List<Map<String, String>> getSystemischeTherapienFromDiagnose(final Map<String, Object> input) {
+ var diagnoseId = AnalyzerUtils.getRequiredId(input, "DiagnoseId");
+ if (diagnoseId.isEmpty()) {
+ logger.error("Kein Parameter 'DiagnoseId' angegeben, gebe 'null' zurück");
+ return null;
+ }
+
+ return systemtherapieService.getSystemischeTherapienFromDiagnose(diagnoseId.get());
+ }
+
+ public String getProzedurenFromDiagnose(final Map<String, Object> input) {
+ // Prozedur, Feldname, Wert
+ var dataForm = AnalyzerUtils.getRequiredValue(input, "dataForm", String.class);
+ var diagnoseId = AnalyzerUtils.getRequiredId(input, "DiagnoseId");
+ var patientId = AnalyzerUtils.getRequiredId(input, "PatientId");
+
+ if (dataForm.isEmpty() || diagnoseId.isEmpty() || patientId.isEmpty()) {
+ return "";
+ }
+
+ var formulare = new ArrayList<Map<String, Object>>();
+ List<Procedure> prozeduren = onkostarApi.getProceduresByPatientId(patientId.get());
+ for (Procedure Prozedur : prozeduren) {
+ // Formular gehört zur aktuellen Diagnose und hat den angegebenen Namen
+ if (Prozedur.getDiseaseIds().contains(diagnoseId.get()) && Prozedur.getFormName().contains(dataForm.get())) {
+ // alle Werte auslesen
+ // System.out.println(WerteListe.getKey() + ": " + WerteListe.getValue());
+ formulare.add(Map.of(
+ "Formular", Prozedur.getFormName(),
+ "Felder", new HashMap<>(Prozedur.getAllValues())
+ ));
+ }
+ }
+ try {
+ ObjectMapper objectMapper = new ObjectMapper();
+ return objectMapper.writeValueAsString(formulare);
+ } catch (JsonProcessingException e) {
+ logger.error("Kann Formulare nicht in JSON mappen", e);
+ }
+ return "";
+ }
+
+ public Object getEmpfehlung(final Map<String, Object> input) {
+ var procedureID = AnalyzerUtils.getRequiredId(input, "ProcedureID");
+
+ if (procedureID.isEmpty()) {
+ logger.error("Kein Parameter 'ProcedureID' angegeben, gebe 'null' zurück");
+ return null;
+ }
+
+ try {
+ SessionFactory sessionFactory = onkostarApi.getSessionFactory();
+ Session session = sessionFactory.getCurrentSession();
+ var sql = "SELECT prozedur.id, genname, geneid, geneidlink, empfehlung, beginndatum FROM prozedur "
+ + "LEFT JOIN dk_mtb_einzelempfehlung em ON em.id = prozedur.id "
+ + "JOIN data_form df ON prozedur.data_form_id = df.id AND df.name = 'MR.MTB_Einzelempfehlung' "
+ + "WHERE prozedur.hauptprozedur_id = " + procedureID.get() + " AND prozedur.geloescht = 0 "
+ + "ORDER BY beginndatum";
+
+ SQLQuery query = session.createSQLQuery(sql)
+ .addScalar("id", StandardBasicTypes.STRING)
+ .addScalar("genname", StandardBasicTypes.STRING)
+ .addScalar("geneid", StandardBasicTypes.STRING)
+ .addScalar("geneidlink", StandardBasicTypes.STRING)
+ .addScalar("empfehlung", StandardBasicTypes.STRING)
+ .addScalar("beginndatum", StandardBasicTypes.STRING);
+
+ @SuppressWarnings("unchecked")
+ List<String[]> rows = query.list();
+ return rows;
+ } catch (Exception e) {
+ logger.error("Fehler bei Abfrage von Empfehlungen", e);
+ return null;
+ }
+ }
+
+ public Object updateEmpfehlungPrio(final Map<String, Object> input) {
+ // Auslesen und Prüfen der Parameter aus 'input'
+ var rid = AnalyzerUtils.getRequiredId(input, "rid");
+ if (rid.isEmpty()) {
+ logger.error("Kein Parameter 'rid' angegeben, gebe 'false' zurück");
+ return false;
+ }
+
+ var strDate = AnalyzerUtils.getRequiredValueMatching(input, "bd", "[\\d]{4}-[\\d]{2}-[\\d]{2}");
+ if (strDate.isEmpty()) {
+ logger.error("Kein oder ungültiger Parameter 'bd' angegeben, gebe 'false' zurück");
+ return false;
+ }
+
+ //String strD = strDate.toString();
+ //String CompareDate = strD.substring(1, 11);
+ //DateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd");
+
+ try {
+ String sql = "UPDATE prozedur SET beginndatum = '" + strDate.get() + "' WHERE id = '" + rid.get() + "' ";
+ SQLQuery result = onkostarApi.getSessionFactory().getCurrentSession().createSQLQuery(sql);
+ result.executeUpdate();
+ return true;
+ } catch (Exception e) {
+ return "Achtung: Ein Fehler ist aufgetreten, Änderung konnte nicht gespeichert werden!";
+ //return null;
+ }
+
+ }
+
+ public List<EcogStatusWithDate> getEcogStatus(final Map<String, Object> input) {
+ var pid = AnalyzerUtils.getRequiredId(input, "PatientId");
+ if (pid.isEmpty()) {
+ logger.error("Kein Parameter 'PatientId' angegeben, gebe leere Liste zurück");
+ return List.of();
+ }
+
+ var patient = onkostarApi.getPatient(pid.get());
+ if (null == patient) {
+ logger.error("Patient nicht gefunden, gebe leere Liste zurück");
+ return List.of();
+ }
+
+ if (delegatingDataBasedPermissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(), patient, PermissionType.READ)) {
+ return systemtherapieService.ecogStatus(patient);
+ }
+
+ throw new IllegalSecuredObjectAccessException("Kein Zugriff auf diesen Patienten");
+ }
+} \ No newline at end of file
diff --git a/src/main/java/dev/dnpm/analyzer/EinzelempfehlungAnalyzer.java b/src/main/java/dev/dnpm/analyzer/EinzelempfehlungAnalyzer.java
new file mode 100644
index 0000000..4a6bfdf
--- /dev/null
+++ b/src/main/java/dev/dnpm/analyzer/EinzelempfehlungAnalyzer.java
@@ -0,0 +1,134 @@
+package dev.dnpm.analyzer;
+
+import dev.dnpm.dto.Studie;
+import dev.dnpm.dto.Variant;
+import dev.dnpm.security.PermissionType;
+import dev.dnpm.security.PersonPoolBasedPermissionEvaluator;
+import dev.dnpm.services.StudienService;
+import dev.dnpm.services.molekulargenetik.MolekulargenetikFormService;
+import de.itc.onkostar.api.Disease;
+import de.itc.onkostar.api.IOnkostarApi;
+import de.itc.onkostar.api.Procedure;
+import de.itc.onkostar.api.analysis.AnalyzerRequirement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Diese Klasse implementiert ein Plugin, welches Funktionen für DNPM UF Einzelempfehlung bereitstellt.
+ *
+ * @since 0.2.0
+ */
+@Component
+public class EinzelempfehlungAnalyzer extends BackendService {
+
+ private final static Logger logger = LoggerFactory.getLogger(EinzelempfehlungAnalyzer.class);
+
+ private final IOnkostarApi onkostarApi;
+
+ private final MolekulargenetikFormService molekulargenetikFormService;
+
+ private final StudienService studienService;
+
+ private final PersonPoolBasedPermissionEvaluator permissionEvaluator;
+
+ public EinzelempfehlungAnalyzer(
+ final IOnkostarApi onkostarApi,
+ final StudienService studienService,
+ final MolekulargenetikFormService molekulargenetikFormService,
+ final PersonPoolBasedPermissionEvaluator permissionEvaluator
+ ) {
+ this.onkostarApi = onkostarApi;
+ this.studienService = studienService;
+ this.molekulargenetikFormService = molekulargenetikFormService;
+ this.permissionEvaluator = permissionEvaluator;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Stellt Funktionen zur Nutzung im Therapieplan-Unterformular für Einzelempfehlungen bereit";
+ }
+
+ /**
+ * @deprecated
+ */
+ @Override
+ public boolean isRelevantForDeletedProcedure() {
+ return false;
+ }
+
+ @Override
+ public boolean isRelevantForAnalyzer(Procedure procedure, Disease disease) {
+ return false;
+ }
+
+ @Override
+ public boolean isSynchronous() {
+ return false;
+ }
+
+ @Override
+ public AnalyzerRequirement getRequirement() {
+ return AnalyzerRequirement.PROCEDURE;
+ }
+
+ public List<Variant> getVariants(Map<String, Object> input) {
+ var procedureId = AnalyzerUtils.getRequiredId(input, "id");
+
+ if (procedureId.isEmpty()) {
+ return List.of();
+ }
+
+ var procedure = onkostarApi.getProcedure(procedureId.get());
+ if (null == procedure) {
+ return List.of();
+ }
+
+ if (permissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(), procedure, PermissionType.READ)) {
+ return molekulargenetikFormService.getVariants(procedure);
+ } else {
+ logger.error("Security: No permission to access procedure '{}'", procedure.getId());
+ return List.of();
+ }
+ }
+
+ /**
+ * Übergibt alle Studien, deren (Kurz-)Beschreibung oder NCT-Nummer den übergebenen Eingabewert <code>q</code> enthält
+ *
+ * <p>Wurde der Eingabewert nicht angegeben oder ist leer, werden alle Studien übergeben.
+ *
+ * <p>Beispiel zur Nutzung in einem Formularscript
+ * <pre>
+ * executePluginMethod(
+ * 'TherapieplanAnalyzer',
+ * 'getStudien',
+ * { q: 'NCT-12', inactive: true },
+ * (response) => console.log(response),
+ * false
+ * );
+ * </pre>
+ *
+ * @param input Map mit Eingabewerten
+ * @return Liste mit Studien
+ */
+ public List<Studie> getStudien(Map<String, Object> input) {
+ var query = AnalyzerUtils.getRequiredValue(input, "q", String.class);
+ var inactive = AnalyzerUtils.getRequiredValue(input, "inactive", Boolean.class).orElse(false);
+
+ if (query.isEmpty() || query.get().isBlank()) {
+ if (inactive) {
+ return studienService.findAll();
+ }
+ return studienService.findActive();
+ }
+ if (inactive) {
+ return studienService.findByQuery(query.get());
+ }
+ return studienService.findActiveByQuery(query.get());
+ }
+
+}
diff --git a/src/main/java/dev/dnpm/analyzer/FollowUpAnalyzer.java b/src/main/java/dev/dnpm/analyzer/FollowUpAnalyzer.java
new file mode 100644
index 0000000..1e1bbb9
--- /dev/null
+++ b/src/main/java/dev/dnpm/analyzer/FollowUpAnalyzer.java
@@ -0,0 +1,103 @@
+package dev.dnpm.analyzer;
+
+import de.itc.onkostar.api.Disease;
+import de.itc.onkostar.api.IOnkostarApi;
+import de.itc.onkostar.api.Item;
+import de.itc.onkostar.api.Procedure;
+import de.itc.onkostar.api.analysis.AnalyseTriggerEvent;
+import de.itc.onkostar.api.analysis.AnalyzerRequirement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.Set;
+
+/**
+ * Diese Klasse implementiert ein Plugin, welches Aktionen nach Bearbeitung eines FollowUps durchführt.
+ *
+ * @since 0.0.2
+ */
+@Component
+public class FollowUpAnalyzer extends Analyzer {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private final IOnkostarApi onkostarApi;
+
+ public FollowUpAnalyzer(IOnkostarApi onkostarApi) {
+ this.onkostarApi = onkostarApi;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Aktualisiert verknüpfte Formulare nach Änderungen im FollowUp-Formular";
+ }
+
+ /**
+ * @deprecated
+ */
+ @Override
+ public boolean isRelevantForDeletedProcedure() {
+ return false;
+ }
+
+ @Override
+ public boolean isRelevantForAnalyzer(Procedure procedure, Disease disease) {
+ return null != procedure && procedure.getFormName().equals("DNPM FollowUp");
+ }
+
+ @Override
+ public boolean isSynchronous() {
+ return false;
+ }
+
+ @Override
+ public AnalyzerRequirement getRequirement() {
+ return AnalyzerRequirement.PROCEDURE;
+ }
+
+ @Override
+ public Set<AnalyseTriggerEvent> getTriggerEvents() {
+ return Set.of(
+ AnalyseTriggerEvent.EDIT_SAVE,
+ AnalyseTriggerEvent.EDIT_LOCK,
+ AnalyseTriggerEvent.REORG
+ );
+ }
+
+ @Override
+ public void analyze(Procedure procedure, Disease disease) {
+ backlinkToEinzelempfehlung(procedure);
+ }
+
+ /**
+ * Verlinke aktuelles FollowUp in angegebener Einzelempfehlung
+ *
+ * @param procedure Das FollowUp
+ */
+ private void backlinkToEinzelempfehlung(Procedure procedure) {
+ if (null == procedure.getValue("LinkTherapieempfehlung")) {
+ return;
+ }
+
+ var referencedProcedureId = procedure.getValue("LinkTherapieempfehlung");
+ if (null == referencedProcedureId || referencedProcedureId.getInt() == 0) {
+ // Alles gut, es ist keine Einzelempfehlung angegeben
+ return;
+ }
+
+ var referencedProcedure = onkostarApi.getProcedure(referencedProcedureId.getInt());
+ if (null == referencedProcedure) {
+ logger.error("Referenzierte Einzelempfehlung wurde nicht gefunden: {}", referencedProcedureId);
+ return;
+ }
+
+ referencedProcedure.setValue("refdnpmfollowup", new Item("ref_dnpm_followup", procedure.getId()));
+
+ try {
+ onkostarApi.saveProcedure(referencedProcedure);
+ } catch (Exception e) {
+ logger.error("FollowUp konnte nicht mit Einzelempfehlung verknüpft werden", e);
+ }
+ }
+}
diff --git a/src/main/java/dev/dnpm/analyzer/IPluginPart.java b/src/main/java/dev/dnpm/analyzer/IPluginPart.java
new file mode 100644
index 0000000..23940fa
--- /dev/null
+++ b/src/main/java/dev/dnpm/analyzer/IPluginPart.java
@@ -0,0 +1,19 @@
+package dev.dnpm.analyzer;
+
+import de.itc.onkostar.api.analysis.IProcedureAnalyzer;
+
+public interface IPluginPart extends IProcedureAnalyzer {
+
+ default String getVersion() {
+ return "0.4.0";
+ }
+
+ default String getName() {
+ return "DNPM Plugin";
+ }
+
+ default String getDescription() {
+ return String.format("Plugin-Bestandteil '%s'", this.getClass().getSimpleName());
+ }
+
+}
diff --git a/src/main/java/dev/dnpm/analyzer/Merkmalskatalog.java b/src/main/java/dev/dnpm/analyzer/Merkmalskatalog.java
new file mode 100644
index 0000000..76892f3
--- /dev/null
+++ b/src/main/java/dev/dnpm/analyzer/Merkmalskatalog.java
@@ -0,0 +1,97 @@
+package dev.dnpm.analyzer;
+
+import de.itc.onkostar.api.Disease;
+import de.itc.onkostar.api.IOnkostarApi;
+import de.itc.onkostar.api.Procedure;
+import de.itc.onkostar.api.analysis.AnalyzerRequirement;
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.type.StandardBasicTypes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Map;
+
+public class Merkmalskatalog extends BackendService {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private final IOnkostarApi onkostarApi;
+
+ public Merkmalskatalog(final IOnkostarApi onkostarApi) {
+ this.onkostarApi = onkostarApi;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Methoden für Merkmalskataloge";
+ }
+
+ @Override
+ public boolean isRelevantForDeletedProcedure() {
+ return false;
+ }
+
+ @Override
+ public boolean isSynchronous() {
+ return true;
+ }
+
+ @Override
+ public AnalyzerRequirement getRequirement() {
+ return AnalyzerRequirement.PROCEDURE;
+ }
+
+ @Override
+ public boolean isRelevantForAnalyzer(Procedure procedure, Disease currentDisease) {
+ return false;
+ }
+
+ public List<String[]> getMerkmalskatalog(final Map<String, Object> input) {
+ var merkmalskatalog = AnalyzerUtils.getRequiredValue(input, "Merkmalskatalog", String.class);
+ var spalten = AnalyzerUtils.getRequiredValue(input, "Spalten", String.class);
+
+ if (merkmalskatalog.isEmpty()) {
+ logger.error("Kein Merkmalskatalog angegeben!");
+ return null;
+ }
+
+ if (spalten.isEmpty()) {
+ logger.error("Keine Spalten angegeben!");
+ return null;
+ }
+
+ String[] spaltenArray = spalten.get().split("\\s*,\\s*");
+
+ try {
+ SQLQuery query = getSqlQuery(merkmalskatalog.get());
+
+ for (String s : spaltenArray) {
+ query.addScalar(s, StandardBasicTypes.STRING);
+ }
+
+ @SuppressWarnings("unchecked")
+ List<String[]> rows = query.list();
+ return rows;
+ } catch (Exception e) {
+ logger.error("Fehler bei der Ausführung von getMerkmalskatalog()", e);
+ return null;
+ }
+ }
+
+ private SQLQuery getSqlQuery(String merkmalskatalog) {
+ SessionFactory sessionFactory = onkostarApi.getSessionFactory();
+ Session session = sessionFactory.getCurrentSession();
+
+ String sql = "SELECT p.id, p.code, p.shortdesc, p.description, p.note, p.synonyms "
+ + "FROM property_catalogue "
+ + "LEFT JOIN property_catalogue_version ON property_catalogue_version.datacatalog_id = property_catalogue.id "
+ + "LEFT JOIN property_catalogue_version_entry p ON p.property_version_id = property_catalogue_version.id "
+ + "WHERE name = '" + merkmalskatalog + "' AND aktiv = 1 "
+ + "ORDER BY position ASC";
+
+ return session.createSQLQuery(sql);
+ }
+}
diff --git a/src/main/java/dev/dnpm/analyzer/TherapieMitEcogAnalyzer.java b/src/main/java/dev/dnpm/analyzer/TherapieMitEcogAnalyzer.java
new file mode 100644
index 0000000..8afa7d8
--- /dev/null
+++ b/src/main/java/dev/dnpm/analyzer/TherapieMitEcogAnalyzer.java
@@ -0,0 +1,168 @@
+package dev.dnpm.analyzer;
+
+import dev.dnpm.dto.EcogStatusWithDate;
+import dev.dnpm.services.strahlentherapie.StrahlentherapieService;
+import dev.dnpm.services.systemtherapie.SystemtherapieService;
+import de.itc.onkostar.api.Disease;
+import de.itc.onkostar.api.IOnkostarApi;
+import de.itc.onkostar.api.Item;
+import de.itc.onkostar.api.Procedure;
+import de.itc.onkostar.api.analysis.AnalyseTriggerEvent;
+import de.itc.onkostar.api.analysis.AnalyzerRequirement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.text.SimpleDateFormat;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Diese Klasse implementiert ein Plugin, welches Aktionen nach Bearbeitung eines Formulars zur Systemtherapie durchführt.
+ *
+ * @since 0.6.0
+ */
+@Component
+public class TherapieMitEcogAnalyzer extends Analyzer {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private final IOnkostarApi onkostarApi;
+
+ private final StrahlentherapieService strahlentherapieService;
+ private final SystemtherapieService systemtherapieService;
+
+ public TherapieMitEcogAnalyzer(
+ final IOnkostarApi onkostarApi,
+ final StrahlentherapieService strahlentherapieService,
+ final SystemtherapieService systemtherapieService
+ ) {
+ this.onkostarApi = onkostarApi;
+ this.strahlentherapieService = strahlentherapieService;
+ this.systemtherapieService = systemtherapieService;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Aktualisiert verknüpfte Formulare nach Änderungen in Formularen vom Typ Strahlen-/Systemtherapie mit ECOG-Status";
+ }
+
+ /**
+ * @deprecated
+ */
+ @Override
+ public boolean isRelevantForDeletedProcedure() {
+ return true;
+ }
+
+ @Override
+ public boolean isRelevantForAnalyzer(Procedure procedure, Disease disease) {
+ return null != procedure && null != disease && (
+ procedure.getFormName().equals("OS.Strahlentherapie")
+ || procedure.getFormName().equals("OS.Strahlentherapie.VarianteUKW")
+ || procedure.getFormName().equals("OS.Systemische Therapie")
+ || procedure.getFormName().equals("OS.Systemische Therapie.VarianteUKW")
+ );
+ }
+
+ @Override
+ public boolean isSynchronous() {
+ return false;
+ }
+
+ @Override
+ public AnalyzerRequirement getRequirement() {
+ return AnalyzerRequirement.PROCEDURE;
+ }
+
+ @Override
+ public Set<AnalyseTriggerEvent> getTriggerEvents() {
+ return Set.of(
+ AnalyseTriggerEvent.EDIT_SAVE,
+ AnalyseTriggerEvent.EDIT_LOCK,
+ AnalyseTriggerEvent.REORG
+ );
+ }
+
+ @Override
+ public void analyze(Procedure procedure, Disease disease) {
+ var date = procedure.getStartDate();
+ var status = procedure.getValue("ECOGvorTherapie");
+
+ if (null == date || null == status) {
+ // Ignore
+ return;
+ }
+
+ var ecog = strahlentherapieService.ecogStatus(procedure.getPatient())
+ .stream()
+ .filter(ecogStatusWithDate -> ecogStatusWithDate.getDate().after(disease.getDiagnosisDate()))
+ .collect(Collectors.toList());
+
+ ecog.addAll(systemtherapieService.ecogStatus(procedure.getPatient())
+ .stream()
+ .filter(ecogStatusWithDate -> ecogStatusWithDate.getDate().after(disease.getDiagnosisDate()))
+ .collect(Collectors.toList()));
+
+
+ if (ecog.isEmpty()) {
+ // Nothing to do
+ return;
+ }
+
+ procedure.getPatient().getDiseases().stream()
+ .flatMap(d -> onkostarApi.getProceduresForDiseaseByForm(d.getId(), "DNPM Klinik/Anamnese").stream())
+ .forEach(p -> {
+ var ufEcog = p.getValue("ECOGVerlauf");
+ if (null != ufEcog && ufEcog.getValue() instanceof List) {
+ updateExistingEcogVerlauf(p, ecog, ufEcog);
+ } else {
+ newEcogverlauf(p, ecog);
+ }
+ });
+ }
+
+ private void updateExistingEcogVerlauf(Procedure p, List<EcogStatusWithDate> ecogFromCompleted, Item ufEcog) {
+ var shouldSave = false;
+ var existingDates = ufEcog.<List<Map<String, String>>>getValue().stream()
+ .map(v -> v.get("Datum"))
+ .collect(Collectors.toList());
+ for (var ecog : ecogFromCompleted) {
+ var formattedDate = new SimpleDateFormat("yyyy-MM-dd").format(ecog.getDate());
+ if (!existingDates.contains(formattedDate)) {
+ var newSubProcedure = new Procedure(onkostarApi);
+ newSubProcedure.setStartDate(ecog.getDate());
+ newSubProcedure.setValue("Datum", new Item("Datum", ecog.getDate()));
+ newSubProcedure.setValue("ECOG", new Item("ECOG", ecog.getStatus()));
+ p.addSubProcedure("ECOGVerlauf", newSubProcedure);
+ shouldSave = true;
+ }
+ }
+ if (shouldSave) {
+ try {
+ onkostarApi.saveProcedure(p, true);
+ } catch (Exception e) {
+ logger.error("Cannot update ECOG for procedure '{}'", p.getId());
+ }
+ }
+ }
+
+ private void newEcogverlauf(Procedure p, List<EcogStatusWithDate> ecogFromCompleted) {
+ p.setValue("ECOGVerlauf", new Item("ECOGVerlauf", List.of()));
+ for (var ecog : ecogFromCompleted) {
+ var newSubProcedure = new Procedure(onkostarApi);
+ newSubProcedure.setStartDate(ecog.getDate());
+ newSubProcedure.setValue("Datum", new Item("Datum", ecog.getDate()));
+ newSubProcedure.setValue("ECOG", new Item("ECOG", ecog.getStatus()));
+ p.addSubProcedure("ECOGVerlauf", newSubProcedure);
+ }
+ try {
+ onkostarApi.saveProcedure(p, true);
+ } catch (Exception e) {
+ logger.error("Create update ECOG for procedure '{}'", p.getId());
+ }
+ }
+
+}
diff --git a/src/main/java/dev/dnpm/analyzer/TherapieplanAnalyzer.java b/src/main/java/dev/dnpm/analyzer/TherapieplanAnalyzer.java
new file mode 100644
index 0000000..a623a99
--- /dev/null
+++ b/src/main/java/dev/dnpm/analyzer/TherapieplanAnalyzer.java
@@ -0,0 +1,127 @@
+package dev.dnpm.analyzer;
+
+import dev.dnpm.security.DelegatingDataBasedPermissionEvaluator;
+import dev.dnpm.security.PermissionType;
+import dev.dnpm.services.mtb.MtbService;
+import dev.dnpm.services.therapieplan.TherapieplanServiceFactory;
+import de.itc.onkostar.api.Disease;
+import de.itc.onkostar.api.Procedure;
+import de.itc.onkostar.api.analysis.AnalyseTriggerEvent;
+import de.itc.onkostar.api.analysis.AnalyzerRequirement;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Diese Klasse implementiert ein Plugin, welches Aktionen nach Bearbeitung eines Therapieplans durchführt.
+ *
+ * @since 0.0.2
+ */
+@Component
+public class TherapieplanAnalyzer extends Analyzer {
+
+ private final TherapieplanServiceFactory therapieplanServiceFactory;
+
+ private final MtbService mtbService;
+
+ private final DelegatingDataBasedPermissionEvaluator permissionEvaluator;
+
+ public TherapieplanAnalyzer(
+ final TherapieplanServiceFactory therapieplanServiceFactory,
+ final MtbService mtbService,
+ final DelegatingDataBasedPermissionEvaluator permissionEvaluator
+ ) {
+ this.therapieplanServiceFactory = therapieplanServiceFactory;
+ this.mtbService = mtbService;
+ this.permissionEvaluator = permissionEvaluator;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Aktualisiert Unterformulare nach Änderungen im Therapieplan-Formular";
+ }
+
+ /**
+ * @deprecated
+ */
+ @Override
+ public boolean isRelevantForDeletedProcedure() {
+ return false;
+ }
+
+ @Override
+ public boolean isRelevantForAnalyzer(Procedure procedure, Disease disease) {
+ return null != procedure && procedure.getFormName().equals("DNPM Therapieplan");
+ }
+
+ @Override
+ public boolean isSynchronous() {
+ return false;
+ }
+
+ @Override
+ public AnalyzerRequirement getRequirement() {
+ return AnalyzerRequirement.PROCEDURE;
+ }
+
+ @Override
+ public Set<AnalyseTriggerEvent> getTriggerEvents() {
+ return Set.of(
+ AnalyseTriggerEvent.EDIT_SAVE,
+ AnalyseTriggerEvent.EDIT_LOCK,
+ AnalyseTriggerEvent.REORG
+ );
+ }
+
+ @Override
+ public void analyze(Procedure procedure, Disease disease) {
+ therapieplanServiceFactory.currentUsableInstance().updateRequiredMtbEntries(procedure);
+ }
+
+ /**
+ * Übergibt den Text der referenzierten MTBs für den Protokollauszug
+ *
+ * <p>Wurde der Eingabewert <code>id</code> nicht übergeben, wird ein leerer String zurück gegeben.
+ *
+ * <p>Beispiel zur Nutzung in einem Formularscript
+ * <pre>
+ * executePluginMethod(
+ * 'TherapieplanAnalyzer',
+ * 'getProtokollauszug',
+ * { id: 12345 },
+ * (response) => console.log(response),
+ * false
+ * );
+ * </pre>
+ *
+ * @param input Map mit Eingabewerten
+ * @return Zeichenkette mit Protokollauszug
+ */
+ public String getProtokollauszug(Map<String, Object> input) {
+ var procedureId = AnalyzerUtils.getRequiredId(input, "id");
+
+ if (procedureId.isEmpty()) {
+ return "";
+ }
+
+ if (
+ permissionEvaluator.hasPermission(
+ SecurityContextHolder.getContext().getAuthentication(),
+ procedureId.get(),
+ Procedure.class.getSimpleName(),
+ PermissionType.READ
+ )
+ ) {
+ return mtbService.getProtocol(
+ therapieplanServiceFactory
+ .currentUsableInstance()
+ .findReferencedMtbs(procedureId.get())
+ );
+ }
+
+ return "";
+ }
+
+}