diff --git a/CHANGELOG.md b/CHANGELOG.md index 7df6f07be6..dd29aa7df5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## Added - +* When mapping a `DiagnosticReport` which contains a `TestResult` without a `Specimen` attached to it, a new `Specimen` is +created to allow the `TestResult` to be mapped correctly. * When mapping a `DocumentReference` which contains a `NOPAT` `meta.security` or `NOPAT` `securityLabel` tag the resultant XML for that resource will contain a `NOPAT` `confidentialityCode` element. * When mapping `AllergyIntolerances` which contain a `NOPAT` `meta.security` tag the resultant XML for that resource 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 f4f773a9f4..f2009e4de7 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 @@ -8,9 +8,11 @@ import static uk.nhs.adaptors.gp2gp.ehr.mapper.CommentType.LABORATORY_RESULT_COMMENT; import static uk.nhs.adaptors.gp2gp.ehr.mapper.diagnosticreport.ObservationMapper.NARRATIVE_STATEMENT_TEMPLATE; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -73,13 +75,19 @@ public class DiagnosticReportMapper { private final ConfidentialityService confidentialityService; public String mapDiagnosticReportToCompoundStatement(DiagnosticReport diagnosticReport) { - List specimens = fetchSpecimens(diagnosticReport); List observations = fetchObservations(diagnosticReport); + List specimens = fetchSpecimens(diagnosticReport, observations); final IdMapper idMapper = messageContext.getIdMapper(); markObservationsAsProcessed(idMapper, observations); + List observationsExcludingFilingComments = assignDummySpecimensToObservationsWithNoSpecimen( + observations.stream() + .filter(Predicate.not(DiagnosticReportMapper::isFilingComment)) + .toList(), + specimens); + String mappedSpecimens = specimens.stream() - .map(specimen -> specimenMapper.mapSpecimenToCompoundStatement(specimen, observations, diagnosticReport)) + .map(specimen -> specimenMapper.mapSpecimenToCompoundStatement(specimen, observationsExcludingFilingComments, diagnosticReport)) .collect(Collectors.joining()); String reportLevelNarrativeStatements = prepareReportLevelNarrativeStatements(diagnosticReport, observations); @@ -113,21 +121,60 @@ private String fetchExtensionId(List identifiers) { .orElse(StringUtils.EMPTY); } - private List fetchSpecimens(DiagnosticReport diagnosticReport) { - if (!diagnosticReport.hasSpecimen()) { - return Collections.singletonList(generateDefaultSpecimen(diagnosticReport)); + private List fetchSpecimens(DiagnosticReport diagnosticReport, List observations) { + + List specimens = new ArrayList<>(); + + // At least one specimen is required to exist for any DiagnosticReport, according to the mim + if (!diagnosticReport.hasSpecimen() || hasObservationsWithoutSpecimen(observations)) { + specimens.add(generateDummySpecimen(diagnosticReport)); } var inputBundleHolder = messageContext.getInputBundleHolder(); - return diagnosticReport.getSpecimen() + List nonDummySpecimens = diagnosticReport.getSpecimen() .stream() .map(specimenReference -> inputBundleHolder.getResource(specimenReference.getReferenceElement())) .flatMap(Optional::stream) .map(Specimen.class::cast) .collect(Collectors.toList()); + + specimens.addAll(nonDummySpecimens); + + return specimens; + + } + + private boolean hasObservationsWithoutSpecimen(List observations) { + return observations + .stream() + .filter(observation -> !isFilingComment(observation)) + .anyMatch(observation -> !observation.hasSpecimen()); + } + + private List assignDummySpecimensToObservationsWithNoSpecimen( + List observations, List specimens) { + + if (!hasObservationsWithoutSpecimen(observations)) { + return observations; + } + + // 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(); + + Reference dummySpecimenReference = new Reference(dummySpecimen.getId()); + + for (Observation observation : observations) { + if (!observation.hasSpecimen() && !isFilingComment(observation)) { + observation.setSpecimen(dummySpecimenReference); + } + } + + return observations; } - private Specimen generateDefaultSpecimen(DiagnosticReport diagnosticReport) { + private Specimen generateDummySpecimen(DiagnosticReport diagnosticReport) { Specimen specimen = new Specimen(); specimen.setId(DUMMY_SPECIMEN_ID_PREFIX + randomIdGeneratorService.createNewId()); diff --git a/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/SpecimenMapper.java b/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/SpecimenMapper.java index 963bfe60a7..d660d69092 100644 --- a/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/SpecimenMapper.java +++ b/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/diagnosticreport/SpecimenMapper.java @@ -43,7 +43,6 @@ import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -149,7 +148,6 @@ private String mapObservationsAssociatedWithSpecimen(Specimen specimen, List"); + } + + @Test + void When_DiagnosticReport_Has_SpecimenALinkedTestResultAndAnUnlinkedTestResult_Expect_ASpecimenOnAllTestResults() { + final String diagnosticReportFileName = + "diagnostic-report-with-one-specimen-one-linked-observation-and-one-unlinked-observation.json"; + final DiagnosticReport diagnosticReport = getDiagnosticReportResourceFromJson(diagnosticReportFileName); + final Bundle bundle = getBundleResourceFromJson(INPUT_JSON_BUNDLE); + final InputBundle inputBundle = new InputBundle(bundle); + when(messageContext.getInputBundleHolder()).thenReturn(inputBundle); + + final String actualXml = mapper.mapDiagnosticReportToCompoundStatement(diagnosticReport); + // This checks that the unlinked test result is given a dummy specimen. + assertThat(actualXml).containsIgnoringWhitespaces( + ""); + + } + private Bundle getBundleResourceFromJson(String filename) { final String filePath = TEST_FILE_DIRECTORY + filename; return FileParsingUtility.parseResourceFromJsonFile(filePath, Bundle.class); @@ -318,8 +355,7 @@ private static Stream resourceFileParams() { Arguments.of(INPUT_JSON_CODED_DIAGNOSIS, OUTPUT_XML_CODED_DIAGNOSIS), Arguments.of(INPUT_JSON_MULTIPLE_CODED_DIAGNOSIS, OUTPUT_XML_MULTIPLE_CODED_DIAGNOSIS), Arguments.of(INPUT_JSON_EXTENSION_ID, OUTPUT_XML_EXTENSION_ID), - Arguments.of(INPUT_JSON_URN_OID_EXTENSION_ID, OUTPUT_XML_EXTENSION_ID), - Arguments.of(INPUT_JSON_UNRELATED_TEST_RESULT, OUTPUT_XML_UNRELATED_TEST_RESULT) + Arguments.of(INPUT_JSON_URN_OID_EXTENSION_ID, OUTPUT_XML_EXTENSION_ID) ); } @@ -341,7 +377,23 @@ private Answer mockIdForReference() { private Answer mockSpecimenMapping() { return invocation -> { Specimen specimen = invocation.getArgument(0); - return String.format("", specimen.getId()); + List observations = invocation.getArgument(1); + + List linkedObservations = new ArrayList<>(); + + for (Observation observation : observations) { + if (observation.getSpecimen().getReference() != null + && observation.getSpecimen().getReference().equals(specimen.getId())) { + linkedObservations.add(observation.getId()); + } + } + + if (linkedObservations.isEmpty()) { + return String.format("", specimen.getId()); + } + return String.format("", + specimen.getId(), + String.join(",", linkedObservations)); }; } } \ No newline at end of file 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 0075a26cef..e0f4f94e3b 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..bbf2a38a35 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..2e8e85a438 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-multi-specimens.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-multi-specimens.xml index 805aac6620..bc44680efb 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-multi-specimens.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-multi-specimens.xml @@ -20,6 +20,9 @@ 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 fd9303aced..50737bd992 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-one-specimen-and-one-unrelated-observation.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-one-specimen-and-one-unrelated-observation.xml deleted file mode 100644 index 974ec8c162..0000000000 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-one-specimen-and-one-unrelated-observation.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - Filed Report - - - -
- - - - - - CommentType:LABORATORY RESULT COMMENT(E141) -CommentDate:20100225154100 - -Status: unknown - - - - - - - \ No newline at end of file diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-one-specimen-one-linked-observation-and-one-unlinked-observation.json b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-one-specimen-one-linked-observation-and-one-unlinked-observation.json new file mode 100644 index 0000000000..a4e5ea74fe --- /dev/null +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-one-specimen-one-linked-observation-and-one-unlinked-observation.json @@ -0,0 +1,45 @@ +{ + "resourceType": "DiagnosticReport", + "id": "96B93E28-293D-46E7-B4C2-D477EEBF7098", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-DiagnosticReport-1" + ] + }, + "identifier": [ + { + "system": "https://EMISWeb/A82038", + "value": "96B93E28-293D-46E7-B4C2-D477EEBF7098" + } + ], + "status": "unknown", + "category": { + "coding": [ + { + "system": "http://hl7.org/fhir/v2/0074", + "code": "PAT", + "display": "Pathology (gross & histopath, not surgical)" + } + ] + }, + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "721981007", + "display": "Diagnostic studies report" + } + ] + }, + "subject": { + "reference": "Patient/DAED5527-1985-45D9-993E-C5FF51F36828" + }, + "issued": "2010-02-25T15:41:00+00:00", + "specimen": [{ + "reference": "Specimen/96B93E28-293D-46E7-B4C2-D477EEBF7098-SPEC-0" + }], + "result": [ + { "reference": "Observation/B7F05EA7-A1A4-48C0-9C4C-CDB5768796B2" }, + { "reference": "Observation/TestResult-WithoutSpecimenReference" } + ] +} \ No newline at end of file diff --git a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-one-specimen.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-one-specimen.xml index 040389af10..81dc98b00b 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-one-specimen.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-one-specimen.xml @@ -20,6 +20,7 @@ Status: unknown + \ No newline at end of file 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..ee7125e52f 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-status-narrative.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/diagnostic-report-with-status-narrative.xml index c3887c0569..980c082748 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_specimen_with_observation.xml b/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/expected_output_default_specimen_with_observation.xml index aa913507b7..229a309ce4 100644 --- a/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/expected_output_default_specimen_with_observation.xml +++ b/service/src/test/resources/ehr/mapper/diagnosticreport/specimen/expected_output_default_specimen_with_observation.xml @@ -31,6 +31,6 @@ Received Date: 2010-02-24 15:41 - + \ No newline at end of file diff --git a/service/src/test/resources/ehr/request/fhir/output/expected-xml-with-standalone-observations.xml b/service/src/test/resources/ehr/request/fhir/output/expected-xml-with-standalone-observations.xml index aea9b667b2..8a5f1a6c55 100644 --- a/service/src/test/resources/ehr/request/fhir/output/expected-xml-with-standalone-observations.xml +++ b/service/src/test/resources/ehr/request/fhir/output/expected-xml-with-standalone-observations.xml @@ -124,6 +124,39 @@ Status: unknown + + +
+ + + UNKNOWN + + + + + + + CommentType:AGGREGATE COMMENT SET + CommentDate:UNK + + EMPTY REPORT + + + + + + + + + + + +
+ + + + +