From 6b26bdff87be3869ce745ddfde2a86399e278031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20K=C3=BCttner?= Date: Fri, 21 Jun 2024 17:38:25 +0200 Subject: [PATCH] added two example scripts for export of LaborMethods as Questionnaire and LaborMapping as QuestionnaireResponse --- pom.xml | 2 +- .../projects/cxx/ctcue/questionnaire.groovy | 56 ++++++ .../cxx/ctcue/questionnaireResponse.groovy | 180 ++++++++++++++++++ 3 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 src/main/groovy/projects/cxx/ctcue/questionnaire.groovy create mode 100644 src/main/groovy/projects/cxx/ctcue/questionnaireResponse.groovy diff --git a/pom.xml b/pom.xml index 7a9d260b..bef3102b 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ UTF-8 1.8 3.11.0 - 1.32.0 + 1.34.0-SNAPSHOT 5.8.2 3.1.2 1.9.1 diff --git a/src/main/groovy/projects/cxx/ctcue/questionnaire.groovy b/src/main/groovy/projects/cxx/ctcue/questionnaire.groovy new file mode 100644 index 00000000..fe63afe7 --- /dev/null +++ b/src/main/groovy/projects/cxx/ctcue/questionnaire.groovy @@ -0,0 +1,56 @@ +package projects.cxx.ctcue + +import de.kairos.fhir.centraxx.metamodel.CrfTemplateField +import de.kairos.fhir.centraxx.metamodel.CrfTemplateSection +import de.kairos.fhir.centraxx.metamodel.LaborValue +import de.kairos.fhir.centraxx.metamodel.MultilingualEntry +import de.kairos.fhir.centraxx.metamodel.enums.LaborValueDType +import org.hl7.fhir.r4.model.Questionnaire + +import static de.kairos.fhir.centraxx.metamodel.RootEntities.laborMethod + +/** + * transforms a CXX LaborMethod to a Questionnaire. + */ +questionnaire { + + id = "Questionnaire/" + context.source[laborMethod().id()] + + identifier { + value = context.source[laborMethod().code()] + } + + // using first section only + final def firstSection = context.source[laborMethod().crfTemplate().sections()].find() + + firstSection[CrfTemplateSection.FIELDS].each { final def field -> + item { + setLinkId(field[CrfTemplateField.LABOR_VALUE][LaborValue.CODE] as String) + + // assuming the question is stored as description + setText(field[CrfTemplateField.LABOR_VALUE][LaborValue.DESC_MULTILINGUAL_ENTRIES].find { it[MultilingualEntry.LANG] == "en" }[MultilingualEntry.VALUE] as String) + setType(mapToType(field[CrfTemplateField.LABOR_VALUE][LaborValue.D_TYPE] as LaborValueDType)) + } + } + +} + +// more possible, focusing on main types +static mapToType(final LaborValueDType laborValueDType) { + switch (laborValueDType) { + case LaborValueDType.BOOLEAN: + return Questionnaire.QuestionnaireItemType.BOOLEAN + case LaborValueDType.INTEGER: + return Questionnaire.QuestionnaireItemType.INTEGER + case LaborValueDType.DECIMAL: + return Questionnaire.QuestionnaireItemType.QUANTITY + case LaborValueDType.DATE || LaborValueDType.LONGDATE: + return Questionnaire.QuestionnaireItemType.DATETIME + case LaborValueDType.TIME: + return Questionnaire.QuestionnaireItemType.TIME + case LaborValueDType.CATALOG: + return Questionnaire.QuestionnaireItemType.CHOICE + case LaborValueDType.STRING || LaborValueDType.LONGSTRING: + return Questionnaire.QuestionnaireItemType.TEXT + } +} diff --git a/src/main/groovy/projects/cxx/ctcue/questionnaireResponse.groovy b/src/main/groovy/projects/cxx/ctcue/questionnaireResponse.groovy new file mode 100644 index 00000000..7a7a34f4 --- /dev/null +++ b/src/main/groovy/projects/cxx/ctcue/questionnaireResponse.groovy @@ -0,0 +1,180 @@ +package projects.cxx.ctcue + +import de.kairos.fhir.centraxx.metamodel.AbstractCatalog +import de.kairos.fhir.centraxx.metamodel.CatalogEntry +import de.kairos.fhir.centraxx.metamodel.CrfTemplateField +import de.kairos.fhir.centraxx.metamodel.IcdEntry +import de.kairos.fhir.centraxx.metamodel.LaborFindingLaborValue +import de.kairos.fhir.centraxx.metamodel.LaborValue +import de.kairos.fhir.centraxx.metamodel.LaborValueNumeric +import de.kairos.fhir.centraxx.metamodel.PrecisionDate +import de.kairos.fhir.centraxx.metamodel.enums.LaborValueDType +import org.hl7.fhir.r4.model.QuestionnaireResponse + +import static de.kairos.fhir.centraxx.metamodel.AbstractCode.CODE +import static de.kairos.fhir.centraxx.metamodel.AbstractCodeName.NAME_MULTILINGUAL_ENTRIES +import static de.kairos.fhir.centraxx.metamodel.MultilingualEntry.LANG +import static de.kairos.fhir.centraxx.metamodel.MultilingualEntry.VALUE +import static de.kairos.fhir.centraxx.metamodel.RootEntities.laborMapping + +questionnaireResponse { + id = "QuestionnaireResponse/" + context.source[laborMapping().laborFinding().id()] + + identifier { + value = context.source[laborMapping().laborFinding().shortName()] + } + + setQuestionnaire("Questionnaire/" + context.source[laborMapping().laborFinding().laborMethod().id()]) + + // static, could be mapped as a param within the LaborFinding + status = QuestionnaireResponse.QuestionnaireResponseStatus.INPROGRESS + + subject { + reference = "Patient/" + context.source[laborMapping().relatedPatient().id()] + } + + setAuthored(context.source[laborMapping().laborFinding().findingDate()]) + + // author (OrgUnit or Practitioner) has to be coded within the LaborFinding + + context.source[laborMapping().laborFinding().laborFindingLaborValues()].each { final def lflv -> + + final def laborValue = lflv[LaborFindingLaborValue.CRF_TEMPLATE_FIELD][CrfTemplateField.LABOR_VALUE] + item { + setLinkId(laborValue[CODE] as String) + + // assuming the question is stored as description + setText(laborValue[LaborValue.DESC_MULTILINGUAL_ENTRIES].find { it[LANG] == "en" }[VALUE] as String) + + if (isNumeric(laborValue)) { + answer { + valueQuantity { + value = lflv[LaborFindingLaborValue.NUMERIC_VALUE] + unit = laborValue?.getAt(LaborValueNumeric.UNIT)?.getAt(CODE) as String + } + } + } else if (isBoolean(laborValue)) { + answer { + setValueBoolean(lflv[LaborFindingLaborValue.BOOLEAN_VALUE] as Boolean) + } + } else if (isDate(laborValue)) { + answer { + valueDateTime { + date = lflv[LaborFindingLaborValue.DATE_VALUE]?.getAt(PrecisionDate.DATE) + } + } + } else if (isTime(laborValue)) { + answer { + setValueTime(lflv[LaborFindingLaborValue.TIME_VALUE] as String) + } + } else if (isString(laborValue)) { + answer { + setValueString(lflv[LaborFindingLaborValue.STRING_VALUE] as String) + } + } else if (isEnumeration(laborValue)) { + valueCodeableConcept { + lflv[LaborFindingLaborValue.MULTI_VALUE].each { final entry -> + answer { + valueCoding { + system = "urn:centraxx:CodeSystem/UsageEntry" + code = entry[CODE] as String + display = entry[NAME_MULTILINGUAL_ENTRIES]?.find { it[LANG] == "en" }?.getAt(VALUE) as String + } + } + } + lflv[LaborFindingLaborValue.CATALOG_ENTRY_VALUE].each { final entry -> + answer { + valueCoding { + system = "urn:centraxx:CodeSystem/ValueList-" + entry[CatalogEntry.CATALOG]?.getAt(AbstractCatalog.ID) + code = entry[CODE] as String + display = entry[NAME_MULTILINGUAL_ENTRIES]?.find { it[LANG] == "en" }?.getAt(VALUE) as String + } + } + } + } + } else if (isOptionGroup(laborValue)) { + valueCodeableConcept { + lflv[LaborFindingLaborValue.MULTI_VALUE].each { final entry -> + answer { + valueCoding { + system = "urn:centraxx:CodeSystem/UsageEntry" + code = entry[CODE] as String + display = entry[NAME_MULTILINGUAL_ENTRIES]?.find { it[LANG] == "en" }?.getAt(VALUE) as String + } + } + } + lflv[LaborFindingLaborValue.CATALOG_ENTRY_VALUE].each { final entry -> + answer { + valueCoding { + system = "urn:centraxx:CodeSystem/ValueList-" + entry[CatalogEntry.CATALOG]?.getAt(AbstractCatalog.ID) + code = entry[CODE] as String + display = entry[NAME_MULTILINGUAL_ENTRIES]?.find { it[LANG] == "en" }?.getAt(VALUE) as String + } + } + } + } + } else if (isCatalog(laborValue)) { + valueCodeableConcept { + lflv[LaborFindingLaborValue.CATALOG_ENTRY_VALUE].each { final entry -> + answer { + valueCoding { + system = "urn:centraxx:CodeSystem/ValueList-" + entry[CatalogEntry.CATALOG]?.getAt(AbstractCatalog.ID) + code = entry[CODE] as String + display = entry[NAME_MULTILINGUAL_ENTRIES]?.find { it[LANG] == "en" }?.getAt(VALUE) as String + } + } + } + lflv[LaborFindingLaborValue.ICD_ENTRY_VALUE].each { final entry -> + answer { + valueCoding { + system = "urn:centraxx:CodeSystem/IcdCatalog-" + entry[IcdEntry.CATALOGUE]?.getAt(AbstractCatalog.ID) + code = entry[CODE] as String + display = entry[IcdEntry.PREFERRED_LONG] as String + } + } + } + } + } else { + final String msg = laborValue?.getAt(LaborValue.D_TYPE) + " not implemented yet." + System.out.println(msg) + } + } + } + +} + +static boolean isDTypeOf(final Object laborValue, final List types) { + return types.contains(laborValue?.getAt(LaborValue.D_TYPE) as LaborValueDType) +} + +static boolean isBoolean(final Object laborValue) { + return isDTypeOf(laborValue, [LaborValueDType.BOOLEAN]) +} + +static boolean isNumeric(final Object laborValue) { + return isDTypeOf(laborValue, [LaborValueDType.INTEGER, LaborValueDType.DECIMAL, LaborValueDType.SLIDER]) +} + +static boolean isDate(final Object laborValue) { + return isDTypeOf(laborValue, [LaborValueDType.DATE, LaborValueDType.LONGDATE]) +} + +static boolean isTime(final Object laborValue) { + return isDTypeOf(laborValue, [LaborValueDType.TIME]) +} + +static boolean isEnumeration(final Object laborValue) { + return isDTypeOf(laborValue, [LaborValueDType.ENUMERATION]) +} + +static boolean isString(final Object laborValue) { + return isDTypeOf(laborValue, [LaborValueDType.STRING, LaborValueDType.LONGSTRING]) +} + +static boolean isCatalog(final Object laborValue) { + return isDTypeOf(laborValue, [LaborValueDType.CATALOG]) +} + +static boolean isOptionGroup(final Object laborValue) { + return isDTypeOf(laborValue, [LaborValueDType.OPTIONGROUP]) +} \ No newline at end of file