Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions gp2gp-translator/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,8 @@ pitest {
pitestGithub {
deleteOldSummaries = true
}

checkstyle {
configFile file('../config/checkstyle/checkstyle.xml')
toolVersion '13.0.0'
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Resource, Boolean> checker;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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;
Expand Down Expand Up @@ -210,21 +214,16 @@ private Optional<DateTimeType> 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) {
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<RCMRMT030101UKAuthorise> 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,
Expand All @@ -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<RCMRMT030101UKAuthorise> 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()));
}

Expand Down Expand Up @@ -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<RCMRMT030101UKAuthorise> 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");
Expand Down Expand Up @@ -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<RCMRMT030101UKAuthorise> 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<RCMRMT030101UKAuthorise> 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<RCMRMT030101UKAuthorise> 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);
Expand Down