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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* The GP2GP Adaptor now throws an exception when the Access Structure Record is empty, thereby rejecting the transfer

### Fixed
* When DiagnosticReport doesn't contain a Specimen reference, instead of "DUMMY" "NOT-PRESENT" value is used
* When DiagnosticReport doesn't contain a Specimen or Observation reference, instead of "DUMMY" "NOT-PRESENT" value is used

### Update

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
public class DiagnosticReportMapper {

public static final String NOT_PRESENT_SPECIMEN_ID_PREFIX = "NOT-PRESENT-SPECIMEN-";
public static final String DUMMY_OBSERVATION_ID_PREFIX = "DUMMY-OBSERVATION-";
public static final String NOT_PRESENT_OBSERVATION_ID_PREFIX = "NOT-PRESENT-OBSERVATION-";

private static final Mustache DIAGNOSTIC_REPORT_COMPOUND_STATEMENT_TEMPLATE =
TemplateUtils.loadTemplate("diagnostic_report_compound_statement_template.mustache");
Expand All @@ -80,25 +80,25 @@ public String mapDiagnosticReportToCompoundStatement(DiagnosticReport diagnostic
final IdMapper idMapper = messageContext.getIdMapper();
markObservationsAsProcessed(idMapper, observations);

List<Observation> observationsWithAttachedDummySpecimens =
new ArrayList<>(assignDummySpecimensToObservationsWithNoSpecimen(observations, specimens));
List<Observation> observationsWithAttachedNotPresentSpecimens =
new ArrayList<>(assignNotPresentSpecimensToObservationsWithNoSpecimen(observations, specimens));

observations = addDummyObservationsToObservationList(
observationsWithAttachedDummySpecimens,
observations = addNotPresentObservationsToObservationList(
observationsWithAttachedNotPresentSpecimens,
specimens,
diagnosticReport);

List<Observation> observationsWithDummySpecimensAndDummyObservations = observations;
List<Observation> observationsWithNotPresentSpecimensAndNotPresentObservations = observations;

String mappedSpecimens = specimens.stream()
.map(specimen -> specimenMapper.mapSpecimenToCompoundStatement(specimen,
observationsForSpecimen(specimen, observationsWithDummySpecimensAndDummyObservations),
observationsForSpecimen(specimen, observationsWithNotPresentSpecimensAndNotPresentObservations),
diagnosticReport))
.collect(Collectors.joining());

String reportLevelNarrativeStatements = prepareReportLevelNarrativeStatements(
diagnosticReport,
observationsWithDummySpecimensAndDummyObservations);
observationsWithNotPresentSpecimensAndNotPresentObservations);

var diagnosticReportCompoundStatementTemplateParameters = DiagnosticReportCompoundStatementTemplateParameters.builder()
.compoundStatementId(idMapper.getOrNew(ResourceType.DiagnosticReport, diagnosticReport.getIdElement()))
Expand Down Expand Up @@ -146,14 +146,14 @@ private List<Specimen> fetchSpecimens(DiagnosticReport diagnosticReport, List<Ob
}

var inputBundleHolder = messageContext.getInputBundleHolder();
List<Specimen> nonDummySpecimens = diagnosticReport.getSpecimen()
List<Specimen> nonNotPresentSpecimens = diagnosticReport.getSpecimen()
.stream()
.map(specimenReference -> inputBundleHolder.getResource(specimenReference.getReferenceElement()))
.flatMap(Optional::stream)
.map(Specimen.class::cast)
.toList();

specimens.addAll(nonDummySpecimens);
specimens.addAll(nonNotPresentSpecimens);

return specimens;
}
Expand All @@ -166,9 +166,9 @@ private boolean hasObservationsWithoutSpecimen(List<Observation> observations) {
}

/**
* For correct display in EMIS, any observation without a specimen must be assigned a dummy specimen.
* For correct display in EMIS, any observation without a specimen must be assigned a not present specimen.
*/
List<Observation> assignDummySpecimensToObservationsWithNoSpecimen(List<Observation> observations, List<Specimen> specimens) {
List<Observation> assignNotPresentSpecimensToObservationsWithNoSpecimen(List<Observation> observations, List<Specimen> specimens) {

List<Observation> filingComments = getFilingComments(observations);
List<Observation> nonFilingObservations = new ArrayList<>(stripFilingComments(observations));
Expand All @@ -178,7 +178,7 @@ List<Observation> assignDummySpecimensToObservationsWithNoSpecimen(List<Observat
return nonFilingObservations;
}

// The assumption was made that all test results without a specimen will have the same dummy specimen referenced
// The assumption was made that all test results without a specimen will have the same not present specimen referenced
Specimen notPresentSpecimen = specimens.stream()
.filter(specimen -> specimen.getId().contains(NOT_PRESENT_SPECIMEN_ID_PREFIX))
.toList().getFirst();
Expand Down Expand Up @@ -219,21 +219,21 @@ private List<Observation> fetchObservations(DiagnosticReport diagnosticReport) {
}

/**
* For correct display in EMIS, any specimen without an observation must be assigned a dummy observation.
* For correct display in EMIS, any specimen without an observation must be assigned a not present observation.
*/
private List<Observation> addDummyObservationsToObservationList(
private List<Observation> addNotPresentObservationsToObservationList(
List<Observation> observations,
List<Specimen> specimens,
DiagnosticReport diagnosticReport) {
List<Observation> completeObservations = new ArrayList<>();
completeObservations.addAll(observations);

// Generate a dummy Observation for each Specimen without an Observation
// Generate a not present Observation for each Specimen without an Observation
for (String specimenWithoutObservations : getSpecimenIdsWithoutObservation(specimens, observations)) {
Observation dummyObservation = generateDummyObservation(diagnosticReport);
Observation notPresentObservation = generateNotPresentObservation(diagnosticReport);
Reference specimenReference = new Reference(specimenWithoutObservations);
dummyObservation.setSpecimen(specimenReference);
completeObservations.add(dummyObservation);
notPresentObservation.setSpecimen(specimenReference);
completeObservations.add(notPresentObservation);
}

return completeObservations;
Expand All @@ -243,7 +243,7 @@ private List<String> getSpecimenIdsWithoutObservation(List<Specimen> specimens,
List<String> specimenIDList = new ArrayList<>();
List<String> nonOrphanSpecimenIDList = new ArrayList<>();
for (Specimen specimen : specimens) {
// Dummy Specimens should not have a dummy observation attached.
// Not present Specimens should not have a not present observation attached.
if (!specimen.getId().contains(NOT_PRESENT_SPECIMEN_ID_PREFIX)) {
specimenIDList.add(specimen.getId());
}
Expand All @@ -264,10 +264,10 @@ private List<String> getSpecimenIdsWithoutObservation(List<Specimen> specimens,
return specimensWithoutObservations;
}

private Observation generateDummyObservation(DiagnosticReport diagnosticReport) {
private Observation generateNotPresentObservation(DiagnosticReport diagnosticReport) {
Observation observation = new Observation();

observation.setId(DUMMY_OBSERVATION_ID_PREFIX + randomIdGeneratorService.createNewId());
observation.setId(NOT_PRESENT_OBSERVATION_ID_PREFIX + randomIdGeneratorService.createNewId());

return observation
.setIssuedElement(diagnosticReport.getIssuedElement())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package uk.nhs.adaptors.gp2gp.ehr.mapper.diagnosticreport;

import static uk.nhs.adaptors.gp2gp.ehr.mapper.diagnosticreport.DiagnosticReportMapper.DUMMY_OBSERVATION_ID_PREFIX;

import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -46,6 +45,8 @@
import uk.nhs.adaptors.gp2gp.ehr.utils.StatementTimeMappingUtils;
import uk.nhs.adaptors.gp2gp.ehr.utils.TemplateUtils;

import static uk.nhs.adaptors.gp2gp.ehr.mapper.diagnosticreport.DiagnosticReportMapper.NOT_PRESENT_OBSERVATION_ID_PREFIX;

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
Expand Down Expand Up @@ -240,7 +241,7 @@ private String mapObservationToObservationStatement(MultiStatementObservationHol
private Optional<String> prepareNarrativeStatements(MultiStatementObservationHolder holder, boolean interpretationCodeMapped) {
Observation observation = holder.getObservation();

if (observation.getIdElement().getIdPart().contains(DUMMY_OBSERVATION_ID_PREFIX)) {
if (observation.getIdElement().getIdPart().contains(NOT_PRESENT_OBSERVATION_ID_PREFIX)) {
return Optional.of(
mapObservationToNarrativeStatement(holder, observation.getComment(), CommentType.AGGREGATE_COMMENT_SET.getCode())
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ void shouldAssignDummySpecimenOnlyToNonFilingObservationsWithoutSpecimen() {
dummySpecimen.setId(NOT_PRESENT_SPECIMEN_ID_PREFIX + "123");
List<Specimen> specimens = List.of(dummySpecimen);

List<Observation> result = mapper.assignDummySpecimensToObservationsWithNoSpecimen(observations, specimens);
List<Observation> result = mapper.assignNotPresentSpecimensToObservationsWithNoSpecimen(observations, specimens);

assertThat(obsWithoutSpecimen.getSpecimen())
.isNotNull()
Expand All @@ -178,7 +178,7 @@ void shouldThrowIfNoDummySpecimenFound() {

List<Specimen> specimens = List.of();

assertThatThrownBy(() -> mapper.assignDummySpecimensToObservationsWithNoSpecimen(observations, specimens))
assertThatThrownBy(() -> mapper.assignNotPresentSpecimensToObservationsWithNoSpecimen(observations, specimens))
.isInstanceOf(NoSuchElementException.class);
}

Expand All @@ -197,7 +197,7 @@ void shouldAssignDummySpecimenToObservationsWithoutSpecimen() {
realSpecimen.setId("real-specimen");
List<Specimen> specimens = List.of(realSpecimen, dummySpecimen);

List<Observation> result = mapper.assignDummySpecimensToObservationsWithNoSpecimen(observations, specimens);
List<Observation> result = mapper.assignNotPresentSpecimensToObservationsWithNoSpecimen(observations, specimens);

assertThat(result).hasSize(2);
assertThat(result.get(0).getSpecimen().getReference()).contains(dummySpecimen.getId());
Expand Down Expand Up @@ -412,7 +412,7 @@ void When_DiagnosticReport_Has_MultipleSpecimensAndOneObservation_Expect_ADummyO

assertThat(actualXml).containsIgnoringWhitespaces(
"<!-- Mapped Specimen with id: Specimen/96B93E28-293D-46E7-B4C2-D477EEBF7098-SPEC-1 "
+ "with linked Observations: DUMMY-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->");
+ "with linked Observations: NOT-PRESENT-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->");

}

Expand All @@ -438,11 +438,11 @@ void When_DiagnosticReport_Has_ThreeSpecimensAndOneObservation_Expect_DummyObser

assertThat(actualXml).containsIgnoringWhitespaces(
"<!-- Mapped Specimen with id: Specimen/96B93E28-293D-46E7-B4C2-D477EEBF7098-SPEC-1 "
+ "with linked Observations: DUMMY-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->");
+ "with linked Observations: NOT-PRESENT-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->");

assertThat(actualXml).containsIgnoringWhitespaces(
"<!-- Mapped Specimen with id: Specimen/96B93E28-293D-46E7-B4C2-D477EEBF7098-SPEC-2 "
+ "with linked Observations: DUMMY-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->");
+ "with linked Observations: NOT-PRESENT-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->");
}

/**
Expand Down Expand Up @@ -472,7 +472,7 @@ void When_DiagnosticReport_Has_TwoLinkedSpecimensOneUnlinkedSpecimenAndOneObserv

assertThat(actualXml).containsIgnoringWhitespaces(
"<!-- Mapped Specimen with id: Specimen/96B93E28-293D-46E7-B4C2-D477EEBF7098-SPEC-2 "
+ "with linked Observations: DUMMY-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->");
+ "with linked Observations: NOT-PRESENT-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class ObservationMapperTest {
"observation_test_group_header.json";
private static final String OBSERVATION_TEST_RESULT_JSON =
"observation_test_result.json";
private static final String NOT_PRESENT_OBSERVATION_RESULT_JSON =
"not_present_observation.json";
private static final String OBSERVATION_FILING_COMMENT_JSON =
"observation_filing_comment.json";
private static final String OBSERVATION_ASSOCIATED_WITH_IGNORED_MEMBER_JSON =
Expand Down Expand Up @@ -273,6 +275,21 @@ void When_MappingTestResult_With_NopatMetaSecurity_Expect_ConfidentialityCodeWit
assertThatXml(actualXml).containsXPath(OBSERVATION_STATEMENT_CONFIDENTIALITY_CODE_XPATH);
}

@Test
void When_ObservationDoesNotContainNotPresentElements_Expect_MappedObservetionNotContainAggregateComments() {
final Observation not_present_observation = getObservationResourceFromJson(NOT_PRESENT_OBSERVATION_RESULT_JSON);
String expression = "//component/NarrativeStatement/text[contains(normalize-space(.), 'AGGREGATE COMMENT SET')]";

ConfidentialityCodeUtility.appendNopatSecurityToMetaForResource(not_present_observation);
when(confidentialityService.generateConfidentialityCode(not_present_observation))
.thenReturn(Optional.of(NOPAT_HL7_CONFIDENTIALITY_CODE));

final String actualXml = observationMapper.mapObservationToCompoundStatement(not_present_observation);
String wrappedXml = "<root>" + actualXml + "</root>";

assertThatXml(wrappedXml).containsXPath(expression);
}

@Test
void When_MappingTestResult_With_NoscrubMetaSecurity_Expect_ConfidentialityCodeNotPresent() {
final Observation observation = getObservationResourceFromJson(OBSERVATION_TEST_RESULT_JSON);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Status: unknown</text>
<availabilityTime value="20100225154100"/>
</NarrativeStatement>
</component>
<!-- Mapped Specimen with id: Specimen/96B93E28-293D-46E7-B4C2-D477EEBF7098-SPEC-0 with linked Observations: DUMMY-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->
<!-- Mapped Specimen with id: Specimen/96B93E28-293D-46E7-B4C2-D477EEBF7098-SPEC-1 with linked Observations: DUMMY-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->
<!-- Mapped Specimen with id: Specimen/96B93E28-293D-46E7-B4C2-D477EEBF7098-SPEC-2 with linked Observations: DUMMY-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->
<!-- Mapped Specimen with id: Specimen/96B93E28-293D-46E7-B4C2-D477EEBF7098-SPEC-0 with linked Observations: NOT-PRESENT-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->
<!-- Mapped Specimen with id: Specimen/96B93E28-293D-46E7-B4C2-D477EEBF7098-SPEC-1 with linked Observations: NOT-PRESENT-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->
<!-- Mapped Specimen with id: Specimen/96B93E28-293D-46E7-B4C2-D477EEBF7098-SPEC-2 with linked Observations: NOT-PRESENT-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->
</CompoundStatement>
</component>
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ Status: unknown</text>
<availabilityTime value="20100225154100"/>
</NarrativeStatement>
</component>
<!-- Mapped Specimen with id: Specimen/96B93E28-293D-46E7-B4C2-D477EEBF7098-SPEC-0 with linked Observations: DUMMY-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->
<!-- Mapped Specimen with id: Specimen/96B93E28-293D-46E7-B4C2-D477EEBF7098-SPEC-0 with linked Observations: NOT-PRESENT-OBSERVATION-5E496953-065B-41F2-9577-BE8F2FBD0757-->
</CompoundStatement>
</component>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"resourceType": "Observation",
"id": "NOT-PRESENT-OBSERVATION-32685afe-1d46-4d98-8279-39b9e96ee914",
"meta":
{
"profile": [
"https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Observation-1"
]
},
"identifier": [
{
"system": "https://tools.ietf.org/html/rfc4122",
"value": "2af46949-4938-4c57-bad4-c4363e1965d7"
}
],
"status": "final",
"category": [
{
"coding": [
{
"system": "http://snomed.info/sct",
"code": "394595002",
"display": "Pathology"
}
]
}
],
"code": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "1022451000000103",
"display": "Red blood cell count"
}
]
},
"subject": {
"reference": "Patient/11",
"display": "SKELLY, Horace"
},
"issued": "2019-04-06T12:00:00+00:00",
"performer": [
{
"reference": "Organization/7",
"display": "COXWOLD Surgery"
}
],
"valueQuantity": {
"value": 4.5700000000000003,
"unit": "10*12/L"
},
"specimen": {
"reference": "Specimen/756a8361-79ce-4561-afcb-a91fe19df123"
}
}