Search in sources :

Example 1 with REPLACES

use of org.hl7.fhir.r4.model.Composition.DocumentRelationshipType.REPLACES in project hl7v2-fhir-converter by LinuxForHealth.

the class HL7MergeFHIRConversionTest method validateHappyPathADT_A34WithMRG.

// Test ADT_A34 with one MRG segment (the most it supports).
@Test
void validateHappyPathADT_A34WithMRG() {
    String hl7message = "MSH|^~\\&|SENDING_APPLICATION|SENDING_FACILITY|RECEIVING_APPLICATION|RECEIVING_FACILITY|||ADT^A34||P|2.3||||\r" + "EVN|A40|20110613122406637||01\r" + // Identifier value 234 with no system and no identifier type
    "PID|1||123^^^^MR||||||||||||||||||||||||||||||||||||\r" + // Identifier value 456 with no system and no identifier type
    "MRG|456||||||\r";
    // Convert hl7 message
    List<BundleEntryComponent> e = ResourceUtils.createFHIRBundleFromHL7MessageReturnEntryList(ftv, hl7message);
    // Find the patient resources in the FHIR bundle.
    List<Resource> patientResources = ResourceUtils.getResourceList(e, ResourceType.Patient);
    // There should be 2 - One for the PID segment and one for the MRG segment
    assertThat(patientResources).hasSize(2);
    // Get first patient and associated identifiers and id.
    Patient patientOne = PatientUtils.getPatientFromResource(patientResources.get(0));
    String patientOneId = patientOne.getId();
    List<Identifier> patientOneIdentifierList = patientOne.getIdentifier();
    // Get second patient and associated identifiers and id.
    Patient patientTwo = PatientUtils.getPatientFromResource(patientResources.get(1));
    String patientTwoId = patientTwo.getId();
    List<Identifier> patientTwoIdentifierList = patientTwo.getIdentifier();
    /*-----------Verify Patient One-----------*/
    // Verify patient one's identifier is set correctly (this is the patient build
    // from the PID segment)
    // 
    // "identifier":[
    // {
    // "type":{
    // "coding":[
    // {
    // "system":"http://terminology.hl7.org/CodeSystem/v2-0203",
    // "code":"MR",
    // "display":"Medical record number"
    // }
    // ]
    // },
    // "value":"123"
    // },
    // {
    // "use":"old",
    // "value":"456"
    // }
    // ]
    // Verify the patient has two identifiers
    assertThat(patientOneIdentifierList).hasSize(2);
    // Verify the identifier values are correct.
    assertThat(patientOneIdentifierList.get(0).getValue()).isEqualTo("123");
    assertThat(patientOneIdentifierList.get(1).getValue()).isEqualTo("456");
    // Verify the system values are not present
    assertThat(patientOneIdentifierList.get(0).getSystem()).isNull();
    assertThat(patientOneIdentifierList.get(1).getSystem()).isNull();
    // Verify the first identifier has no use field.
    assertThat(patientOneIdentifierList.get(0).getUse()).isNull();
    // Verify the second identifier is marked as old
    assertThat(patientOneIdentifierList.get(1).getUse()).isEqualTo(Identifier.IdentifierUse.OLD);
    // Verify identifier type is set correctly for the first identifier
    CodeableConcept patientOneIdentifierType = patientOneIdentifierList.get(0).getType();
    assertThat(patientOneIdentifierType.getCoding().get(0).getSystem()).isEqualTo("http://terminology.hl7.org/CodeSystem/v2-0203");
    assertThat(patientOneIdentifierType.getCoding().get(0).getDisplay()).isEqualTo("Medical record number");
    assertThat(patientOneIdentifierType.getCoding().get(0).getCode()).isEqualTo("MR");
    // Verify the identifier type for the second identifier is not present.
    assertThat(patientOneIdentifierList.get(1).getType().getCoding()).isEmpty();
    // Verify first patient has these fields
    // 
    // "active":true,
    // "link":[
    // {
    // "other":{
    // "reference":"Patient/expiringID-MRG"
    // },
    // "type":"replaces"
    // }
    // ]
    // The first patient should be active.
    assertThat(patientOne.getActive()).isTrue();
    // Verify link.other.reference references the MRG (2nd) patient with of a type of 'replaces'
    PatientLinkComponent linkOne = patientOne.getLink().get(0);
    assertThat(linkOne.getType()).isEqualTo(Patient.LinkType.REPLACES);
    assertThat(linkOne.getOther().getReference()).isEqualTo(patientTwoId);
    /*-----------Verify Patient Two-----------*/
    // Verify patient two's identifier is set correctly (this is the patient build
    // from the MRG segment)
    // 
    // "identifier":[
    // {
    // "use":"old",
    // "value":"456"
    // }
    // ]
    // Verify has only 1 identifier
    assertThat(patientTwoIdentifierList).hasSize(1);
    // Verify the identifier value is correct.
    assertThat(patientTwoIdentifierList.get(0).getValue()).isEqualTo("456");
    // Verify the system is not present
    assertThat(patientTwoIdentifierList.get(0).getSystem()).isNull();
    // Verify the identifier is marked as old
    assertThat(patientTwoIdentifierList.get(0).getUse()).isEqualTo(Identifier.IdentifierUse.OLD);
    // Verify identifier type is not present
    assertThat(patientTwoIdentifierList.get(0).getType().getCoding()).isEmpty();
    // Verify second patient has these fields.
    // "active":false,
    // "link":[
    // {
    // "other":{
    // "reference":"Patient/survivingID"
    // },
    // "type":"replaced-by"
    // }
    // ]
    // The second patient should NOT be active.
    assertThat(patientTwo.getActive()).isFalse();
    // We should have link.other.reference to the PID (1st) patient with a type of 'replaced-by'
    PatientLinkComponent linkTwo = patientTwo.getLink().get(0);
    assertThat(linkTwo.getType()).isEqualTo(Patient.LinkType.REPLACEDBY);
    assertThat(linkTwo.getOther().getReference()).isEqualTo(patientOneId);
    ;
}
Also used : BundleEntryComponent(org.hl7.fhir.r4.model.Bundle.BundleEntryComponent) Identifier(org.hl7.fhir.r4.model.Identifier) Resource(org.hl7.fhir.r4.model.Resource) Patient(org.hl7.fhir.r4.model.Patient) PatientLinkComponent(org.hl7.fhir.r4.model.Patient.PatientLinkComponent) CodeableConcept(org.hl7.fhir.r4.model.CodeableConcept) Test(org.junit.jupiter.api.Test)

