diff --git a/README.md b/README.md
index eae0bcb..7a0c854 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,19 @@
-= Onkostar-Plugin zur Verwendung mit der DNPM-Formularsammlung
+# Onkostar-Plugin zur Verwendung mit der DNPM-Formularsammlung
+
+## Therapieplan
+
+Soll das automatische Befüllen der Unterformulare *Einzelempfehlung* und *Rebiopsie* nicht durchgeführt werden, weil es mehrere MTBs je MTB-Episode gibt, so muss die Einstellung `mehrere_mtb_in_mtbepisode` vorhanden sein und auf den Wert `true` gesetzt sein.
+
+```
+INSERT INTO einstellung (name, wert, kategorie, optionen, beschreibung)
+VALUES (
+ 'mehrere_mtb_in_mtbepisode',
+ 'true',
+ 'Dokumentation',
+ '[{"key": "true", "value": "Ja"},{"key": "false", "value": "Nein"}]',
+ 'Angabe, ob mehrere MTBs je MTB-Episode verwendet werden.'
+);
+```
+
diff --git a/pom.xml b/pom.xml
index 512f699..c5bec8e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,64 +1,64 @@
- 4.0.0
- DNPMHelper
- DNPMHelper
- 0.0.2
- DNPMHelper
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+ DNPMHelper
+ DNPMHelper
+ 0.0.2
+ DNPMHelper
-
- 11
- 11
- 11
- UTF-8
+
+ 11
+ 11
+ 11
+ UTF-8
- 4.3.8.RELEASE
-
+ 4.3.8.RELEASE
+
-
-
-
- de.itc
- onkostar-parent
- 2.11.1.1
- system
- ${project.basedir}/libs/onkostar-api-2.11.1.1.jar
-
+
+
+
+ de.itc
+ onkostar-parent
+ 2.11.1.1
+ system
+ ${project.basedir}/libs/onkostar-api-2.11.1.1.jar
+
-
-
- org.hibernate
- hibernate-core
- 4.3.11.Final
- provided
-
+
+
+ org.hibernate
+ hibernate-core
+ 4.3.11.Final
+ provided
+
-
-
- org.springframework
- spring-jdbc
- ${spring-version}
- provided
-
-
- org.springframework
- spring-webmvc
- ${spring-version}
- provided
-
-
- com.fasterxml.jackson.core
- jackson-databind
- 2.12.2
- provided
-
-
- org.slf4j
- slf4j-api
- 1.7.2
- provided
-
+
+
+ org.springframework
+ spring-jdbc
+ ${spring-version}
+ provided
+
+
+ org.springframework
+ spring-webmvc
+ ${spring-version}
+ provided
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.12.2
+ provided
+
+
+ org.slf4j
+ slf4j-api
+ 1.7.2
+ provided
+
javax.xml.bind
jaxb-api
@@ -77,6 +77,60 @@
2.6
provided
-
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.9.2
+ test
+
+
+ org.assertj
+ assertj-core
+ 3.24.2
+ test
+
+
+ org.mockito
+ mockito-core
+ 4.11.0
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ 4.11.0
+ test
+
+
+ ca.uhn.hapi
+ hapi-base
+ 2.2
+ test
+
+
+ ca.uhn.hapi
+ hapi-structures-v26
+ 2.2
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.22.2
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ 2.22.2
+
+
+
\ No newline at end of file
diff --git a/src/main/java/DNPM/exceptions/FormException.java b/src/main/java/DNPM/exceptions/FormException.java
new file mode 100644
index 0000000..4d0d6dd
--- /dev/null
+++ b/src/main/java/DNPM/exceptions/FormException.java
@@ -0,0 +1,9 @@
+package DNPM.exceptions;
+
+public class FormException extends RuntimeException {
+
+ public FormException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/DNPM/forms/TherapieplanAnalyzer.java b/src/main/java/DNPM/forms/TherapieplanAnalyzer.java
new file mode 100644
index 0000000..9fd53cc
--- /dev/null
+++ b/src/main/java/DNPM/forms/TherapieplanAnalyzer.java
@@ -0,0 +1,180 @@
+package DNPM.forms;
+
+import DNPM.services.FormService;
+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 de.itc.onkostar.api.analysis.IProcedureAnalyzer;
+import de.itc.onkostar.api.analysis.OnkostarPluginType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.Objects;
+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 implements IProcedureAnalyzer {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private final IOnkostarApi onkostarApi;
+
+ private final FormService formService;
+
+ public TherapieplanAnalyzer(final IOnkostarApi onkostarApi, final FormService formService) {
+ this.onkostarApi = onkostarApi;
+ this.formService = formService;
+ }
+
+ @Override
+ public OnkostarPluginType getType() {
+ return OnkostarPluginType.ANALYZER;
+ }
+
+ @Override
+ public String getVersion() {
+ return "0.1.0";
+ }
+
+ @Override
+ public String getName() {
+ return "DNPM Therapieplan Analyzer";
+ }
+
+ @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 getTriggerEvents() {
+ return Set.of(
+ AnalyseTriggerEvent.EDIT_SAVE,
+ AnalyseTriggerEvent.EDIT_LOCK,
+ AnalyseTriggerEvent.REORG
+ );
+ }
+
+ @Override
+ public void analyze(Procedure procedure, Disease disease) {
+ updateMtbInSections(procedure);
+ updateMtbInSubforms(procedure);
+ }
+
+ /**
+ * Verlinke MTB und Übernahme Datum aus Hauptformular in weiteren Bereichen
+ * "Humangenetische Beratung" und "Reevaluation", wenn erforderlich.
+ *
+ * @param procedure Die Prozedur mit Hauptformular
+ */
+ private void updateMtbInSections(Procedure procedure) {
+ if (
+ null != onkostarApi.getGlobalSetting("mehrere_mtb_in_mtbepisode")
+ && onkostarApi.getGlobalSetting("mehrere_mtb_in_mtbepisode").equals("true")
+ ||
+ !procedure.getValue("humangenberatung").getString().equals("1")
+ && !procedure.getValue("reevaluation").getString().equals("1")
+ ) {
+ return;
+ }
+
+ var mtbReference = procedure.getValue("referstemtb").getInt();
+ var mtbDate = procedure.getValue("datum").getDate();
+
+ if (mtbReference != procedure.getValue("reftkhumangenber").getInt() && !mtbDate.equals(procedure.getValue("datumtkhumangenber").getDate())) {
+ procedure.setValue("reftkhumangenber", new Item("ref_tk_humangenber", mtbReference));
+ procedure.setValue("datumtkhumangenber", new Item("datum_tk_humangenber", mtbDate));
+ }
+
+ if (mtbReference != procedure.getValue("reftkreevaluation").getInt() && !mtbDate.equals(procedure.getValue("datumtkreevaluation").getDate())) {
+ procedure.setValue("reftkreevaluation", new Item("ref_tk_reevaluation", mtbReference));
+ procedure.setValue("datumtkreevaluation", new Item("datum_tk_reevaluation", mtbDate));
+ }
+
+ try {
+ onkostarApi.saveProcedure(procedure, false);
+ } catch (Exception e) {
+ logger.error("Formular 'DNPM Therapieplan' konnte nicht aktualisiert werden", e);
+ }
+ }
+
+ /**
+ * Verlinke MTB und Übernahme Datum aus Hauptformular in Unterformularen
+ *
+ * @param procedure Die Prozedur mit Hauptformular
+ */
+ private void updateMtbInSubforms(Procedure procedure) {
+ if (
+ null != onkostarApi.getGlobalSetting("mehrere_mtb_in_mtbepisode")
+ && onkostarApi.getGlobalSetting("mehrere_mtb_in_mtbepisode").equals("true")
+ ) {
+ return;
+ }
+
+ var mtbReference = procedure.getValue("referstemtb").getInt();
+ var mtbDate = procedure.getValue("datum").getDate();
+
+ formService.getSubFormProcedureIds(procedure.getId()).stream()
+ .map(onkostarApi::getProcedure)
+ .filter(Objects::nonNull)
+ .forEach(subform -> {
+ if (subform.getFormName().equals("DNPM UF Einzelempfehlung")) {
+ if (mtbReference != subform.getValue("mtb").getInt() && !mtbDate.equals(subform.getValue("ufeedatum").getDate())) {
+ subform.setValue("mtb", new Item("ref_tumorkonferenz", mtbReference));
+ subform.setValue("ufeedatum", new Item("datum", mtbDate));
+
+ try {
+ onkostarApi.saveProcedure(subform, false);
+ } catch (Exception e) {
+ logger.error("Formular 'DNPM UF Einzelempfehlung' konnte nicht aktualisiert werden", e);
+ }
+ }
+ }
+
+ if (subform.getFormName().equals("DNPM UF Rebiopsie")) {
+ if (mtbReference != subform.getValue("reftumorkonferenz").getInt() && !mtbDate.equals(subform.getValue("ufrbdatum").getDate())) {
+ subform.setValue("reftumorkonferenz", new Item("ref_tumorkonferenz", mtbReference));
+ subform.setValue("ufrbdatum", new Item("datum", mtbDate));
+
+ try {
+ onkostarApi.saveProcedure(subform, false);
+ } catch (Exception e) {
+ logger.error("Formular 'DNPM UF Rebiopsie' konnte nicht aktualisiert werden", e);
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/src/main/java/DNPM/services/DefaultFormService.java b/src/main/java/DNPM/services/DefaultFormService.java
new file mode 100644
index 0000000..c7fb042
--- /dev/null
+++ b/src/main/java/DNPM/services/DefaultFormService.java
@@ -0,0 +1,34 @@
+package DNPM.services;
+
+import DNPM.exceptions.FormException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Service;
+
+import javax.sql.DataSource;
+import java.util.List;
+
+@Service
+public class DefaultFormService implements FormService {
+
+ private final JdbcTemplate jdbcTemplate;
+
+ public DefaultFormService(final DataSource dataSource) {
+ this.jdbcTemplate = new JdbcTemplate(dataSource);
+ }
+
+ @Override
+ public int getMainFormProcedureId(int procedureId) throws FormException {
+ var sql = "SELECT hauptprozedur_id FROM prozedur WHERE id = ?";
+ try {
+ return jdbcTemplate.queryForObject(sql, (resultSet, i) -> resultSet.getInt("hauptprozedur_id"), procedureId);
+ } catch (Exception e) {
+ throw new FormException(String.format("No main form found for subform with ID '%d'", procedureId));
+ }
+ }
+
+ @Override
+ public List getSubFormProcedureIds(int procedureId) {
+ var sql = "SELECT id FROM prozedur WHERE hauptprozedur_id = ?";
+ return jdbcTemplate.queryForList(sql, Integer.class, procedureId);
+ }
+}
diff --git a/src/main/java/DNPM/services/FormService.java b/src/main/java/DNPM/services/FormService.java
new file mode 100644
index 0000000..824d350
--- /dev/null
+++ b/src/main/java/DNPM/services/FormService.java
@@ -0,0 +1,29 @@
+package DNPM.services;
+
+import DNPM.exceptions.FormException;
+
+import java.util.List;
+
+public interface FormService {
+
+ /**
+ * Diese Methode übergibt die Prozedur-ID des zugehörigen Hauptformulars zu einem Unterformular
+ * Siehe auch: FormInfoService.java
+ *
+ * @param procedureId Die Prozedur-ID des Unterformulars
+ * @return Die Prozedur-ID des zugehörigen Hauptformulars
+ * @throws FormException
+ */
+ int getMainFormProcedureId(int procedureId) throws FormException;
+
+ /**
+ * Diese Methode übergibt die Prozedur-IDs von Unterformularen zu einem Formular
+ * Siehe auch: FormInfoService.java
+ *
+ * @param procedureId Die Prozedur-ID des Formulars
+ * @return Eine Liste mit Prozedur-IDs der Unterformulare
+ * @throws FormException
+ */
+ List getSubFormProcedureIds(int procedureId);
+
+}
diff --git a/src/main/resources/de/itc/onkostar/library/moduleContext.xml b/src/main/resources/de/itc/onkostar/library/moduleContext.xml
index 51844e1..8bd2c82 100644
--- a/src/main/resources/de/itc/onkostar/library/moduleContext.xml
+++ b/src/main/resources/de/itc/onkostar/library/moduleContext.xml
@@ -16,6 +16,7 @@
+
\ No newline at end of file
diff --git a/src/test/java/DNPM/forms/TherapieplanAnalyzerTest.java b/src/test/java/DNPM/forms/TherapieplanAnalyzerTest.java
new file mode 100644
index 0000000..38bc76c
--- /dev/null
+++ b/src/test/java/DNPM/forms/TherapieplanAnalyzerTest.java
@@ -0,0 +1,70 @@
+package DNPM.forms;
+
+import DNPM.services.FormService;
+import de.itc.onkostar.api.IOnkostarApi;
+import de.itc.onkostar.api.Item;
+import de.itc.onkostar.api.Procedure;
+import de.itc.onkostar.api.constants.JaNeinUnbekannt;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.Date;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+public class TherapieplanAnalyzerTest {
+
+ @Mock
+ private IOnkostarApi onkostarApi;
+
+ @Mock
+ private FormService formService;
+
+ private TherapieplanAnalyzer therapieplanAnalyzer;
+
+ @BeforeEach
+ void setUp() {
+ this.therapieplanAnalyzer = new TherapieplanAnalyzer(onkostarApi, formService);
+ }
+
+ @Test
+ void shouldNotUpdateSubformsOrSectionsIfMultipleMtbConfiguration() throws Exception {
+ doAnswer(invocationOnMock -> {
+ var settingName = invocationOnMock.getArgument(0, String.class);
+ if (settingName.equals("mehrere_mtb_in_mtbepisode")) {
+ return "true";
+ }
+ return null;
+ }).when(onkostarApi).getGlobalSetting(anyString());
+
+ this.therapieplanAnalyzer.analyze(new Procedure(onkostarApi), null);
+
+ verify(onkostarApi, never()).saveProcedure(any(Procedure.class), anyBoolean());
+ }
+
+ @Test
+ void shouldNotUpdateSectionsIfSectionsNotEnabled() throws Exception {
+ when(onkostarApi.getGlobalSetting(anyString())).thenReturn(null);
+
+ var testProcedure = new Procedure(onkostarApi);
+ testProcedure.setId(1000);
+
+ // Setzen MTB Referenz und Datum MTB
+ testProcedure.setValue("referstemtb", new Item("ref_tumorkonferenz", 1234));
+ testProcedure.setValue("datum", new Item("datum", new Date()));
+
+ // Keine humangenetische Beratung und keine Reevaluation empfohlen
+ testProcedure.setValue("humangenberatung", new Item("humangen_beratung", JaNeinUnbekannt.NEIN));
+ testProcedure.setValue("reevaluation", new Item("reevaluation", JaNeinUnbekannt.NEIN));
+
+ this.therapieplanAnalyzer.analyze(testProcedure, null);
+
+ verify(onkostarApi, never()).saveProcedure(any(Procedure.class), anyBoolean());
+ }
+
+}