diff --git a/api/consumer/searchDocumentReference/search_document_reference.py b/api/consumer/searchDocumentReference/search_document_reference.py index ae590e0f8..d847e9ef4 100644 --- a/api/consumer/searchDocumentReference/search_document_reference.py +++ b/api/consumer/searchDocumentReference/search_document_reference.py @@ -53,7 +53,7 @@ def handler( pointer_types=metadata.pointer_types, ) return SpineErrorResponse.INVALID_CODE_SYSTEM( - diagnostics="Invalid query parameter (The provided type system does not match the allowed types for this organisation)", + diagnostics="Invalid query parameter (The provided type does not match the allowed types for this organisation)", expression="type", ) diff --git a/api/consumer/searchDocumentReference/tests/test_search_document_reference_consumer.py b/api/consumer/searchDocumentReference/tests/test_search_document_reference_consumer.py index 1f30aafc5..88d1757c8 100644 --- a/api/consumer/searchDocumentReference/tests/test_search_document_reference_consumer.py +++ b/api/consumer/searchDocumentReference/tests/test_search_document_reference_consumer.py @@ -59,6 +59,56 @@ def test_search_document_reference_happy_path(repository: DocumentPointerReposit } +@mock_aws +@mock_repository +def test_search_document_reference_accession_number_in_pointer( + repository: DocumentPointerRepository, +): + doc_ref = load_document_reference("Y05868-736253002-Valid") + doc_ref.identifier = [ + {"type": {"text": "Accession-Number"}, "value": "Y05868.123456789"} + ] + doc_pointer = DocumentPointer.from_document_reference(doc_ref) + repository.create(doc_pointer) + + event = create_test_api_gateway_event( + headers=create_headers(), + query_string_parameters={ + "subject:identifier": "https://fhir.nhs.uk/Id/nhs-number|6700028191", + }, + ) + + result = handler(event, create_mock_context()) + body = result.pop("body") + + assert result == { + "statusCode": "200", + "headers": default_response_headers(), + "isBase64Encoded": False, + } + + parsed_body = json.loads(body) + assert parsed_body == { + "resourceType": "Bundle", + "type": "searchset", + "total": 1, + "link": [ + { + "relation": "self", + "url": "https://pytest.api.service.nhs.uk/record-locator/consumer/FHIR/R4/DocumentReference?subject:identifier=https://fhir.nhs.uk/Id/nhs-number|6700028191", + } + ], + "entry": [{"resource": doc_ref.model_dump(exclude_none=True)}], + } + + created_doc_pointer = repository.get_by_id("Y05868-99999-99999-999999") + + assert created_doc_pointer is not None + assert json.loads(created_doc_pointer.document)["identifier"] == [ + {"type": {"text": "Accession-Number"}, "value": "Y05868.123456789"} + ] + + @mock_aws @mock_repository def test_search_document_reference_happy_path_with_custodian( @@ -451,7 +501,7 @@ def test_search_document_reference_invalid_type(repository: DocumentPointerRepos } ] }, - "diagnostics": "Invalid query parameter (The provided type system does not match the allowed types for this organisation)", + "diagnostics": "Invalid query parameter (The provided type does not match the allowed types for this organisation)", "expression": ["type"], } ], diff --git a/api/consumer/searchPostDocumentReference/search_post_document_reference.py b/api/consumer/searchPostDocumentReference/search_post_document_reference.py index 35f91366c..6cb9b7e8c 100644 --- a/api/consumer/searchPostDocumentReference/search_post_document_reference.py +++ b/api/consumer/searchPostDocumentReference/search_post_document_reference.py @@ -57,7 +57,7 @@ def handler( pointer_types=metadata.pointer_types, ) return SpineErrorResponse.INVALID_CODE_SYSTEM( - diagnostics="Invalid type (The provided type system does not match the allowed types for this organisation)", + diagnostics="The provided type does not match the allowed types for this organisation", expression="type", ) diff --git a/api/consumer/searchPostDocumentReference/tests/test_search_post_document_reference_consumer.py b/api/consumer/searchPostDocumentReference/tests/test_search_post_document_reference_consumer.py index 4e3ed4e4d..6616ec51c 100644 --- a/api/consumer/searchPostDocumentReference/tests/test_search_post_document_reference_consumer.py +++ b/api/consumer/searchPostDocumentReference/tests/test_search_post_document_reference_consumer.py @@ -424,7 +424,7 @@ def test_search_post_document_reference_invalid_type( } ] }, - "diagnostics": "Invalid type (The provided type system does not match the allowed types for this organisation)", + "diagnostics": "The provided type does not match the allowed types for this organisation", "expression": ["type"], } ], diff --git a/api/producer/searchDocumentReference/search_document_reference.py b/api/producer/searchDocumentReference/search_document_reference.py index eb980f80c..e961e7b9f 100644 --- a/api/producer/searchDocumentReference/search_document_reference.py +++ b/api/producer/searchDocumentReference/search_document_reference.py @@ -55,7 +55,7 @@ def handler( pointer_types=metadata.pointer_types, ) return SpineErrorResponse.INVALID_CODE_SYSTEM( - diagnostics="Invalid query parameter (The provided type system does not match the allowed types for this organisation)", + diagnostics="Invalid query parameter (The provided type does not match the allowed types for this organisation)", expression="type", ) diff --git a/api/producer/searchDocumentReference/tests/test_search_document_reference_producer.py b/api/producer/searchDocumentReference/tests/test_search_document_reference_producer.py index d7a46ece7..b577f7754 100644 --- a/api/producer/searchDocumentReference/tests/test_search_document_reference_producer.py +++ b/api/producer/searchDocumentReference/tests/test_search_document_reference_producer.py @@ -201,7 +201,7 @@ def test_search_document_reference_invalid_type(repository: DocumentPointerRepos } ] }, - "diagnostics": "Invalid query parameter (The provided type system does not match the allowed types for this organisation)", + "diagnostics": "Invalid query parameter (The provided type does not match the allowed types for this organisation)", "expression": ["type"], } ], diff --git a/api/producer/searchPostDocumentReference/search_post_document_reference.py b/api/producer/searchPostDocumentReference/search_post_document_reference.py index fc6d8b535..023dcfe7c 100644 --- a/api/producer/searchPostDocumentReference/search_post_document_reference.py +++ b/api/producer/searchPostDocumentReference/search_post_document_reference.py @@ -49,7 +49,7 @@ def handler( pointer_types=metadata.pointer_types, ) return SpineErrorResponse.INVALID_CODE_SYSTEM( - diagnostics="The provided type system does not match the allowed types for this organisation", + diagnostics="The provided type does not match the allowed types for this organisation", expression="type", ) diff --git a/api/producer/searchPostDocumentReference/tests/test_search_post_document_reference_producer.py b/api/producer/searchPostDocumentReference/tests/test_search_post_document_reference_producer.py index f17de3fb1..8340ee0d3 100644 --- a/api/producer/searchPostDocumentReference/tests/test_search_post_document_reference_producer.py +++ b/api/producer/searchPostDocumentReference/tests/test_search_post_document_reference_producer.py @@ -206,7 +206,7 @@ def test_search_document_reference_invalid_type(repository: DocumentPointerRepos } ] }, - "diagnostics": "The provided type system does not match the allowed types for this organisation", + "diagnostics": "The provided type does not match the allowed types for this organisation", "expression": ["type"], } ], diff --git a/layer/nrlf/core/validators.py b/layer/nrlf/core/validators.py index cb80b0e7d..cb8140f1e 100644 --- a/layer/nrlf/core/validators.py +++ b/layer/nrlf/core/validators.py @@ -26,7 +26,7 @@ def validate_type(type_: Optional[RequestQueryType], pointer_types: List[str]) -> bool: """ - Validates if the given type system is present in the list of pointer types. + Validates if the given type is present in the list of pointer types. """ if not type_: return True diff --git a/tests/features/consumer/searchDocumentReference-failure.feature b/tests/features/consumer/searchDocumentReference-failure.feature index 1de20623a..161e12bcd 100644 --- a/tests/features/consumer/searchDocumentReference-failure.feature +++ b/tests/features/consumer/searchDocumentReference-failure.feature @@ -77,7 +77,35 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios "display": "Invalid code system" }] }, - "diagnostics": "Invalid query parameter (The provided type system does not match the allowed types for this organisation)", + "diagnostics": "Invalid query parameter (The provided type does not match the allowed types for this organisation)", + "expression": ["type"] + } + """ + + Scenario: Search rejects request with type they are not allowed to use + Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API + And the organisation 'RX898' is authorised to access pointer types: + | system | value | + | http://snomed.info/sct | 736253002 | + When consumer 'RX898' searches for DocumentReferences with parameters: + | parameter | value | + | subject | 9278693472 | + | type | http://snomed.info/sct\|887701000000100 | + Then the response status code is 400 + And the response is an OperationOutcome with 1 issue + And the OperationOutcome contains the issue: + """ + { + "severity": "error", + "code": "code-invalid", + "details": { + "coding": [{ + "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", + "code": "INVALID_CODE_SYSTEM", + "display": "Invalid code system" + }] + }, + "diagnostics": "Invalid query parameter (The provided type does not match the allowed types for this organisation)", "expression": ["type"] } """ diff --git a/tests/features/consumer/searchDocumentReference-success.feature b/tests/features/consumer/searchDocumentReference-success.feature index ead47a40e..1fd296127 100644 --- a/tests/features/consumer/searchDocumentReference-success.feature +++ b/tests/features/consumer/searchDocumentReference-success.feature @@ -36,6 +36,44 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | custodian | 02V | | author | 02V | + Scenario: Search for a DocumentReference and Accession Number is in response + Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API + And the organisation 'RX898' is authorised to access pointer types: + | system | value | + | http://snomed.info/sct | 736253002 | + And a DocumentReference resource exists with values: + | property | value | + | id | 02V-1111111111-SearchDocRefTest | + | subject | 9278693472 | + | status | current | + | type | 736253002 | + | category | 734163000 | + | contentType | application/pdf | + | url | https://example.org/my-doc.pdf | + | custodian | 02V | + | author | 02V | + | identifier | 02V.123456789 | + When consumer 'RX898' searches for DocumentReferences with parameters: + | parameter | value | + | subject | 9278693472 | + Then the response status code is 200 + And the response is a searchset Bundle + And the Bundle has a self link matching 'DocumentReference?subject:identifier=https://fhir.nhs.uk/Id/nhs-number|9278693472' + And the Bundle has a total of 1 + And the Bundle has 1 entry + And the Bundle contains an DocumentReference with values + | property | value | + | id | 02V-1111111111-SearchDocRefTest | + | subject | 9278693472 | + | status | current | + | type | 736253002 | + | category | 734163000 | + | contentType | application/pdf | + | url | https://example.org/my-doc.pdf | + | custodian | 02V | + | author | 02V | + | identifier | 02V.123456789 | + Scenario: Search for a DocumentReference by NHS Number and Custodian where both search parameters match Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API And the organisation 'RX898' is authorised to access pointer types: diff --git a/tests/features/consumer/searchPostDocumentReference-failure.feature b/tests/features/consumer/searchPostDocumentReference-failure.feature index 91380c764..3c76f708a 100644 --- a/tests/features/consumer/searchPostDocumentReference-failure.feature +++ b/tests/features/consumer/searchPostDocumentReference-failure.feature @@ -77,7 +77,35 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios "display": "Invalid code system" }] }, - "diagnostics": "Invalid type (The provided type system does not match the allowed types for this organisation)", + "diagnostics": "The provided type does not match the allowed types for this organisation", + "expression": ["type"] + } + """ + + Scenario: Search rejects request with type they are not allowed to use + Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API + And the organisation 'RX898' is authorised to access pointer types: + | system | value | + | http://snomed.info/sct | 736253002 | + When consumer 'RX898' searches for DocumentReferences using POST with request body: + | key | value | + | subject | 9278693472 | + | type | http://snomed.info/sct\|887701000000100 | + Then the response status code is 400 + And the response is an OperationOutcome with 1 issue + And the OperationOutcome contains the issue: + """ + { + "severity": "error", + "code": "code-invalid", + "details": { + "coding": [{ + "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", + "code": "INVALID_CODE_SYSTEM", + "display": "Invalid code system" + }] + }, + "diagnostics": "The provided type does not match the allowed types for this organisation", "expression": ["type"] } """ diff --git a/tests/features/steps/3_assert.py b/tests/features/steps/3_assert.py index 1ce9c82f8..445f2268d 100644 --- a/tests/features/steps/3_assert.py +++ b/tests/features/steps/3_assert.py @@ -218,6 +218,14 @@ def assert_document_reference_matches_value( context.response.json(), ) + if identifier := items.get("identifier"): + assert doc_ref.identifier[0].value == identifier, format_error( + "DocumentReference Identifier does not match", + identifier, + doc_ref.identifier[0].value, + context.response.json(), + ) + @then("the Bundle contains an DocumentReference with values") def assert_bundle_contains_documentreference_values_step(context: Context): diff --git a/tests/features/utils/data.py b/tests/features/utils/data.py index 94be4f427..35c3eb393 100644 --- a/tests/features/utils/data.py +++ b/tests/features/utils/data.py @@ -160,6 +160,12 @@ def create_test_document_reference(items: dict) -> DocumentReference: ), ) ] + if items.get("identifier"): + base_doc_ref.identifier = [ + Identifier( + type=CodeableConcept(text="Accession-Number"), value=items["identifier"] + ) + ] return base_doc_ref