Example 2 with REPLACES

use of org.hl7.fhir.r4.model.Composition.DocumentRelationshipType.REPLACES in project synthea by synthetichealth.

the class FhirR4 method mapCodeToCodeableConcept.

/**
 * Helper function to convert a Code into a CodeableConcept. Takes an optional system, which
 * replaces the Code.system in the resulting CodeableConcept if not null.
 *
 * @param from   The Code to create a CodeableConcept from.
 * @param system The system identifier, such as a URI. Optional; may be null.
 * @return The converted CodeableConcept
 */
private static CodeableConcept mapCodeToCodeableConcept(Code from, String system) {
    CodeableConcept to = new CodeableConcept();
    system = system == null ? null : ExportHelper.getSystemURI(system);
    from.system = ExportHelper.getSystemURI(from.system);
    if (from.display != null) {
        to.setText(from.display);
    }
    Coding coding = new Coding();
    coding.setCode(from.code);
    coding.setDisplay(from.display);
    if (from.system == null) {
        coding.setSystem(system);
    } else {
        coding.setSystem(from.system);
    }
    to.addCoding(coding);
    return to;
}
Also used : Coding(org.hl7.fhir.r4.model.Coding) CodeableConcept(org.hl7.fhir.r4.model.CodeableConcept)

Example 3 with REPLACES

use of org.hl7.fhir.r4.model.Composition.DocumentRelationshipType.REPLACES in project synthea by synthetichealth.

the class FHIRSTU3ExporterTest method testFHIRSTU3Export.

