diff --git a/CHANGELOG.md b/CHANGELOG.md index 06d0ddec6d..2b7da17a04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * The GP2GP Adaptor now populates the ObservationStatement / confidentialityCode field when the .meta.security field of an Uncategorized Data Observation contains NOPAT * When List.meta.security field contains NOPAT, the GP2GP Adaptor will now populate the CompoundStatement.confidentialityCode +### Fixed +* When DiagnosticReport doesn't contain a Specimen reference, instead of "DUMMY" "NOT-PRESENT" value is used + ### Update * [GP Connect 1.6.1] The GP2GP Adaptor is now able to identify e-referrals by using either `https://fhir.nhs.uk/Id/ubr-number` or `https://fhir.nhs.uk/Id/UBRN` when provided as an identifier system URL. diff --git a/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/DiagnosticReportMapper.java b/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/DiagnosticReportMapper.java index 266dd9ed51..8cee1400c9 100644 --- a/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/DiagnosticReportMapper.java +++ b/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/DiagnosticReportMapper.java @@ -52,7 +52,7 @@ @Slf4j public class DiagnosticReportMapper { - public static final String DUMMY_SPECIMEN_ID_PREFIX = "DUMMY-SPECIMEN-"; + public static final String NOT_PRESENT_SPECIMEN_ID_PREFIX = "NOT-PRESENT-SPECIMEN-"; public static final String DUMMY_OBSERVATION_ID_PREFIX = "DUMMY-OBSERVATION-"; private static final Mustache DIAGNOSTIC_REPORT_COMPOUND_STATEMENT_TEMPLATE = @@ -142,7 +142,7 @@ private List fetchSpecimens(DiagnosticReport diagnosticReport, List observations) { /** * For correct display in EMIS, any observation without a specimen must be assigned a dummy specimen. */ - private List assignDummySpecimensToObservationsWithNoSpecimen( - List observations, List specimens) { + List assignDummySpecimensToObservationsWithNoSpecimen(List observations, List specimens) { List filingComments = getFilingComments(observations); - observations = new ArrayList<>(stripFilingComments(observations)); + List nonFilingObservations = new ArrayList<>(stripFilingComments(observations)); - if (!hasObservationsWithoutSpecimen(observations)) { - observations.addAll(filingComments); - return observations; + if (!hasObservationsWithoutSpecimen(nonFilingObservations)) { + nonFilingObservations.addAll(filingComments); + return nonFilingObservations; } // The assumption was made that all test results without a specimen will have the same dummy specimen referenced - Specimen dummySpecimen = specimens.stream() - .filter(specimen -> specimen.getId().contains(DUMMY_SPECIMEN_ID_PREFIX)) - .toList().getFirst(); + Specimen notPresentSpecimen = specimens.stream() + .filter(specimen -> specimen.getId().contains(NOT_PRESENT_SPECIMEN_ID_PREFIX)) + .toList().getFirst(); - Reference dummySpecimenReference = new Reference(dummySpecimen.getId()); + Reference notPresentSpecimenReference = new Reference(notPresentSpecimen.getId()); - for (Observation observation : observations) { - if (!observation.hasSpecimen() && !isFilingComment(observation)) { - observation.setSpecimen(dummySpecimenReference); - } - } + nonFilingObservations.stream() + .filter(obs -> !obs.hasSpecimen() && !isFilingComment(obs)) + .forEach(obs -> obs.setSpecimen(notPresentSpecimenReference)); - observations.addAll(filingComments); - return observations; + nonFilingObservations.addAll(filingComments); + return nonFilingObservations; } - private Specimen generateDummySpecimen(DiagnosticReport diagnosticReport) { + private Specimen generateNotPresentSpecimen(DiagnosticReport diagnosticReport) { Specimen specimen = new Specimen(); - specimen.setId(DUMMY_SPECIMEN_ID_PREFIX + randomIdGeneratorService.createNewId()); + specimen.setId(NOT_PRESENT_SPECIMEN_ID_PREFIX + randomIdGeneratorService.createNewId()); return specimen - .setAccessionIdentifier(new Identifier().setValue("DUMMY")) + .setAccessionIdentifier(new Identifier().setValue("NOT PRESENT")) .setCollection(new Specimen.SpecimenCollectionComponent().setCollected(new DateTimeType(diagnosticReport.getIssued()))) .setType(new CodeableConcept().setText("UNKNOWN")); } @@ -247,7 +244,7 @@ private List getSpecimenIdsWithoutObservation(List specimens, List nonOrphanSpecimenIDList = new ArrayList<>(); for (Specimen specimen : specimens) { // Dummy Specimens should not have a dummy observation attached. - if (!specimen.getId().contains(DUMMY_SPECIMEN_ID_PREFIX)) { + if (!specimen.getId().contains(NOT_PRESENT_SPECIMEN_ID_PREFIX)) { specimenIDList.add(specimen.getId()); } } diff --git a/service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/DiagnosticReportMapperTest.java b/service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/DiagnosticReportMapperTest.java index 58c7da6e11..7d491c5b9b 100644 --- a/service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/DiagnosticReportMapperTest.java +++ b/service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/DiagnosticReportMapperTest.java @@ -1,17 +1,21 @@ package uk.nhs.adaptors.gp2gp.ehr.mapper.diagnosticreport; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertAll; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.NoSuchElementException; import java.util.Optional; import java.util.stream.Stream; import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.CodeableConcept; +import org.hl7.fhir.dstu3.model.Coding; import org.hl7.fhir.dstu3.model.DiagnosticReport; import org.hl7.fhir.dstu3.model.IdType; import org.hl7.fhir.dstu3.model.Observation; @@ -54,12 +58,15 @@ @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) class DiagnosticReportMapperTest { + private static final String TEST_FILE_DIRECTORY = "/ehr/mapper/diagnosticreport/"; private static final String INPUT_JSON_BUNDLE = "fhir_bundle.json"; private static final String INPUT_JSON_BUNDLE_WITH_FILING_COMMENTS = "fhir_bundle_with_filing_comments.json"; private static final String TEST_ID = "5E496953-065B-41F2-9577-BE8F2FBD0757"; + public static final String NOT_PRESENT_SPECIMEN_ID_PREFIX = "NOT-PRESENT-SPECIMEN-"; + private static final String COMMENT_NOTE = "37331000000100"; private static final String INPUT_JSON_REQUIRED_DATA = "diagnostic-report-with-required-data.json"; private static final String INPUT_JSON_EMPTY_SPECIMENS = "diagnostic-report-with-empty-specimens.json"; @@ -128,6 +135,75 @@ public void tearDown() { messageContext.resetMessageContext(); } + @Test + void shouldAssignDummySpecimenOnlyToNonFilingObservationsWithoutSpecimen() { + + Observation obsWithoutSpecimen = new Observation(); + obsWithoutSpecimen.setId("obs1"); + + Observation obsWithSpecimen = new Observation(); + obsWithSpecimen.setId("obs2"); + obsWithSpecimen.setSpecimen(new Reference("real-specimen")); + + Observation filingCommentObs = new Observation(); + filingCommentObs.setId("obs3"); + filingCommentObs.getCode().addCoding(new Coding().setCode(COMMENT_NOTE)); + + List observations = List.of(obsWithoutSpecimen, obsWithSpecimen, filingCommentObs); + + Specimen dummySpecimen = new Specimen(); + dummySpecimen.setId(NOT_PRESENT_SPECIMEN_ID_PREFIX + "123"); + List specimens = List.of(dummySpecimen); + + List result = mapper.assignDummySpecimensToObservationsWithNoSpecimen(observations, specimens); + + assertThat(obsWithoutSpecimen.getSpecimen()) + .isNotNull() + .extracting(Reference::getReference) + .isEqualTo(dummySpecimen.getId()); + + assertThat(obsWithSpecimen.getSpecimen()) + .extracting(Reference::getReference) + .isEqualTo("real-specimen"); + + assertFalse(filingCommentObs.hasSpecimen()); + assertThat(result).containsExactlyInAnyOrder(obsWithoutSpecimen, obsWithSpecimen, filingCommentObs); + } + + @Test + void shouldThrowIfNoDummySpecimenFound() { + + Observation obsWithoutSpecimen = new Observation(); + List observations = List.of(obsWithoutSpecimen); + + List specimens = List.of(); + + assertThatThrownBy(() -> mapper.assignDummySpecimensToObservationsWithNoSpecimen(observations, specimens)) + .isInstanceOf(NoSuchElementException.class); + } + + @Test + void shouldAssignDummySpecimenToObservationsWithoutSpecimen() { + + Observation obsWithoutSpecimen = new Observation(); + Observation obsWithSpecimen = new Observation(); + obsWithSpecimen.setSpecimen(new Reference("real-specimen")); + + List observations = List.of(obsWithoutSpecimen, obsWithSpecimen); + + Specimen dummySpecimen = new Specimen(); + dummySpecimen.setId("dummy-" + NOT_PRESENT_SPECIMEN_ID_PREFIX); + Specimen realSpecimen = new Specimen(); + realSpecimen.setId("real-specimen"); + List specimens = List.of(realSpecimen, dummySpecimen); + + List result = mapper.assignDummySpecimensToObservationsWithNoSpecimen(observations, specimens); + + assertThat(result).hasSize(2); + assertThat(result.get(0).getSpecimen().getReference()).contains(dummySpecimen.getId()); + assertThat(result.get(1).getSpecimen().getReference()).contains("real-specimen"); + } + @ParameterizedTest @MethodSource("resourceFileParams") void When_MappingDiagnosticReportJson_Expect_CompoundStatementXmlOutput(String inputJson, String outputXml) { @@ -250,12 +326,14 @@ void When_DiagnosticReport_With_ObservationEffectivePeriodAndCommentNote_Expect_ } @Test - void When_DiagnosticReport_With_NoReferencedSpecimenAndFilingCommentWithNoComment_Expect_MatchesSnapshotXml() { + void When_DR_With_NoReferencedSpecimenAndFilingCommentWithNoComment_Expect_MatchesSnapshotXmlIncludesSpecimenRoleWithNotPresentTag() { final String diagnosticReportFileName = "diagnostic-report-with-no-specimen.json"; final DiagnosticReport diagnosticReport = getDiagnosticReportResourceFromJson(diagnosticReportFileName); final Bundle bundle = getBundleResourceFromJson(INPUT_JSON_BUNDLE); final InputBundle inputBundle = new InputBundle(bundle); final String expectedXml = getXmlStringFromFile(TEST_FILE_DIRECTORY, "diagnostic-report-with-no-specimen.xml"); + final List expectedXPaths = Collections.singletonList( + "/component/CompoundStatement/component/CompoundStatement/specimen/specimenRole/id[@extension=\"NOT PRESENT\"]"); when(specimenMapper.mapSpecimenToCompoundStatement( any(Specimen.class), @@ -288,6 +366,7 @@ void When_DiagnosticReport_With_NoReferencedSpecimenAndFilingCommentWithNoCommen final String actualXml = mapper.mapDiagnosticReportToCompoundStatement(diagnosticReport); assertThat(actualXml).isEqualToIgnoringWhitespace(expectedXml); + assertThatXml(actualXml).containsAllXPaths(expectedXPaths); } /** @@ -307,7 +386,7 @@ void When_DiagnosticReport_Has_SpecimenAndUnlinkedTestResult_Expect_ADummySpecim // This checks that the unlinked test result is given a dummy specimen. assertThat(actualXml).containsIgnoringWhitespaces( - ""); } @@ -408,7 +487,7 @@ void When_DiagnosticReport_Has_SpecimenALinkedTestResultAndAnUnlinkedTestResult_ final String actualXml = mapper.mapDiagnosticReportToCompoundStatement(diagnosticReport); // This checks that the unlinked observation is given a dummy specimen. assertThat(actualXml).containsIgnoringWhitespaces( - ""); } diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-coded-diagnosis.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-coded-diagnosis.xml index 788650a164..58dffbdeb7 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-coded-diagnosis.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-coded-diagnosis.xml @@ -30,6 +30,6 @@ Status: unknown - + \ No newline at end of file diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-conclusion.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-conclusion.xml index ae32c6c163..c0fb782802 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-conclusion.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-conclusion.xml @@ -30,6 +30,6 @@ Status: unknown - + \ No newline at end of file diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-extension-id.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-extension-id.xml index 911c174646..ca21824539 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-extension-id.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-extension-id.xml @@ -21,6 +21,6 @@ Status: unknown - + \ No newline at end of file diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-multiple-coded-diagnosis.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-multiple-coded-diagnosis.xml index d463c9db9c..b19880215f 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-multiple-coded-diagnosis.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-multiple-coded-diagnosis.xml @@ -30,6 +30,6 @@ Status: unknown - + \ No newline at end of file diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-multiple-results.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-multiple-results.xml index 737f71cac4..44f4c2eb52 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-multiple-results.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-multiple-results.xml @@ -62,6 +62,6 @@ CommentDate:20100225154100 - + \ No newline at end of file diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-no-specimen.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-no-specimen.xml index 9fe37d75a0..c25c429ac7 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-no-specimen.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-no-specimen.xml @@ -48,7 +48,7 @@ - + @@ -58,7 +58,7 @@ - +
diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-participant.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-participant.xml index 9da82f5740..c870dddc41 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-participant.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-participant.xml @@ -30,7 +30,7 @@ Participants: TEMPLE SOWERBY MEDICAL PRACTICE - + diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-required-data.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-required-data.xml index c3887c0569..4221f5fc8b 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-required-data.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-required-data.xml @@ -20,6 +20,6 @@ Status: unknown - + \ No newline at end of file diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-status-narrative.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-status-narrative.xml index c3887c0569..4221f5fc8b 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-status-narrative.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-status-narrative.xml @@ -20,6 +20,6 @@ Status: unknown - + \ No newline at end of file diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/expected_output_default_empty_specimen.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/expected_output_default_empty_specimen.xml index af084d6448..d231f29ded 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/expected_output_default_empty_specimen.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/expected_output_default_empty_specimen.xml @@ -10,7 +10,7 @@ - +
diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/expected_output_default_specimen_and_default_observation.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/expected_output_default_specimen_and_default_observation.xml index ac97da2af0..0e41bd8ecd 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/expected_output_default_specimen_and_default_observation.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/expected_output_default_specimen_and_default_observation.xml @@ -10,7 +10,7 @@ - +
diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/input_default_specimen.json b/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/input_default_specimen.json index 6884715794..cbfcccd5f9 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/input_default_specimen.json +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/input_default_specimen.json @@ -1,13 +1,13 @@ { "resourceType": "Specimen", - "id": "DUMMY-SPECIMEN-5E496953-065B-41F2-9577-BE8F2FBD0757", + "id": "NOT-PRESENT-SPECIMEN-5E496953-065B-41F2-9577-BE8F2FBD0757", "meta": { "profile": [ "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Specimen-1" ] }, "accessionIdentifier": { - "value": "DUMMY" + "value": "NOT PRESENT" }, "type": { "text": "UNKNOWN"