diff --git a/pom.xml b/pom.xml index 5c017bef..451cb04d 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ UTF-8 1.8 3.11.0 - 1.30.0 + 1.31.0-SNAPSHOT 5.8.2 3.1.2 1.9.1 diff --git a/src/main/groovy/projects/patientfinder/procedureWithMapping.groovy b/src/main/groovy/projects/patientfinder/procedureWithMapping.groovy new file mode 100644 index 00000000..74e3a98b --- /dev/null +++ b/src/main/groovy/projects/patientfinder/procedureWithMapping.groovy @@ -0,0 +1,144 @@ +package projects.patientfinder + +import ca.uhn.fhir.model.api.TemporalPrecisionEnum +import de.kairos.fhir.centraxx.metamodel.CrfTemplateField +import de.kairos.fhir.centraxx.metamodel.Episode +import de.kairos.fhir.centraxx.metamodel.LaborFinding +import de.kairos.fhir.centraxx.metamodel.LaborFindingLaborValue +import de.kairos.fhir.centraxx.metamodel.LaborMapping +import de.kairos.fhir.centraxx.metamodel.OrganisationUnit +import de.kairos.fhir.centraxx.metamodel.ValueReference +import org.hl7.fhir.r4.model.Procedure + +import static de.kairos.fhir.centraxx.metamodel.AbstractCode.CODE +import static de.kairos.fhir.centraxx.metamodel.AbstractIdContainer.PSN +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.medProcedure + +/** + * Represented by CXX MedProcedure + * Exports extra data that is documented in a measurement profile with code ADDITIONAL_PROCEDURE_DATA + * The measurement profile 2 parameters: + * 1. Code: "DEPARTMENT", Type: SingleChoice on MasterDataCatalog of all OrgUnits + * 2. Code: "IS_SURGICAL_PROCEDURE", Type: boolean + * + */ +procedure { + id = "Procedure/" + context.source[medProcedure().id()] + + status = Procedure.ProcedureStatus.UNKNOWN + //println(context.source) + + final def mapping = context.source[medProcedure().laborMappings()].find { + it[LaborMapping.LABOR_FINDING][LaborFinding.LABOR_METHOD][CODE] == "ADDITIONAL_PROCEDURE_DATA" + } + + if (mapping != null) { + final def departmentValue = mapping[LaborMapping.LABOR_FINDING][LaborFinding.LABOR_FINDING_LABOR_VALUES].find { + it[LaborFindingLaborValue.CRF_TEMPLATE_FIELD][CrfTemplateField.LABOR_VALUE][CODE] == "DEPARTMENT" + } + + final def procedureType = mapping[LaborMapping.LABOR_FINDING][LaborFinding.LABOR_FINDING_LABOR_VALUES].find { + it[LaborFindingLaborValue.CRF_TEMPLATE_FIELD][CrfTemplateField.LABOR_VALUE][CODE] == "IS_SURGICAL_PROCEDURE" + } + + println(departmentValue) + println(procedureType) + + + if (departmentValue != null) { + println(departmentValue[LaborFindingLaborValue.MULTI_VALUE_REFERENCES]) + departmentValue[LaborFindingLaborValue.MULTI_VALUE_REFERENCES].each { final def valRef -> + performer { + onBehalfOf { + reference = "Organization/" + valRef[ValueReference.ORGANIZATION_VALUE][OrganisationUnit.ID] + } + } + } + } + + if (procedureType != null && procedureType[LaborFindingLaborValue.BOOLEAN_VALUE] == true) { + category { + coding { + system = "http://hl7.org/fhir/ValueSet/procedure-category" + code = "387713003" + display = "Surgical procedure (procedure)" + } + } + } + } + + code { + if (context.source[medProcedure().opsEntry()]) { + coding { + system = "https://fhir.centraxx.de/system/" + context.source[medProcedure().opsEntry().catalogue().name()] + version = context.source[medProcedure().opsEntry().catalogue().catalogueVersion()] + code = context.source[medProcedure().opsEntry().code()] as String + display = context.source[medProcedure().opsEntry().preferredLong()] as String + } + } + + if (context.source[medProcedure().userDefinedCatalogEntry()]) { + coding { + system = "https://fhir.centraxx.de/system/" + context.source[medProcedure().userDefinedCatalogEntry().catalog().code()] + version = context.source[medProcedure().userDefinedCatalogEntry().catalog().version()] + code = context.source[medProcedure().userDefinedCatalogEntry().code()] as String + display = context.source[medProcedure().userDefinedCatalogEntry().nameMultilingualEntries()]?.find { it[LANG] == "en" }?.getAt(VALUE) + } + } + + if (context.source[medProcedure().procedureCode()]) { + coding { + code = context.source[medProcedure().procedureCode()] as String + display = context.source[medProcedure().procedureText()] as String + } + } + } + + if (context.source[medProcedure().procedureDate().date()]) { + performedDateTime { + date = normalizeDate(context.source[medProcedure().procedureDate().date()] as String) + precision = TemporalPrecisionEnum.DAY.toString() + } + } + + final String opsNote = context.source[medProcedure().comments()] as String + if (opsNote) { + note { + text = opsNote + } + } + + subject { + reference = "Patient/" + context.source[medProcedure().patientContainer().id()] + } + + if (!isFakeEpisode(context.source[medProcedure().episode()])) { + encounter { + reference = "Encounter/" + context.source[medProcedure().episode().id()] + } + } +} + +static boolean isFakeEpisode(final def episode) { + if (episode == null) { + return true + } + + if (["SACT", "COSD"].contains(episode[Episode.ENTITY_SOURCE])) { + return true + } + + final def fakeId = episode[Episode.ID_CONTAINER]?.find { (it[PSN] as String).toUpperCase().startsWith("FAKE") } + return fakeId != null +} + +/** + * removes milli seconds and time zone. + * @param dateTimeString the date time string + * @return the result might be something like "1989-01-15T00:00:00" + */ +static String normalizeDate(final String dateTimeString) { + return dateTimeString != null ? dateTimeString.substring(0, 19) : null +} diff --git a/src/main/groovy/projects/patientfinder/specimen.groovy b/src/main/groovy/projects/patientfinder/specimen.groovy index 571c813b..80eca1fe 100644 --- a/src/main/groovy/projects/patientfinder/specimen.groovy +++ b/src/main/groovy/projects/patientfinder/specimen.groovy @@ -2,6 +2,10 @@ package projects.patientfinder import de.kairos.centraxx.fhir.r4.utils.FhirUrls import de.kairos.fhir.centraxx.metamodel.AbstractSample +import de.kairos.fhir.centraxx.metamodel.CrfTemplateField +import de.kairos.fhir.centraxx.metamodel.LaborFinding +import de.kairos.fhir.centraxx.metamodel.LaborFindingLaborValue +import de.kairos.fhir.centraxx.metamodel.LaborMapping import static de.kairos.fhir.centraxx.metamodel.AbstractCode.CODE import static de.kairos.fhir.centraxx.metamodel.AbstractIdContainer.ID_CONTAINER_TYPE @@ -9,10 +13,16 @@ import static de.kairos.fhir.centraxx.metamodel.AbstractIdContainer.PSN import static de.kairos.fhir.centraxx.metamodel.IdContainerType.DECISIVE import static de.kairos.fhir.centraxx.metamodel.RootEntities.sample +/** + * Export additional data via a SAMPLETYPELABORMAPPING that links to a finding + * with LABORMETHOD code "ADDITIONAL_SAMPLE_DATA". If that finding + * contains a value for a parameter with code "COLLECTION_METHOD", the value + * is exported to collection.method.coding.code + */ specimen { id = "Specimen/" + context.source[sample().id()] - + println(context.source) context.source[sample().idContainer()].each { final idContainer -> final boolean isDecisive = idContainer[ID_CONTAINER_TYPE]?.getAt(DECISIVE) if (isDecisive) { @@ -28,6 +38,7 @@ specimen { } } + type { coding { system = FhirUrls.System.Sample.SampleKind.BASE_URL @@ -41,12 +52,17 @@ specimen { final def parentSample = context.source[sample().parent()] - if (parentSample != null){ + if (parentSample != null) { parent { reference = "Specimen/" + parentSample[AbstractSample.ID] } } + final def finding = context.source[sample().laborMappings()].find { + it[LaborMapping.LABOR_FINDING][LaborFinding.LABOR_METHOD][CODE] == "ADDITIONAL_SAMPLE_DATA" + } + + collection { collectedDateTime { date = context.source[sample().samplingDate().date()] @@ -55,5 +71,19 @@ specimen { unit = context.source[sample().initialAmount().unit()] } } + + if (finding != null) { + final def collectionMethod = finding[LaborMapping.LABOR_FINDING][LaborFinding.LABOR_FINDING_LABOR_VALUES].find { + it[LaborFindingLaborValue.CRF_TEMPLATE_FIELD][CrfTemplateField.LABOR_VALUE][CODE] == "COLLECTION_METHOD" + } + + if (collectionMethod != null) { + method { + coding { + code = collectionMethod[LaborFindingLaborValue.STRING_VALUE] + } + } + } + } } } \ No newline at end of file