From 8c5ce1f57e613d39bdbfddc0d43f7b8251e4985e Mon Sep 17 00:00:00 2001 From: martin-nhs <127403254+martin-nhs@users.noreply.github.com> Date: Wed, 3 Jul 2024 15:17:32 +0100 Subject: [PATCH] NAID-3122 - Add `confidentialityCode` support to `AllergyIntoleranceMapper.java` (#684) * [NIAD-3122] Add Predicate to ObservationUtil.java * [NIAD-3122] Add initial mapping logic * [NIAD-3122] Add initial mapping logic * [NIAD-3122] Add CodingFactory.java * [NIAD-3122] Add comment * [NIAD-3122] Refactor ResourceUtil.java * [NIAD-3122] Refactor ResourceUtil.java * [NIAD-3122] Refactor ResourceUtil.java * [NIAD-3122] Refactor ResourceUtil.java * [NIAD-3122] Add unit tests * [NIAD-3122] Refactor unit tests * [NIAD-3122] Refactor unit tests * [NIAD-3122] Update CHANGELOG.md --- CHANGELOG.md | 3 + .../mapper/AllergyIntoleranceMapper.java | 11 +- .../translator/util/ConfidentialityUtil.java | 44 +++ .../translator/util/builder/MetaBuilder.java | 33 ++ .../mapper/AllergyIntoleranceMapperTest.java | 311 ++++++++++++------ .../util/ConfidentialityUtilTest.java | 65 ++++ ...h-ehr-composition-confidentiality-code.xml | 54 +++ ...rvation-statement-confidentiality-code.xml | 54 +++ 8 files changed, 477 insertions(+), 98 deletions(-) create mode 100644 gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/util/ConfidentialityUtil.java create mode 100644 gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/util/builder/MetaBuilder.java create mode 100644 gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/util/ConfidentialityUtilTest.java create mode 100644 gp2gp-translator/src/test/resources/xml/AllergyIntolerance/allergy-structure-with-ehr-composition-confidentiality-code.xml create mode 100644 gp2gp-translator/src/test/resources/xml/AllergyIntolerance/allergy-structure-with-observation-statement-confidentiality-code.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 8965df9bb..97d6e7a13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Added +* The AllergyIntoleranceMapper has been enhanced to support the redaction fix. If an Allergy Intolerance record includes a confidentialityCode, the meta.security field of the corresponding FHIR resource will now be appropriately populated. + ## [3.0.0] - 2024-07-02 ### Removed diff --git a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/AllergyIntoleranceMapper.java b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/AllergyIntoleranceMapper.java index a7fba0b4b..8c7b0b2d4 100644 --- a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/AllergyIntoleranceMapper.java +++ b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/AllergyIntoleranceMapper.java @@ -24,6 +24,7 @@ import org.hl7.fhir.dstu3.model.DateTimeType; import org.hl7.fhir.dstu3.model.Encounter; import org.hl7.fhir.dstu3.model.Extension; +import org.hl7.fhir.dstu3.model.Meta; import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Reference; import org.hl7.v3.CD; @@ -40,6 +41,7 @@ import lombok.RequiredArgsConstructor; import uk.nhs.adaptors.pss.translator.util.DegradedCodeableConcepts; import uk.nhs.adaptors.pss.translator.util.ResourceFilterUtil; +import uk.nhs.adaptors.pss.translator.util.builder.MetaBuilder; @Service @RequiredArgsConstructor(onConstructor = @__(@Autowired)) @@ -88,6 +90,13 @@ private AllergyIntolerance mapAllergyIntolerance(RCMRMT030101UKEhrComposition eh .getId() .getRoot(); + final Meta meta = new MetaBuilder() + .withInitialMeta(() -> generateMeta(META_PROFILE)) + .withSecurityIfConfidentialityCodesPresent( + ehrComposition.getConfidentialityCode(), + observationStatement.getConfidentialityCode() + ).build(); + allergyIntolerance .addCategory(getCategory(compoundStatement)) .setAssertedDateElement(getAssertedDateElement(compoundStatement.getAvailabilityTime(), ehrComposition)) @@ -95,7 +104,7 @@ private AllergyIntolerance mapAllergyIntolerance(RCMRMT030101UKEhrComposition eh .setClinicalStatus(ACTIVE) .setVerificationStatus(UNCONFIRMED) .addIdentifier(buildIdentifier(id, practiseCode)) - .setMeta(generateMeta(META_PROFILE)) + .setMeta(meta) .setId(id); buildOnset(compoundStatement, allergyIntolerance); diff --git a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/util/ConfidentialityUtil.java b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/util/ConfidentialityUtil.java new file mode 100644 index 000000000..db2a23b0c --- /dev/null +++ b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/util/ConfidentialityUtil.java @@ -0,0 +1,44 @@ +package uk.nhs.adaptors.pss.translator.util; + +import org.hl7.fhir.dstu3.model.Coding; +import org.hl7.fhir.dstu3.model.Meta; +import org.hl7.v3.CV; + +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; + +public final class ConfidentialityUtil { + + private ConfidentialityUtil() { } + + private static final Coding CONFIDENTIALITY_CODING = new Coding() + .setSystem("http://hl7.org/fhir/v3/ActCode") + .setCode("NOPAT") + .setDisplay("no disclosure to patient, family or caregivers without attending provider's authorization"); + + public static Meta addSecurityToMetaIfConfidentialityCodesPresent(Collection> confidentialityCodes, Meta meta) { + final boolean isCodePresent = confidentialityCodes.stream() + .filter(Optional::isPresent) + .map(Optional::get) + .anyMatch(ConfidentialityUtil::isNopat); + + if (isCodePresent) { + return ConfidentialityUtil.addConfidentialityToMeta(meta); + } + + return meta; + } + + private static Meta addConfidentialityToMeta(final Meta meta) { + return meta.setSecurity( + Collections.singletonList( + CONFIDENTIALITY_CODING + ) + ); + } + + private static boolean isNopat(CV coding) { + return coding.getCode().equals("NOPAT"); + } +} \ No newline at end of file diff --git a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/util/builder/MetaBuilder.java b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/util/builder/MetaBuilder.java new file mode 100644 index 000000000..b28db4de0 --- /dev/null +++ b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/util/builder/MetaBuilder.java @@ -0,0 +1,33 @@ +package uk.nhs.adaptors.pss.translator.util.builder; + +import org.hl7.fhir.dstu3.model.Meta; +import org.hl7.v3.CV; +import uk.nhs.adaptors.pss.translator.util.ConfidentialityUtil; + +import java.util.Arrays; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; + +public final class MetaBuilder { + private Meta meta; + + public MetaBuilder withInitialMeta(final Supplier metaSupplier) { + this.meta = Objects.requireNonNull(metaSupplier.get()); + return this; + } + + @SafeVarargs + public final MetaBuilder withSecurityIfConfidentialityCodesPresent(Optional... confidentialityCodes) { + this.meta = ConfidentialityUtil.addSecurityToMetaIfConfidentialityCodesPresent( + Arrays.asList(confidentialityCodes), + this.meta + ); + + return this; + } + + public Meta build() { + return this.meta.copy(); + } +} \ No newline at end of file diff --git a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/AllergyIntoleranceMapperTest.java b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/AllergyIntoleranceMapperTest.java index 49ee82eb2..793c61dc3 100644 --- a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/AllergyIntoleranceMapperTest.java +++ b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/AllergyIntoleranceMapperTest.java @@ -15,17 +15,20 @@ import static uk.nhs.adaptors.pss.translator.util.XmlUnmarshallUtil.unmarshallFile; +import java.util.Collections; import java.util.List; import java.util.stream.Stream; import org.hl7.fhir.dstu3.model.AllergyIntolerance; import org.hl7.fhir.dstu3.model.CodeableConcept; +import org.hl7.fhir.dstu3.model.Coding; import org.hl7.fhir.dstu3.model.Encounter; import org.hl7.fhir.dstu3.model.Extension; import org.hl7.fhir.dstu3.model.Identifier; import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Reference; import org.hl7.v3.CD; +import org.hl7.v3.CV; import org.hl7.v3.RCMRMT030101UKEhrExtract; import org.junit.jupiter.api.Test; @@ -45,7 +48,7 @@ import static uk.nhs.adaptors.common.util.CodeableConceptUtils.createCodeableConcept; @ExtendWith(MockitoExtension.class) -public class AllergyIntoleranceMapperTest { +class AllergyIntoleranceMapperTest { private static final String XML_RESOURCES_BASE = "xml/AllergyIntolerance/"; private static final String COMPOUND_STATEMENT_ROOT_ID = "394559384658936"; @@ -74,6 +77,10 @@ public class AllergyIntoleranceMapperTest { private static final String MULTILEX_COCONUT_OIL = "01142009"; private static final String SNOMED_CODE_SYSTEM = "2.16.840.1.113883.2.1.3.2.4.15"; private static final String SNOMED_COCONUT_OIL = "14613911000001107"; + private static final Coding CONFIDENTIALITY_CODING = new Coding() + .setSystem("http://hl7.org/fhir/v3/ActCode") + .setCode("NOPAT") + .setDisplay("no disclosure to patient, family or caregivers without attending provider's authorization"); @Mock private CodeableConceptMapper codeableConceptMapper; @@ -85,20 +92,22 @@ public class AllergyIntoleranceMapperTest { private AllergyIntoleranceMapper allergyIntoleranceMapper; @Test - public void testMapDrugAllergyWithAllData() { + void testGivenDrugAllergyWithAllDataThenAllDataPopulated() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("drug-allergy-structure.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) .thenReturn(defaultCodeableConcept()) .thenReturn(secondaryCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("drug-allergy-structure.xml"); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); assertThat(allergyIntolerances).hasSize(1); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertFixedValues(allergyIntolerance); - assertExtension(allergyIntolerance); + assertThat(allergyIntolerance.getCategory().get(0).getValue()).isEqualTo(MEDICATION); assertThat(allergyIntolerance.getAssertedDateElement().asStringValue()).isEqualTo("1978-12-31"); assertThat(allergyIntolerance.getRecorder().getReference()).isEqualTo("Practitioner/2D70F602-6BB1-47E0-B2EC-39912A59787D"); @@ -113,17 +122,18 @@ public void testMapDrugAllergyWithAllData() { } @Test - public void testMapAuthorAndParticipantToRecorderAndAsserterAllergyIntolerance() { + void testGivenAuthorAndParticipantThenMapsToRecorderAndAsserterAllergyIntolerance() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("allergy-structure-with-valid-author-and-participant2.xml"); when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) .thenReturn(defaultCodeableConcept()) .thenReturn(secondaryCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("allergy-structure-with-valid-author-and-participant2.xml"); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), - getEncounterList(), PRACTISE_CODE); + + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + getEncounterList(), PRACTISE_CODE); assertEquals(1, allergyIntolerances.size()); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertAll( () -> assertExtension(allergyIntolerance), @@ -132,19 +142,23 @@ public void testMapAuthorAndParticipantToRecorderAndAsserterAllergyIntolerance() ); } + /** + * At this moment it is not very clear if this is the correct behavior. + * We haven't seen a supplier send over a HL7 in this form, but we want to specify some behaviour. + */ @Test - public void testGivenAuthorAndAutParticipant2AuthorAndRecorderPopulatedWithParticipant2() { - // At this moment it is not very clear if this is the correct behavior. - // We haven't seen a supplier send over a HL7 in this form, but we want to specify some behaviour. + void testGivenAuthorAndAutParticipant2AuthorAndRecorderThenPopulatedWithParticipant2() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("allergy-structure-with-participant-of-aut-typecode.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) .thenReturn(defaultCodeableConcept()) .thenReturn(secondaryCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("allergy-structure-with-participant-of-aut-typecode.xml"); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), - getEncounterList(), PRACTISE_CODE); + + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + getEncounterList(), PRACTISE_CODE); assertEquals(1, allergyIntolerances.size()); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertAll( () -> assertExtension(allergyIntolerance), @@ -154,18 +168,107 @@ public void testGivenAuthorAndAutParticipant2AuthorAndRecorderPopulatedWithParti } @Test - public void testGivenAuthorAndMultipleParticipant2sAndOneAutParticipant2AuthorAndRecorderPopulatedWithAuthorAndParticipant2() { - // At this moment it is not very clear if this is the correct behavior with such number of participants. - // We haven't seen a supplier send over a HL7 in this form, but we want to specify some behaviour. + void testGivenConfidentialityCodeWithNopatWithinObservationStatementThenMetaSecurityPopulated() { + final RCMRMT030101UKEhrExtract ehrExtract = + unmarshallEhrExtract("allergy-structure-with-observation-statement-confidentiality-code.xml"); + + final List allergyIntolerances = allergyIntoleranceMapper + .mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); + + assertEquals(1, allergyIntolerances.size()); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); + assertThat(allergyIntolerance.getMeta().getSecurity()) + .usingRecursiveComparison() + .isEqualTo(Collections.singletonList(CONFIDENTIALITY_CODING)); + } + + @Test + void testGivenConfidentialityCodeWithNopatWithinEhrCompositionAndNotObservationStatementThenMetaSecurityPopulated() { + final RCMRMT030101UKEhrExtract ehrExtract = + unmarshallEhrExtract("allergy-structure-with-ehr-composition-confidentiality-code.xml"); + + final List allergyIntolerances = allergyIntoleranceMapper + .mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); + + assertEquals(1, allergyIntolerances.size()); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); + assertThat(allergyIntolerance.getMeta().getSecurity()) + .usingRecursiveComparison() + .isEqualTo(Collections.singletonList(CONFIDENTIALITY_CODING)); + } + + @Test + void testGivenConfidentialityCodeWithCodeOtherThanNopatWithinObservationStatementThenMetaSecurityNotPopulated() { + final RCMRMT030101UKEhrExtract ehrExtract = + unmarshallEhrExtract("allergy-structure-with-observation-statement-confidentiality-code.xml"); + final CV invalidCoding = new CV(); + + invalidCoding.setCode("NOSCRUB"); + + ehrExtract + .getComponent().get(0).getEhrFolder() + .getComponent().get(0).getEhrComposition() + .getComponent().get(0).getCompoundStatement() + .getComponent().get(0).getObservationStatement() + .setConfidentialityCode(invalidCoding); + + final List allergyIntolerances = allergyIntoleranceMapper + .mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); + + assertEquals(1, allergyIntolerances.size()); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); + assertThat(allergyIntolerance.getMeta().getSecurity()).isEmpty(); + } + + @Test + void testGivenConfidentialityCodeWithCodeOtherThanNopatWithinEhrCompositionThenMetaSecurityNotPopulated() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("allergy-structure-with-ehr-composition-confidentiality-code.xml"); + final CV invalidCoding = new CV(); + + invalidCoding.setCode("NOSCRUB"); + + ehrExtract + .getComponent().get(0).getEhrFolder() + .getComponent().get(0).getEhrComposition() + .setConfidentialityCode(invalidCoding); + + final List allergyIntolerances = allergyIntoleranceMapper + .mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); + + assertEquals(1, allergyIntolerances.size()); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); + assertThat(allergyIntolerance.getMeta().getSecurity()).isEmpty(); + } + + @Test + void testGivenNoConfidentialityCodeThenMetaSecurityNotPopulated() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("allergy-structure-with-participant-of-aut-typecode.xml"); + + final List allergyIntolerances = allergyIntoleranceMapper + .mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); + + assertEquals(1, allergyIntolerances.size()); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); + assertThat(allergyIntolerance.getMeta().getSecurity()).isEmpty(); + } + + /** + * At this moment it is not very clear if this is the correct behavior with such number of participants. + * We haven't seen a supplier send over a HL7 in this form, but we want to specify some behaviour. + */ + @Test + void testGivenAuthorAndMultipleParticipant2sAndOneAutParticipant2AuthorAndRecorderThenPopulatedWithAuthorAndParticipant2() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("allergy-structure-with-author-and-multiple-participants.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) .thenReturn(defaultCodeableConcept()) .thenReturn(secondaryCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("allergy-structure-with-author-and-multiple-participants.xml"); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), - getEncounterList(), PRACTISE_CODE); + + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + getEncounterList(), PRACTISE_CODE); assertEquals(1, allergyIntolerances.size()); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertAll( () -> assertExtension(allergyIntolerance), @@ -175,16 +278,18 @@ public void testGivenAuthorAndMultipleParticipant2sAndOneAutParticipant2AuthorAn } @Test - public void testMapNonDrugAllergyWithAllData() { + void testGivenNonDrugAllergyWithAllDataThenMapsSuccessfully() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("non-drug-allergy-structure.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) .thenReturn(defaultCodeableConcept()) .thenReturn(secondaryCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("non-drug-allergy-structure.xml"); - List allergyIntolerances - = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); + + final List allergyIntolerances + = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); assertEquals(1, allergyIntolerances.size()); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertFixedValues(allergyIntolerance); @@ -201,49 +306,51 @@ public void testMapNonDrugAllergyWithAllData() { } @Test - public void testMapDegradedNonDrugAllergy() { + void testGivenCompoundStatementCodeOfNonDrugAllergyCodeThenSetsCodeToTransferDegradedNonDrugAllergy() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("degraded-non-drug-allergy-structure.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) - .thenReturn(new CodeableConcept()); + .thenReturn(new CodeableConcept()); - var ehrExtract = unmarshallEhrExtract("degraded-non-drug-allergy-structure.xml"); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); assertThat(allergyIntolerances).hasSize(1); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertThat(allergyIntolerance.getCode().getCodingFirstRep()) .isEqualTo(DegradedCodeableConcepts.DEGRADED_NON_DRUG_ALLERGY); } @Test - public void testMapDegradedDrugAllergy() { + void testGivenCompoundStatementCodeOfDrugAllergyCodeThenSetsCodeToTransferDegradedDrugAllergy() { when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) .thenReturn(nonSnomedCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("degraded-drug-allergy-structure.xml"); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("degraded-drug-allergy-structure.xml"); + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); assertThat(allergyIntolerances).hasSize(1); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertThat(allergyIntolerance.getCode().getCodingFirstRep()) .isEqualTo(DegradedCodeableConcepts.DEGRADED_DRUG_ALLERGY); } @Test - public void When_AllergyWithOriginalTextAndNoValue_Expect_MapsCodingTextFromCodeOriginalText() { + void testGivenAllergyWithOriginalTextAndNoValueThenMapsCodingTextFromCodeOriginalText() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("allergy-structure-with-original-text-in-code.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) .thenReturn(defaultCodeableConcept()) .thenReturn(secondaryCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("allergy-structure-with-original-text-in-code.xml"); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); assertThat(allergyIntolerances).hasSize(1); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertFixedValues(allergyIntolerance); @@ -251,17 +358,17 @@ public void When_AllergyWithOriginalTextAndNoValue_Expect_MapsCodingTextFromCode } @Test - public void testMapAllergyWithNoOptionalData() { + void testGivenAllergyWithNoOptionalData() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("allergy-structure-with-optional-data.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))).thenReturn(defaultCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("allergy-structure-with-optional-data.xml"); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); assertThat(allergyIntolerances).hasSize(1); - var allergyIntolerance = allergyIntolerances.get(0); - + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertFixedValues(allergyIntolerance); - assertThat(allergyIntolerance.getCode().getCodingFirstRep()).isEqualTo(DegradedCodeableConcepts.DEGRADED_DRUG_ALLERGY); assertThat(allergyIntolerance.getCode().getCoding().get(1).getDisplay()).isEqualTo(CODING_DISPLAY_1); assertThat(allergyIntolerance.getAssertedDateElement().asStringValue()).isEqualTo("2019-07-08T13:35:00+00:00"); @@ -272,14 +379,16 @@ public void testMapAllergyWithNoOptionalData() { } @Test - public void testMapAllergyAssertedDateFallbackData() { + void testGivenUnkAvailabilityTimeThenAssertedDateIsAuthorTime() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("allergy-structure-with-asserted-date-fallback.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))).thenReturn(defaultCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("allergy-structure-with-asserted-date-fallback.xml"); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), - getEncounterList(), PRACTISE_CODE); + + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + getEncounterList(), PRACTISE_CODE); assertThat(allergyIntolerances).hasSize(1); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertFixedValues(allergyIntolerance); @@ -287,35 +396,41 @@ public void testMapAllergyAssertedDateFallbackData() { } @Test - public void testMapMultipleAllergies() { + void testGivenMultipleAllergiesThenExpectAllToBePresent() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("allergy-structure-with-multiple-allergy.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))).thenReturn(defaultCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("allergy-structure-with-multiple-allergy.xml"); - List allergyIntolerances - = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); + + final List allergyIntolerances + = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); assertEquals(THREE, allergyIntolerances.size()); } @Test - public void testMapStandaloneAllergy() { + void testGivenStandaloneAllergyThenNoExtensionPresent() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("allergy-structure-invalid-encounter-reference.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))).thenReturn(defaultCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("allergy-structure-invalid-encounter-reference.xml"); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertThat(allergyIntolerance.getExtension()).isEmpty(); } @Test - public void testMapAllergyWithSameTermTexts() { + void testGivenAllergyWithSameTermTexts() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("drug-allergy-structure-with-term-text.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))).thenReturn(defaultCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("drug-allergy-structure-with-term-text.xml"); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); assertThat(allergyIntolerances).hasSize(1); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertFixedValues(allergyIntolerance); @@ -333,16 +448,18 @@ public void testMapAllergyWithSameTermTexts() { } @Test - public void testMapAllergyWithDrugTermText() { + void testMapAllergyWithDrugTermText() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("drug-allergy-structure-with-term-text.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) .thenReturn(tertiaryCodeableConcept()) .thenReturn(tertiaryCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("drug-allergy-structure-with-term-text.xml"); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); assertThat(allergyIntolerances).hasSize(1); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertFixedValues(allergyIntolerance); @@ -360,16 +477,18 @@ public void testMapAllergyWithDrugTermText() { } @Test - public void When_DrugAllergyWithValueElement_Expect_MapsCodingTextFromValueDescription() { + void testGivenDrugAllergyWithValueElementThenMapsCodingTextFromValueDescription() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("drug-allergy-with-value.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) .thenReturn(defaultCodeableConcept()) .thenReturn(secondaryCodeableConcept()); - var ehrExtract = unmarshallEhrExtract("drug-allergy-with-value.xml"); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); assertThat(allergyIntolerances).hasSize(1); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertFixedValues(allergyIntolerance); @@ -379,59 +498,57 @@ public void When_DrugAllergyWithValueElement_Expect_MapsCodingTextFromValueDescr } @Test - public void When_AllergyIntoleranceWithQualifierAndOriginalText_Expect_NotesContainsEpisodicity() { - when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) - .thenReturn(defaultCodeableConcept()); + void testGivenAllergyIntoleranceWithQualifierAndOriginalTextThenNotesContainsEpisodicity() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("drug_allergy_with_qualifier_and_original_text.xml"); - var ehrExtract = unmarshallEhrExtract("drug_allergy_with_qualifier_and_original_text.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) + .thenReturn(defaultCodeableConcept()); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), - getEncounterList(), PRACTISE_CODE); + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + getEncounterList(), PRACTISE_CODE); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertThat(allergyIntolerance.getNote().get(0).getText()) .isEqualTo(EPISODICITY_WITH_ORIGINAL_TEXT_NOTE_TEXT); } @Test - public void When_AllergyIntoleranceWithQualifierAndWithoutOriginalText_Expect_NotesContainsEpisodicity() { - when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) - .thenReturn(defaultCodeableConcept()); + void testGivenAllergyIntoleranceWithQualifierAndWithoutOriginalTextThenNotesContainsEpisodicity() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("drug_allergy_with_qualifier_without_original_text.xml"); - var ehrExtract = unmarshallEhrExtract("drug_allergy_with_qualifier_without_original_text.xml"); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) + .thenReturn(defaultCodeableConcept()); - List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), - getEncounterList(), PRACTISE_CODE); + final List allergyIntolerances = allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), + getEncounterList(), PRACTISE_CODE); - var allergyIntolerance = allergyIntolerances.get(0); + final AllergyIntolerance allergyIntolerance = allergyIntolerances.get(0); assertThat(allergyIntolerance.getNote().get(0).getText()) .isEqualTo(EPISODICITY_WITHOUT_ORIGINAL_TEXT_NOTE_TEXT); } - - @ParameterizedTest @MethodSource("allergyStructuresWithTranslations") - public void testTppNamedSchemaInValue(String filename) { - when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) - .thenReturn(tertiaryCodeableConcept()); + void testTppNamedSchemaInValue(String filename) { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract(filename); - var ehrExtract = unmarshallEhrExtract(filename); + when(codeableConceptMapper.mapToCodeableConcept(any(CD.class))) + .thenReturn(tertiaryCodeableConcept()); allergyIntoleranceMapper.mapResources(ehrExtract, getPatient(), getEncounterList(), PRACTISE_CODE); verify(codeableConceptMapper, times(2)).mapToCodeableConcept(cdCaptor.capture()); - CD cd = cdCaptor.getAllValues().get(1); + final CD cd = cdCaptor.getAllValues().get(1); assertThat(cd.getCode()).isEqualTo(MULTILEX_COCONUT_OIL); assertThat(cd.getCodeSystem()).isEqualTo(MULTILEX_CODE_SYSTEM); assertThat(cd.getDisplayName()).isEqualTo(CODING_DISPLAY_4); assertThat(cd.getTranslation().size()).isOne(); - var translation = cd.getTranslation().get(0); + final CD translation = cd.getTranslation().get(0); assertThat(translation.getCodeSystem()).isEqualTo(SNOMED_CODE_SYSTEM); assertThat(translation.getCode()).isEqualTo(SNOMED_COCONUT_OIL); @@ -503,4 +620,4 @@ private CodeableConcept nonSnomedCodeableConcept() { private RCMRMT030101UKEhrExtract unmarshallEhrExtract(String fileName) { return unmarshallFile(getFile("classpath:" + XML_RESOURCES_BASE + fileName), RCMRMT030101UKEhrExtract.class); } -} +} \ No newline at end of file diff --git a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/util/ConfidentialityUtilTest.java b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/util/ConfidentialityUtilTest.java new file mode 100644 index 000000000..27050291a --- /dev/null +++ b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/util/ConfidentialityUtilTest.java @@ -0,0 +1,65 @@ +package uk.nhs.adaptors.pss.translator.util; + +import org.hl7.fhir.dstu3.model.Meta; +import org.hl7.fhir.dstu3.model.UriType; +import org.hl7.v3.CV; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +class ConfidentialityUtilTest { + private static final CV CV_WITH_NOPAT = new CV(); + private static final CV CV_WITHOUT_NOPAT = new CV(); + private static final Meta INITIAL_META = new Meta().setProfile( + Collections.singletonList( + new UriType("https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-AllergyIntolerance-1") + ) + ); + + static { + CV_WITH_NOPAT.setCode("NOPAT"); + CV_WITHOUT_NOPAT.setCode("NOSCRUB"); + } + + @Test + void When_CvWithNopatAndOptionalEmpty_Expect_MetaSecurityAdded() { + // when + final Meta expected = ConfidentialityUtil.addSecurityToMetaIfConfidentialityCodesPresent(List.of( + Optional.of(CV_WITH_NOPAT), + Optional.empty() + ), INITIAL_META); + + // then + assertThat(expected.getSecurity()).hasSize(1); + assertThat(expected.getSecurity().get(0).getCode()).isEqualTo("NOPAT"); + } + + @Test + void When_CvWithNopatAndCvWithoutNopat_Expect_MetaSecurityAdded() { + // when + final Meta expected = ConfidentialityUtil.addSecurityToMetaIfConfidentialityCodesPresent(List.of( + Optional.of(CV_WITH_NOPAT), + Optional.of(CV_WITHOUT_NOPAT) + ), INITIAL_META); + + // then + assertThat(expected.getSecurity()).hasSize(1); + assertThat(expected.getSecurity().get(0).getCode()).isEqualTo("NOPAT"); + } + + @Test + void When_CvWithoutNopatAndOptionalEmpty_Expect_MetaSecurityNotAdded() { + // when + final Meta expected = ConfidentialityUtil.addSecurityToMetaIfConfidentialityCodesPresent(List.of( + Optional.of(CV_WITHOUT_NOPAT), + Optional.empty() + ), INITIAL_META); + + // then + assertThat(expected.getSecurity()).isEmpty(); + } +} \ No newline at end of file diff --git a/gp2gp-translator/src/test/resources/xml/AllergyIntolerance/allergy-structure-with-ehr-composition-confidentiality-code.xml b/gp2gp-translator/src/test/resources/xml/AllergyIntolerance/allergy-structure-with-ehr-composition-confidentiality-code.xml new file mode 100644 index 000000000..a8aa99034 --- /dev/null +++ b/gp2gp-translator/src/test/resources/xml/AllergyIntolerance/allergy-structure-with-ehr-composition-confidentiality-code.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/gp2gp-translator/src/test/resources/xml/AllergyIntolerance/allergy-structure-with-observation-statement-confidentiality-code.xml b/gp2gp-translator/src/test/resources/xml/AllergyIntolerance/allergy-structure-with-observation-statement-confidentiality-code.xml new file mode 100644 index 000000000..21b1121ec --- /dev/null +++ b/gp2gp-translator/src/test/resources/xml/AllergyIntolerance/allergy-structure-with-observation-statement-confidentiality-code.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + \ No newline at end of file