diff --git a/codex-process-data-transfer/pom.xml b/codex-process-data-transfer/pom.xml index 91e1ee9e..364a6523 100644 --- a/codex-process-data-transfer/pom.xml +++ b/codex-process-data-transfer/pom.xml @@ -8,7 +8,7 @@ de.netzwerk-universitaetsmedizin.codex codex-processes-ap1 - 1.0.0.0 + 1.1.0.0 diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/ConstantsDataTransfer.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/ConstantsDataTransfer.java index 1ce6db98..c6bd6309 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/ConstantsDataTransfer.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/ConstantsDataTransfer.java @@ -91,6 +91,7 @@ public interface ConstantsDataTransfer String CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_BAD_PATIENT_REFERENCE = "bad-patient-reference"; String CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_FTTP_NOT_REACHABLE = "fttp-not-reachable"; String CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_NO_DIC_PSEUDONYM_FOR_BLOOMFILTER = "no-dic-pseudonym-for-bloomfilter"; + String CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_NO_DIC_PSEUDONYM_FOR_LOCAL_PSEUDONYM = "no-dic-pseudonym-for-local-pseudonym"; String CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_VALIDATION_FAILED = "validation-failed"; String CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_ECRYPTION_OF_DATA_FOR_CRR_FAILED = "ecryption-of-data-for-crr-failed"; String CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_UNABLE_TO_STORE_ECRYPTED_DATA = "unable-to-store-ecrypted-data"; diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/DataTransferProcessPluginDefinition.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/DataTransferProcessPluginDefinition.java index b21a881c..85965d8c 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/DataTransferProcessPluginDefinition.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/DataTransferProcessPluginDefinition.java @@ -17,8 +17,8 @@ public class DataTransferProcessPluginDefinition implements ProcessPluginDefinition { - public static final String VERSION = "1.0.0.0"; - public static final LocalDate DATE = LocalDate.of(2023, 10, 11); + public static final String VERSION = "1.1.0.0"; + public static final LocalDate DATE = LocalDate.of(2024, 3, 25); @Override public String getName() diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/DataStoreClientFactory.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/DataStoreClientFactory.java index a2cffdb6..a2ebd6cb 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/DataStoreClientFactory.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/DataStoreClientFactory.java @@ -155,11 +155,10 @@ public void testConnection() { logger.info( "Testing connection to Data Store FHIR server with {trustStorePath: {}, certificatePath: {}, privateKeyPath: {}, privateKeyPassword: {}," - + " basicAuthUsername {}, basicAuthPassword {}, bearerToken {}, serverBase: {}, proxyUrl {}, proxyUsername, proxyPassword {}}", + + " basicAuthUsername: {}, basicAuthPassword: {}, bearerToken: {}, serverBase: {}, proxy: values from 'DEV_DSF_PROXY'... config}", trustStorePath, certificatePath, privateKeyPath, privateKeyPassword != null ? "***" : "null", dataStoreServerBasicAuthUsername, dataStoreServerBasicAuthPassword != null ? "***" : "null", - dataStoreServerBearerToken != null ? "***" : "null", dataStoreServerBase, proxyUrl, proxyUsername, - proxyPassword != null ? "***" : "null"); + dataStoreServerBearerToken != null ? "***" : "null", dataStoreServerBase); getDataStoreClient().testConnection(); } diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/DataStoreClientImpl.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/DataStoreClientImpl.java index 9963ad47..19ca8fdf 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/DataStoreClientImpl.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/DataStoreClientImpl.java @@ -81,8 +81,7 @@ private void configureProxy(IRestfulClientFactory clientFactory, String proxyUrl clientFactory.setProxy(url.getHost(), url.getPort()); clientFactory.setProxyCredentials(proxyUsername, proxyPassword); - logger.info("Using proxy for data FHIR server connection with {host: {}, port: {}, username: {}}", - url.getHost(), url.getPort(), proxyUsername); + logger.info("Using proxy for data FHIR server connection with values from 'DEV_DSF_PROXY'... config"); } catch (MalformedURLException e) { diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClient.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClient.java index 236910fa..1dba9d65 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClient.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClient.java @@ -18,5 +18,7 @@ public interface FttpClient */ Optional getDicPseudonym(String bloomFilter); + Optional getDicPseudonymForLocalPseudonym(String localPseudonym); + void testConnection(); } diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClientFactory.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClientFactory.java index bbffd72e..d86083d5 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClientFactory.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClientFactory.java @@ -62,6 +62,18 @@ public Optional getDicPseudonym(String bloomFilter) return pseudonym; } + @Override + public Optional getDicPseudonymForLocalPseudonym(String localPseudonym) + { + Optional pseudonym = sha256(localPseudonym).map(p -> "dic_test/" + p); + + logger.warn( + "Returning simulated DIC pseudonym '{}' for local pseudonym '{}', fTTP connection not configured.", + pseudonym.orElseThrow(), localPseudonym); + + return pseudonym; + } + private Optional sha256(String original) { try @@ -142,11 +154,10 @@ public void testConnection() { logger.info( "Testing connection to fTTP with {trustStorePath: {}, certificatePath: {}, privateKeyPath: {}, privateKeyPassword: {}," - + " basicAuthUsername {}, basicAuthPassword {}, serverBase: {}, apiKey: {}, study: {}, target: {}, proxyUrl {}, proxyUsername, proxyPassword {}}", + + " basicAuthUsername: {}, basicAuthPassword: {}, serverBase: {}, apiKey: {}, study: {}, target: {}, proxy: values from 'DEV_DSF_PROXY'... config}", trustStorePath, certificatePath, privateKeyPath, privateKeyPassword != null ? "***" : "null", fttpBasicAuthUsername, fttpBasicAuthPassword != null ? "***" : "null", fttpServerBase, - fttpApiKey != null ? "***" : "null", fttpStudy, fttpTarget, proxyUrl, proxyUsername, - proxyPassword != null ? "***" : "null"); + fttpApiKey != null ? "***" : "null", fttpStudy, fttpTarget); getFttpClient().testConnection(); } diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClientImpl.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClientImpl.java index 5b95253b..2eef3560 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClientImpl.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClientImpl.java @@ -101,8 +101,7 @@ private void configureProxy(IRestfulClientFactory clientFactory, String proxyUrl clientFactory.setProxy(url.getHost(), url.getPort()); clientFactory.setProxyCredentials(proxyUsername, proxyPassword); - logger.info("Using proxy for fTTP connection with {host: {}, port: {}, username: {}}", url.getHost(), - url.getPort(), proxyUsername); + logger.info("Using proxy for fTTP connection with values from 'DEV_DSF_PROXY'... config"); } catch (MalformedURLException e) { @@ -154,6 +153,18 @@ protected Parameters createParametersForPsnWorkflow(String dicSourceAndPseudonym return p; } + protected Parameters createParametersForPsnWorkflowLocalPseudonym(String localPseudonym) + { + Parameters p = new Parameters(); + p.addParameter("study", fttpStudy); + p.addParameter("original", localPseudonym); + p.addParameter("source", "local"); + p.addParameter("target", fttpTarget); + p.addParameter("apikey", fttpApiKey); + + return p; + } + @Override public Optional getDicPseudonym(String bloomFilter) { @@ -178,6 +189,30 @@ public Optional getDicPseudonym(String bloomFilter) } } + @Override + public Optional getDicPseudonymForLocalPseudonym(String localPseudonym) + { + Objects.requireNonNull(localPseudonym, "localPseudonym"); + + logger.info("Requesting DIC Pseudonym for local Pseudonym {} ...", localPseudonym); + + try + { + IGenericClient client = createGenericClient(); + + Parameters parameters = client.operation().onServer().named("requestPsnWorkflow") + .withParameters(createParametersForPsnWorkflowLocalPseudonym(localPseudonym)) + .accept(Constants.CT_FHIR_XML_NEW).encoded(EncodingEnum.XML).execute(); + + return getPseudonym(parameters).map(p -> fttpTarget + "/" + p); + } + catch (Exception e) + { + logger.error("Error while retrieving DIC pseudonym: {} - {}", e.getClass().getName(), e.getMessage()); + throw new BpmnError(CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_FTTP_NOT_REACHABLE, e.getMessage()); + } + } + protected Parameters createParametersForBfWorkflow(String bloomFilter) { Parameters p = new Parameters(); diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/AbstractComplexFhirClient.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/AbstractComplexFhirClient.java index 0a952726..2e16d982 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/AbstractComplexFhirClient.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/AbstractComplexFhirClient.java @@ -66,7 +66,7 @@ else if (resource instanceof Encounter e) e.setSubject(patientRef); else if (resource instanceof Immunization i) i.setPatient(patientRef); - else if (resource instanceof Medication m) + else if (resource instanceof Medication) ; // nothing to do else if (resource instanceof MedicationAdministration ma) ma.setSubject(patientRef); @@ -94,7 +94,7 @@ else if (resource instanceof Encounter e) return Optional.of(e.getSubject()); else if (resource instanceof Immunization i) return Optional.of(i.getPatient()); - else if (resource instanceof Medication m) + else if (resource instanceof Medication) return Optional.empty(); else if (resource instanceof MedicationAdministration ma) return Optional.of(ma.getSubject()); @@ -198,8 +198,8 @@ protected Optional findPatientInLocalFhirStore(String pseudonym) } catch (Exception e) { - logger.warn("Error while searching for Patient with pseudonym " + NAMING_SYSTEM_NUM_CODEX_CRR_PSEUDONYM - + "|" + pseudonym, e); + logger.warn("Error while searching for Patient with pseudonym {}|{}", NAMING_SYSTEM_NUM_CODEX_CRR_PSEUDONYM, + pseudonym, e); throw e; } } diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/AbstractFhirClient.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/AbstractFhirClient.java index 28717c57..bd2ab69d 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/AbstractFhirClient.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/AbstractFhirClient.java @@ -636,7 +636,7 @@ public Optional getPatient(String reference) logger.warn("Patient {} not found: {} - {}", reference, e.getClass().getName(), e.getMessage()); if (logger.isDebugEnabled()) - logger.debug("Error while reading patient " + reference, e); + logger.debug("Error while reading patient {}", reference, e); return Optional.empty(); } @@ -653,6 +653,8 @@ public void updatePatient(Patient patient) Objects.requireNonNull(patient, "patient"); String id = patient.getIdElement().toVersionless().getValue(); + // set the patient id to versionless id to workaround a `If-Match`-header bug in hapi fhir client + patient.setId(id); logger.info("Updating patient {}", id); try @@ -682,7 +684,7 @@ public void updatePatient(Patient patient) } catch (Exception e) { - logger.warn("Could not update patient " + id, e); + logger.warn("Could not update patient {}", id, e); throw e; } } diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/FhirBridgeClient.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/FhirBridgeClient.java index 4517f360..aaf7a5bc 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/FhirBridgeClient.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/FhirBridgeClient.java @@ -167,7 +167,7 @@ private Optional update(Patient existingPatient, Patient newPatient, St } catch (Exception e) { - logger.warn("Could not update patient " + newPatient.getIdElement().toString(), e); + logger.warn("Could not update patient {}", newPatient.getIdElement().toString(), e); throw e; } } @@ -230,7 +230,7 @@ private Optional create(Patient newPatient, String pseudonym, String bu } catch (Exception e) { - logger.warn("Could not create patient " + newPatient.getIdElement().toString(), e); + logger.warn("Could not create patient {}", newPatient.getIdElement().toString(), e); throw e; } } @@ -318,7 +318,7 @@ private Optional findResourceInLocalFhirStore(String url, Class resourcesStre .collect(Collectors.toMap(r -> r.getIdElement().toUnqualifiedVersionless().getValue(), r -> "urn:uuid:" + UUID.randomUUID().toString())); + List resourcesWithTemporaryReferences = fixReferences(resources, resourcesById, uuidsById); List entries = resourcesWithTemporaryReferences.stream().map(r -> { @@ -240,12 +243,20 @@ else if (resource instanceof Observation o) Observation::setEncounter); fixReferences(o, uuidsById, "Observation.hasMember", Observation::hasHasMember, Observation::getHasMember, Observation::setHasMember); + fixReference(o, uuidsById, "Observation.specimen", Observation::hasSpecimen, Observation::getSpecimen, + Observation::setSpecimen); } else if (resource instanceof Procedure p) { fixReference(p, uuidsById, "Procedure.encounter", Procedure::hasEncounter, Procedure::getEncounter, Procedure::setEncounter); } + else if (resource instanceof Specimen s) + { + fixReferences(s, uuidsById, "Specimen.parent", Specimen::hasParent, Specimen::getParent, + Specimen::setParent); + } + return resource; } @@ -269,6 +280,18 @@ else if (oldReference.hasReference() && oldReference.getReference() == null && o { logger.debug("Not removing empty reference at {} with data-absent-reason extension", path); } + else if (!oldReference.getResource().isEmpty()) + { + String internalId = "#" + UUID.randomUUID(); + Reference fixedReference = new Reference(internalId); + IBaseResource oldContainedResource = clean((DomainResource) oldReference.getResource()); + oldContainedResource.setId(internalId); + fixedReference.setResource(oldContainedResource); + setReference.apply(resource, fixedReference); + logger.debug( + "Replacing reference to contained resource at {} from resource {} with bundle temporary id in transport bundle", + path, getAbsoluteId(resource).getValue()); + } else { logger.warn("Removing reference at {} from resource {} in transport bundle", path, @@ -307,6 +330,18 @@ else if (oldReference.hasReference() && oldReference.getReference() == null logger.debug("Not removing empty reference at {}[{}] with data-absent-reason extension", path, i); fixedReferences.add(oldReference); } + else if (!oldReference.getResource().isEmpty()) + { + String internalId = "#" + UUID.randomUUID(); + Reference fixedReference = new Reference(internalId); + IBaseResource oldContainedResource = clean((DomainResource) oldReference.getResource()); + oldContainedResource.setId(internalId); + fixedReference.setResource(oldContainedResource); + fixedReferences.add(fixedReference); + logger.debug( + "Replacing reference to contained resource at {}[{}] from resource {} with bundle temporary id in transport bundle", + path, i, getAbsoluteId(resource).getValue()); + } else { logger.warn("Removing reference at {}[{}] from resource {} in transport bundle", path, i, @@ -337,20 +372,22 @@ private R fixReferenceFromComponents(R resource, M && uuidsById.containsKey(oldReference.getReference())) { logger.debug( - "Replacing reference at " + path - + " from resource {} with bundle temporary id in transport bundle", - i, getAbsoluteId(resource).getValue()); + "Replacing reference at {}[{}] from resource {} with bundle temporary id in transport bundle", + path, i, getAbsoluteId(resource).getValue()); setReference.apply(component, new Reference(uuidsById.get(oldReference.getReference()))); } - else if (oldReference.hasReference() && oldReference.getReference() == null + else if ((oldReference.hasReference() && oldReference.getReference() == null && oldReference.getReferenceElement_() .hasExtension("http://hl7.org/fhir/StructureDefinition/data-absent-reason")) + || oldReference.hasExtension("http://hl7.org/fhir/StructureDefinition/data-absent-reason")) { - logger.debug("Not removing empty reference at " + path + " with data-absent-reason extension", i); + logger.debug( + "Not removing empty reference at {}[{}] with data-absent-reason extension from resource {} in transport bundle", + path, i, getAbsoluteId(resource).getValue()); } else { - logger.warn("Removing reference at " + path + " from resource {} in transport bundle", i, + logger.warn("Removing reference at {}[{}] from resource {} in transport bundle", path, i, getAbsoluteId(resource).getValue()); setReference.apply(component, null); } @@ -418,7 +455,7 @@ private void cleanUnsupportedReferenceFromComponen C component = components.get(i); if (hasReference.apply(component)) { - logger.warn("Removing reference at " + path + " from resource {} in transport bundle", i, + logger.warn("Removing reference at {}[{}] from resource {} in transport bundle", path, i, getAbsoluteId(resource).getValue()); setReference.apply(component, null); } @@ -435,7 +472,7 @@ private void cleanUnsupportedReferenceFromComponen C component = getComponents.apply(resource); if (hasReference.apply(component)) { - logger.warn("Removing reference at " + path + " from resource {} in transport bundle", + logger.warn("Removing reference at {} from resource {} in transport bundle", path, getAbsoluteId(resource).getValue()); setReference.apply(component, null); } @@ -454,7 +491,7 @@ private void cleanUnsupportedReferencesFromCompone C component = components.get(i); if (hasReferences.apply(component)) { - logger.warn("Removing references at " + path + " from resource {} in transport bundle", i, + logger.warn("Removing references at {}[{}] from resource {} in transport bundle", path, i, getAbsoluteId(resource).getValue()); setReferences.apply(component, null); } @@ -478,7 +515,7 @@ private void cleanUnsupportedReferencesFromCo C2 component2 = components2.get(i); if (hasReference.apply(component2)) { - logger.warn("Removing reference at " + path + "[{}] from resource {} in transport bundle", i, + logger.warn("Removing reference at {}[{}] from resource {} in transport bundle", path, i, getAbsoluteId(resource).getValue()); setReference.apply(component2, null); } @@ -645,7 +682,6 @@ else if (resource instanceof Observation o) cleanUnsupportedReferences(o, "Observation.focus", Observation::hasFocus, Observation::setFocus); cleanUnsupportedReferences(o, "Observation.performer", Observation::hasPerformer, Observation::setPerformer); - cleanUnsupportedReference(o, "Observation.specimen", Observation::hasSpecimen, Observation::setSpecimen); cleanUnsupportedReference(o, "Observation.device", Observation::hasDevice, Observation::setDevice); cleanUnsupportedReferences(o, "Observation.derivedFrom", Observation::hasDerivedFrom, Observation::setDerivedFrom); @@ -674,6 +710,20 @@ else if (resource instanceof Procedure p) cleanUnsupportedReferences(p, "Procedure.usedReference", Procedure::hasUsedReference, Procedure::setUsedReference); } + else if (resource instanceof Specimen s) + { + cleanUnsupportedReferences(s, "Specimen.request", Specimen::hasRequest, Specimen::setRequest); + cleanUnsupportedReferenceFromComponent(s, "Specimen.collection.collector", Specimen::hasCollection, + Specimen::getCollection, Specimen.SpecimenCollectionComponent::hasCollector, + Specimen.SpecimenCollectionComponent::setCollector); + cleanUnsupportedReferencesFromComponents(s, "Specimen.processing[{}].additive", Specimen::hasProcessing, + Specimen::getProcessing, Specimen.SpecimenProcessingComponent::hasAdditive, + Specimen.SpecimenProcessingComponent::setAdditive); + cleanUnsupportedReferenceFromComponents(s, "Specimen.container[{}].additiveReference", + Specimen::hasContainer, Specimen::getContainer, + Specimen.SpecimenContainerComponent::hasAdditiveReference, + Specimen.SpecimenContainerComponent::setAdditive); + } else throw new RuntimeException("Resource of type " + resource.getResourceType().name() + " not supported"); } @@ -741,10 +791,21 @@ else if (resource instanceof Procedure p) p.setIdentifier(Collections.emptyList()); p.setSubject(patientRef); } + else if (resource instanceof Specimen s) + { + s.setIdentifier(Collections.emptyList()); + s.setAccessionIdentifier(null); + s.setSubject(patientRef); + } else throw new RuntimeException("Resource of type " + resource.getResourceType().name() + " not supported"); } + if (resource instanceof DomainResource d) + d.getContained().forEach(r -> setSubjectOrIdentifier(r, pseudonym)); + else + throw new RuntimeException("Resource of type " + resource.getResourceType().name() + " not supported"); + return resource; } diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/send/ResolvePsn.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/send/ResolvePsn.java index aa0e14b0..7459a5c2 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/send/ResolvePsn.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/send/ResolvePsn.java @@ -2,11 +2,13 @@ import static de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_PATIENT_REFERENCE; import static de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.ConstantsDataTransfer.CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_NO_DIC_PSEUDONYM_FOR_BLOOMFILTER; +import static de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.ConstantsDataTransfer.CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_NO_DIC_PSEUDONYM_FOR_LOCAL_PSEUDONYM; import static de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.ConstantsDataTransfer.CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_PATIENT_NOT_FOUND; import static de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.ConstantsDataTransfer.IDENTIFIER_NUM_CODEX_DIC_PSEUDONYM_TYPE_CODE; import static de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.ConstantsDataTransfer.IDENTIFIER_NUM_CODEX_DIC_PSEUDONYM_TYPE_SYSTEM; import static de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.ConstantsDataTransfer.NAMING_SYSTEM_NUM_CODEX_BLOOM_FILTER; import static de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.ConstantsDataTransfer.NAMING_SYSTEM_NUM_CODEX_DIC_PSEUDONYM; +import static de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.ConstantsDataTransfer.RFC_4122_SYSTEM; import java.util.Objects; import java.util.Optional; @@ -94,8 +96,33 @@ private Optional getPseudonym(Patient patient) private String resolvePseudonymAndUpdatePatient(Patient patient) { - String bloomFilter = getBloomFilter(patient); - String pseudonym = resolveBloomFilter(bloomFilter); + String pseudonym; + // first try to find a bloom filter + Optional bloomFilter = getBloomFilter(patient); + if (bloomFilter.isPresent()) + { + pseudonym = resolveBloomFilter(bloomFilter.get()); + } + else + { + // otherwise try to find a local pseudonym + // --> no record linkage + logger.info( + "No bloom filter present for patient {}. Try to use the local pseudonym for data transfer without record linkage", + patient.getIdElement().getValue()); + Optional localPseudonym = getLocalPseudonym(patient); + if (localPseudonym.isPresent()) + { + pseudonym = resolveLocalPseudonym(localPseudonym.get()); + } + else + { + logger.info("No local pseudonym present for patient {}. Aborted", patient.getIdElement().getValue()); + throw new RuntimeException("Could not find pseudonym"); + } + + + } patient.getIdentifier().removeIf(i -> NAMING_SYSTEM_NUM_CODEX_BLOOM_FILTER.equals(i.getSystem())); patient.addIdentifier().setSystem(NAMING_SYSTEM_NUM_CODEX_DIC_PSEUDONYM).setValue(pseudonym).getType() @@ -107,12 +134,18 @@ private String resolvePseudonymAndUpdatePatient(Patient patient) return pseudonym; } - private String getBloomFilter(Patient patient) + private Optional getBloomFilter(Patient patient) { return patient.getIdentifier().stream().filter(Identifier::hasSystem) .filter(i -> NAMING_SYSTEM_NUM_CODEX_BLOOM_FILTER.equals(i.getSystem())).filter(Identifier::hasValue) - .findFirst().map(Identifier::getValue).orElseThrow(() -> new RuntimeException( - "No bloom filter present in patient " + patient.getIdElement().getValue())); + .findFirst().map(Identifier::getValue); + } + + private Optional getLocalPseudonym(Patient patient) + { + return patient.getIdentifier().stream().filter(Identifier::hasSystem) + .filter(i -> RFC_4122_SYSTEM.equals(i.getSystem())).filter(Identifier::hasValue).findFirst() + .map(Identifier::getValue); } private String resolveBloomFilter(String bloomFilter) @@ -123,6 +156,15 @@ private String resolveBloomFilter(String bloomFilter) "Unable to get DIC pseudonym for given BloomFilter")); } + private String resolveLocalPseudonym(String localPseudonym) + { + return fttpClientFactory.getFttpClient().getDicPseudonymForLocalPseudonym(localPseudonym) + .orElseThrow(() -> new BpmnError( + CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_NO_DIC_PSEUDONYM_FOR_LOCAL_PSEUDONYM, + "Unable to get DIC pseudonym for given localPseudonym")); + } + + private void updatePatient(Patient patient) { dataStoreClientFactory.getDataStoreClient().getFhirClient().updatePatient(patient); diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/send/StoreDataForDts.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/send/StoreDataForDts.java index 265e0bc1..46e99f6a 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/send/StoreDataForDts.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/send/StoreDataForDts.java @@ -15,7 +15,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ca.uhn.fhir.context.FhirContext; +import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.logging.DataLogger; import dev.dsf.bpe.v1.ProcessPluginApi; import dev.dsf.bpe.v1.activity.AbstractServiceDelegate; import dev.dsf.bpe.v1.constants.NamingSystems; @@ -27,12 +27,14 @@ public class StoreDataForDts extends AbstractServiceDelegate private static final Logger logger = LoggerFactory.getLogger(StoreDataForDts.class); private final String dtsIdentifierValue; + private final DataLogger dataLogger; - public StoreDataForDts(ProcessPluginApi api, String dtsIdentifierValue) + public StoreDataForDts(ProcessPluginApi api, String dtsIdentifierValue, DataLogger dataLogger) { super(api); this.dtsIdentifierValue = dtsIdentifierValue; + this.dataLogger = dataLogger; } @Override @@ -41,6 +43,7 @@ public void afterPropertiesSet() throws Exception super.afterPropertiesSet(); Objects.requireNonNull(dtsIdentifierValue, "dtsIdentifierValue"); + Objects.requireNonNull(dataLogger, "dataLogger"); } @Override @@ -72,8 +75,8 @@ private IdType createBinaryResource(Binary binary) } catch (Exception e) { - logger.debug("Binary to create {}", FhirContext.forR4().newJsonParser().encodeResourceToString(binary)); - logger.warn("Error while creating Binary resource: " + e.getMessage(), e); + dataLogger.logData("Binary to create", binary); + logger.warn("Error while creating Binary resource: {}", e.getMessage(), e); throw new BpmnError(CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_UNABLE_TO_STORE_ECRYPTED_DATA, "Unable to create Binary resource with encrypted data for DTS in local DSF FHIR server"); diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/DownloadDataFromDic.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/DownloadDataFromDic.java index 616cff55..18923934 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/DownloadDataFromDic.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/DownloadDataFromDic.java @@ -52,7 +52,7 @@ protected void doExecute(DelegateExecution execution, Variables variables) throw } catch (Exception e) { - logger.warn("Error while reading Binary resoruce: " + e.getMessage(), e); + logger.warn("Error while reading Binary resoruce: {}", e.getMessage(), e); throw new BpmnError( CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_DOWNLOAD_OF_ENCRYPTED_DATA_FROM_DIC_FAILED, diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/DownloadValidationErrorFromCrr.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/DownloadValidationErrorFromCrr.java index da628f9d..890b9005 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/DownloadValidationErrorFromCrr.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/DownloadValidationErrorFromCrr.java @@ -44,7 +44,7 @@ protected void doExecute(DelegateExecution execution, Variables variables) throw } catch (Exception e) { - logger.warn("Error while reading Binary resoruce: " + e.getMessage(), e); + logger.warn("Error while reading Binary resoruce: {}", e.getMessage(), e); throw new BpmnError( CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_DOWNLOAD_OF_ENCRYTPED_VALIDATION_ERROR_FROM_CRR_FAILED, diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/StoreDataForCrr.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/StoreDataForCrr.java index 0bb0a771..5b448825 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/StoreDataForCrr.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/StoreDataForCrr.java @@ -15,7 +15,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ca.uhn.fhir.context.FhirContext; +import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.logging.DataLogger; import dev.dsf.bpe.v1.ProcessPluginApi; import dev.dsf.bpe.v1.activity.AbstractServiceDelegate; import dev.dsf.bpe.v1.constants.NamingSystems; @@ -27,12 +27,14 @@ public class StoreDataForCrr extends AbstractServiceDelegate private static final Logger logger = LoggerFactory.getLogger(StoreDataForCrr.class); private final String crrIdentifierValue; + private final DataLogger dataLogger; - public StoreDataForCrr(ProcessPluginApi api, String crrIdentifierValue) + public StoreDataForCrr(ProcessPluginApi api, String crrIdentifierValue, DataLogger dataLogger) { super(api); this.crrIdentifierValue = crrIdentifierValue; + this.dataLogger = dataLogger; } @Override @@ -41,6 +43,7 @@ public void afterPropertiesSet() throws Exception super.afterPropertiesSet(); Objects.requireNonNull(crrIdentifierValue, "crrIdentifierValue"); + Objects.requireNonNull(dataLogger, "dataLogger"); } @Override @@ -72,8 +75,8 @@ private IdType createBinaryResource(Binary binary) } catch (Exception e) { - logger.debug("Binary to create {}", FhirContext.forR4().newJsonParser().encodeResourceToString(binary)); - logger.warn("Error while creating Binary resource: " + e.getMessage(), e); + dataLogger.logData("Binary to create", binary); + logger.warn("Error while creating Binary resource: {}", e.getMessage(), e); throw new BpmnError(CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_UNABLE_TO_STORE_ECRYPTED_DATA, "Unable to create Binary resource with encrypted data for CRR in local DSF FHIR server"); diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/StoreValidationErrorForDic.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/StoreValidationErrorForDic.java index b153cbe5..1d63fe34 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/StoreValidationErrorForDic.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/service/translate/StoreValidationErrorForDic.java @@ -4,6 +4,8 @@ import static de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_BUNDLE; import static de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.ConstantsDataTransfer.CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_UNABLE_TO_STORE_ECRYPTED_VALIDATION_ERROR; +import java.util.Objects; + import org.camunda.bpm.engine.delegate.BpmnError; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.hl7.fhir.r4.model.Binary; @@ -12,21 +14,34 @@ import org.hl7.fhir.r4.model.ResourceType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; -import ca.uhn.fhir.context.FhirContext; +import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.logging.DataLogger; import dev.dsf.bpe.v1.ProcessPluginApi; import dev.dsf.bpe.v1.activity.AbstractServiceDelegate; import dev.dsf.bpe.v1.constants.NamingSystems; import dev.dsf.bpe.v1.variables.Variables; import jakarta.ws.rs.core.MediaType; -public class StoreValidationErrorForDic extends AbstractServiceDelegate +public class StoreValidationErrorForDic extends AbstractServiceDelegate implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(StoreValidationErrorForDic.class); - public StoreValidationErrorForDic(ProcessPluginApi api) + private DataLogger dataLogger; + + public StoreValidationErrorForDic(ProcessPluginApi api, DataLogger dataLogger) { super(api); + + this.dataLogger = dataLogger; + } + + @Override + public void afterPropertiesSet() throws Exception + { + super.afterPropertiesSet(); + + Objects.requireNonNull(dataLogger, "dataLogger"); } @Override @@ -60,8 +75,8 @@ private IdType createBinaryResource(Binary binary) } catch (Exception e) { - logger.debug("Binary to create {}", FhirContext.forR4().newJsonParser().encodeResourceToString(binary)); - logger.warn("Error while creating Binary resource: " + e.getMessage(), e); + dataLogger.logData("Binary to create", binary); + logger.warn("Error while creating Binary resource: {}", e.getMessage(), e); throw new BpmnError( CODESYSTEM_NUM_CODEX_DATA_TRANSFER_ERROR_VALUE_UNABLE_TO_STORE_ECRYPTED_VALIDATION_ERROR, diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/ReceiveConfig.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/ReceiveConfig.java index 1073cfc6..7f1311ec 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/ReceiveConfig.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/ReceiveConfig.java @@ -84,7 +84,8 @@ public EncryptValidationError encryptValidationError() @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public StoreValidationErrorForDts storeValidationErrorForDts() { - return new StoreValidationErrorForDts(api, transferDataConfig.dtsIdentifierValue()); + return new StoreValidationErrorForDts(api, transferDataConfig.dtsIdentifierValue(), + transferDataConfig.dataLogger()); } @Bean diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/SendConfig.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/SendConfig.java index b5ef9fc8..58daee36 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/SendConfig.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/SendConfig.java @@ -125,7 +125,7 @@ public AfterDryRunEndListener afterDryRunEndListener() @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public StoreDataForDts storeDataForDts() { - return new StoreDataForDts(api, transferDataConfig.dtsIdentifierValue()); + return new StoreDataForDts(api, transferDataConfig.dtsIdentifierValue(), transferDataConfig.dataLogger()); } @Bean diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/TranslateConfig.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/TranslateConfig.java index 85282048..4b6eeac1 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/TranslateConfig.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/TranslateConfig.java @@ -52,7 +52,7 @@ public ReplacePseudonym replacePseudonym() @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public StoreDataForCrr storeDataForCodex() { - return new StoreDataForCrr(api, transferDataConfig.crrIdentifierValue()); + return new StoreDataForCrr(api, transferDataConfig.crrIdentifierValue(), transferDataConfig.dataLogger()); } @Bean @@ -108,7 +108,7 @@ public DownloadValidationErrorFromCrr downloadValidationErrorFromCrr() @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public StoreValidationErrorForDic storeValidationErrorForDic() { - return new StoreValidationErrorForDic(api); + return new StoreValidationErrorForDic(api, transferDataConfig.dataLogger()); } @Bean diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/ValidationConfig.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/ValidationConfig.java index 928fa7c9..98a53723 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/ValidationConfig.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/ValidationConfig.java @@ -54,6 +54,7 @@ import de.rwh.utils.crypto.CertificateHelper; import de.rwh.utils.crypto.io.CertificateReader; import de.rwh.utils.crypto.io.PemIo; +import dev.dsf.bpe.v1.ProcessPluginApi; import dev.dsf.bpe.v1.documentation.ProcessDocumentation; import dev.dsf.fhir.validation.SnapshotGenerator; import dev.dsf.fhir.validation.ValueSetExpander; @@ -65,6 +66,9 @@ public class ValidationConfig { private static final Logger logger = LoggerFactory.getLogger(ValidationConfig.class); + @Autowired + private ProcessPluginApi api; + public static enum TerminologyServerConnectionTestStatus { OK, NOT_OK, DISABLED @@ -75,7 +79,7 @@ public static enum TerminologyServerConnectionTestStatus private boolean validationEnabled; @ProcessDocumentation(description = "FHIR implementation guide package used to validated resources, specify as `name|version`", processNames = "wwwnetzwerk-universitaetsmedizinde_dataSend") - @Value("#{'${de.netzwerk.universitaetsmedizin.rdp.validation.package:de.basisprofil.r4|1.4.0,de.medizininformatikinitiative.kerndatensatz.diagnose|1.0.4,de.medizininformatikinitiative.kerndatensatz.fall|1.0.1,de.medizininformatikinitiative.kerndatensatz.laborbefund|1.0.6,de.medizininformatikinitiative.kerndatensatz.medikation|1.0.11,de.medizininformatikinitiative.kerndatensatz.person|1.0.16,de.medizininformatikinitiative.kerndatensatz.prozedur|1.0.7}'.trim().split('(,[ ]?)|(\\n)')}") + @Value("#{'${de.netzwerk.universitaetsmedizin.rdp.validation.package:de.basisprofil.r4|1.4.0,de.medizininformatikinitiative.kerndatensatz.meta|1.0.3,de.medizininformatikinitiative.kerndatensatz.person|2024.0.0-ballot,de.medizininformatikinitiative.kerndatensatz.fall|2024.0.0-ballot,de.medizininformatikinitiative.kerndatensatz.mikrobiologie|2024.0.0}'.trim().split('(,[ ]?)|(\\n)')}") private List validationPackages; @ProcessDocumentation(description = "FHIR implementation guide packages that do not need to be downloaded, list with `name|version` values", processNames = "wwwnetzwerk-universitaetsmedizinde_dataSend") @@ -114,18 +118,6 @@ public static enum TerminologyServerConnectionTestStatus @Value("${de.netzwerk.universitaetsmedizin.rdp.validation.package.client.authentication.basic.password:#{null}}") private char[] packageClientBasicAuthPassword; - @ProcessDocumentation(description = "Forwarding proxy server url, set if the FHIR implementation guide package server can only be reached via a proxy server", processNames = "wwwnetzwerk-universitaetsmedizinde_dataSend", example = "http://proxy.foo:8080") - @Value("${de.netzwerk.universitaetsmedizin.rdp.validation.package.client.proxy.schemeHostPort:#{null}}") - private String packageClientProxySchemeHostPort; - - @ProcessDocumentation(description = "Forwarding proxy server basic authentication username, set if the FHIR implementation guide package server can only be reached via a proxy server that requires basic authentication", processNames = "wwwnetzwerk-universitaetsmedizinde_dataSend") - @Value("${de.netzwerk.universitaetsmedizin.rdp.validation.package.client.proxy.username:#{null}}") - private String packageClientProxyUsername; - - @ProcessDocumentation(description = "Forwarding proxy server basic authentication password, set if the FHIR implementation guide package server can only be reached via a proxy server that requires basic authentication", processNames = "wwwnetzwerk-universitaetsmedizinde_dataSend", recommendation = "Use docker secret file to configure by using `${env_variable}_FILE`", example = "/run/secrets/validation_package_server_proxy_basicauth.password") - @Value("${de.netzwerk.universitaetsmedizin.rdp.validation.package.client.proxy.password:#{null}}") - private char[] packageClientProxyPassword; - @ProcessDocumentation(description = "Connection timeout in milliseconds used when accessing the FHIR implementation guide package server, time until a connection needs to be established before aborting", processNames = "wwwnetzwerk-universitaetsmedizinde_dataSend") @Value("${de.netzwerk.universitaetsmedizin.rdp.validation.package.client.timeout.connect:10000}") private int packageClientConnectTimeout; @@ -174,18 +166,6 @@ public static enum TerminologyServerConnectionTestStatus @Value("${de.netzwerk.universitaetsmedizin.rdp.validation.valueset.expansion.client.authentication.basic.password:#{null}}") private char[] valueSetExpansionClientBasicAuthPassword; - @ProcessDocumentation(description = "Forwarding proxy server url, set if the terminology server can only be reached via a proxy server", processNames = "wwwnetzwerk-universitaetsmedizinde_dataSend", example = "http://proxy.foo:8080") - @Value("${de.netzwerk.universitaetsmedizin.rdp.validation.valueset.expansion.client.proxy.schemeHostPort:#{null}}") - private String valueSetExpansionClientProxySchemeHostPort; - - @ProcessDocumentation(description = "Forwarding proxy server basic authentication username, set if the terminology server can only be reached via a proxy server that requires basic authentication", processNames = "wwwnetzwerk-universitaetsmedizinde_dataSend") - @Value("${de.netzwerk.universitaetsmedizin.rdp.validation.valueset.expansion.client.proxy.username:#{null}}") - private String valueSetExpansionClientProxyUsername; - - @ProcessDocumentation(description = "Forwarding proxy server basic authentication password, set if the terminology server can only be reached via a proxy server that requires basic authentication", processNames = "wwwnetzwerk-universitaetsmedizinde_dataSend", recommendation = "Use docker secret file to configure by using `${env_variable}_FILE`", example = "/run/secrets/terminology_server_proxy_basicauth.password") - @Value("${de.netzwerk.universitaetsmedizin.rdp.validation.valueset.expansion.client.proxy.password:#{null}}") - private char[] valueSetExpansionClientProxyPassword; - @ProcessDocumentation(description = "Connection timeout in milliseconds used when accessing the terminology server, time until a connection needs to be established before aborting", processNames = "wwwnetzwerk-universitaetsmedizinde_dataSend") @Value("${de.netzwerk.universitaetsmedizin.rdp.validation.valueset.expansion.client.timeout.connect:10000}") private int valueSetExpansionClientConnectTimeout; @@ -200,6 +180,8 @@ public static enum TerminologyServerConnectionTestStatus @ProcessDocumentation(description = "List of ValueSet modifier classes, modifiers are executed before atempting to expand a ValueSet and after", processNames = "wwwnetzwerk-universitaetsmedizinde_dataSend") @Value("#{'${de.netzwerk.universitaetsmedizin.rdp.validation.valueset.expansion.modifierClasses:" + + "de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.value_set.KdsMikrobiologieBugFixer" + + "," + "de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.value_set.MissingEntriesIncluder" + "}'.trim().split('(,[ ]?)|(\\n)')}") private List valueSetModifierClasses; @@ -392,9 +374,13 @@ private ValidationPackageClientJersey validationPackageClientJersey() "Package client basic authentication username or password not specified"); } - if ((packageClientProxyUsername != null) != (packageClientProxyPassword != null)) + String proxyUrl = null, proxyUsername = null; + char[] proxyPassword = null; + if (api.getProxyConfig().isEnabled() && !api.getProxyConfig().isNoProxyUrl(packageServerBaseUrl)) { - throw new IllegalArgumentException("Package client proxy username or password not specified"); + proxyUrl = api.getProxyConfig().getUrl(); + proxyUsername = api.getProxyConfig().getUsername(); + proxyPassword = api.getProxyConfig().getPassword() == null ? null : api.getProxyConfig().getPassword(); } KeyStore packageClientTrustStore = trustStore("FHIR package client", packageClientTrustCertificates); @@ -405,9 +391,8 @@ private ValidationPackageClientJersey validationPackageClientJersey() return new ValidationPackageClientJersey(packageServerBaseUrl, packageClientTrustStore, packageClientKeyStore, packageClientKeyStore == null ? null : packageClientKeyStorePassword, packageClientBasicAuthUsername, - packageClientBasicAuthPassword, packageClientProxySchemeHostPort, packageClientProxyUsername, - packageClientProxyPassword, packageClientConnectTimeout, packageClientReadTimeout, - packageClientVerbose); + packageClientBasicAuthPassword, proxyUrl, proxyUsername, proxyPassword, packageClientConnectTimeout, + packageClientReadTimeout, packageClientVerbose); } @Bean @@ -452,9 +437,13 @@ private ValueSetExpansionClient valueSetExpansionClientJersey() "ValueSet expansion client basic authentication username or password not specified"); } - if ((valueSetExpansionClientProxyUsername != null) != (valueSetExpansionClientProxyPassword != null)) + String proxyUrl = null, proxyUsername = null; + char[] proxyPassword = null; + if (api.getProxyConfig().isEnabled() && !api.getProxyConfig().isNoProxyUrl(valueSetExpansionServerBaseUrl)) { - throw new IllegalArgumentException("ValueSet expansion client proxy username or password not specified"); + proxyUrl = api.getProxyConfig().getUrl(); + proxyUsername = api.getProxyConfig().getUsername(); + proxyPassword = api.getProxyConfig().getPassword() == null ? null : api.getProxyConfig().getPassword(); } KeyStore valueSetExpansionClientTrustStore = trustStore("ValueSet expansion client", @@ -467,10 +456,9 @@ private ValueSetExpansionClient valueSetExpansionClientJersey() return new ValueSetExpansionClientJersey(valueSetExpansionServerBaseUrl, valueSetExpansionClientTrustStore, valueSetExpansionClientKeyStore, valueSetExpansionClientKeyStore == null ? null : valueSetExpansionClientKeyStorePassword, - valueSetExpansionClientBasicAuthUsername, valueSetExpansionClientBasicAuthPassword, - valueSetExpansionClientProxySchemeHostPort, valueSetExpansionClientProxyUsername, - valueSetExpansionClientProxyPassword, valueSetExpansionClientConnectTimeout, - valueSetExpansionClientReadTimeout, valueSetExpansionClientVerbose, objectMapper, fhirContext); + valueSetExpansionClientBasicAuthUsername, valueSetExpansionClientBasicAuthPassword, proxyUrl, + proxyUsername, proxyPassword, valueSetExpansionClientConnectTimeout, valueSetExpansionClientReadTimeout, + valueSetExpansionClientVerbose, objectMapper, fhirContext); } public TerminologyServerConnectionTestStatus testConnectionToTerminologyServer() @@ -478,25 +466,21 @@ public TerminologyServerConnectionTestStatus testConnectionToTerminologyServer() if (validationEnabled) logger.info( "Testing connection to terminology server with {trustStorePath: {}, certificatePath: {}, privateKeyPath: {}, privateKeyPassword: {}," - + " basicAuthUsername {}, basicAuthPassword {}, serverBase: {}, proxyUrl {}, proxyUsername {}, proxyPassword {}}", + + " basicAuthUsername: {}, basicAuthPassword: {}, serverBase: {}, proxy: values from 'DEV_DSF_PROXY'... config}", valueSetExpansionClientTrustCertificates, valueSetExpansionClientCertificate, valueSetExpansionClientCertificatePrivateKey, valueSetExpansionClientCertificatePrivateKeyPassword != null ? "***" : "null", valueSetExpansionClientBasicAuthUsername, - valueSetExpansionClientBasicAuthPassword != null ? "***" : "null", valueSetExpansionServerBaseUrl, - valueSetExpansionClientProxySchemeHostPort, valueSetExpansionClientProxyUsername, - valueSetExpansionClientProxyPassword != null ? "***" : "null"); + valueSetExpansionClientBasicAuthPassword != null ? "***" : "null", valueSetExpansionServerBaseUrl); else logger.warn( "Not testing connection to terminology server with {trustStorePath: {}, certificatePath: {}, privateKeyPath: {}, privateKeyPassword: {}," - + " basicAuthUsername {}, basicAuthPassword {}, serverBase: {}, proxyUrl {}, proxyUsername {}, proxyPassword {}}, validation disabled", + + " basicAuthUsername: {}, basicAuthPassword: {}, serverBase: {}, proxy: values from 'DEV_DSF_PROXY'... config}, validation disabled", valueSetExpansionClientTrustCertificates, valueSetExpansionClientCertificate, valueSetExpansionClientCertificatePrivateKey, valueSetExpansionClientCertificatePrivateKeyPassword != null ? "***" : "null", valueSetExpansionClientBasicAuthUsername, - valueSetExpansionClientBasicAuthPassword != null ? "***" : "null", valueSetExpansionServerBaseUrl, - valueSetExpansionClientProxySchemeHostPort, valueSetExpansionClientProxyUsername, - valueSetExpansionClientProxyPassword != null ? "***" : "null"); + valueSetExpansionClientBasicAuthPassword != null ? "***" : "null", valueSetExpansionServerBaseUrl); if (!validationEnabled) return TerminologyServerConnectionTestStatus.DISABLED; diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/PluginSnapshotGeneratorWithFileSystemCache.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/PluginSnapshotGeneratorWithFileSystemCache.java index 32541dac..2c031b37 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/PluginSnapshotGeneratorWithFileSystemCache.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/PluginSnapshotGeneratorWithFileSystemCache.java @@ -105,7 +105,7 @@ private SnapshotWithValidationMessages generateSnapshotAndWriteToCache(Structure if (PublicationStatus.DRAFT.equals(snapshot.getSnapshot().getStatus())) { - logger.info("Not writing StructureDefinition {}|{} with snapshot and status {} to cache", + logger.warn("Not writing StructureDefinition {}|{} with snapshot and status {} to cache", snapshot.getSnapshot().getUrl(), snapshot.getSnapshot().getVersion(), snapshot.getSnapshot().getStatus()); return snapshot; diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidationMain.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidationMain.java index ad8a65b6..048d70af 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidationMain.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidationMain.java @@ -252,7 +252,7 @@ private FileNameAndResource tryJson(String file) } catch (Exception e) { - logger.warn("Unable to read " + file + " as JSON, {}: {}", e.getClass().getName(), e.getMessage()); + logger.warn("Unable to read {} as JSON, {}: {}", file, e.getClass().getName(), e.getMessage()); return null; } } @@ -267,7 +267,7 @@ private FileNameAndResource tryXml(String file) } catch (Exception e) { - logger.warn("Unable to read " + file + " as XML, {}: {}", e.getClass().getName(), e.getMessage()); + logger.warn("Unable to read {} as XML, {}: {}", file, e.getClass().getName(), e.getMessage()); return null; } } diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidationPackage.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidationPackage.java index 3f14aba8..62608f61 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidationPackage.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidationPackage.java @@ -155,16 +155,19 @@ private Consumer doParseResources(FhirContext context, L || (entry.getFileName() != null && (entry.getFileName().startsWith("package/example") || entry.getFileName().endsWith(".index.json") || !entry.getFileName().endsWith(".json")))) { - logger.debug("Ignoring " + entry.getFileName()); + logger.debug("Ignoring {}", entry.getFileName()); return; } - logger.debug("Reading " + entry.getFileName()); + logger.debug("Reading {}", entry.getFileName()); try { - IBaseResource resource = context.newJsonParser() - .parseResource(new String(entry.getContent(), StandardCharsets.UTF_8)); + String resourceString = new String(entry.getContent(), StandardCharsets.UTF_8); + // fix profiles because their text contains invalid html + // Issue: https://github.com/medizininformatik-initiative/kerndatensatzmodul-mikrobiologie/issues/18 + resourceString = resourceString.replaceAll("

[\\s\\w\\[\\]]*", ""); + IBaseResource resource = context.newJsonParser().parseResource(resourceString); if (resource instanceof CodeSystem) codeSystems.add((CodeSystem) resource); diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidationPackageManagerImpl.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidationPackageManagerImpl.java index 661286b1..666e79ba 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidationPackageManagerImpl.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidationPackageManagerImpl.java @@ -17,6 +17,7 @@ import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport; import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain; import org.hl7.fhir.r4.model.Enumerations.BindingStrength; +import org.hl7.fhir.r4.model.Enumerations.PublicationStatus; import org.hl7.fhir.r4.model.StructureDefinition; import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent; @@ -367,9 +368,22 @@ private void createSnapshot(ValidationPackageWithDepedencies packageWithDependen definitions.stream() .filter(sd -> !sd.equals(diff) && !sd.getUrl().equals(diff.getBaseDefinition()) && !(sd.getUrl() + "|" + sd.getVersion()).equals(diff.getBaseDefinition())) - .map(sd -> sd.getUrl() + "|" + sd.getVersion()).sorted() + .map(sd -> sd.getUrl() + "|" + sd.getVersion()).distinct().sorted() .collect(Collectors.joining(", ", "[", "]"))); + String dependenciesWithDifferentStatus = definitions.stream() + .filter(sd -> !sd.equals(diff) && !sd.getUrl().equals(diff.getBaseDefinition()) + && !(sd.getUrl() + "|" + sd.getVersion()).equals(diff.getBaseDefinition())) + .filter(sd -> !sd.getStatus().equals(diff.getStatus())) + .map(sd -> sd.getUrl() + "|" + sd.getVersion() + ": " + sd.getStatus().toCode()).distinct().sorted() + .collect(Collectors.joining(", ")); + + if (PublicationStatus.ACTIVE.equals(diff.getStatus()) && !dependenciesWithDifferentStatus.isEmpty()) + { + logger.warn("StructureDefinition {}|{}, has dependencies with no active status [{}]", diff.getUrl(), + diff.getVersion(), dependenciesWithDifferentStatus); + } + definitions.stream().filter(sd -> sd.hasDifferential() && !sd.hasSnapshot() && !snapshots.containsKey(sd.getUrl() + "|" + sd.getVersion())).forEach(sd -> { diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValueSetExpansionClientWithModifiers.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValueSetExpansionClientWithModifiers.java index dde91d13..84db1c39 100644 --- a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValueSetExpansionClientWithModifiers.java +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValueSetExpansionClientWithModifiers.java @@ -11,6 +11,7 @@ import org.hl7.fhir.r4.model.ValueSet; import org.springframework.beans.factory.InitializingBean; +import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.value_set.KdsMikrobiologieBugFixer; import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.value_set.MissingEntriesIncluder; import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.value_set.ValueSetModifier; import jakarta.ws.rs.WebApplicationException; @@ -18,13 +19,14 @@ public class ValueSetExpansionClientWithModifiers implements ValueSetExpansionClient, InitializingBean { public static final ValueSetModifier MISSING_ENTRIES_INCLUDER = new MissingEntriesIncluder(); + public static final KdsMikrobiologieBugFixer KDS_MIKROBIOLOGIE_BUG_FIXER = new KdsMikrobiologieBugFixer(); private final ValueSetExpansionClient delegate; private final List valueSetModifiers = new ArrayList<>(); public ValueSetExpansionClientWithModifiers(ValueSetExpansionClient delegate) { - this(delegate, Arrays.asList(MISSING_ENTRIES_INCLUDER)); + this(delegate, Arrays.asList(KDS_MIKROBIOLOGIE_BUG_FIXER, MISSING_ENTRIES_INCLUDER)); } public ValueSetExpansionClientWithModifiers(ValueSetExpansionClient delegate, diff --git a/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/value_set/KdsMikrobiologieBugFixer.java b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/value_set/KdsMikrobiologieBugFixer.java new file mode 100644 index 00000000..f955e325 --- /dev/null +++ b/codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/value_set/KdsMikrobiologieBugFixer.java @@ -0,0 +1,39 @@ +package de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.value_set; + +import java.util.Map; + +import org.hl7.fhir.r4.model.ValueSet; + +import ca.uhn.fhir.context.FhirContext; + +/** + * Replace a few ValueSets from MII KDS Mikrobiologie module. This ValueSetModifier currently resolves the following + * issues: #15 + * #16 + */ +public class KdsMikrobiologieBugFixer implements ValueSetModifier +{ + private final Map fixedValueSets = Map.of( + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/ValueSet/mii-vs-mikrobio-empfindlichkeit-phenotyp-loinc", + "mii-vs-mikrobio-empfindlichkeit-phenotyp-loinc.json", + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/ValueSet/mii-vs-mikrobio-empfindlichkeit-genotyp-loinc", + "mii-vs-mikrobio-empfindlichkeit.json", + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/ValueSet/mii-vs-mikrobio-mre-klasse-snomedct", + "mii-vs-mikrobio-mre-klasse-snomedct.json"); + + @Override + public ValueSet modifyPreExpansion(ValueSet vs) + { + if (vs.getUrl() != null && vs.getVersion() != null && vs.getVersion().equals("2024.0.0")) + { + String fileName = fixedValueSets.get(vs.getUrl()); + if (fileName != null) + { + return (ValueSet) FhirContext.forR4().newJsonParser() + .parseResource(getClass().getResourceAsStream("/bugfix/fhir/ValueSet/" + fileName)); + } + } + + return vs; + } +} diff --git a/codex-process-data-transfer/src/main/resources/bugfix/fhir/ValueSet/mii-vs-mikrobio-empfindlichkeit-phenotyp-loinc.json b/codex-process-data-transfer/src/main/resources/bugfix/fhir/ValueSet/mii-vs-mikrobio-empfindlichkeit-phenotyp-loinc.json new file mode 100644 index 00000000..f79e32c8 --- /dev/null +++ b/codex-process-data-transfer/src/main/resources/bugfix/fhir/ValueSet/mii-vs-mikrobio-empfindlichkeit-phenotyp-loinc.json @@ -0,0 +1,55 @@ +{ + "resourceType": "ValueSet", + "url": "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/ValueSet/mii-vs-mikrobio-empfindlichkeit-phenotyp-loinc", + "title": "MII VS Mikrobio Empfindlichkeit Phenotyp [LOINC]", + "name": "MII_VS_Mikrobio_Empfindlichkeit_Phenotyp_LOINC", + "status": "active", + "version": "2024.0.0", + "compose": { + "include": [ + { + "filter": [ + { + "property": "CLASS", + "op": "=", + "value": "ABXBACT" + }, + { + "property": "PROPERTY", + "value": "LP6870-2", + "op": "=" + }, + { + "property": "STATUS", + "value": "ACTIVE", + "op": "=" + }, + { + "property": "ORDER_OBS", + "value": "Observation", + "op": "=" + } + ], + "system": "http://loinc.org" + } + ], + "exclude": [ + { + "system": "http://loinc.org", + "filter": [ + { + "property": "METHOD_TYP", + "value": "LP28723-2", + "op": "=" + } + ] + } + ] + }, + "text": { + "status": "generated", + "div": "

MII VS Mikrobio Empfindlichkeit Phenotyp [LOINC]

https://www.medizininformatik-initiative.de/fhir/ext/modul-mikrobiologie/ValueSet/mii-vs-mikrobio-empfindlichkeit-phenotyp-loinc
" + }, + "id": "mii-vs-mikrobio-empfindlichkeit-phenotyp-loinc", + "date": "2023-03-02T00:00:00.000Z" +} diff --git a/codex-process-data-transfer/src/main/resources/bugfix/fhir/ValueSet/mii-vs-mikrobio-empfindlichkeit.json b/codex-process-data-transfer/src/main/resources/bugfix/fhir/ValueSet/mii-vs-mikrobio-empfindlichkeit.json new file mode 100644 index 00000000..531926d4 --- /dev/null +++ b/codex-process-data-transfer/src/main/resources/bugfix/fhir/ValueSet/mii-vs-mikrobio-empfindlichkeit.json @@ -0,0 +1,38 @@ +{ + "resourceType": "ValueSet", + "id": "mii-vs-mikrobio-empfindlichkeit-genotyp-loinc", + "text": { + "status": "generated", + "div": "

MII VS Mikrobio Empfänglichkeit Genotyp

https://www.medizininformatik-initiative.de/fhir/ext/modul-mikrobio/ValueSet/mii-vs-mikrobio-empfindlichkeit-genotyp-loinc
" + }, + "url": "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/ValueSet/mii-vs-mikrobio-empfindlichkeit-genotyp-loinc", + "version": "2024.0.0", + "name": "MII_VS_Mikrobio_Empfänglichkeit_Genotyp_LOINC", + "title": "MII VS Mikrobio Empfänglichkeit Genotyp [LOINC]", + "status": "active", + "date": "2023-03-02T00:00:00.000Z", + "compose": { + "include": [ + { + "system": "http://loinc.org", + "filter": [ + { + "property": "CLASS", + "op": "=", + "value": "ABXBACT" + }, + { + "property": "PROPERTY", + "op": "=", + "value": "LP6870-2" + }, + { + "property": "METHOD_TYP", + "op": "=", + "value": "LP28723-2" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/codex-process-data-transfer/src/main/resources/bugfix/fhir/ValueSet/mii-vs-mikrobio-mre-klasse-snomedct.json b/codex-process-data-transfer/src/main/resources/bugfix/fhir/ValueSet/mii-vs-mikrobio-mre-klasse-snomedct.json new file mode 100644 index 00000000..ad52e8df --- /dev/null +++ b/codex-process-data-transfer/src/main/resources/bugfix/fhir/ValueSet/mii-vs-mikrobio-mre-klasse-snomedct.json @@ -0,0 +1,48 @@ +{ + "resourceType": "ValueSet", + "url": "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/ValueSet/mii-vs-mikrobio-mre-klasse-snomedct", + "title": "MII VS Mikrobio MRE Klasse [SNOMED CT]", + "name": "MII_VS_Mikrobio_MRE_Klasse_SNOMEDCT", + "status": "active", + "version": "2024.0.0", + "compose": { + "include": [ + { + "filter": [ + { + "property": "concept", + "op": "is-a", + "value": "409795000" + } + ], + "system": "http://snomed.info/sct" + }, + { + "filter": [ + { + "property": "concept", + "op": "is-a", + "value": "409794001" + } + ], + "system": "http://snomed.info/sct" + }, + { + "filter": [ + { + "property": "concept", + "op": "is-a", + "value": "409793007" + } + ], + "system": "http://snomed.info/sct" + } + ] + }, + "text": { + "status": "generated", + "div": "

MII VS Mikrobio MRE Klasse

https://www.medizininformatik-initiative.de/fhir/ext/modul-mikrobio/ValueSet/mii-vs-mikrobio-mre-klasse-snomedct
" + }, + "id": "mii-vs-mikrobio-mre-klasse-snomedct", + "date": "2023-03-02T00:00:00.000Z" +} \ No newline at end of file diff --git a/codex-process-data-transfer/src/main/resources/fhir/Bundle/SearchBundle.xml b/codex-process-data-transfer/src/main/resources/fhir/Bundle/SearchBundle.xml index 4372c167..ec284ed3 100644 --- a/codex-process-data-transfer/src/main/resources/fhir/Bundle/SearchBundle.xml +++ b/codex-process-data-transfer/src/main/resources/fhir/Bundle/SearchBundle.xml @@ -3,7 +3,7 @@ - + @@ -15,31 +15,13 @@ - + - - - - - - - - - - - - - - - - - - - + diff --git a/codex-process-data-transfer/src/main/resources/fhir/CodeSystem/data-transfer-error.xml b/codex-process-data-transfer/src/main/resources/fhir/CodeSystem/data-transfer-error.xml index da257853..9e4356b3 100644 --- a/codex-process-data-transfer/src/main/resources/fhir/CodeSystem/data-transfer-error.xml +++ b/codex-process-data-transfer/src/main/resources/fhir/CodeSystem/data-transfer-error.xml @@ -81,6 +81,11 @@ + + + + + diff --git a/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/PolarDataTest.java b/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/PolarDataTest.java index 2504c61f..283c1206 100644 --- a/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/PolarDataTest.java +++ b/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/PolarDataTest.java @@ -54,6 +54,7 @@ import org.hl7.fhir.r4.model.Procedure; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; +import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -85,6 +86,7 @@ import de.rwh.utils.crypto.io.PemIo; import dev.dsf.fhir.validation.ValueSetExpanderImpl; +@Ignore public class PolarDataTest { private static final Logger logger = LoggerFactory.getLogger(PolarDataTest.class); @@ -274,7 +276,7 @@ private static Bundle fixBundle(String trace, Bundle bundle, Set resourc fixIdentifier(eTrace, resource); - if (resource instanceof Patient patient) + if (resource instanceof Patient) { // nothing to do } @@ -303,7 +305,7 @@ else if (resource instanceof Condition condition) { fixReference(eTrace + "/subject", condition.getSubject(), idTranslation); } - else if (resource instanceof Medication medication) + else if (resource instanceof Medication) { // nothing to do } diff --git a/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/AbstractFhirClientTest.java b/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/AbstractFhirClientTest.java index 7c4ea6bd..9f241dcc 100644 --- a/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/AbstractFhirClientTest.java +++ b/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/fhir/AbstractFhirClientTest.java @@ -36,7 +36,7 @@ public void testSetSearchBundleWithExportTo() throws Exception DataStoreClient dataClient = Mockito.mock(DataStoreClient.class); DataLogger dataLogger = Mockito.mock(DataLogger.class); when(dataClient.getSearchBundleOverride()) - .thenReturn(Paths.get("src/main/resources/fhir/Bundle/SearchBundle.xml")); + .thenReturn(Paths.get("src/test/resources/fhir/Bundle/SearchBundle.xml")); when(dataClient.getFhirContext()).thenReturn(fhirContext); AbstractFhirClient client = Mockito.mock(AbstractFhirClient.class, Mockito.withSettings().useConstructor(dataClient, dataLogger).defaultAnswer(CALLS_REAL_METHODS)); @@ -69,7 +69,7 @@ public void testSetSearchBundleWithExportFromAndExportTo() throws Exception DataStoreClient dataClient = Mockito.mock(DataStoreClient.class); DataLogger dataLogger = Mockito.mock(DataLogger.class); when(dataClient.getSearchBundleOverride()) - .thenReturn(Paths.get("src/main/resources/fhir/Bundle/SearchBundle.xml")); + .thenReturn(Paths.get("src/test/resources/fhir/Bundle/SearchBundle.xml")); when(dataClient.getFhirContext()).thenReturn(fhirContext); AbstractFhirClient client = Mockito.mock(AbstractFhirClient.class, Mockito.withSettings().useConstructor(dataClient, dataLogger).defaultAnswer(CALLS_REAL_METHODS)); @@ -104,7 +104,7 @@ public void testSetSearchBundleWithPatientIdAndExportFromAndExportTo() throws Ex DataStoreClient dataClient = Mockito.mock(DataStoreClient.class); DataLogger dataLogger = Mockito.mock(DataLogger.class); when(dataClient.getSearchBundleOverride()) - .thenReturn(Paths.get("src/main/resources/fhir/Bundle/SearchBundle.xml")); + .thenReturn(Paths.get("src/test/resources/fhir/Bundle/SearchBundle.xml")); when(dataClient.getFhirContext()).thenReturn(fhirContext); AbstractFhirClient client = Mockito.mock(AbstractFhirClient.class, Mockito.withSettings().useConstructor(dataClient, dataLogger).defaultAnswer(CALLS_REAL_METHODS)); @@ -140,7 +140,7 @@ public void testSetSearchBundleWithPseudonymIdAndExportFromAndExportTo() throws DataStoreClient dataClient = Mockito.mock(DataStoreClient.class); DataLogger dataLogger = Mockito.mock(DataLogger.class); when(dataClient.getSearchBundleOverride()) - .thenReturn(Paths.get("src/main/resources/fhir/Bundle/SearchBundle.xml")); + .thenReturn(Paths.get("src/test/resources/fhir/Bundle/SearchBundle.xml")); when(dataClient.getFhirContext()).thenReturn(fhirContext); AbstractFhirClient client = Mockito.mock(AbstractFhirClient.class, Mockito.withSettings().useConstructor(dataClient, dataLogger).defaultAnswer(CALLS_REAL_METHODS)); diff --git a/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/MiiTest.java b/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/MiiTest.java index f385c0d4..090cc8e3 100644 --- a/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/MiiTest.java +++ b/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/MiiTest.java @@ -71,9 +71,9 @@ public void testInit() throws Exception for (ValidationPackageWithDepedencies p : packagesWithDependencies) { - logger.info(p.getName() + "|" + p.getVersion()); + logger.info("{}|{}", p.getName(), p.getVersion()); for (ValidationPackage d : p.getDependencies()) - logger.info("\t" + d.getName() + "|" + d.getVersion()); + logger.info("\t{}|{}", d.getName(), d.getVersion()); } } diff --git a/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidateDataLearningTest.java b/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidateDataLearningTest.java index b94938eb..ca2f78f3 100644 --- a/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidateDataLearningTest.java +++ b/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/validation/ValidateDataLearningTest.java @@ -190,8 +190,8 @@ public void testDownloadTarGzAndParseDescriptor() throws Exception }); ValidationPackageDescriptor descriptor = validationPackage.getDescriptor(mapper); - logger.debug(descriptor.getName() + "/" + descriptor.getVersion() + ":"); - descriptor.getDependencies().forEach((k, v) -> logger.debug("\t" + k + "/" + v)); + logger.debug("{}/{}:", descriptor.getName(), descriptor.getVersion()); + descriptor.getDependencies().forEach((k, v) -> logger.debug("\t{}/{}", k, v)); } @Test @@ -372,7 +372,7 @@ public void testGenerateSnapshots() throws Exception packageWithDependencies.getAllStructureDefinitions().stream() .sorted(Comparator.comparing(StructureDefinition::getUrl) .thenComparing(Comparator.comparing(StructureDefinition::getVersion))) - .forEach(s -> logger.debug(s.getUrl() + " " + s.getVersion())); + .forEach(s -> logger.debug("{} {}", s.getUrl(), s.getVersion())); StructureDefinition miiRef = packageWithDependencies.getAllStructureDefinitions().stream() .filter(s -> "https://www.medizininformatik-initiative.de/fhir/core/StructureDefinition/MII-Reference" @@ -427,13 +427,13 @@ private void printTree(StructureDefinition def, Map { logger.debug(""); logger.debug(" Profile-Dependencies:"); - profileDependencies.stream().sorted().forEach(url -> logger.debug(" " + url)); + profileDependencies.stream().sorted().forEach(url -> logger.debug(" {}", url)); } if (!targetProfileDependencies.isEmpty()) { logger.debug(""); logger.debug(" TargetProfile-Dependencies:"); - targetProfileDependencies.stream().sorted().forEach(url -> logger.debug(" " + url)); + targetProfileDependencies.stream().sorted().forEach(url -> logger.debug(" {}", url)); } } @@ -441,13 +441,13 @@ private void printTree(String k, StructureDefinition def, Map structureDefinitionsByUrl, String indentation, Set profileDependencies, Set targetProfileDependencies) { - logger.debug(indentation + "Profile: " + k); + logger.debug("{}Profile: {}", indentation, k); for (ElementDefinition element : def.getDifferential().getElement()) { if (element.getType().stream().filter(t -> !t.getProfile().isEmpty() || !t.getTargetProfile().isEmpty()) .findAny().isPresent()) { - logger.debug(indentation + " Element: " + element.getId() + " (Path: " + element.getPath() + ")"); + logger.debug("{} Element: {} (Path: {})", indentation, element.getId(), element.getPath()); for (TypeRefComponent type : element.getType()) { if (!type.getProfile().isEmpty()) @@ -461,7 +461,7 @@ private void printTree(String k, StructureDefinition def, structureDefinitionsByUrl, indentation + " ", profileDependencies, targetProfileDependencies); else - logger.debug(indentation + " Profile: " + profile.getValue() + " ?"); + logger.debug("{} Profile: {} ?", indentation, profile.getValue()); } } if (!type.getTargetProfile().isEmpty()) @@ -469,7 +469,7 @@ private void printTree(String k, StructureDefinition def, for (CanonicalType targetProfile : type.getTargetProfile()) { targetProfileDependencies.add(targetProfile.getValue()); - logger.debug(indentation + " TargetProfile: " + targetProfile.getValue()); + logger.debug("{} TargetProfile: {}", indentation, targetProfile.getValue()); } } } diff --git a/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/variables/PatientReferenceListTest.java b/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/variables/PatientReferenceListTest.java index aad7e131..e31b3cba 100644 --- a/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/variables/PatientReferenceListTest.java +++ b/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/variables/PatientReferenceListTest.java @@ -10,6 +10,7 @@ import java.util.UUID; import org.hl7.fhir.r4.model.Identifier; +import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,6 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; +@Ignore public class PatientReferenceListTest { private static final Logger logger = LoggerFactory.getLogger(PatientReferenceListTest.class); diff --git a/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/variables/PatientReferenceTest.java b/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/variables/PatientReferenceTest.java index 39b43140..abe0d615 100644 --- a/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/variables/PatientReferenceTest.java +++ b/codex-process-data-transfer/src/test/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/variables/PatientReferenceTest.java @@ -9,6 +9,7 @@ import java.util.UUID; import org.hl7.fhir.r4.model.Identifier; +import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,6 +19,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; +@Ignore public class PatientReferenceTest { private static final Logger logger = LoggerFactory.getLogger(PatientReferenceTest.class); diff --git a/codex-process-data-transfer/src/test/resources/fhir/Bundle/SearchBundle.xml b/codex-process-data-transfer/src/test/resources/fhir/Bundle/SearchBundle.xml new file mode 100644 index 00000000..05aebb53 --- /dev/null +++ b/codex-process-data-transfer/src/test/resources/fhir/Bundle/SearchBundle.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/codex-process-data-transfer/src/test/resources/fhir/Bundle/dic_fhir_store_demo_risk_principe.json b/codex-process-data-transfer/src/test/resources/fhir/Bundle/dic_fhir_store_demo_risk_principe.json new file mode 100644 index 00000000..0193624b --- /dev/null +++ b/codex-process-data-transfer/src/test/resources/fhir/Bundle/dic_fhir_store_demo_risk_principe.json @@ -0,0 +1,2068 @@ +{ + "resourceType": "Bundle", + "type": "transaction", + "entry": [ + { + "fullUrl": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba", + "resource": { + "resourceType": "Patient", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/core/modul-person/StructureDefinition/PatientPseudonymisiert" + ] + }, + "identifier": [ + { + "type": { + "coding": [ + { + "code": "PSEUDED", + "system": "http://terminology.hl7.org/CodeSystem/v3-ObservationValue" + } + ] + }, + "system": "urn:ietf:rfc:4122", + "value": "07f602e0-579e-4fe3-95af-381728b00015" + } + ], + "gender": "other", + "_gender": { + "extension": [ + { + "url": "http://fhir.de/StructureDefinition/gender-amtlich-de", + "valueCoding": { + "code": "D", + "system": "http://fhir.de/CodeSystem/gender-amtlich-de", + "display": "divers" + } + } + ] + }, + "birthDate": "2022-12-01", + "managingOrganization": { + "identifier": { + "system": "https://www.medizininformatik-initiative.de/fhir/core/CodeSystem/core-location-identifier", + "value": "MHH" + } + } + }, + "request": { + "method": "POST", + "url": "Patient" + } + }, + { + "fullUrl": "urn:uuid:d7f5f52c-ce49-4e2e-8b2a-b5b4a602a6e2", + "resource": { + "resourceType": "Encounter", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/core/modul-fall/StructureDefinition/KontaktGesundheitseinrichtung" + ] + }, + "serviceType": { + "coding": [ + { + "system": "https://www.medizininformatik-initiative.de/fhir/core/modul-fall/CodeSystem/Fachabteilungsschluessel", + "code": "3700", + "display": "Sonstige Fachabteilung", + "userSelected": false + } + ] + }, + "class": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + }, + "status": "finished", + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "identifier": [ + { + "type": { + "coding": [ + { + "code": "VN", + "system": "http://terminology.hl7.org/CodeSystem/v2-0203" + } + ] + }, + "system": "http://medizininformatik-initiative.de/fhir/NamingSystem/Aufnahmenummer/MusterKrankenhaus", + "value": "F_0000001" + } + ], + "diagnosis": [ + { + "use": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + }, + "condition": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + }, + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "period": { + "start": "2020-01-08T07:00:00+01:00", + "end": "2020-01-11T05:00:00+01:00" + } + }, + "request": { + "method": "POST", + "url": "Encounter" + } + }, + { + "fullUrl": "urn:uuid:bb8e9846-9bc1-4a7a-8e1a-cf941c5fddb6", + "resource": { + "resourceType": "Observation", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-kultur-nachweis" + ] + }, + "contained": [ + { + "resourceType": "Observation", + "id": "empf-1", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-empfindlichkeit" + ] + }, + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "18868-0", + "display": "Aztreonam [Susceptibility]" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueQuantity": { + "system": "http://unitsofmeasure.org", + "value": 32, + "code": "mg/L", + "unit": "mg/L" + }, + "specimen": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + }, + "interpretation": [ + { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "1306577009", + "display": "European Committee on Antimicrobial Susceptibility Testing category 2019 Susceptible, standard dosing regimen", + "version": "20240301" + } + ] + } + ] + }, + { + "resourceType": "Observation", + "id": "mre-1", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-mre-klasse" + ] + }, + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "1285113001", + "display": "Type of antimicrobial resistant organism (observable entity)" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "115329001", + "display": "Methicillin resistant Staphylococcus aureus" + } + ] + }, + "specimen": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + }, + { + "resourceType": "Specimen", + "id": "probe-1", + "meta": { + "profile": [ + "http://hl7.org/fhir/StructureDefinition/Specimen" + ] + }, + "collection": { + "collectedDateTime": "2011-08-16T06:15:00Z" + } + } + ], + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "11475-1", + "display": "Microorganism identified in Specimen by Culture" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "260373001", + "display": "Detected (qualifier value)" + } + ] + }, + "specimen": { + "reference": "#probe-1" + }, + "hasMember": [ + { + "reference": "#empf-1" + }, + { + "reference": "#mre-1" + } + ], + "encounter": { + "reference": "urn:uuid:d7f5f52c-ce49-4e2e-8b2a-b5b4a602a6e2" + }, + "component": [ + { + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "89248-9" + } + ] + }, + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "840533007", + "display": "Severe acute respiratory syndrome coronavirus 2 (organism)" + } + ] + } + } + ] + }, + "request": { + "method": "POST", + "url": "Observation" + } + }, + { + "fullUrl": "urn:uuid:17e03942-3286-4b7c-86c2-9ff7f218a74e", + "resource": { + "resourceType": "Observation", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-kultur-nachweis" + ] + }, + "contained": [ + { + "resourceType": "Observation", + "id": "empf-1", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-empfindlichkeit" + ] + }, + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "18868-0", + "display": "Aztreonam [Susceptibility]" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueQuantity": { + "system": "http://unitsofmeasure.org", + "value": 32, + "code": "mg/L", + "unit": "mg/L" + }, + "specimen": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + }, + "interpretation": [ + { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "1306577009", + "display": "European Committee on Antimicrobial Susceptibility Testing category 2019 Susceptible, standard dosing regimen", + "version": "20240301" + } + ] + } + ] + }, + { + "resourceType": "Observation", + "id": "mre-1", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-mre-klasse" + ] + }, + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "1285113001", + "display": "Type of antimicrobial resistant organism (observable entity)" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "113727004", + "display": "Vancomycin resistant Enterococcus" + } + ] + }, + "specimen": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + }, + { + "resourceType": "Specimen", + "id": "probe-1", + "meta": { + "profile": [ + "http://hl7.org/fhir/StructureDefinition/Specimen" + ] + }, + "collection": { + "collectedDateTime": "2011-08-16T06:15:00Z" + } + } + ], + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "11475-1", + "display": "Microorganism identified in Specimen by Culture" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "260373001", + "display": "Detected (qualifier value)" + } + ] + }, + "specimen": { + "reference": "#probe-1" + }, + "hasMember": [ + { + "reference": "#empf-1" + }, + { + "reference": "#mre-1" + } + ], + "encounter": { + "reference": "urn:uuid:d7f5f52c-ce49-4e2e-8b2a-b5b4a602a6e2" + }, + "component": [ + { + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "89248-9" + } + ] + }, + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "840533007", + "display": "Severe acute respiratory syndrome coronavirus 2 (organism)" + } + ] + } + } + ] + }, + "request": { + "method": "POST", + "url": "Observation" + } + }, + { + "fullUrl": "urn:uuid:863d6462-1293-4999-b173-b37d0b817444", + "resource": { + "resourceType": "Observation", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-kultur-nachweis" + ] + }, + "contained": [ + { + "resourceType": "Observation", + "id": "empf-1", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-empfindlichkeit" + ] + }, + "identifier": [ + { + "type": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "OBI" + } + ] + }, + "system": "https://example.org/fhir/sid/test-lab-results", + "value": "59826-8_1234567890", + "assigner": { + "identifier": { + "system": "https://www.medizininformatik-initiative.de/fhir/core/CodeSystem/core-location-identifier", + "value": "DIZ-ID" + } + } + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "18868-0", + "display": "Aztreonam [Susceptibility]" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueQuantity": { + "system": "http://unitsofmeasure.org", + "value": 32, + "code": "mg/L", + "unit": "mg/L" + }, + "specimen": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + }, + "interpretation": [ + { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "1306577009", + "display": "European Committee on Antimicrobial Susceptibility Testing category 2019 Susceptible, standard dosing regimen", + "version": "20240301" + } + ] + } + ] + }, + { + "resourceType": "Observation", + "id": "mrgn-1", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-mrgn-klasse" + ] + }, + "identifier": [ + { + "type": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "OBI" + } + ] + }, + "system": "https://example.org/fhir/sid/test-lab-results", + "value": "59826-8_1234567890", + "assigner": { + "identifier": { + "system": "https://www.medizininformatik-initiative.de/fhir/core/CodeSystem/core-location-identifier", + "value": "DIZ-ID" + } + } + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "99780-9", + "display": "Multidrug resistant gram-negative organism classification [Type]" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://loinc.org", + "code": "LA33214-0", + "display": "2MRGN" + } + ] + }, + "specimen": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + }, + { + "resourceType": "Specimen", + "id": "probe-1", + "meta": { + "profile": [ + "http://hl7.org/fhir/StructureDefinition/Specimen" + ] + }, + "collection": { + "collectedDateTime": "2011-08-16T06:15:00Z" + } + } + ], + "identifier": [ + { + "type": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "OBI" + } + ] + }, + "system": "https://example.org/fhir/sid/test-lab-results", + "value": "59826-8_1234567890", + "assigner": { + "identifier": { + "system": "https://www.medizininformatik-initiative.de/fhir/core/CodeSystem/core-location-identifier", + "value": "DIZ-ID" + } + } + } + ], + "status": "final", + "performer": [ + { + "identifier": { + "system": "https://www.medizininformatik-initiative.de/fhir/core/CodeSystem/core-location-identifiers", + "value": "Charité" + } + } + ], + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "11475-1", + "display": "Microorganism identified in Specimen by Culture" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "260373001", + "display": "Detected (qualifier value)" + } + ] + }, + "specimen": { + "reference": "#probe-1" + }, + "hasMember": [ + { + "reference": "#empf-1" + }, + { + "reference": "#mrgn-1" + } + ], + "encounter": { + "reference": "urn:uuid:d7f5f52c-ce49-4e2e-8b2a-b5b4a602a6e2" + }, + "component": [ + { + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "89248-9" + } + ] + }, + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "840533007", + "display": "Severe acute respiratory syndrome coronavirus 2 (organism)" + } + ] + } + } + ] + }, + "request": { + "method": "POST", + "url": "Observation" + } + }, + { + "fullUrl": "urn:uuid:37a62b3c-2521-4c8c-b713-b3ae41f9224c", + "resource": { + "resourceType": "Observation", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-kultur-nachweis" + ] + }, + "contained": [ + { + "resourceType": "Observation", + "id": "empf-1", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-empfindlichkeit" + ] + }, + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "18868-0", + "display": "Aztreonam [Susceptibility]" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "specimen": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + }, + "valueQuantity": { + "system": "http://unitsofmeasure.org", + "value": 32, + "code": "mg/L", + "unit": "mg/L" + }, + "interpretation": [ + { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "1306577009", + "display": "European Committee on Antimicrobial Susceptibility Testing category 2019 Susceptible, standard dosing regimen", + "version": "20240301" + } + ] + } + ] + }, + { + "resourceType": "Observation", + "id": "mrgn-1", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-mrgn-klasse" + ] + }, + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "99780-9", + "display": "Multidrug resistant gram-negative organism classification [Type]" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://loinc.org", + "code": "LA33215-7", + "display": "3MRGN" + } + ] + }, + "specimen": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + }, + { + "resourceType": "Specimen", + "id": "probe-1", + "meta": { + "profile": [ + "http://hl7.org/fhir/StructureDefinition/Specimen" + ] + }, + "collection": { + "collectedDateTime": "2011-08-16T06:15:00Z" + } + } + ], + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "11475-1", + "display": "Microorganism identified in Specimen by Culture" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "260373001", + "display": "Detected (qualifier value)" + } + ] + }, + "specimen": { + "reference": "#probe-1" + }, + "hasMember": [ + { + "reference": "#empf-1" + }, + { + "reference": "#mrgn-1" + } + ], + "encounter": { + "reference": "urn:uuid:d7f5f52c-ce49-4e2e-8b2a-b5b4a602a6e2" + }, + "component": [ + { + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "89248-9" + } + ] + }, + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "840533007", + "display": "Severe acute respiratory syndrome coronavirus 2 (organism)" + } + ] + } + } + ] + }, + "request": { + "method": "POST", + "url": "Observation" + } + }, + { + "fullUrl": "urn:uuid:e616f94e-534d-40a4-9d15-59a5dc271e48", + "resource": { + "resourceType": "Observation", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-kultur-nachweis" + ] + }, + "contained": [ + { + "resourceType": "Observation", + "id": "empf-1", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-empfindlichkeit" + ] + }, + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "18868-0", + "display": "Aztreonam [Susceptibility]" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueQuantity": { + "system": "http://unitsofmeasure.org", + "value": 32, + "code": "mg/L", + "unit": "mg/L" + }, + "specimen": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + }, + "interpretation": [ + { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "1306577009", + "display": "European Committee on Antimicrobial Susceptibility Testing category 2019 Susceptible, standard dosing regimen", + "version": "20240301" + } + ] + } + ] + }, + { + "resourceType": "Observation", + "id": "mrgn-1", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-mrgn-klasse" + ] + }, + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "99780-9", + "display": "Multidrug resistant gram-negative organism classification [Type]" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://loinc.org", + "code": "LA33215-7", + "display": "3MRGN" + } + ] + }, + "specimen": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + }, + { + "resourceType": "Specimen", + "id": "probe-1", + "meta": { + "profile": [ + "http://hl7.org/fhir/StructureDefinition/Specimen" + ] + }, + "collection": { + "collectedDateTime": "2011-08-16T06:15:00Z" + } + } + ], + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "11475-1", + "display": "Microorganism identified in Specimen by Culture" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "260373001", + "display": "Detected (qualifier value)" + } + ] + }, + "specimen": { + "reference": "#probe-1" + }, + "hasMember": [ + { + "reference": "#empf-1" + }, + { + "reference": "#mrgn-1" + } + ], + "encounter": { + "reference": "urn:uuid:d7f5f52c-ce49-4e2e-8b2a-b5b4a602a6e2" + }, + "component": [ + { + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "89248-9" + } + ] + }, + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "840533007", + "display": "Severe acute respiratory syndrome coronavirus 2 (organism)" + } + ] + } + } + ] + }, + "request": { + "method": "POST", + "url": "Observation" + } + }, + { + "fullUrl": "urn:uuid:a96ea433-8a27-4f67-9606-c19b0a4c12fa", + "resource": { + "resourceType": "Observation", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-kultur-nachweis" + ] + }, + "contained": [ + { + "resourceType": "Observation", + "id": "empf-1", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-empfindlichkeit" + ] + }, + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "18868-0", + "display": "Aztreonam [Susceptibility]" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueQuantity": { + "system": "http://unitsofmeasure.org", + "value": 32, + "code": "mg/L", + "unit": "mg/L" + }, + "specimen": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + }, + "interpretation": [ + { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "1306577009", + "display": "European Committee on Antimicrobial Susceptibility Testing category 2019 Susceptible, standard dosing regimen", + "version": "20240301" + } + ] + } + ] + }, + { + "resourceType": "Observation", + "id": "mrgn-1", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-mrgn-klasse" + ] + }, + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "99780-9", + "display": "Multidrug resistant gram-negative organism classification [Type]" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://loinc.org", + "code": "LA33215-7", + "display": "3MRGN" + } + ] + }, + "specimen": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + }, + { + "resourceType": "Specimen", + "id": "probe-1", + "meta": { + "profile": [ + "http://hl7.org/fhir/StructureDefinition/Specimen" + ] + }, + "collection": { + "collectedDateTime": "2011-08-16T06:15:00Z" + } + } + ], + "identifier": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unsupported" + } + ] + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "11475-1", + "display": "Microorganism identified in Specimen by Culture" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "260373001", + "display": "Detected (qualifier value)" + } + ] + }, + "specimen": { + "reference": "#probe-1" + }, + "hasMember": [ + { + "reference": "#empf-1" + }, + { + "reference": "#mrgn-1" + } + ], + "encounter": { + "reference": "urn:uuid:d7f5f52c-ce49-4e2e-8b2a-b5b4a602a6e2" + }, + "component": [ + { + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "89248-9" + } + ] + }, + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "840533007", + "display": "Severe acute respiratory syndrome coronavirus 2 (organism)" + } + ] + } + } + ] + }, + "request": { + "method": "POST", + "url": "Observation" + } + }, + { + "fullUrl": "urn:uuid:09059c94-cf9e-4d9e-aefd-fff90ebe8873", + "resource": { + "resourceType": "Observation", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-molekulare-diagnostik" + ] + }, + "contained": [ + { + "resourceType": "Specimen", + "id": "probe-1", + "meta": { + "profile": [ + "http://hl7.org/fhir/StructureDefinition/Specimen" + ] + }, + "collection": { + "collectedDateTime": "2011-08-16T06:15:00Z" + } + } + ], + "identifier": [ + { + "type": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "OBI" + } + ] + }, + "system": "https://example.org/fhir/sid/test-lab-results", + "value": "59826-8_1234567890", + "assigner": { + "identifier": { + "system": "https://www.medizininformatik-initiative.de/fhir/core/CodeSystem/core-location-identifier", + "value": "DIZ-ID" + } + } + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "92253-4", + "display": "Microorganism identified in Isolate or Specimen by Molecular genetics method" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "10828004", + "display": "Positive" + } + ] + }, + "specimen": { + "reference": "#probe-1" + }, + "encounter": { + "reference": "urn:uuid:d7f5f52c-ce49-4e2e-8b2a-b5b4a602a6e2" + }, + "component": [ + { + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "398545005" + } + ] + }, + "valueQuantity": { + "value": 25.5, + "unit": "ng/mL", + "system": "http://unitsofmeasure.org", + "code": "ng/mL" + } + }, + { + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "89248-9" + } + ] + }, + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "840533007", + "display": "Severe acute respiratory syndrome coronavirus 2 (organism)" + } + ] + } + } + ] + }, + "request": { + "method": "POST", + "url": "Observation" + } + }, + { + "fullUrl": "urn:uuid:7bc9bea7-852f-446e-83f9-9bab165b5c17", + "resource": { + "resourceType": "Observation", + "meta": { + "profile": [ + "https://www.medizininformatik-initiative.de/fhir/modul-mikrobio/StructureDefinition/mii-pr-mikrobio-molekulare-diagnostik" + ] + }, + "contained": [ + { + "resourceType": "Specimen", + "id": "probe-1", + "meta": { + "profile": [ + "http://hl7.org/fhir/StructureDefinition/Specimen" + ] + }, + "collection": { + "collectedDateTime": "2011-08-16T06:15:00Z" + } + } + ], + "identifier": [ + { + "type": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "OBI" + } + ] + }, + "system": "https://example.org/fhir/sid/test-lab-results", + "value": "59826-8_1234567890", + "assigner": { + "identifier": { + "system": "https://www.medizininformatik-initiative.de/fhir/core/CodeSystem/core-location-identifier", + "value": "DIZ-ID" + } + } + } + ], + "status": "final", + "category": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/observation-category", + "code": "laboratory", + "display": "Laboratory" + }, + { + "system": "http://loinc.org", + "code": "26436-6", + "display": "Laboratory studies (set)" + }, + { + "system": "http://loinc.org", + "code": "18725-2", + "display": "Microbiology studies" + } + ] + } + ], + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "92253-4", + "display": "Microorganism identified in Isolate or Specimen by Molecular genetics method" + } + ] + }, + "subject": { + "reference": "urn:uuid:1a4cef52-3418-4be7-b1e2-30dd9639f7ba" + }, + "effectiveDateTime": "2018-11-20T12:05:00+01:00", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "10828004", + "display": "Positive" + } + ] + }, + "specimen": { + "reference": "#probe-1" + }, + "encounter": { + "reference": "urn:uuid:d7f5f52c-ce49-4e2e-8b2a-b5b4a602a6e2" + }, + "performer": [ + { + "identifier": { + "system": "https://www.medizininformatik-initiative.de/fhir/core/CodeSystem/core-location-identifiers", + "value": "Charité" + } + } + ], + "component": [ + { + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "398545005" + } + ] + }, + "valueQuantity": { + "value": 25.5, + "unit": "ng/mL", + "system": "http://unitsofmeasure.org", + "code": "ng/mL" + } + }, + { + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "89248-9" + } + ] + }, + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "840533007", + "display": "Severe acute respiratory syndrome coronavirus 2 (organism)" + } + ] + } + } + ] + }, + "request": { + "method": "POST", + "url": "Observation" + } + } + ] +} \ No newline at end of file diff --git a/codex-processes-ap1-docker-test-setup/docker-compose.yml b/codex-processes-ap1-docker-test-setup/docker-compose.yml index 44570507..f40c528e 100644 --- a/codex-processes-ap1-docker-test-setup/docker-compose.yml +++ b/codex-processes-ap1-docker-test-setup/docker-compose.yml @@ -74,7 +74,7 @@ services: dic-fhir: - image: ghcr.io/datasharingframework/fhir:1.3.0 + image: ghcr.io/datasharingframework/fhir:1.5.0 restart: "no" ports: - 127.0.0.1:5000:5000 @@ -136,7 +136,7 @@ services: - db - proxy dic-bpe: - image: ghcr.io/datasharingframework/bpe:1.3.0 + image: ghcr.io/datasharingframework/bpe:1.5.0 restart: "no" ports: - 127.0.0.1:5003:5003 @@ -220,7 +220,7 @@ services: aliases: - dic-fhir-store dic-fhir-store-blaze: - image: ghcr.io/num-codex/blaze + image: samply/blaze ports: - 127.0.0.1:8080:8080 environment: @@ -232,7 +232,7 @@ services: dts-fhir: - image: ghcr.io/datasharingframework/fhir:1.3.0 + image: ghcr.io/datasharingframework/fhir:1.5.0 restart: "no" ports: - 127.0.0.1:5001:5001 @@ -293,7 +293,7 @@ services: - db - proxy dts-bpe: - image: ghcr.io/datasharingframework/bpe:1.3.0 + image: ghcr.io/datasharingframework/bpe:1.5.0 restart: "no" ports: - 127.0.0.1:5004:5004 @@ -356,7 +356,7 @@ services: crr-fhir: - image: ghcr.io/datasharingframework/fhir:1.3.0 + image: ghcr.io/datasharingframework/fhir:1.5.0 restart: "no" ports: - 127.0.0.1:5002:5002 @@ -417,7 +417,7 @@ services: - db - proxy crr-bpe: - image: ghcr.io/datasharingframework/bpe:1.3.0 + image: ghcr.io/datasharingframework/bpe:1.5.0 restart: "no" ports: - 127.0.0.1:5005:5005 diff --git a/codex-processes-ap1-test-data-generator/pom.xml b/codex-processes-ap1-test-data-generator/pom.xml index d1c5fc71..3bdc202c 100644 --- a/codex-processes-ap1-test-data-generator/pom.xml +++ b/codex-processes-ap1-test-data-generator/pom.xml @@ -6,7 +6,7 @@ de.netzwerk-universitaetsmedizin.codex codex-processes-ap1 - 1.0.0.0 + 1.1.0.0 diff --git a/pom.xml b/pom.xml index 59d3cb11..82b7ca28 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.netzwerk-universitaetsmedizin.codex codex-processes-ap1 - 1.0.0.0 + 1.1.0.0 pom @@ -20,7 +20,7 @@ ${project.basedir} 5.1.0 - 1.3.0 + 1.5.0 Business processes for the NUM RDP project (AP1) as plugins for the Data Sharing Framework.