@Test
public void testFHIRSTU3Export() throws Exception {
    TestHelper.loadTestProperties();
    Generator.DEFAULT_STATE = Config.get("test_state.default", "Massachusetts");
    Config.set("exporter.baseDirectory", tempFolder.newFolder().toString());
    FhirContext ctx = FhirStu3.getContext();
    IParser parser = ctx.newJsonParser().setPrettyPrint(true);
    FhirValidator validator = ctx.newValidator();
    validator.setValidateAgainstStandardSchema(true);
    validator.setValidateAgainstStandardSchematron(true);
    ValidationResources validationResources = new ValidationResources();
    List<String> errors = ParallelTestingService.runInParallel((person) -> {
        List<String> validationErrors = new ArrayList<String>();
        TestHelper.exportOff();
        Config.set("exporter.fhir_stu3.export", "true");
        Config.set("exporter.fhir.use_shr_extensions", "true");
        FhirStu3.TRANSACTION_BUNDLE = person.randBoolean();
        String fhirJson = FhirStu3.convertToFHIRJson(person, System.currentTimeMillis());
        // (these should have been converted into URIs)
        if (fhirJson.contains("SNOMED-CT")) {
            validationErrors.add("JSON contains unconverted references to 'SNOMED-CT' (should be URIs)");
        }
        // let's crack open the Bundle and validate
        // each individual entry.resource to get context-sensitive error
        // messages...
        Bundle bundle = parser.parseResource(Bundle.class, fhirJson);
        for (BundleEntryComponent entry : bundle.getEntry()) {
            ValidationResult eresult = validator.validateWithResult(entry.getResource());
            if (!eresult.isSuccessful()) {
                for (SingleValidationMessage emessage : eresult.getMessages()) {
                    boolean valid = false;
                    if (emessage.getMessage().contains("@ Observation obs-7")) {
                        /*
               * The obs-7 invariant basically says that Observations should have values, unless
               * they are made of components. This test replaces an invalid XPath expression
               * that was causing correct instances to fail validation.
               */
                        valid = validateObs7((Observation) entry.getResource());
                    } else if (emessage.getMessage().contains("@ Condition con-4")) {
                        /*
               * The con-4 invariant says "If condition is abated, then clinicalStatus must be
               * either inactive, resolved, or remission" which is very clear and sensical.
               * However, the XPath expression does not evaluate correctly for valid instances,
               * so we must manually validate.
               */
                        valid = validateCon4((Condition) entry.getResource());
                    } else if (emessage.getMessage().contains("@ MedicationRequest mps-1")) {
                        /*
               * The mps-1 invariant says MedicationRequest.requester.onBehalfOf can only be
               * specified if MedicationRequest.requester.agent is practitioner or device.
               * But the invariant is poorly written and does not correctly handle references
               * starting with "urn:uuid"
               */
                        // ignore this error
                        valid = true;
                    } else if (emessage.getMessage().contains("per-1: If present, start SHALL have a lower value than end")) {
                        /*
               * The per-1 invariant does not account for daylight savings time... so, if the
               * daylight savings switch happens between the start and end, the validation
               * fails, even if it is valid.
               */
                        // ignore this error
                        valid = true;
                    }
                    if (!valid) {
                        System.out.println(parser.encodeResourceToString(entry.getResource()));
                        System.out.println("ERROR: " + emessage.getMessage());
                        validationErrors.add(emessage.getMessage());
                    }
                }
            }
            // Check ExplanationOfBenefit Resources against BlueButton
            if (entry.getResource().fhirType().equals("ExplanationOfBenefit")) {
                ValidationResult bbResult = validationResources.validateSTU3(entry.getResource());
                for (SingleValidationMessage message : bbResult.getMessages()) {
                    if (message.getMessage().contains("extension https://bluebutton.cms.gov/assets")) {
                        /*
               * The instance validator complains about the BlueButton extensions, ignore
               */
                        continue;
                    } else if (message.getSeverity() == ResultSeverityEnum.ERROR) {
                        if (!(message.getMessage().contains("Element 'ExplanationOfBenefit.id': minimum required = 1, but only found 0") || message.getMessage().contains("Could not verify slice for profile"))) {
                            // For some reason the validator is not detecting the IDs on the resources,
                            // even though they appear to be present while debugging and during normal
                            // operations.
                            System.out.println(message.getSeverity() + ": " + message.getMessage());
                            Assert.fail(message.getSeverity() + ": " + message.getMessage());
                        }
                    }
                }
            }
        }
        if (!validationErrors.isEmpty()) {
            Exporter.export(person, System.currentTimeMillis());
        }
        return validationErrors;
    });
    assertTrue("Validation of exported FHIR bundle failed: " + String.join("|", errors), errors.size() == 0);
}
Also used : FhirContext(ca.uhn.fhir.context.FhirContext) SingleValidationMessage(ca.uhn.fhir.validation.SingleValidationMessage) Bundle(org.hl7.fhir.dstu3.model.Bundle) ArrayList(java.util.ArrayList) FhirValidator(ca.uhn.fhir.validation.FhirValidator) ValidationResult(ca.uhn.fhir.validation.ValidationResult) BundleEntryComponent(org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent) Observation(org.hl7.fhir.dstu3.model.Observation) IParser(ca.uhn.fhir.parser.IParser) Test(org.junit.Test)

