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()); + } + +}