Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIAD-3220: Detect Referral + Document LinkSets and not create a Problem (Condition) from them #937

Merged
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

### Fixed

* When a `LinkSet` which is a linkage between a `ReferralRequest` and one or more `DocumentReferences` is mapped then a
`Condition` will no longer be mapped for this `Linkset`.
Instead, the `statementRef`s will be added to the `supportingInfo` when mapping the `ReferralRequest`
as `DocumentReferences`

## [3.0.7] - 2024-11-19

### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2073,6 +2073,11 @@
} ],
"text": "Referral to private doctor"
} ],
"supportingInfo": [ {
"reference": "DocumentReference/BFBF038A-F142-4C67-B05B-D155E2C89990"
}, {
"reference": "DocumentReference/6DC83A17-4DFD-4C1C-A452-45F8F8A8FBA1"
} ],
"note": [ {
"text": "Priority: Routine"
}, {
Expand Down Expand Up @@ -2623,61 +2628,6 @@
} ],
"comment": "This is a dry eyes problem {Episodicity : code=255217005, displayName=First}"
}
}, {
"resource": {
"resourceType": "Condition",
"id": "E0EF416A-A513-4668-B454-1F3002573B80",
"meta": {
"profile": [ "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-ProblemHeader-Condition-1" ]
},
"extension": [ {
"url": "https://fhir.hl7.org.uk/STU3/StructureDefinition/Extension-CareConnect-ProblemSignificance-1",
"valueCode": "minor"
}, {
"url": "https://fhir.hl7.org.uk/STU3/StructureDefinition/Extension-CareConnect-ActualProblem-1",
"valueReference": {
"reference": "ReferralRequest/E63AF323-919F-4D5F-9A1D-BA933BC230BC"
}
}, {
"url": "https://fhir.hl7.org.uk/STU3/StructureDefinition/Extension-CareConnect-RelatedClinicalContent-1",
"valueReference": {
"reference": "DocumentReference/BFBF038A-F142-4C67-B05B-D155E2C89990"
}
}, {
"url": "https://fhir.hl7.org.uk/STU3/StructureDefinition/Extension-CareConnect-RelatedClinicalContent-1",
"valueReference": {
"reference": "DocumentReference/6DC83A17-4DFD-4C1C-A452-45F8F8A8FBA1"
}
} ],
"identifier": [ {
"system": "https://PSSAdaptor/B83002",
"value": "E0EF416A-A513-4668-B454-1F3002573B80"
} ],
"clinicalStatus": "active",
"category": [ {
"coding": [ {
"system": "https://fhir.hl7.org.uk/STU3/CodeSystem/CareConnect-ConditionCategory-1",
"code": "problem-list-item",
"display": "Problem List Item"
} ]
} ],
"subject": {
"reference": "Patient/00000000-0000-0000-0000-000000000012"
},
"context": {
"reference": "Encounter/7626FAAD-8562-478D-B79C-598520953E86"
},
"onsetDateTime": "2010-01-19T11:32:00+00:00",
"assertedDate": "2010-01-19T11:32:30+00:00",
"asserter": {
"reference": "Practitioner/1E473786-E7FA-785E-C911-A8D38FB56F20"
},
"note": [ {
"text": "Defaulted status to active : Unknown status at source"
}, {
"text": "Unspecified Significance: Defaulted to Minor"
} ]
}
}, {
"resource": {
"resourceType": "Condition",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import uk.nhs.adaptors.pss.translator.service.ConfidentialityService;
import uk.nhs.adaptors.pss.translator.util.CompoundStatementResourceExtractors;
import uk.nhs.adaptors.pss.translator.util.DegradedCodeableConcepts;
import uk.nhs.adaptors.pss.translator.util.ResourceFilterUtil;
import static uk.nhs.adaptors.common.util.CodeableConceptUtils.createCodeableConcept;

@Service
Expand Down Expand Up @@ -96,6 +97,7 @@ public List<Condition> mapResources(RCMRMT030101UKEhrExtract ehrExtract, Patient
return mapEhrExtractToFhirResource(ehrExtract, (extract, composition, component) ->
extractAllLinkSets(component)
.filter(Objects::nonNull)
.filter(linkSet -> !ResourceFilterUtil.isReferralRequestToExternalDocumentLinkSet(ehrExtract, linkSet))
.map(linkSet -> getCondition(
patient,
encounters,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,36 @@
import static uk.nhs.adaptors.pss.translator.util.CompoundStatementResourceExtractors.extractAllRequestStatements;
import static uk.nhs.adaptors.pss.translator.util.ResourceUtil.buildIdentifier;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.dstu3.model.Annotation;
import org.hl7.fhir.dstu3.model.DateTimeType;
import org.hl7.fhir.dstu3.model.Encounter;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Meta;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.dstu3.model.ReferralRequest;
import org.hl7.fhir.dstu3.model.ReferralRequest.ReferralCategory;
import org.hl7.fhir.dstu3.model.ReferralRequest.ReferralRequestStatus;
import org.hl7.fhir.dstu3.model.ResourceType;
import org.hl7.v3.CD;
import org.hl7.v3.CR;
import org.hl7.v3.CV;
import org.hl7.v3.IVLTS;
import org.hl7.v3.RCMRMT030101UKComponent;
import org.hl7.v3.RCMRMT030101UKComponent3;
import org.hl7.v3.RCMRMT030101UKComponent4;
import org.hl7.v3.RCMRMT030101UKEhrComposition;
import org.hl7.v3.RCMRMT030101UKEhrExtract;
import org.hl7.v3.RCMRMT030101UKLinkSet;
import org.hl7.v3.RCMRMT030101UKPart;
import org.hl7.v3.RCMRMT030101UKRequestStatement;
import org.hl7.v3.RCMRMT030101UKResponsibleParty3;
Expand All @@ -38,6 +47,7 @@
import uk.nhs.adaptors.pss.translator.util.DateFormatUtil;
import uk.nhs.adaptors.pss.translator.util.DegradedCodeableConcepts;
import uk.nhs.adaptors.pss.translator.util.ParticipantReferenceUtil;
import uk.nhs.adaptors.pss.translator.util.ResourceFilterUtil;

@Service
@AllArgsConstructor
Expand All @@ -57,6 +67,18 @@ public class ReferralRequestMapper extends AbstractMapper<ReferralRequest> {
);
private static final String SNOMED_CODE_SYSTEM = "2.16.840.1.113883.2.1.3.2.4.15";

private static final BinaryOperator<List<Reference>> DOCUMENT_REFERENCE_MERGE_FUNCTION = (existing, added) -> {
added.forEach(addedReference -> {
if (existing.stream().noneMatch(
existingReference -> addedReference.getReference().equals(existingReference.getReference())
)) {
existing.add(addedReference);
}
});

return existing;
};

private CodeableConceptMapper codeableConceptMapper;
private ConfidentialityService confidentialityService;

Expand All @@ -65,12 +87,27 @@ public List<ReferralRequest> mapResources(RCMRMT030101UKEhrExtract ehrExtract,
List<Encounter> encounters,
String practiceCode) {

var referralRequestToDocumentReferences = extractReferralRequestIdToDocumentReferences(ehrExtract);

return mapEhrExtractToFhirResource(ehrExtract, (extract, composition, component) ->
extractAllRequestStatements(component)
.filter(Objects::nonNull)
.filter(this::isNotSelfReferral)
.map(requestStatement
-> mapToReferralRequest(ehrExtract, composition, requestStatement, patient, encounters, practiceCode)))
.map(requestStatement -> {
var documentReferences = referralRequestToDocumentReferences.getOrDefault(
requestStatement.getId().getFirst().getRoot(),
List.of()
);
return mapToReferralRequest(
ehrExtract,
composition,
requestStatement,
patient,
encounters,
documentReferences,
practiceCode
);
}))
.toList();
}

Expand All @@ -79,14 +116,20 @@ public ReferralRequest mapToReferralRequest(RCMRMT030101UKEhrExtract ehrExtract,
RCMRMT030101UKRequestStatement requestStatement,
Patient patient,
List<Encounter> encounters,
String practiceCode) {
List<Reference> documentReferences,
String practiceCode
) {

var referralRequest = initializeReferralRequest(ehrComposition, requestStatement, patient, practiceCode);

setReferralRequestContext(referralRequest, ehrComposition, encounters);
setReferralRequestRecipient(ehrExtract, requestStatement, referralRequest);
setReferralRequestReasonCode(referralRequest, requestStatement.getCode());

if (!documentReferences.isEmpty()) {
referralRequest.setSupportingInfo(documentReferences);
}

return referralRequest;
}

Expand Down Expand Up @@ -274,4 +317,32 @@ private boolean isNotSelfReferral(RCMRMT030101UKRequestStatement requestStatemen
}
return true;
}

private static Map<String, List<Reference>> extractReferralRequestIdToDocumentReferences(
MartinWheelerMT marked this conversation as resolved.
Show resolved Hide resolved
RCMRMT030101UKEhrExtract ehrExtract) {

return ehrExtract.getComponent()
.stream()
.map(RCMRMT030101UKComponent::getEhrFolder)
.flatMap(ehrFolder -> ehrFolder.getComponent().stream())
.map(RCMRMT030101UKComponent3::getEhrComposition)
.flatMap(ehrComposition -> ehrComposition.getComponent().stream())
.map(RCMRMT030101UKComponent4::getLinkSet)
.filter(Objects::nonNull)
.filter(linkSet -> ResourceFilterUtil.isReferralRequestToExternalDocumentLinkSet(ehrExtract, linkSet))
.map(ReferralRequestMapper::buildReferralRequestToDocumentReferenceSimpleEntry)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, DOCUMENT_REFERENCE_MERGE_FUNCTION));
}

private static AbstractMap.SimpleEntry<String, List<Reference>> buildReferralRequestToDocumentReferenceSimpleEntry(
RCMRMT030101UKLinkSet linkSet
) {
var referralRequestId = linkSet.getConditionNamed().getNamedStatementRef().getId().getRoot();
var documentReferences = linkSet.getComponent().stream()
.map(component -> component.getStatementRef().getId().getRoot())
.map(id -> new Reference(new IdType(ResourceType.DocumentReference.name(), id)))
.collect(Collectors.toCollection(ArrayList::new));

return new AbstractMap.SimpleEntry<>(referralRequestId, documentReferences);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,18 @@ void When_Condition_With_NopatConfidentialityCodeInEhrComposition_Expect_MetaFro
);
}

@Test
void When_MappingLinksetWhichIsAReferralRequestToExternalDocumentLinkSet_Expect_ConditionNotToBeMapped() {
final var ehrExtract = unmarshallEhrExtract(
"ResourceFilter",
"ehr_extract_with_referral_request_to_external_document_linkset.xml"
);

final List<Condition> conditions = conditionMapper.mapResources(ehrExtract, patient, Collections.emptyList(), PRACTISE_CODE);

assertThat(conditions).hasSize(0);
}

private void addMedicationRequestsToBundle(Bundle bundle) {
var planMedicationRequest = new MedicationRequest().setId(AUTHORISE_ID);
var orderMedicationRequest = new MedicationRequest().setId(PRESCRIBE_ID);
Expand Down Expand Up @@ -448,11 +460,16 @@ private void assertAllConditionsHaveMeta(List<Condition> conditions, Meta expect
}

@SneakyThrows
private RCMRMT030101UKEhrExtract unmarshallEhrExtract(String filename) {
final File file = FileFactory.getXmlFileFor(TEST_FILES_DIRECTORY, filename);
private RCMRMT030101UKEhrExtract unmarshallEhrExtract(String testFilesDirectory, String filename) {
final File file = FileFactory.getXmlFileFor(testFilesDirectory, filename);
return unmarshallFile(file, RCMRMT030101UKEhrExtract.class);
}

@SneakyThrows
private RCMRMT030101UKEhrExtract unmarshallEhrExtract(String filename) {
return unmarshallEhrExtract(TEST_FILES_DIRECTORY, filename);
}

private void configureCommonStubs() {
Mockito.lenient().when(dateTimeMapper.mapDateTime(
any(String.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.ReferralRequest;
import org.hl7.fhir.dstu3.model.ReferralRequest.ReferralRequestStatus;
import org.hl7.fhir.dstu3.model.ResourceType;
import org.hl7.v3.CV;
import org.hl7.v3.RCMRMT030101UKEhrComposition;
import org.hl7.v3.RCMRMT030101UKEhrExtract;
Expand Down Expand Up @@ -552,6 +553,63 @@ void When_MapToReferralRequest_With_NopatConfidentialityCodeWithinEhrComposition
);
}

@Test
void When_MappingReferralRequestReferencedByReferralRequestToExternalDocumentLinkSet_Expect_SupportingInfoReferencesLinksetDocuments() {
final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtractElement(
"ResourceFilter",
"ehr_extract_with_referral_request_to_external_document_linkset.xml"
);

final var referralRequests = referralRequestMapper.mapResources(
ehrExtract,
(Patient) new Patient().setId(PATIENT_ID),
List.of(),
PRACTISE_CODE
);
final var referralRequest = referralRequests.getFirst();

assertAll(
() -> assertThat(referralRequest.getSupportingInfo())
.hasSize(2),
() -> assertThat(referralRequest.getSupportingInfo().getFirst().getReferenceElement().getResourceType())
.isEqualTo(ResourceType.DocumentReference.name()),
() -> assertThat(referralRequest.getSupportingInfo().getFirst().getReferenceElement().getIdPart())
.isEqualTo("narrative-statement-1"),
() -> assertThat(referralRequest.getSupportingInfo().getLast().getReferenceElement().getResourceType())
.isEqualTo(ResourceType.DocumentReference.name()),
() -> assertThat(referralRequest.getSupportingInfo().getLast().getReferenceElement().getIdPart())
.isEqualTo("narrative-statement-2")
);
}

@Test
void When_ReferralRequestReferencedByMultipleLinkSets_Expect_AllRelatedDocumentReferencesAddedAsSupportingInfo() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice.

final var expectedSize = 3;
final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtractElement(
"ehr_extract_with_multiple_request_statement_to_external_document_linksets.xml"
);


final var referralRequests = referralRequestMapper.mapResources(
ehrExtract,
(Patient) new Patient().setId(PATIENT_ID),
List.of(),
PRACTISE_CODE
);
final var referralRequest = referralRequests.getFirst();
assertAll(
() -> assertThat(referralRequest.getSupportingInfo()).hasSize(expectedSize),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: The containsExactly below already checks that there will be three items, so this is a little redundant.

() -> assertThat(referralRequest.getSupportingInfo())
.extracting(reference -> reference.getReferenceElement().getIdPart())
.containsExactly(
"narrative-statement-1",
"narrative-statement-2",
"narrative-statement-3"
)
);

}

private RCMRMT030101UKRequestStatement getNestedRequestStatement(RCMRMT030101UKEhrComposition ehrComposition) {
return ehrComposition.getComponent()
.getFirst()
Expand Down Expand Up @@ -595,6 +653,7 @@ private static ReferralRequest mapReferralRequest(RCMRMT030101UKEhrExtract ehrEx
requestStatement,
patient,
List.of(encounter),
List.of(),
PRACTISE_CODE);
}

Expand All @@ -618,10 +677,17 @@ private RCMRMT030101UKEhrComposition unmarshallStringToEhrCompositionElement(Str

@SneakyThrows
private RCMRMT030101UKEhrExtract unmarshallEhrExtractElement(String fileName) {
final File file = FileFactory.getXmlFileFor(TEST_DIRECTORY_NAME, fileName);
return unmarshallEhrExtractElement(TEST_DIRECTORY_NAME, fileName);
}

@SneakyThrows
private RCMRMT030101UKEhrExtract unmarshallEhrExtractElement(String testDirectory, String fileName) {
final File file = FileFactory.getXmlFileFor(testDirectory, fileName);
return unmarshallFile(file, RCMRMT030101UKEhrExtract.class);
}



@SneakyThrows
private RCMRMT030101UKEhrExtract unmarshallStringToEhrExtractElement(String inputXml) {
return unmarshallString(inputXml, RCMRMT030101UKEhrExtract.class);
Expand Down
Loading