Example 4 with REPLACES

use of org.hl7.fhir.r4.model.Composition.DocumentRelationshipType.REPLACES in project synthea by synthetichealth.

the class FhirStu3 method mapCodeToCodeableConcept.

/**
 * Helper function to convert a Code into a CodeableConcept. Takes an optional system, which
 * replaces the Code.system in the resulting CodeableConcept if not null.
 *
 * @param from The Code to create a CodeableConcept from.
 * @param system The system identifier, such as a URI. Optional; may be null.
 * @return The converted CodeableConcept
 */
private static CodeableConcept mapCodeToCodeableConcept(Code from, String system) {
    CodeableConcept to = new CodeableConcept();
    system = system == null ? null : ExportHelper.getSystemURI(system);
    from.system = ExportHelper.getSystemURI(from.system);
    if (from.display != null) {
        to.setText(from.display);
    }
    Coding coding = new Coding();
    coding.setCode(from.code);
    coding.setDisplay(from.display);
    if (from.system == null) {
        coding.setSystem(system);
    } else {
        coding.setSystem(from.system);
    }
    to.addCoding(coding);
    return to;
}
Also used : Coding(org.hl7.fhir.dstu3.model.Coding) CodeableConcept(org.hl7.fhir.dstu3.model.CodeableConcept)

Example 5 with REPLACES

use of org.hl7.fhir.r4.model.Composition.DocumentRelationshipType.REPLACES in project summary-care-record-api by NHSDigital.

the class GpSummaryMapper method map.

