diff --git a/CHANGELOG.md b/CHANGELOG.md index fde97680d..299d637b2 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 +### Changed +* Updated the Requesting Adaptor to map newly granular EHRSupplyType values from EMIS into the corresponding GPC JSON record fields. + ### Added * Added support for mapping different EhrSupplyType (e.g. NHS prescription, OTC sale) into the Medication Statement Prescribing Agency extension * Added fallback for Condition.asserter to use the EHRComposition / author / agent field when EHRComposition / participant2 is absent diff --git a/gp2gp-translator/build.gradle b/gp2gp-translator/build.gradle index 67577303c..f7d84553a 100644 --- a/gp2gp-translator/build.gradle +++ b/gp2gp-translator/build.gradle @@ -132,3 +132,8 @@ pitest { pitestGithub { deleteOldSummaries = true } + +checkstyle { + configFile file('../config/checkstyle/checkstyle.xml') + toolVersion '13.0.0' +} diff --git a/gp2gp-translator/src/integrationTest/java/uk/nhs/adaptors/pss/util/JsonPathIgnoreGeneratorUtil.java b/gp2gp-translator/src/integrationTest/java/uk/nhs/adaptors/pss/util/JsonPathIgnoreGeneratorUtil.java index 920213d8b..d83b4fbdc 100644 --- a/gp2gp-translator/src/integrationTest/java/uk/nhs/adaptors/pss/util/JsonPathIgnoreGeneratorUtil.java +++ b/gp2gp-translator/src/integrationTest/java/uk/nhs/adaptors/pss/util/JsonPathIgnoreGeneratorUtil.java @@ -94,7 +94,7 @@ private static Boolean isUnknownPerformer(Resource resource) { @Data @RequiredArgsConstructor @AllArgsConstructor - private static class IgnoreParameters { + private static final class IgnoreParameters { private final ResourceType resourceType; private final String fieldName; private Function checker; diff --git a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/medication/MedicationStatementMapper.java b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/medication/MedicationStatementMapper.java index c0b86ba54..85f104e60 100644 --- a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/medication/MedicationStatementMapper.java +++ b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/medication/MedicationStatementMapper.java @@ -56,8 +56,6 @@ public class MedicationStatementMapper { private static final String PRESCRIBING_AGENCY_SYSTEM = "https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-PrescribingAgency-1"; - private static final String PRESCRIPTION = "NHS prescription"; - private static final String MS_SUFFIX = "-MS"; private static final String PRESCRIBED_CODE = "prescribed-at-gp-practice"; private static final String PRESCRIBED_DISPLAY = "Prescribed at GP practice"; @@ -67,6 +65,12 @@ public class MedicationStatementMapper { private static final String PRESCRIBED_BY_PREVIOUS_PRACTICE_DISPLAY = "Prescribed by previous practice"; private static final String OTC_SALE = "OTC Sale"; private static final String COMPLETE = "COMPLETE"; + private static final String PRESCRIPTION_BY_ANOTHER_ORGANISATION = "Prescription by another organisation"; + private static final String PERSONAL_ADMINISTRATION = "Personal Administration"; + private static final String ACBS_PRESCRIPTION = "ACBS Prescription"; + private static final String NHS_PRESCRIPTION = "NHS Prescription"; + private static final String PRIVATE_PRESCRIPTION = "Private Prescription"; + private static final String PAST_MEDICATION = "Past medication"; private final MedicationMapper medicationMapper; private final ConfidentialityService confidentialityService; @@ -210,21 +214,16 @@ private Optional extractHighestSupplyPrescribeTime(RCMRMT030101UKE private Extension generatePrescribingAgencyExtension(RCMRMT030101UKAuthorise supplyAuthorise) { String displayName = supplyAuthorise.getCode().getDisplayName(); - String code; - String display; - - if (PRESCRIBED_BY_ANOTHER_ORGANISATION_DISPLAY.equals(displayName) || OTC_SALE.equals(displayName)) { - code = PRESCRIBED_BY_ANOTHER_ORGANISATION_CODE; - display = PRESCRIBED_BY_ANOTHER_ORGANISATION_DISPLAY; - } else if (PRESCRIBED_BY_PREVIOUS_PRACTICE_DISPLAY.equals(displayName)) { - code = PRESCRIBED_BY_PREVIOUS_PRACTICE_CODE; - display = PRESCRIBED_BY_PREVIOUS_PRACTICE_DISPLAY; - } else { - code = PRESCRIBED_CODE; - display = PRESCRIBED_DISPLAY; - } - - return buildExtension(code, display); + return switch (displayName) { + case String display when isPrescribedByAnotherOrganisation(display) + -> buildExtension(PRESCRIBED_BY_ANOTHER_ORGANISATION_CODE, PRESCRIBED_BY_ANOTHER_ORGANISATION_DISPLAY); + case String display when isPrescribedByPreviousPractice(display) + -> buildExtension(PRESCRIBED_BY_PREVIOUS_PRACTICE_CODE, PRESCRIBED_BY_PREVIOUS_PRACTICE_DISPLAY); + case String s when isPrescribedAtThisPractice(s) + -> buildExtension(PRESCRIBED_CODE, PRESCRIBED_DISPLAY); + default + -> throw new IllegalArgumentException("Unsupported prescribing agency: " + displayName); + }; } private Extension buildExtension(String code, String display) { @@ -239,4 +238,22 @@ private boolean hasLinkedInFulfillment(RCMRMT030101UKPrescribe prescribe, String && prescribe.getInFulfillmentOf().getPriorMedicationRef().getId().hasRoot() && prescribe.getInFulfillmentOf().getPriorMedicationRef().getId().getRoot().equals(id); } + + private static Boolean isPrescribedByAnotherOrganisation(String display) { + return display.equalsIgnoreCase(PRESCRIBED_BY_ANOTHER_ORGANISATION_DISPLAY) + || display.equalsIgnoreCase(OTC_SALE) + || display.equalsIgnoreCase(PERSONAL_ADMINISTRATION) + || display.equalsIgnoreCase(PRESCRIPTION_BY_ANOTHER_ORGANISATION); + } + + private static boolean isPrescribedByPreviousPractice(String display) { + return display.equalsIgnoreCase(PRESCRIBED_BY_PREVIOUS_PRACTICE_DISPLAY); + } + + private static boolean isPrescribedAtThisPractice(String display) { + return display.equalsIgnoreCase(NHS_PRESCRIPTION) + || display.equalsIgnoreCase(PRIVATE_PRESCRIPTION) + || display.equalsIgnoreCase(ACBS_PRESCRIPTION) + || display.equalsIgnoreCase(PAST_MEDICATION); + } } diff --git a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/medication/MedicationStatementMapperTest.java b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/medication/MedicationStatementMapperTest.java index 2666cc962..21e8a74f6 100644 --- a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/medication/MedicationStatementMapperTest.java +++ b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/medication/MedicationStatementMapperTest.java @@ -7,6 +7,7 @@ import static org.hl7.fhir.dstu3.model.MedicationStatement.MedicationStatementTaken.UNK; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @@ -72,6 +73,11 @@ class MedicationStatementMapperTest { private static final String PRESCRIBED_CODE = "prescribed-at-gp-practice"; private static final String PRESCRIBED_DISPLAY = "Prescribed at GP practice"; private static final String OTC_SALE = "OTC Sale"; + private static final String ACBS_PRESCRIPTION = "ACBS Prescription"; + private static final String PRIVATE_PRESCRIPTION = "Private Prescription"; + private static final String PAST_MEDICATION = "Past medication"; + private static final String PERSONAL_ADMINISTRATION = "Personal Administration"; + private static final String PRESCRIPTION_BY_ANOTHER_ORGANISATION = "Prescription by another organisation"; @Mock private MedicationMapper medicationMapper; @@ -108,6 +114,32 @@ void When_MappingPrescribedWithUnknownEhrSupplyType_Expect_MedStatementMappedToD .findFirst(); authorise.get().getCode().setDisplayName("unknown EhrSupplyType"); + Exception exception = assertThrows(IllegalArgumentException.class, + () -> medicationStatementMapper.mapToMedicationStatement( + ehrExtract, + ehrComposition, + medicationStatement, + authorise.get(), + PRACTISE_CODE, + new DateTimeType())); + + assertThat(exception.getMessage()).contains("Unsupported prescribing agency: unknown EhrSupplyType"); + } + + @Test + void When_MappingPrescribedByAnotherOrganization_Expect_AllFieldsToBeMappedCorrectly() throws JAXBException { + final File file = FileFactory.getXmlFileFor("MedicationStatement", "ehrExtract3.xml"); + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallFile(file, RCMRMT030101UKEhrExtract.class); + final RCMRMT030101UKEhrComposition ehrComposition = GET_EHR_COMPOSITION.apply(ehrExtract); + final RCMRMT030101UKMedicationStatement medicationStatement = + unmarshallMedicationStatement("medicationStatementAuthoriseAllOptionals_MedicationStatement.xml"); + final Optional authorise = medicationStatement.getComponent() + .stream() + .filter(RCMRMT030101UKComponent2::hasEhrSupplyAuthorise) + .map(RCMRMT030101UKComponent2::getEhrSupplyAuthorise) + .findFirst(); + authorise.get().getCode().setDisplayName(PRESCRIPTION_BY_ANOTHER_ORGANISATION); + final MedicationStatement result = medicationStatementMapper.mapToMedicationStatement( ehrExtract, ehrComposition, @@ -117,8 +149,38 @@ void When_MappingPrescribedWithUnknownEhrSupplyType_Expect_MedStatementMappedToD new DateTimeType()); assertAll( - () -> assertEquals(PRESCRIBED_CODE, ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getCode()), - () -> assertEquals(PRESCRIBED_DISPLAY, + () -> assertEquals(PRESCRIBED_BY_ANOTHER_ORGANISATION_CODE, + ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getCode()), + () -> assertEquals(PRESCRIBED_BY_ANOTHER_ORGANISATION_DISPLAY, + ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getDisplay())); + } + + @Test + void When_MappingPrescribedByPersonalAdministration_Expect_AllFieldsToBeMappedCorrectly() throws JAXBException { + final File file = FileFactory.getXmlFileFor("MedicationStatement", "ehrExtract3.xml"); + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallFile(file, RCMRMT030101UKEhrExtract.class); + final RCMRMT030101UKEhrComposition ehrComposition = GET_EHR_COMPOSITION.apply(ehrExtract); + final RCMRMT030101UKMedicationStatement medicationStatement = + unmarshallMedicationStatement("medicationStatementAuthoriseAllOptionals_MedicationStatement.xml"); + final Optional authorise = medicationStatement.getComponent() + .stream() + .filter(RCMRMT030101UKComponent2::hasEhrSupplyAuthorise) + .map(RCMRMT030101UKComponent2::getEhrSupplyAuthorise) + .findFirst(); + authorise.get().getCode().setDisplayName(PERSONAL_ADMINISTRATION); + + final MedicationStatement result = medicationStatementMapper.mapToMedicationStatement( + ehrExtract, + ehrComposition, + medicationStatement, + authorise.get(), + PRACTISE_CODE, + new DateTimeType()); + + assertAll( + () -> assertEquals(PRESCRIBED_BY_ANOTHER_ORGANISATION_CODE, + ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getCode()), + () -> assertEquals(PRESCRIBED_BY_ANOTHER_ORGANISATION_DISPLAY, ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getDisplay())); } @@ -150,6 +212,34 @@ void When_MappingPrescribedByNhsResource_Expect_AllFieldsToBeMappedCorrectly() t ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getDisplay())); } + @Test + void When_MappingPrescribedByLowercaseNhsResource_Expect_AllFieldsToBeMappedCorrectly() throws JAXBException { + final File file = FileFactory.getXmlFileFor("MedicationStatement", "ehrExtract3.xml"); + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallFile(file, RCMRMT030101UKEhrExtract.class); + final RCMRMT030101UKEhrComposition ehrComposition = GET_EHR_COMPOSITION.apply(ehrExtract); + final RCMRMT030101UKMedicationStatement medicationStatement = + unmarshallMedicationStatement("medicationStatementAuthoriseAllOptionals_MedicationStatement.xml"); + final Optional authorise = medicationStatement.getComponent() + .stream() + .filter(RCMRMT030101UKComponent2::hasEhrSupplyAuthorise) + .map(RCMRMT030101UKComponent2::getEhrSupplyAuthorise) + .findFirst(); + authorise.get().getCode().setDisplayName(PRESCRIPTION.toLowerCase()); + + final MedicationStatement result = medicationStatementMapper.mapToMedicationStatement( + ehrExtract, + ehrComposition, + medicationStatement, + authorise.get(), + PRACTISE_CODE, + new DateTimeType()); + + assertAll( + () -> assertEquals(PRESCRIBED_CODE, ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getCode()), + () -> assertEquals(PRESCRIBED_DISPLAY, + ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getDisplay())); + } + @Test void When_MappingPrescribeResourceWithAnotherOrg_Expect_AllFieldsToBeMappedCorrectly() throws JAXBException { final File file = FileFactory.getXmlFileFor("MedicationStatement", "ehrExtract3.xml"); @@ -237,6 +327,93 @@ void When_MappingPrescribeResourceWithOtcSale_Expect_AllFieldsToBeMappedCorrectl ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getDisplay())); } + @Test + void When_MappingPrescribeResourceWithACBSPrescription_Expect_AllFieldsToBeMappedCorrectly() throws JAXBException { + final File file = FileFactory.getXmlFileFor("MedicationStatement", "ehrExtract3.xml"); + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallFile(file, RCMRMT030101UKEhrExtract.class); + final RCMRMT030101UKEhrComposition ehrComposition = GET_EHR_COMPOSITION.apply(ehrExtract); + final RCMRMT030101UKMedicationStatement medicationStatement = + unmarshallMedicationStatement("medicationStatementAuthoriseAllOptionals_MedicationStatement.xml"); + final Optional authorise = medicationStatement.getComponent() + .stream() + .filter(RCMRMT030101UKComponent2::hasEhrSupplyAuthorise) + .map(RCMRMT030101UKComponent2::getEhrSupplyAuthorise) + .findFirst(); + authorise.get().getCode().setDisplayName(ACBS_PRESCRIPTION); + + final MedicationStatement result = medicationStatementMapper.mapToMedicationStatement( + ehrExtract, + ehrComposition, + medicationStatement, + authorise.get(), + PRACTISE_CODE, + new DateTimeType()); + + assertAll( + () -> assertEquals(PRESCRIBED_CODE, + ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getCode()), + () -> assertEquals(PRESCRIBED_DISPLAY, + ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getDisplay())); + } + + @Test + void When_MappingPrescribeResourceWithPastMedication_Expect_AllFieldsToBeMappedCorrectly() throws JAXBException { + final File file = FileFactory.getXmlFileFor("MedicationStatement", "ehrExtract3.xml"); + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallFile(file, RCMRMT030101UKEhrExtract.class); + final RCMRMT030101UKEhrComposition ehrComposition = GET_EHR_COMPOSITION.apply(ehrExtract); + final RCMRMT030101UKMedicationStatement medicationStatement = + unmarshallMedicationStatement("medicationStatementAuthoriseAllOptionals_MedicationStatement.xml"); + final Optional authorise = medicationStatement.getComponent() + .stream() + .filter(RCMRMT030101UKComponent2::hasEhrSupplyAuthorise) + .map(RCMRMT030101UKComponent2::getEhrSupplyAuthorise) + .findFirst(); + authorise.get().getCode().setDisplayName(PAST_MEDICATION); + + final MedicationStatement result = medicationStatementMapper.mapToMedicationStatement( + ehrExtract, + ehrComposition, + medicationStatement, + authorise.get(), + PRACTISE_CODE, + new DateTimeType()); + + assertAll( + () -> assertEquals(PRESCRIBED_CODE, + ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getCode()), + () -> assertEquals(PRESCRIBED_DISPLAY, + ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getDisplay())); + } + + @Test + void When_MappingPrescribeResourceWithPrivatePrescription_Expect_AllFieldsToBeMappedCorrectly() throws JAXBException { + final File file = FileFactory.getXmlFileFor("MedicationStatement", "ehrExtract3.xml"); + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallFile(file, RCMRMT030101UKEhrExtract.class); + final RCMRMT030101UKEhrComposition ehrComposition = GET_EHR_COMPOSITION.apply(ehrExtract); + final RCMRMT030101UKMedicationStatement medicationStatement = + unmarshallMedicationStatement("medicationStatementAuthoriseAllOptionals_MedicationStatement.xml"); + final Optional authorise = medicationStatement.getComponent() + .stream() + .filter(RCMRMT030101UKComponent2::hasEhrSupplyAuthorise) + .map(RCMRMT030101UKComponent2::getEhrSupplyAuthorise) + .findFirst(); + authorise.get().getCode().setDisplayName(PRIVATE_PRESCRIPTION); + + final MedicationStatement result = medicationStatementMapper.mapToMedicationStatement( + ehrExtract, + ehrComposition, + medicationStatement, + authorise.get(), + PRACTISE_CODE, + new DateTimeType()); + + assertAll( + () -> assertEquals(PRESCRIBED_CODE, + ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getCode()), + () -> assertEquals(PRESCRIBED_DISPLAY, + ((CodeableConcept) result.getExtension().get(0).getValue()).getCoding().get(0).getDisplay())); + } + @Test void When_MappingPrescribeResourceWithNoOptionals_Expect_AllFieldsToBeMappedCorrectly() throws JAXBException { registerDefaultDependencies(confidentialityService);