diff --git a/api/consumer/swagger.yaml b/api/consumer/swagger.yaml index a6fb5141e..4652ddba5 100644 --- a/api/consumer/swagger.yaml +++ b/api/consumer/swagger.yaml @@ -1015,10 +1015,16 @@ components: - "https://fhir.nhs.uk/England/CodeSystem/England-RetrievalMechanism" code: type: string - enum: ["SSP", "Direct", "LDR"] + enum: ["SSP", "Direct", "LDR", "InContext"] display: type: string - enum: ["Spine Secure Proxy", "Direct", "Large Document Retrieval"] + enum: + [ + "Spine Secure Proxy", + "Direct", + "Large Document Retrieval", + "Direct using In-Context", + ] required: - system - code diff --git a/api/producer/swagger.yaml b/api/producer/swagger.yaml index d513cec19..14f6f052f 100644 --- a/api/producer/swagger.yaml +++ b/api/producer/swagger.yaml @@ -1671,10 +1671,16 @@ components: - "https://fhir.nhs.uk/England/CodeSystem/England-RetrievalMechanism" code: type: string - enum: ["SSP", "Direct", "LDR"] + enum: ["SSP", "Direct", "LDR", "InContext"] display: type: string - enum: ["Spine Secure Proxy", "Direct", "Large Document Retrieval"] + enum: + [ + "Spine Secure Proxy", + "Direct", + "Large Document Retrieval", + "Direct using In-Context", + ] required: - system - code diff --git a/layer/nrlf/consumer/fhir/r4/model.py b/layer/nrlf/consumer/fhir/r4/model.py index 36cbefce2..d008c8015 100644 --- a/layer/nrlf/consumer/fhir/r4/model.py +++ b/layer/nrlf/consumer/fhir/r4/model.py @@ -242,8 +242,13 @@ class ContentStabilityExtensionCoding(Coding): class RetrievalMechanismExtensionCoding(Coding): system: Literal["https://fhir.nhs.uk/England/CodeSystem/England-RetrievalMechanism"] - code: Literal["SSP", "Direct", "LDR"] - display: Literal["Spine Secure Proxy", "Direct", "Large Document Retrieval"] + code: Literal["SSP", "Direct", "LDR", "InContext"] + display: Literal[ + "Spine Secure Proxy", + "Direct", + "Large Document Retrieval", + "Direct using In-Context", + ] class NRLFormatCode(Coding): diff --git a/layer/nrlf/core/constants.py b/layer/nrlf/core/constants.py index d72162829..a3ccb4583 100644 --- a/layer/nrlf/core/constants.py +++ b/layer/nrlf/core/constants.py @@ -688,6 +688,7 @@ def coding_value(self): "Direct": "Direct", "SSP": "Spine Secure Proxy", "LDR": "Large Document Retrieval", + "InContext": "Direct using In-Context", } CONTENT_FORMAT_CODE_URL = "https://fhir.nhs.uk/England/CodeSystem/England-NRLFormatCode" CONTENT_FORMAT_CODE_MAP = { diff --git a/layer/nrlf/core/tests/test_validators.py b/layer/nrlf/core/tests/test_validators.py index 03c458ca7..40ab6a84a 100644 --- a/layer/nrlf/core/tests/test_validators.py +++ b/layer/nrlf/core/tests/test_validators.py @@ -1884,6 +1884,7 @@ def test_validate_content_stability_extension_display_mismatch(code, display): ("SSP", "Spine Secure Proxy"), ("Direct", "Direct"), ("LDR", "Large Document Retrieval"), + ("InContext", "Direct using In-Context"), ], ) def test_validate_retrieval_mechanism_extension_valid(code, display): @@ -1911,3 +1912,45 @@ def test_validate_retrieval_mechanism_extension_display_mismatch(code, display): in issue.diagnostics for issue in validator.result.issues ) + + +def test_validate_structured_format_with_text_html_for_incontext_launch(): + validator = DocumentReferenceValidator() + document_ref_data = load_document_reference_json("Y05868-736253002-Valid") + + # Set up for direct in-context launch + document_ref_data["content"][0]["attachment"]["contentType"] = "text/html" + document_ref_data["content"][0]["format"] = { + "system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLFormatCode", + "code": "urn:nhs-ic:structured", + "display": "Structured Document", + } + document_ref_data["content"][0]["extension"] = [ + { + "url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-RetrievalMechanism", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/England/CodeSystem/England-RetrievalMechanism", + "code": "InContext", + "display": "Direct using In-Context", + } + ] + }, + }, + { + "url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-ContentStability", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLContentStability", + "code": "dynamic", + "display": "Dynamic", + } + ] + }, + }, + ] + + result = validator.validate(document_ref_data) + assert result.is_valid is True diff --git a/layer/nrlf/core/validators.py b/layer/nrlf/core/validators.py index 6c906cf50..768a47dc4 100644 --- a/layer/nrlf/core/validators.py +++ b/layer/nrlf/core/validators.py @@ -472,7 +472,8 @@ def _validate_content_format(self, model: DocumentReference): for i, content in enumerate(model.content): if ( content.attachment.contentType == "text/html" - and content.format.code != "urn:nhs-ic:record-contact" + and content.format.code + not in ["urn:nhs-ic:record-contact", "urn:nhs-ic:structured"] ): self.result.add_error( issue_code="business-rule", diff --git a/layer/nrlf/producer/fhir/r4/model.py b/layer/nrlf/producer/fhir/r4/model.py index 8b0e3fc64..714cc39f2 100644 --- a/layer/nrlf/producer/fhir/r4/model.py +++ b/layer/nrlf/producer/fhir/r4/model.py @@ -286,8 +286,13 @@ class ContentStabilityExtensionCoding(Coding): class RetrievalMechanismExtensionCoding(Coding): system: Literal["https://fhir.nhs.uk/England/CodeSystem/England-RetrievalMechanism"] - code: Literal["SSP", "Direct", "LDR"] - display: Literal["Spine Secure Proxy", "Direct", "Large Document Retrieval"] + code: Literal["SSP", "Direct", "LDR", "InContext"] + display: Literal[ + "Spine Secure Proxy", + "Direct", + "Large Document Retrieval", + "Direct using In-Context", + ] class NRLFormatCode(Coding): diff --git a/layer/nrlf/producer/fhir/r4/strict_model.py b/layer/nrlf/producer/fhir/r4/strict_model.py index 87cdefcdc..6e3886bcf 100644 --- a/layer/nrlf/producer/fhir/r4/strict_model.py +++ b/layer/nrlf/producer/fhir/r4/strict_model.py @@ -257,8 +257,13 @@ class ContentStabilityExtensionCoding(Coding): class RetrievalMechanismExtensionCoding(Coding): system: Literal["https://fhir.nhs.uk/England/CodeSystem/England-RetrievalMechanism"] - code: Literal["SSP", "Direct", "LDR"] - display: Literal["Spine Secure Proxy", "Direct", "Large Document Retrieval"] + code: Literal["SSP", "Direct", "LDR", "InContext"] + display: Literal[ + "Spine Secure Proxy", + "Direct", + "Large Document Retrieval", + "Direct using In-Context", + ] class NRLFormatCode(Coding): diff --git a/resources/fhir/NRLF-Retrieval-CodeSystem.json b/resources/fhir/NRLF-Retrieval-CodeSystem.json index 9d28dc3d2..406c02677 100644 --- a/resources/fhir/NRLF-Retrieval-CodeSystem.json +++ b/resources/fhir/NRLF-Retrieval-CodeSystem.json @@ -2,7 +2,7 @@ "resourceType": "CodeSystem", "id": "England-RetrievalMechanismNRL", "url": "https://fhir.nhs.uk/England/CodeSystem/England-RetrievalMechanismNRL", - "version": "1.0.1", + "version": "1.1.0", "name": "EnglandRetrievalMechanismNRL", "title": "England Retrieval MechanismNRL", "status": "draft", @@ -40,7 +40,14 @@ { "code": "Direct", "display": "Direct", - "definition": "This document can be directly retrieved via HTTP(s) at its public URL." + "definition": "This document can be directly retrieved via HTTP(s) at its public URL.", + "concept": [ + { + "code": "InContext", + "display": "Direct using In-Context", + "definition": "This document can be retrieved in-context via the In-Context launch mechanism." + } + ] }, { "code": "Proxy", diff --git a/resources/fhir/NRLF-RetrievalMechanism-ValueSet.json b/resources/fhir/NRLF-RetrievalMechanism-ValueSet.json index 6af55f053..e680a09d2 100644 --- a/resources/fhir/NRLF-RetrievalMechanism-ValueSet.json +++ b/resources/fhir/NRLF-RetrievalMechanism-ValueSet.json @@ -2,7 +2,7 @@ "resourceType": "ValueSet", "id": "England-RetrievalMechanism", "url": "https://fhir.nhs.uk/England/ValueSet/England-RetrievalMechanism", - "version": "1.0.1", + "version": "1.1.0", "name": "EnglandRetrievalMechanism", "status": "draft", "date": "2025-02-28", @@ -33,6 +33,10 @@ { "code": "LDR", "display": "Large Document Retrieval" + }, + { + "code": "InContext", + "display": "Direct using In-Context" } ] } diff --git a/tests/data/samples/SYNTHETIC_IN_CONTEXT_LAUNCH_EXAMPLE.json b/tests/data/samples/SYNTHETIC_IN_CONTEXT_LAUNCH_EXAMPLE.json new file mode 100644 index 000000000..94b54f179 --- /dev/null +++ b/tests/data/samples/SYNTHETIC_IN_CONTEXT_LAUNCH_EXAMPLE.json @@ -0,0 +1,107 @@ +{ + "resourceType": "DocumentReference", + "id": "INCTX-197ca0ca-f547-42b6-a68c-99b75a3a2df5", + "meta": { + "lastUpdated": "2025-02-10T16:48:27.326Z" + }, + "masterIdentifier": { + "system": "urn:ietf:rfc:3986", + "value": "mid_197ca0ca-f547-42b6-a68c-99b75a3a2df5" + }, + "status": "current", + "type": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "736253002", + "display": "Mental health crisis plan" + } + ] + }, + "category": [ + { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "734163000", + "display": "Care plan" + } + ] + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "9999999999" + } + }, + "date": "2025-02-10T16:48:27.326Z", + "author": [ + { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "L85012" + } + } + ], + "custodian": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "INCTX" + } + }, + "content": [ + { + "attachment": { + "contentType": "text/html", + "url": "https://supplier.inctxlaunch.example/content", + "creation": "2025-02-10T16:48:27.326Z" + }, + "format": { + "system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLFormatCode", + "code": "urn:nhs-ic:structured", + "display": "Structured Document" + }, + "extension": [ + { + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLContentStability", + "code": "dynamic", + "display": "Dynamic" + } + ] + }, + "url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-ContentStability" + }, + { + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/England/CodeSystem/England-RetrievalMechanism", + "code": "InContext", + "display": "Direct using In-Context" + } + ] + }, + "url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-RetrievalMechanism" + } + ] + } + ], + "context": { + "period": { + "start": "2025-02-10T16:48:27.326Z" + }, + "practiceSetting": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "1060971000000108", + "display": "General practice service" + } + ] + } + } +} diff --git a/tests/features/producer/createDocumentReference-failure.feature b/tests/features/producer/createDocumentReference-failure.feature index 099ae18c1..6651b90ac 100644 --- a/tests/features/producer/createDocumentReference-failure.feature +++ b/tests/features/producer/createDocumentReference-failure.feature @@ -1369,7 +1369,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios } ] }, - "diagnostics": "Invalid content retrieval extension (content[0].extension[0].valueCodeableConcept.coding[0].code: Input should be 'SSP', 'Direct' or 'LDR', see: https://fhir.nhs.uk/England/ValueSet/England-RetrievalMechanism)", + "diagnostics": "Invalid content retrieval extension (content[0].extension[0].valueCodeableConcept.coding[0].code: Input should be 'SSP', 'Direct', 'LDR' or 'InContext', see: https://fhir.nhs.uk/England/ValueSet/England-RetrievalMechanism)", "expression": ["content[0].extension[0].valueCodeableConcept.coding[0].code"] } """ @@ -1436,7 +1436,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios } ] }, - "diagnostics": "Invalid content retrieval extension (content[0].extension[0].valueCodeableConcept.coding[0].display: Input should be 'Spine Secure Proxy', 'Direct' or 'Large Document Retrieval', see: https://fhir.nhs.uk/England/ValueSet/England-RetrievalMechanism)", + "diagnostics": "Invalid content retrieval extension (content[0].extension[0].valueCodeableConcept.coding[0].display: Input should be 'Spine Secure Proxy', 'Direct', 'Large Document Retrieval' or 'Direct using In-Context', see: https://fhir.nhs.uk/England/ValueSet/England-RetrievalMechanism)", "expression": ["content[0].extension[0].valueCodeableConcept.coding[0].display"] } """ diff --git a/tests/features/producer/createDocumentReference-success.feature b/tests/features/producer/createDocumentReference-success.feature index cc7186b12..fa654a1fd 100644 --- a/tests/features/producer/createDocumentReference-success.feature +++ b/tests/features/producer/createDocumentReference-success.feature @@ -491,3 +491,80 @@ Feature: Producer - createDocumentReference - Success Scenarios | content[1].attachment.url | https://example.org/doc2.pdf | | content[1].extension[1].valueCodeableConcept.coding[0].code | SSP | | content[1].extension[1].valueCodeableConcept.coding[0].display | Spine Secure Proxy | + + Scenario: Successfully create a Document Pointer with InContext retrieval mechanism and structured format + Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API + And the organisation 'TSTCUS' is authorised to access pointer types: + | system | value | + | http://snomed.info/sct | 1363501000000100 | + When producer 'TSTCUS' requests creation of a DocumentReference with default test values except 'content' is: + """ + "content": [ + { + "attachment": { + "contentType": "text/html", + "url": "https://example.org/incontext-launch.html" + }, + "format": { + "system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLFormatCode", + "code": "urn:nhs-ic:structured", + "display": "Structured Document" + }, + "extension": [ + { + "url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-ContentStability", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLContentStability", + "code": "dynamic", + "display": "Dynamic" + } + ] + } + }, + { + "url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-RetrievalMechanism", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/England/CodeSystem/England-RetrievalMechanism", + "code": "InContext", + "display": "Direct using In-Context" + } + ] + } + } + ] + } + ] + """ + Then the response status code is 201 + And the response is an OperationOutcome with 1 issue + And the OperationOutcome contains the issue: + """ + { + "severity": "information", + "code": "informational", + "details": { + "coding": [ + { + "system": "https://fhir.nhs.uk/ValueSet/NRL-ResponseCode", + "code": "RESOURCE_CREATED", + "display": "Resource created" + } + ] + }, + "diagnostics": "The document has been created" + } + """ + And the response has a Location header + And the Location header starts with '/producer/FHIR/R4/DocumentReference/TSTCUS-' + And the resource in the Location header exists with values: + | property | value | + | content[0].attachment.url | https://example.org/incontext-launch.html | + | content[0].attachment.contentType | text/html | + | content[0].format.code | urn:nhs-ic:structured | + | content[0].format.display | Structured Document | + | content[0].extension[1].valueCodeableConcept.coding[0].code | InContext | + | content[0].extension[1].valueCodeableConcept.coding[0].display | Direct using In-Context |