@SneakyThrows
public List<Resource> map(Node document) {
    var gpSummaryId = xmlUtils.getValueByXPath(document, GP_SUMMARY_ID_XPATH);
    var gpSummaryCodeCode = xmlUtils.getValueByXPath(document, GP_SUMMARY_CODE_CODE_XPATH);
    var gpSummaryCodeDisplayName = xmlUtils.getValueByXPath(document, GP_SUMMARY_CODE_DISPLAY_NAME_XPATH);
    var gpSummaryStatusCode = xmlUtils.getValueByXPath(document, GP_SUMMARY_STATUS_CODE_XPATH);
    var gpSummaryEffectiveTime = parseDate(xmlUtils.getValueByXPath(document, GP_SUMMARY_EFFECTIVE_TIME_XPATH), InstantType.class);
    var authorTime = parseDate(xmlUtils.getValueByXPath(document, GP_SUMMARY_AUTHOR_TIME_XPATH), DateTimeType.class);
    var replacementOfPriorMessageRefIdRoot = xmlUtils.getOptionalValueByXPath(document, REPLACEMENT_OF_PRIOR_MESSAGE_REF_ID_ROOT_XPATH);
    var pertinentRootCreTypeCodeCode = xmlUtils.getValueByXPath(document, PERTINENT_ROOT_CRE_TYPE_CODE_CODE_XPATH);
    var pertinentRootCreTypeCodeDisplayName = xmlUtils.getValueByXPath(document, PERTINENT_ROOT_CRE_TYPE_CODE_DISPLAY_NAME_XPATH);
    var presentationTextValue = xmlUtils.detachOptionalNodeByXPath(document, PRESENTATION_TEXT_VALUE);
    var eventId = xmlUtils.getValueByXPath(document, EVENT_ID_XPATH);
    List<Resource> resources = new ArrayList<>();
    var composition = new Composition();
    composition.setId(eventId);
    composition.setIdentifier(new Identifier().setValue(gpSummaryId).setSystem("https://tools.ietf.org/html/rfc4122"));
    composition.setType(new CodeableConcept().addCoding(new Coding().setCode(gpSummaryCodeCode).setSystem(SNOMED_SYSTEM).setDisplay(gpSummaryCodeDisplayName)));
    composition.setMeta(new Meta().setLastUpdatedElement(gpSummaryEffectiveTime));
    composition.setStatus(mapCompositionStatus(gpSummaryStatusCode));
    composition.setDateElement(authorTime);
    replacementOfPriorMessageRefIdRoot.ifPresent(val -> composition.addRelatesTo(new Composition.CompositionRelatesToComponent().setTarget(new Identifier().setValue(val)).setCode(REPLACES)));
    composition.addCategory(new CodeableConcept().addCoding(new Coding().setCode(pertinentRootCreTypeCodeCode).setSystem(SNOMED_SYSTEM).setDisplay(pertinentRootCreTypeCodeDisplayName)));
    Map<String, List<String>> references = sectionReferences(document);
    presentationTextValue.map(htmlParser::parse).map(Collection::stream).ifPresent(it -> it.forEach(section -> {
        if (section.getTitle() != null && CODED_ENTRY_RESOURCE_MAP.keySet().contains(section.getTitle()) && references.containsKey(section.getTitle())) {
            for (String codedEntryId : references.get(section.getTitle())) {
                section.addEntry(new Reference(CODED_ENTRY_RESOURCE_MAP.get(section.getTitle()) + "/" + codedEntryId));
            }
        }
        composition.addSection(section);
    }));
    resources.add(composition);
    addAuthor(document, resources, composition);
    return resources;
}
Also used : SneakyThrows(lombok.SneakyThrows) DateTimeType(org.hl7.fhir.r4.model.DateTimeType) Collection(java.util.Collection) Identifier(org.hl7.fhir.r4.model.Identifier) RequiredArgsConstructor(lombok.RequiredArgsConstructor) CodeableConcept(org.hl7.fhir.r4.model.CodeableConcept) Resource(org.hl7.fhir.r4.model.Resource) Autowired(org.springframework.beans.factory.annotation.Autowired) HashMap(java.util.HashMap) Composition(org.hl7.fhir.r4.model.Composition) Reference(org.hl7.fhir.r4.model.Reference) PractitionerRole(org.hl7.fhir.r4.model.PractitionerRole) ArrayList(java.util.ArrayList) Organization(org.hl7.fhir.r4.model.Organization) List(java.util.List) InstantType(org.hl7.fhir.r4.model.InstantType) Component(org.springframework.stereotype.Component) XmlToFhirMapper.parseDate(uk.nhs.adaptors.scr.mappings.from.hl7.XmlToFhirMapper.parseDate) Coding(org.hl7.fhir.r4.model.Coding) Map(java.util.Map) Node(org.w3c.dom.Node) REPLACES(org.hl7.fhir.r4.model.Composition.DocumentRelationshipType.REPLACES) XmlUtils(uk.nhs.adaptors.scr.utils.XmlUtils) Meta(org.hl7.fhir.r4.model.Meta) Meta(org.hl7.fhir.r4.model.Meta) Composition(org.hl7.fhir.r4.model.Composition) Reference(org.hl7.fhir.r4.model.Reference) Resource(org.hl7.fhir.r4.model.Resource) ArrayList(java.util.ArrayList) Identifier(org.hl7.fhir.r4.model.Identifier) Coding(org.hl7.fhir.r4.model.Coding) ArrayList(java.util.ArrayList) List(java.util.List) CodeableConcept(org.hl7.fhir.r4.model.CodeableConcept) SneakyThrows(lombok.SneakyThrows)

Aggregations

Complex (org.hl7.fhir.dstu3.utils.formats.Turtle.Complex)6 Complex (org.hl7.fhir.r4.utils.formats.Turtle.Complex)6 ValidationMessage (org.hl7.fhir.utilities.validation.ValidationMessage)6 CodeableConcept (org.hl7.fhir.r4.model.CodeableConcept)5 Identifier (org.hl7.fhir.r4.model.Identifier)5 Resource (org.hl7.fhir.r4.model.Resource)5 DefinitionException (org.hl7.fhir.exceptions.DefinitionException)4 FHIRFormatError (org.hl7.fhir.exceptions.FHIRFormatError)4 CommaSeparatedStringBuilder (org.hl7.fhir.utilities.CommaSeparatedStringBuilder)4 Test (org.junit.jupiter.api.Test)3 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 Coding (org.hl7.fhir.dstu3.model.Coding)2 BundleEntryComponent (org.hl7.fhir.r4.model.Bundle.BundleEntryComponent)2 Coding (org.hl7.fhir.r4.model.Coding)2 Patient (org.hl7.fhir.r4.model.Patient)2 PatientLinkComponent (org.hl7.fhir.r4.model.Patient.PatientLinkComponent)2 FhirContext (ca.uhn.fhir.context.FhirContext)1 IParser (ca.uhn.fhir.parser.IParser)1 InvalidRequestException (ca.uhn.fhir.rest.server.exceptions.InvalidRequestException)1