diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b7da17a04..78cbf46964 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * The GP2GP Adaptor now adds the EhrComposition / confidentialityCode field when Encounter.meta.security contains NOPAT security entry * 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 +* 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 diff --git a/docker/run-e2e-tests.sh b/docker/run-e2e-tests.sh index db756c8f65..895f62d00c 100755 --- a/docker/run-e2e-tests.sh +++ b/docker/run-e2e-tests.sh @@ -2,10 +2,10 @@ set -e -if [ -f "vars.sh" ]; then - source vars.sh +if [ -f "vars.local.e2e.sh" ]; then + source vars.local.e2e.sh else - echo "No vars.sh defined. Using docker-compose defaults." + echo "No vars.local.e2e.sh defined. Using docker-compose defaults." fi if [[ "$(docker network ls | grep "commonforgp2gp")" == "" ]] ; then docker network create commonforgp2gp diff --git a/e2e-tests/src/test/java/uk/nhs/adaptors/gp2gp/e2e/EhrExtractTest.java b/e2e-tests/src/test/java/uk/nhs/adaptors/gp2gp/e2e/EhrExtractTest.java index 0770bc8c3a..4b1832100d 100644 --- a/e2e-tests/src/test/java/uk/nhs/adaptors/gp2gp/e2e/EhrExtractTest.java +++ b/e2e-tests/src/test/java/uk/nhs/adaptors/gp2gp/e2e/EhrExtractTest.java @@ -72,6 +72,7 @@ class EhrExtractTest { private static final String NHS_NUMBER_RESPONSE_MISSING_PATIENT_RESOURCE = "2906543841"; private static final String NHS_NUMBER_MEDICUS_BASED_ON = "9302014592"; private static final String NHS_NUMBER_INVALID_CONTENT_TYPE_DOC = "9817280691"; + private static final String NHS_NUMBER_NO_CLINICAL_CONTENT_STRUCTURE = "9736435687"; private static final String NHS_NUMBER_BODY_SITE = "1239577290"; private static final String EHR_EXTRACT_REQUEST_TEST_FILE = "/ehrExtractRequest.json"; private static final String EHR_EXTRACT_REQUEST_WITHOUT_NHS_NUMBER_TEST_FILE = "/ehrExtractRequestWithoutNhsNumber.json"; @@ -442,6 +443,30 @@ void When_ExtractRequestReceivedForMedicusPatientWithBasedOn_Expect_ExtractStatu } + @Test + void When_ExtractRequestReceivedForPatientWithoutClinicalContent_Expect_ExtractStatusAndDocumentDataAddedToDbAndReturnCode10() throws Exception { + String conversationId = UUID.randomUUID().toString(); + String ehrExtractRequest = buildEhrExtractRequest(conversationId, NHS_NUMBER_NO_CLINICAL_CONTENT_STRUCTURE, FROM_ODS_CODE_1); + MessageQueue.sendToMhsInboundQueue(ehrExtractRequest); + + var requestJournal = waitFor(() -> { + try { + return mhsMockRequestsJournal.getRequestsJournal(conversationId); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + }); + + assertThat(requestJournal).hasSize(1); + + var ehrExtractStatus = waitFor(() -> Mongo.findEhrExtractStatus(conversationId)); + assertThatInitialRecordWasCreated(conversationId, ehrExtractStatus, NHS_NUMBER_NO_CLINICAL_CONTENT_STRUCTURE, FROM_ODS_CODE_1); + + var error = (Document) ehrExtractStatus.get("error"); + assertThat(error).isNotEmpty(); + softly.assertThat(error.get("code")).isEqualTo(NACK_CODE_FAILED_TO_GENERATE_EHR); + } + @Test void When_ExtractRequestReceivedForEMISPWTP2_Expect_ExtractStatusAndDocumentDataAddedToDatabase() throws IOException, NamingException, JMSException { String conversationId = UUID.randomUUID().toString(); diff --git a/service/build.gradle b/service/build.gradle index d56003807d..f063d4e5a6 100644 --- a/service/build.gradle +++ b/service/build.gradle @@ -84,13 +84,13 @@ dependencies { testImplementation 'org.wiremock:wiremock-standalone:3.13.1' testImplementation 'com.squareup.okhttp3:okhttp:5.1.0' testImplementation 'com.squareup.okhttp3:mockwebserver3:5.1.0' - testImplementation 'com.adobe.testing:s3mock-testcontainers:4.9.1' + testImplementation 'com.adobe.testing:s3mock-testcontainers:4.7.0' spotbugs 'com.github.spotbugs:spotbugs:4.9.6' spotbugs 'com.github.spotbugs:spotbugs-annotations:4.9.6' pitest 'com.arcmutate:base:1.3.2' - pitest 'com.arcmutate:pitest-git-plugin:2.2.4' + pitest 'com.arcmutate:pitest-git-plugin:2.1.0' } test { @@ -165,7 +165,7 @@ spotbugsMain { } pitest { - pitestVersion = '1.16.1' + pitestVersion = '1.16.3' junit5PluginVersion = '1.2.1' outputFormats = ['gitci'] diff --git a/service/src/intTest/java/uk/nhs/adaptors/gp2gp/ehr/SendEhrExtractCoreComponentTest.java b/service/src/intTest/java/uk/nhs/adaptors/gp2gp/ehr/SendEhrExtractCoreComponentTest.java index 9acbac24b8..ed847e1d9e 100644 --- a/service/src/intTest/java/uk/nhs/adaptors/gp2gp/ehr/SendEhrExtractCoreComponentTest.java +++ b/service/src/intTest/java/uk/nhs/adaptors/gp2gp/ehr/SendEhrExtractCoreComponentTest.java @@ -64,6 +64,7 @@ @ExtendWith({SpringExtension.class, MongoDBExtension.class, ActiveMQExtension.class, MockitoExtension.class}) @SpringBootTest @DirtiesContext +@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") public class SendEhrExtractCoreComponentTest extends BaseTaskTest { private static final String OUTBOUND_MESSAGE = serializeOutboundMessage("payload"); public static final String OUTBOUND_MESSAGE_WITH_PLACEHOLDER = diff --git a/service/src/intTest/java/uk/nhs/adaptors/gp2gp/testcontainers/ActiveMqContainer.java b/service/src/intTest/java/uk/nhs/adaptors/gp2gp/testcontainers/ActiveMqContainer.java index b42a8e4ba1..bff231a203 100644 --- a/service/src/intTest/java/uk/nhs/adaptors/gp2gp/testcontainers/ActiveMqContainer.java +++ b/service/src/intTest/java/uk/nhs/adaptors/gp2gp/testcontainers/ActiveMqContainer.java @@ -22,7 +22,7 @@ public static ActiveMqContainer getInstance() { @Override public void start() { super.start(); - var containerBrokerUri = "amqp://" + getContainerIpAddress() + ":" + getMappedPort(ACTIVEMQ_PORT); + var containerBrokerUri = "amqp://" + getHost() + ":" + getMappedPort(ACTIVEMQ_PORT); System.setProperty("GP2GP_AMQP_BROKERS", containerBrokerUri); } } diff --git a/service/src/main/java/uk/nhs/adaptors/gp2gp/common/task/TaskErrorHandler.java b/service/src/main/java/uk/nhs/adaptors/gp2gp/common/task/TaskErrorHandler.java index 91f4de79f6..cb598e3fd2 100644 --- a/service/src/main/java/uk/nhs/adaptors/gp2gp/common/task/TaskErrorHandler.java +++ b/service/src/main/java/uk/nhs/adaptors/gp2gp/common/task/TaskErrorHandler.java @@ -15,6 +15,7 @@ import uk.nhs.adaptors.gp2gp.ehr.SendAcknowledgementTaskDefinition; import uk.nhs.adaptors.gp2gp.ehr.exception.EhrExtractException; import uk.nhs.adaptors.gp2gp.ehr.exception.EhrMapperException; +import uk.nhs.adaptors.gp2gp.ehr.exception.EhrValidationException; import uk.nhs.adaptors.gp2gp.gpc.exception.EhrRequestException; import uk.nhs.adaptors.gp2gp.gpc.exception.GpConnectException; import uk.nhs.adaptors.gp2gp.gpc.exception.GpConnectInvalidException; @@ -30,6 +31,7 @@ public class TaskErrorHandler { EhrRequestException.class, this::handleRequestError, EhrExtractException.class, this::handleTranslationError, EhrMapperException.class, this::handleTranslationError, + EhrValidationException.class, this::handleTranslationError, FhirValidationException.class, this::handleTranslationError, GpConnectException.class, this::handleGpConnectError, GpConnectInvalidException.class, this::handleInvalidNotAuthError, diff --git a/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/exception/EhrValidationException.java b/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/exception/EhrValidationException.java new file mode 100644 index 0000000000..a373fb810a --- /dev/null +++ b/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/exception/EhrValidationException.java @@ -0,0 +1,8 @@ +package uk.nhs.adaptors.gp2gp.ehr.exception; + +public class EhrValidationException extends RuntimeException { + + public EhrValidationException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/EhrExtractMapper.java b/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/EhrExtractMapper.java index cbb6d3274c..5736798a3f 100644 --- a/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/EhrExtractMapper.java +++ b/service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/mapper/EhrExtractMapper.java @@ -21,6 +21,8 @@ import uk.nhs.adaptors.gp2gp.ehr.utils.TemplateUtils; import uk.nhs.adaptors.gp2gp.gpc.GetGpcStructuredTaskDefinition; +import uk.nhs.adaptors.gp2gp.ehr.exception.EhrValidationException; + import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -56,6 +58,12 @@ public EhrExtractTemplateParameters mapBundleToEhrFhirExtractParams( mappedComponents.addAll(nonConsultationResourceMapper.mapRemainingResourcesToEhrCompositions(bundle)); ehrExtractTemplateParameters.setComponents(mappedComponents); + if (mappedComponents.isEmpty()) { + final String message = "could not extract EHR Extract: empty structured access record."; + LOGGER.error(message); + throw new EhrValidationException(message); + } + ehrExtractTemplateParameters.setAgentDirectory( agentDirectoryMapper.mapEHRFolderToAgentDirectory(bundle, getPatientNhsNumber(getGpcStructuredTaskDefinition)) ); diff --git a/service/src/test/java/uk/nhs/adaptors/gp2gp/common/task/TaskErrorHandlerTest.java b/service/src/test/java/uk/nhs/adaptors/gp2gp/common/task/TaskErrorHandlerTest.java index c9e1a629a2..7d6d934dc9 100644 --- a/service/src/test/java/uk/nhs/adaptors/gp2gp/common/task/TaskErrorHandlerTest.java +++ b/service/src/test/java/uk/nhs/adaptors/gp2gp/common/task/TaskErrorHandlerTest.java @@ -30,6 +30,7 @@ import uk.nhs.adaptors.gp2gp.common.service.ProcessFailureHandlingService; import uk.nhs.adaptors.gp2gp.ehr.exception.EhrExtractException; import uk.nhs.adaptors.gp2gp.ehr.exception.EhrMapperException; +import uk.nhs.adaptors.gp2gp.ehr.exception.EhrValidationException; import uk.nhs.adaptors.gp2gp.gpc.exception.EhrRequestException; import uk.nhs.adaptors.gp2gp.gpc.exception.GpConnectException; import uk.nhs.adaptors.gp2gp.gpc.exception.GpConnectInvalidException; @@ -65,6 +66,17 @@ void When_HandleProcessingError_WithEhrRequestException_Expect_ProcessToBeFailed any()); } + @Test + void When_HandleProcessingError_WithEhrValidationException_Expect_ProcessToBeFailedWithCorrectCode() { + taskErrorHandler.handleProcessingError(new EhrValidationException(TEST_EXCEPTION_MESSAGE), taskDefinition); + + verify(processFailureHandlingService).failProcess( + any(), + eq("10"), + eq("Failed to successfully generate EHR Extract."), + any()); + } + @Test void When_HandleProcessingError_WithEhrRequestException_Expect_ReturnValueOfFailService() { when(processFailureHandlingService.failProcess(any(), any(), any(), any())) diff --git a/service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/EhrExtractMapperTest.java b/service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/EhrExtractMapperTest.java index ba6e543ec7..013cafff52 100644 --- a/service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/EhrExtractMapperTest.java +++ b/service/src/test/java/uk/nhs/adaptors/gp2gp/ehr/mapper/EhrExtractMapperTest.java @@ -3,11 +3,15 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.mock; + import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.Arrays; +import java.util.Collections; import org.hl7.fhir.dstu3.model.Bundle; import org.junit.jupiter.api.Test; @@ -19,6 +23,7 @@ import uk.nhs.adaptors.gp2gp.common.service.RandomIdGeneratorService; import uk.nhs.adaptors.gp2gp.common.service.TimestampService; +import uk.nhs.adaptors.gp2gp.ehr.exception.EhrValidationException; import uk.nhs.adaptors.gp2gp.gpc.GetGpcStructuredTaskDefinition; @ExtendWith(MockitoExtension.class) @@ -50,6 +55,8 @@ class EhrExtractMapperTest { @Test void When_NhsOverrideNumberProvided_Expect_OverrideToBeUsed() { + when(nonConsultationResourceMapper.mapRemainingResourcesToEhrCompositions(any())) + .thenReturn(Arrays.asList("not", "empty")); ReflectionTestUtils.setField(ehrExtractMapper, OVERRIDE_NHS_NUMBER, OVERRIDE_NHS_NUMBER_VALUE); when(agentDirectoryMapper.mapEHRFolderToAgentDirectory(any(Bundle.class), eq(OVERRIDE_NHS_NUMBER_VALUE))) .thenReturn(OVERRIDE_NHS_NUMBER_VALUE); @@ -66,6 +73,8 @@ void When_NhsOverrideNumberProvided_Expect_OverrideToBeUsed() { @Test void When_NhsOverrideNumberIsBlank_Expect_ActualNhsNumberIsUsed() { + when(nonConsultationResourceMapper.mapRemainingResourcesToEhrCompositions(any())) + .thenReturn(Arrays.asList("not", "empty")); when(agentDirectoryMapper.mapEHRFolderToAgentDirectory(any(Bundle.class), eq(NHS_NUMBER))) .thenReturn(NHS_NUMBER); when(timestampService.now()).thenReturn(Instant.now().truncatedTo(ChronoUnit.MILLIS)); @@ -79,6 +88,27 @@ void When_NhsOverrideNumberIsBlank_Expect_ActualNhsNumberIsUsed() { assertThat(parameters.getAgentDirectory()).isEqualTo(NHS_NUMBER); } + @Test + void When_BundleHasNoMappableContent_Expect_EhrValidationExceptionIsThrown() { + when(timestampService.now()).thenReturn(Instant.now().truncatedTo(ChronoUnit.MILLIS)); + + var taskDef = GetGpcStructuredTaskDefinition.builder() + .nhsNumber(NHS_NUMBER) + .build(); + var bundle = mock(Bundle.class); + + when(nonConsultationResourceMapper.mapRemainingResourcesToEhrCompositions(any(Bundle.class))) + .thenReturn(Collections.emptyList()); + + EhrValidationException thrown = assertThrows(EhrValidationException.class, () -> + ehrExtractMapper.mapBundleToEhrFhirExtractParams(taskDef, bundle) + ); + + assertThat(thrown.getMessage()).isEqualTo("could not extract EHR Extract: empty structured access record."); + } + + + @Test void When_BuildEhrCompositionForSkeletonEhrExtract_Expect_ExpectedComponentBuilt() { var documentId = "documentId"; diff --git a/wiremock/stubs/__files/invalidPatientNoClinicalContentStructuredRecordResponse.json b/wiremock/stubs/__files/invalidPatientNoClinicalContentStructuredRecordResponse.json new file mode 100644 index 0000000000..1b01d81ef3 --- /dev/null +++ b/wiremock/stubs/__files/invalidPatientNoClinicalContentStructuredRecordResponse.json @@ -0,0 +1,631 @@ +{ + "resourceType": "Bundle", + "type": "collection", + "id": "6dc1bede-ace2-457a-829f-687b478f4855", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/GPConnect-StructuredRecord-Bundle-1" + ] + }, + "entry": [ + { + "resource": { + "resourceType": "Patient", + "id": "515f42c8-6f82-f011-b4cc-6045bd1427a6", + "meta": { + "versionId": "3", + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Patient-1" + ] + }, + "active": true, + "name": [ + { + "use": "official", + "text": "Leo SUNTER", + "family": "SUNTER", + "given": [ + "Leo" + ], + "prefix": [ + "Mr" + ] + } + ], + "gender": "male", + "extension": [ + { + "url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-RegistrationDetails-1", + "extension": [ + { + "url": "registrationPeriod", + "valuePeriod": { + "start": "2025-08-26T11:28:28+00:00" + } + }, + { + "url": "preferredBranchSurgery", + "valueReference": { + "reference": "Location/1000" + } + } + ] + }, + { + "url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-NHSCommunication-1", + "extension": [ + { + "url": "modeOfCommunication", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-LanguageAbilityMode-1", + "code": "EWR", + "display": "Expressed written" + } + ] + } + }, + { + "url": "communicationProficiency", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-LanguageAbilityProficiency-1", + "code": "F", + "display": "Fair" + } + ] + } + } + ] + } + ], + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "9736435687" + } + ], + "birthDate": "1945-08-10", + "generalPractitioner": [ + { + "reference": "Practitioner/1135" + } + ], + "managingOrganization": { + "reference": "Organization/1000" + } + } + }, + { + "resource": { + "resourceType": "Practitioner", + "id": "1135", + "meta": { + "versionId": "1", + "lastUpdated": "2025-08-26T13:06:37+00:00", + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Practitioner-1" + ] + }, + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/sds-user-id", + "value": "G152136" + } + ], + "name": [ + { + "use": "usual", + "family": "Consultant", + "given": [ + "Steve" + ], + "prefix": [ + "mr" + ] + } + ], + "gender": "male" + } + }, + { + "resource": { + "resourceType": "PractitionerRole", + "id": "a7b8fe2e-557d-ee11-8179-0022481b5bbc", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-PractitionerRole-1" + ] + }, + "practitioner": { + "reference": "Practitioner/1135" + }, + "organization": { + "reference": "Organization/1000" + }, + "code": [ + { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/STU3/CodeSystem/CareConnect-SDSJobRoleName-1", + "code": "R8000", + "display": "Clinical Practitioner Access Role" + } + ] + } + ] + } + }, + { + "resource": { + "resourceType": "Organization", + "id": "1000", + "meta": { + "versionId": "5", + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Organization-1" + ] + }, + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "D82626" + } + ], + "name": "Dr CM Nash's Practice", + "address": [ + { + "line": [ + "Ash Close" + ], + "city": "Norwich", + "district": "Norfolk", + "postalCode": "NR9 3RE" + } + ], + "telecom": [ + { + "system": "phone", + "value": "01189345689", + "use": "work" + } + ] + } + }, + { + "resource": { + "resourceType": "Location", + "id": "1000", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Location-1" + ], + "versionId": "5", + "lastUpdated": "2025-07-24T06:47:43+00:00" + }, + "name": "Building KK", + "address": { + "line": [ + "12 Front of naka" + ], + "city": "New wok", + "district": "South Yorkshire", + "postalCode": "450111", + "country": "UK" + } + } + }, + { + "resource": { + "resourceType": "List", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-List-1" + ] + }, + "extension": [ + { + "url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-ClinicalSetting-1", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "1060971000000108", + "display": "General practice service" + } + ] + } + } + ], + "status": "current", + "mode": "snapshot", + "title": "Medications and medical devices", + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "933361000000108", + "display": "Medications and medical devices" + } + ] + }, + "subject": { + "reference": "Patient/515f42c8-6f82-f011-b4cc-6045bd1427a6" + }, + "date": "2025-08-26T13:52:39+00:00", + "orderedBy": { + "coding": [ + { + "system": "http://hl7.org/fhir/codesystem-list-order.html", + "code": "event-date", + "display": "Sorted by Event Date" + } + ] + }, + "note": [ + { + "text": "Information not available" + } + ], + "emptyReason": { + "coding": [ + { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-ListEmptyReasonCode-1", + "code": "no-content-recorded", + "display": "No Content Recorded" + } + ] + } + } + }, + { + "resource": { + "resourceType": "List", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-List-1" + ] + }, + "status": "current", + "mode": "snapshot", + "title": "Uncategorised data", + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "826501000000100", + "display": "Miscellaneous record" + } + ] + }, + "subject": { + "reference": "Patient/515f42c8-6f82-f011-b4cc-6045bd1427a6" + }, + "date": "2025-08-26T13:52:39+00:00", + "orderedBy": { + "coding": [ + { + "system": "http://hl7.org/fhir/codesystem-list-order.html", + "code": "event-date", + "display": "Sorted by Event Date" + } + ] + }, + "note": [ + { + "text": "Information not available" + } + ], + "emptyReason": { + "coding": [ + { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-ListEmptyReasonCode-1", + "code": "no-content-recorded", + "display": "No Content Recorded" + } + ] + } + } + }, + { + "resource": { + "resourceType": "List", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-List-1" + ] + }, + "status": "current", + "mode": "snapshot", + "title": "Patient recall administration", + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "714311000000108", + "display": "Patient recall administration" + } + ] + }, + "subject": { + "reference": "Patient/515f42c8-6f82-f011-b4cc-6045bd1427a6" + }, + "date": "2025-08-26T13:52:40+00:00", + "orderedBy": { + "coding": [ + { + "system": "http://hl7.org/fhir/list-order", + "code": "event-date" + } + ] + }, + "note": [ + { + "text": "Information not available" + } + ], + "emptyReason": { + "coding": [ + { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-ListEmptyReasonCode-1", + "code": "no-content-recorded", + "display": "No Content Recorded" + } + ] + } + } + }, + { + "resource": { + "resourceType": "List", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-List-1" + ] + }, + "status": "current", + "mode": "snapshot", + "title": "Outbound referral", + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "792931000000107", + "display": "Outbound referral" + } + ] + }, + "subject": { + "reference": "Patient/515f42c8-6f82-f011-b4cc-6045bd1427a6" + }, + "date": "2025-08-26T13:52:40+00:00", + "orderedBy": { + "coding": [ + { + "system": "http://hl7.org/fhir/codesystem-list-order.html", + "code": "event-date", + "display": "Sorted by Event Date" + } + ] + }, + "note": [ + { + "text": "Information not available" + } + ], + "emptyReason": { + "coding": [ + { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-ListEmptyReasonCode-1", + "code": "no-content-recorded", + "display": "No Content Recorded" + } + ] + } + } + }, + { + "resource": { + "resourceType": "HealthcareService", + "id": "1000", + "meta": { + "profile": [ + "https://fhir.hl7.org.uk/STU3/StructureDefinition/CareConnect-HealthcareService-1" + ] + }, + "name": "DR CM Nash's Practice", + "providedBy": { + "reference": "Organization/1000" + } + } + }, + { + "resource": { + "resourceType": "List", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-List-1" + ] + }, + "status": "current", + "mode": "snapshot", + "title": "Investigations and results", + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "887191000000108", + "display": "Investigations and results" + } + ] + }, + "subject": { + "reference": "Patient/515f42c8-6f82-f011-b4cc-6045bd1427a6" + }, + "date": "2025-08-26T13:52:40+00:00", + "orderedBy": { + "coding": [ + { + "system": "http://hl7.org/fhir/codesystem-list-order.html", + "code": "event-date", + "display": "Sorted by Event Date" + } + ] + }, + "note": [ + { + "text": "Information not available" + } + ], + "emptyReason": { + "coding": [ + { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-ListEmptyReasonCode-1", + "code": "no-content-recorded", + "display": "No Content Recorded" + } + ] + } + } + }, + { + "resource": { + "resourceType": "List", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-List-1" + ] + }, + "status": "current", + "mode": "snapshot", + "title": "List of consultations", + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "1149501000000101", + "display": "List of consultations" + } + ] + }, + "subject": { + "reference": "Patient/515f42c8-6f82-f011-b4cc-6045bd1427a6" + }, + "date": "2025-08-26T13:52:40+00:00", + "orderedBy": { + "coding": [ + { + "system": "http://hl7.org/fhir/codesystem-list-order.html", + "code": "event-date", + "display": "Sorted by Event Date" + } + ] + }, + "note": [ + { + "text": "Information not available" + } + ], + "emptyReason": { + "coding": [ + { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-ListEmptyReasonCode-1", + "code": "no-content-recorded", + "display": "No Content Recorded" + } + ] + } + } + }, + { + "resource": { + "resourceType": "List", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-List-1" + ] + }, + "status": "current", + "mode": "snapshot", + "title": "Allergies and adverse reactions", + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "886921000000105", + "display": "Allergies and adverse reactions" + } + ] + }, + "subject": { + "reference": "Patient/515f42c8-6f82-f011-b4cc-6045bd1427a6" + }, + "note": [ + { + "text": "Information not available" + } + ], + "emptyReason": { + "coding": [ + { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-ListEmptyReasonCode-1", + "code": "no-content-recorded", + "display": "No Content Recorded" + } + ] + } + } + }, + { + "resource": { + "resourceType": "List", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-List-1" + ] + }, + "status": "current", + "mode": "snapshot", + "title": "Problems", + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "717711000000103", + "display": "Problems" + } + ] + }, + "subject": { + "reference": "Patient/515f42c8-6f82-f011-b4cc-6045bd1427a6" + }, + "date": "2025-08-26T13:52:41+00:00", + "orderedBy": { + "coding": [ + { + "system": "http://hl7.org/fhir/codesystem-list-order.html", + "code": "event-date", + "display": "Sorted by Event Date" + } + ] + }, + "note": [ + { + "text": "Information not available" + } + ], + "emptyReason": { + "coding": [ + { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-ListEmptyReasonCode-1", + "code": "no-content-recorded", + "display": "No Content Recorded" + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/wiremock/stubs/mappings/retrievePatientStructuredRecordNoClinicalContentStructure.json b/wiremock/stubs/mappings/retrievePatientStructuredRecordNoClinicalContentStructure.json new file mode 100644 index 0000000000..449e9e632c --- /dev/null +++ b/wiremock/stubs/mappings/retrievePatientStructuredRecordNoClinicalContentStructure.json @@ -0,0 +1,27 @@ +{ + "priority": 1, + "request": { + "method": "POST", + "urlPattern": "/.*/STU3/1/gpconnect/fhir/Patient/[$]gpc[.]migratestructuredrecord", + "bodyPatterns" : [ { + "matchesJsonPath" : "$.parameter[?(@.name == 'patientNHSNumber')]" + }, + { + "matchesJsonPath" : "$.parameter[0].valueIdentifier[?(@.value == '9736435687')]" + }] + }, + "response": { + "status": 200, + "bodyFileName": "invalidPatientNoClinicalContentStructuredRecordResponse.json", + "headers": { + "Server": "nginx", + "Date": "{{now format='E, d MMM y HH:mm:ss z'}}", + "Content-Type": "application/fhir+json;charset=UTF-8", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Cache-Control": "no-store", + "X-Powered-By": "HAPI FHIR 3.0.0 REST Server (FHIR Server; FHIR 3.0.1/DSTU3)", + "Strict-Transport-Security":"max-age=31536000" + } + } +} \ No newline at end of file