From ea4b0e4ec1432d0afa4873607302e79b4cb0ac2f Mon Sep 17 00:00:00 2001 From: MartinWheelerMT <88717465+MartinWheelerMT@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:03:44 +0000 Subject: [PATCH] NIAD-3220: Add Resource filter to identify ReferralRequest to external document LinkSets (#936) * Add Test to check verify that the provided `LinkSet` is a "Referral Request to External Document LinkSet." * Add test XML file containing a "Referral Request to External Document LinkSet." * Add method `isReferralRequestToExternalDocumentLinkSet` to `ResourceFilterUtil` with parameters for the `ehrExtract` and te `LinkSet` itself to identify `LinkSets` matching the criteria for a "Referral Request to External Document LinkSet." --- .../translator/util/ResourceFilterUtil.java | 65 ++++++++ .../util/ResourceFilterUtilTest.java | 102 ++++++++++++ ...l_request_to_external_document_linkset.xml | 149 ++++++++++++++++++ 3 files changed, 316 insertions(+) create mode 100644 gp2gp-translator/src/test/resources/xml/ResourceFilter/ehr_extract_with_referral_request_to_external_document_linkset.xml diff --git a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/util/ResourceFilterUtil.java b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/util/ResourceFilterUtil.java index 3059cf8a6..7794857d8 100644 --- a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/util/ResourceFilterUtil.java +++ b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/util/ResourceFilterUtil.java @@ -5,11 +5,17 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.hl7.v3.RCMRMT030101UKComponent; +import org.hl7.v3.RCMRMT030101UKComponent3; +import org.hl7.v3.RCMRMT030101UKComponent4; import org.hl7.v3.RCMRMT030101UKCompoundStatement; import org.hl7.v3.RCMRMT030101UKEhrExtract; +import org.hl7.v3.RCMRMT030101UKLinkSet; import org.hl7.v3.RCMRMT030101UKNarrativeStatement; @NoArgsConstructor(access = AccessLevel.PRIVATE) @@ -17,6 +23,8 @@ public class ResourceFilterUtil { private static final List ALLERGY_CODES = List.of("SN53.00", "14L..00"); private static final String CODE_SYSTEM_READ_CODE_V2 = "2.16.840.1.113883.2.1.6.2"; + private static final String SNOMED_CODE_SYSTEM = "2.16.840.1.113883.2.1.3.2.4.15"; + private static final String UNSPECIFIED_PROBLEM_CODE = "394776006"; private static final String PATHOLOGY_CODE = "16488004"; private static final String SPECIMEN_CODE = "123038009"; private static final String BATTERY_VALUE = "BATTERY"; @@ -82,6 +90,63 @@ public static boolean isTemplate(RCMRMT030101UKCompoundStatement compoundStateme && List.of(BATTERY_VALUE, CLUSTER_VALUE).contains(compoundStatement.getClassCode().getFirst()); } + public static boolean isReferralRequestToExternalDocumentLinkSet(RCMRMT030101UKEhrExtract ehrExtract, RCMRMT030101UKLinkSet linkSet) { + return hasUnspecifiedProblemCodeWithoutQualifierOrOriginalText(linkSet) + && !linkSet.getComponent().isEmpty() + && hasNamedStatementRefReferencingARequestStatement(ehrExtract, linkSet) + && containsOnlyComponentsWithStatementRefReferencingADocument(ehrExtract, linkSet); + } + + private static boolean hasUnspecifiedProblemCodeWithoutQualifierOrOriginalText(RCMRMT030101UKLinkSet linkSet) { + return linkSet.hasCode() + && SNOMED_CODE_SYSTEM.equals(linkSet.getCode().getCodeSystem()) + && UNSPECIFIED_PROBLEM_CODE.equals(linkSet.getCode().getCode()) + && linkSet.getCode().getQualifier().isEmpty() + && !linkSet.getCode().hasOriginalText(); + } + + private static boolean containsOnlyComponentsWithStatementRefReferencingADocument( + RCMRMT030101UKEhrExtract ehrExtract, + RCMRMT030101UKLinkSet linkSet + ) { + var statementRefIds = linkSet.getComponent() + .stream() + .map(component -> component.getStatementRef().getId().getRoot()) + .collect(Collectors.toSet()); + + return extractAllEhrCompositionComponentsAsStream(ehrExtract) + .flatMap(CompoundStatementResourceExtractors::extractAllNonBloodPressureNarrativeStatements) + .filter(Objects::nonNull) + .filter(ResourceFilterUtil::isDocumentReference) + .map(narrativeStatement -> narrativeStatement.getId().getRoot()) + .collect(Collectors.toSet()) + .containsAll(statementRefIds); + } + + private static boolean hasNamedStatementRefReferencingARequestStatement( + RCMRMT030101UKEhrExtract ehrExtract, + RCMRMT030101UKLinkSet linkSet + ) { + if (linkSet.getConditionNamed() == null) { + return false; + } + var namedStatementRefId = linkSet.getConditionNamed().getNamedStatementRef().getId().getRoot(); + + return extractAllEhrCompositionComponentsAsStream(ehrExtract) + .flatMap(CompoundStatementResourceExtractors::extractAllRequestStatements) + .filter(Objects::nonNull) + .anyMatch(requestStatement -> namedStatementRefId.equals(requestStatement.getId().getFirst().getRoot())); + } + + private static Stream extractAllEhrCompositionComponentsAsStream(RCMRMT030101UKEhrExtract ehrExtract) { + return ehrExtract.getComponent() + .stream() + .map(RCMRMT030101UKComponent::getEhrFolder) + .flatMap(ehrFolder -> ehrFolder.getComponent().stream()) + .map(RCMRMT030101UKComponent3::getEhrComposition) + .flatMap(ehrComposition -> ehrComposition.getComponent().stream()); + } + private static boolean hasCode(RCMRMT030101UKCompoundStatement compoundStatement) { return compoundStatement.hasCode() && compoundStatement.getCode().hasCode(); } diff --git a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/util/ResourceFilterUtilTest.java b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/util/ResourceFilterUtilTest.java index 509f64f9b..5d1f879d4 100644 --- a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/util/ResourceFilterUtilTest.java +++ b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/util/ResourceFilterUtilTest.java @@ -5,9 +5,15 @@ import static uk.nhs.adaptors.pss.translator.util.XmlUnmarshallUtil.unmarshallFile; +import java.util.Objects; import java.util.stream.Stream; +import org.hl7.v3.CR; +import org.hl7.v3.RCMRMT030101UKComponent; +import org.hl7.v3.RCMRMT030101UKComponent4; import org.hl7.v3.RCMRMT030101UKCompoundStatement; +import org.hl7.v3.RCMRMT030101UKEhrExtract; +import org.hl7.v3.RCMRMT030101UKLinkSet; import org.hl7.v3.RCMRMT030101UKNarrativeStatement; import org.hl7.v3.RCMRMT030101UKObservationStatement; import org.junit.jupiter.api.Test; @@ -157,6 +163,96 @@ private static Stream nonSpecimenTestFiles() { ); } + @Test + public void testIsReferralRequestToExternalDocumentLinkSet() { + final var ehrExtract = unmarshallEhrExtractElement("ehr_extract_with_referral_request_to_external_document_linkset.xml"); + final var linkSet = extractFirstLinkSetFromEhrExtract(ehrExtract); + + assertThat(ResourceFilterUtil.isReferralRequestToExternalDocumentLinkSet(ehrExtract, linkSet)) + .isTrue(); + } + + @Test + public void When_ActiveProblem_Expect_IsNotReferralRequestToExternalDocumentLinkSet() { + final var ehrExtract = unmarshallEhrExtractElement("ehr_extract_with_referral_request_to_external_document_linkset.xml"); + final var linkSet = extractFirstLinkSetFromEhrExtract(ehrExtract); + linkSet.getCode().setCode("394774009"); + + assertThat(ResourceFilterUtil.isReferralRequestToExternalDocumentLinkSet(ehrExtract, linkSet)) + .isFalse(); + } + + @Test + public void When_LinkSetHasReadV2Code_Expect_IsNotReferralRequestToExternalDocumentLinkSet() { + final var ehrExtract = unmarshallEhrExtractElement("ehr_extract_with_referral_request_to_external_document_linkset.xml"); + final var linkSet = extractFirstLinkSetFromEhrExtract(ehrExtract); + linkSet.getCode().setCodeSystem("2.16.840.1.113883.2.1.6.2"); + + assertThat(ResourceFilterUtil.isReferralRequestToExternalDocumentLinkSet(ehrExtract, linkSet)) + .isFalse(); + } + + @Test + public void When_LinkSetHasCodeWithQualifier_Expect_IsNotReferralRequestToExternalDocumentLinkSet() { + final var ehrExtract = unmarshallEhrExtractElement("ehr_extract_with_referral_request_to_external_document_linkset.xml"); + final var linkSet = extractFirstLinkSetFromEhrExtract(ehrExtract); + linkSet.getCode().getQualifier().add(new CR()); + + assertThat(ResourceFilterUtil.isReferralRequestToExternalDocumentLinkSet(ehrExtract, linkSet)) + .isFalse(); + } + + @Test + public void When_LinkSetHasCodeWithOriginalText_Expect_IsNotReferralRequestToExternalDocumentLinkSet() { + final var ehrExtract = unmarshallEhrExtractElement("ehr_extract_with_referral_request_to_external_document_linkset.xml"); + final var linkSet = extractFirstLinkSetFromEhrExtract(ehrExtract); + linkSet.getCode().setOriginalText("original-text"); + + assertThat(ResourceFilterUtil.isReferralRequestToExternalDocumentLinkSet(ehrExtract, linkSet)) + .isFalse(); + } + + @Test + public void When_LinkSetHasNoComponents_Expect_IsNotReferralRequestToExternalDocumentLinkSet() { + final var ehrExtract = unmarshallEhrExtractElement("ehr_extract_with_referral_request_to_external_document_linkset.xml"); + final var linkSet = extractFirstLinkSetFromEhrExtract(ehrExtract); + linkSet.getComponent().clear(); + + assertThat(ResourceFilterUtil.isReferralRequestToExternalDocumentLinkSet(ehrExtract, linkSet)) + .isFalse(); + } + + @Test + public void When_LinkSetHasNamedStatementRefWhichIsANarrativeStatement_Expect_IsNotReferralRequestToExternalDocumentLinkSet() { + final var ehrExtract = unmarshallEhrExtractElement("ehr_extract_with_referral_request_to_external_document_linkset.xml"); + final var linkSet = extractFirstLinkSetFromEhrExtract(ehrExtract); + linkSet.getConditionNamed().getNamedStatementRef().getId().setRoot("narrative-statement-1"); + + assertThat(ResourceFilterUtil.isReferralRequestToExternalDocumentLinkSet(ehrExtract, linkSet)) + .isFalse(); + } + + @Test + public void When_LinkSetHasComponentWhichReferencesRequestStatement_Expect_IsNotReferralRequestToExternalDocumentLinkSet() { + final var ehrExtract = unmarshallEhrExtractElement("ehr_extract_with_referral_request_to_external_document_linkset.xml"); + final var linkSet = extractFirstLinkSetFromEhrExtract(ehrExtract); + linkSet.getComponent().getFirst().getStatementRef().getId().setRoot("request-statement-1"); + + assertThat(ResourceFilterUtil.isReferralRequestToExternalDocumentLinkSet(ehrExtract, linkSet)) + .isFalse(); + } + + private RCMRMT030101UKLinkSet extractFirstLinkSetFromEhrExtract(RCMRMT030101UKEhrExtract ehrExtract) { + return ehrExtract.getComponent().stream() + .map(RCMRMT030101UKComponent::getEhrFolder) + .flatMap(ehrFolder -> ehrFolder.getComponent().stream()) + .flatMap(component -> component.getEhrComposition().getComponent().stream()) + .map(RCMRMT030101UKComponent4::getLinkSet) + .filter(Objects::nonNull) + .findFirst() + .orElseThrow(); + } + @SneakyThrows private RCMRMT030101UKCompoundStatement unmarshallCompoundStatementElement(String fileName) { return unmarshallFile(getFile("classpath:" + XML_RESOURCES + fileName), @@ -174,4 +270,10 @@ private RCMRMT030101UKNarrativeStatement unmarshallNarrativeStatementElement(Str return unmarshallFile(getFile("classpath:" + XML_RESOURCES + fileName), RCMRMT030101UKNarrativeStatement.class); } + + @SneakyThrows + private RCMRMT030101UKEhrExtract unmarshallEhrExtractElement(String fileName) { + return unmarshallFile(getFile("classpath:" + XML_RESOURCES + fileName), + RCMRMT030101UKEhrExtract.class); + } } diff --git a/gp2gp-translator/src/test/resources/xml/ResourceFilter/ehr_extract_with_referral_request_to_external_document_linkset.xml b/gp2gp-translator/src/test/resources/xml/ResourceFilter/ehr_extract_with_referral_request_to_external_document_linkset.xml new file mode 100644 index 000000000..f8c2f8ec9 --- /dev/null +++ b/gp2gp-translator/src/test/resources/xml/ResourceFilter/ehr_extract_with_referral_request_to_external_document_linkset.xml @@ -0,0 +1,149 @@ + + + + + + + + + Outbound Referral + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + +
+ + + + + + + + + + + + + NHS e-Referral Service, Purpose: Unknown + + +
+ + + + Routine + + + + + + + + + + + +
+ + + + + + NHS e-Referral UBRN [redacted] for Orthopaedic referral, NHS e-RS UBRN [redacted] for Orthopaedic referral + + + + + + + e-RS Letter (25-May-2021) + + + + + + + + + + + + NHS e-Referral UBRN [redacted] for Orthopaedic referral, NHS e-RS UBRN [redacted] for Orthopaedic referral + + + + + + + e-RS Letter (25-May-2021) + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file