diff --git a/sandbox/src/mocks/stu3/changeShortlist/requests/TriagedProviderToAction.json b/sandbox/src/mocks/stu3/changeShortlist/requests/TriagedProviderToAction.json new file mode 100644 index 000000000..44429d3c8 --- /dev/null +++ b/sandbox/src/mocks/stu3/changeShortlist/requests/TriagedProviderToAction.json @@ -0,0 +1,105 @@ +{ + "resourceType": "Parameters", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/eRS-ChangeShortlist-Parameters-1" + ] + }, + "parameter": [ + { + "name": "shortlist", + "resource": { + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/eRS-Shortlist-List-1" + ] + }, + "resourceType": "List", + "status": "current", + "mode": "snapshot", + "contained": [ + { + "resourceType": "Parameters", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/eRS-ServiceSearchCriteria-Parameters-1" + ] + }, + "id": "ServiceSearchCriteria-1", + "parameter": [ + { + "name": "priority", + "valueCoding": { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/eRS-Priority-1", + "code": "ROUTINE" + } + }, + { + "name": "specialty", + "valueCoding": { + "system": "_baseUrl_/STU3/CodeSystem/SPECIALTY", + "code": "CARDIOLOGY" + } + }, + { + "name": "clinicType", + "valueCoding": { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/eRS-ClinicType-1", + "code": "HEART_FAILURE" + } + }, + { + "name": "ageAndGenderAppropriate", + "valueBoolean": false + }, + { + "name": "commissioningProvisioning", + "valueCoding": { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/eRS-CommissioningProvisioning-1", + "code": "ALL_AVAILABLE_FOR_BOOKING" + } + } + ] + } + ], + "entry": [ + { + "item": { + "identifier": { + "system": "http://fhir.nhs.net/Id/ers-service", + "value": "11000" + } + } + }, + { + "item": { + "identifier": { + "system": "http://fhir.nhs.net/Id/ers-service", + "value": "11003" + } + } + } + ], + "extension": [ + { + "url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-eRS-Shortlist-SearchCriteria-1", + "valueReference": { + "reference": "#ServiceSearchCriteria-1" + } + } + ] + } + }, + { + "name": "intentionToAddReferralLetter", + "valueCoding": { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/eRS-ReferralLetterIntention-1", + "code": "NOT_INTENDING_TO_ADD" + } + }, + { + "name": "firstReminderLetterFollowUpDays", + "valueUnsignedInt": 0 + } + ] +} diff --git a/sandbox/src/mocks/stu3/changeShortlist/responses/TriagedProviderToAction.json b/sandbox/src/mocks/stu3/changeShortlist/responses/TriagedProviderToAction.json new file mode 100644 index 000000000..31a0b0279 --- /dev/null +++ b/sandbox/src/mocks/stu3/changeShortlist/responses/TriagedProviderToAction.json @@ -0,0 +1,142 @@ +{ + "id": "000000070000", + "meta": { + "versionId": "9", + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/eRS-ReferralRequest-1" + ] + }, + "resourceType": "ReferralRequest", + "extension": [ + { + "url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-eRS-ReferralPriority-1", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/eRS-Priority-1", + "code": "ROUTINE", + "display": "Routine" + } + ] + } + }, + { + "url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-eRS-ReferralShortlist-1", + "valueReference": { + "reference": "#shortlist" + } + }, + { + "url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-eRS-ReferralState-1", + "extension": [ + { + "url": "state", + "valueCoding": { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/eRS-ReferralState-1", + "code": "NOT_BOOKED", + "display": "Not Booked" + } + } + ] + } + ], + "contained": [ + { + "id": "serviceSearchCriteria", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/eRS-ServiceSearchCriteria-Parameters-1" + ] + }, + "resourceType": "Parameters", + "parameter": [ + { + "name": "priority", + "valueCoding": { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/eRS-Priority-1", + "code": "ROUTINE" + } + }, + { + "name": "specialty", + "valueCoding": { + "system": "_baseUrl_/STU3/CodeSystem/SPECIALTY", + "code": "CARDIOLOGY" + } + }, + { + "name": "clinicType", + "valueCoding": { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/eRS-ClinicType-1", + "code": "HEART_FAILURE" + } + }, + { + "name": "ageAndGenderAppropriate", + "valueBoolean": false + }, + { + "name": "commissioningProvisioning", + "valueCoding": { + "system": "https://fhir.nhs.uk/STU3/CodeSystem/eRS-CommissioningProvisioning-1", + "code": "ALL_AVAILABLE_FOR_BOOKING" + } + } + ] + }, + { + "id": "shortlist", + "meta": { + "profile": [ + "https://fhir.nhs.uk/STU3/StructureDefinition/eRS-Shortlist-List-1" + ] + }, + "resourceType": "List", + "extension": [ + { + "url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-eRS-Shortlist-SearchCriteria-1", + "valueReference": { + "reference": "#serviceSearchCriteria" + } + } + ], + "status": "current", + "mode": "snapshot", + "entry": [ + { + "item": { + "identifier": { + "system": "http://fhir.nhs.net/Id/ers-service", + "value": "11000" + }, + "display": "Forthright Cardiology Business Service" + } + }, + { + "item": { + "identifier": { + "system": "http://fhir.nhs.net/Id/ers-service", + "value": "11003" + }, + "display": "Indirect Cardiology Business Service" + } + } + ] + } + ], + "status": "active", + "subject": { + "identifier": { + "system": "http://fhir.nhs.net/Id/nhs-number", + "value": "1000000001" + } + }, + "supportingInfo": [], + "intent": "plan", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ers-request-id", + "value": "r.c18c4ec4-7d0a-480e-8506-347e0ec228b0" + } + ] +} diff --git a/sandbox/src/routes/stu3/changeShortlist.js b/sandbox/src/routes/stu3/changeShortlist.js index 78f0d91e4..0b35e52d8 100644 --- a/sandbox/src/routes/stu3/changeShortlist.js +++ b/sandbox/src/routes/stu3/changeShortlist.js @@ -9,7 +9,7 @@ module.exports = [ method: 'POST', path: '/FHIR/STU3/ReferralRequest/{ubrn}/$ers.changeShortlist', handler: (request, h) => { - const allowedBusinessFunctions = ["REFERRING_CLINICIAN", "REFERRING_CLINICIAN_ADMIN"] + const allowedBusinessFunctions = ["REFERRING_CLINICIAN", "REFERRING_CLINICIAN_ADMIN", "SERVICE_PROVIDER_CLINICIAN", "SERVICE_PROVIDER_CLINICIAN_ADMIN"] const validationResult = validationUtils.validateBusinessFunction(request, h, allowedBusinessFunctions) if (validationResult) { @@ -24,4 +24,4 @@ module.exports = [ return h.file(responsePath, { etagMethod: false }).code(200).type('application/fhir+json').etag("3", { weak: true }) } } -] \ No newline at end of file +] diff --git a/sandbox/src/routes/stu3/services/mockResponseProvider.js b/sandbox/src/routes/stu3/services/mockResponseProvider.js index 3e31b22f5..02e4c3d11 100644 --- a/sandbox/src/routes/stu3/services/mockResponseProvider.js +++ b/sandbox/src/routes/stu3/services/mockResponseProvider.js @@ -464,14 +464,26 @@ module.exports = { }, getExampleResponseForChangeShortlist: function (request) { - var responseMap = { + var responseMapForReferringUsers = { 'src/mocks/stu3/changeShortlist/requests/UnbookedReferral.json': 'stu3/changeShortlist/responses/UnbookedReferral.json', 'src/mocks/stu3/changeShortlist/requests/UnbookedReferralMultipleServices.json': 'stu3/changeShortlist/responses/UnbookedReferralMultipleServices.json', 'src/mocks/stu3/changeShortlist/requests/UnbookedReferralMixedShortlist.json': 'stu3/changeShortlist/responses/UnbookedReferralMixedShortlist.json', 'src/mocks/stu3/changeShortlist/requests/NonMixedShortlistWithDocument.json': 'stu3/changeShortlist/responses/NonMixedShortlistWithDocument.json' } - return mapExampleResponse(request, responseMap) + var responseMapForServiceProviderUsers = { + 'src/mocks/stu3/changeShortlist/requests/TriagedProviderToAction.json': 'stu3/changeShortlist/responses/TriagedProviderToAction.json' + } + + const isServiceProviderBusinessRole = [ + 'SERVICE_PROVIDER_CLINICIAN', + 'SERVICE_PROVIDER_CLINICIAN_ADMIN' + ].includes(request.headers["nhsd-ers-business-function"]) + + return mapExampleResponse( + request, + isServiceProviderBusinessRole ? responseMapForServiceProviderUsers : responseMapForReferringUsers + ) }, getExampleResponseForChangeShortlistAndSendForTriage: function (request) { diff --git a/specification/components/stu3/schemas/endpoints/a031-change-shortlist.yaml b/specification/components/stu3/schemas/endpoints/a031-change-shortlist.yaml index 9f990831e..e7334a07d 100644 --- a/specification/components/stu3/schemas/endpoints/a031-change-shortlist.yaml +++ b/specification/components/stu3/schemas/endpoints/a031-change-shortlist.yaml @@ -37,11 +37,15 @@ description: | In order to use this endpoint you must be an authenticated e-RS user and use one of the following e-RS roles: - `REFERRING_CLINICIAN` - `REFERRING_CLINICIAN_ADMIN` + - `SERVICE_PROVIDER_CLINICIAN` + - `SERVICE_PROVIDER_CLINICIAN_ADMIN` You need to use the `Unique Booking Reference Number` (UBRN) of a referral request in order to use this endpoint. You need to have found services that meet the referral needs of a patient using [[HYPERLINK_A010]]. - + + Where a `SERVICE_PROVIDER_CLINICIAN_ADMIN` (SPCA) is acting on behalf of a `SERVICE_PROVIDER_CLINICIAN` (SPC), the 'on behalf of' user ID must be that of an appropriate SPC. You can use endpoint [[HYPERLINK_A040]] to determine which e-RS users a `SERVICE_PROVIDER_CLINICIAN_ADMIN` is allowed to work 'on-behalf-of'. + ## Use case As an authenticated user @@ -59,6 +63,8 @@ description: | For the referral to be processed by the service provider, you must ensure appropriate referral letter information has been added to the referral. You can add/manage referrer letter information by using [[HYPERLINK_A012]]. You can check to see what referral letter information has already been added to a referral by using [[HYPERLINK_A005]], [[HYPERLINK_A007]], and [[HYPERLINK_A006]] endpoints where necessary. + + When making a request as a `SERVICE_PROVIDER_CLINICIAN_ADMIN` (SPCA), use endpoint [[HYPERLINK_A040]] to determine which `SERVICE_PROVIDER_CLINICIAN` (SPC) the SPCA is allowed to act 'on-behalf-of'. ## Known Issues @@ -75,6 +81,7 @@ parameters: - $ref: '../headers/request/BusinessFunction.yaml' - $ref: '../headers/request/CorrelationID.yaml' - $ref: '../headers/request/IfMatch.yaml' + - $ref: '../headers/request/OnBehalfOfUserID.yaml' - $ref: '../pathParameters/Ubrn.yaml' requestBody: required: true diff --git a/specification/components/stu3/schemas/responses/changeShortlist/422Response.yaml b/specification/components/stu3/schemas/responses/changeShortlist/422Response.yaml index 0dbbebdaa..8fdd6ffaa 100644 --- a/specification/components/stu3/schemas/responses/changeShortlist/422Response.yaml +++ b/specification/components/stu3/schemas/responses/changeShortlist/422Response.yaml @@ -12,6 +12,7 @@ description: | | INVALID_CODE | The input provided for a field is not one of the defined legal values. | | UNEXPECTED_FIELD | A field is provided that is not expected as part of the request. E.g. a field is mis-spelt, was defined on a previous version of the endpoint but has subsequently been removed. | | INVALID_FHIR_STRUCTURE | The FHIR data structure in the message body does not match the expected structure (e.g. an array is present for a value when no array is expected). | + | INVALID_STATE | Indicates that the referenced item is not in the correct state for the request to be processed (e.g. a service of the wrong type). | | ORGANISATION_IS_CLOSED | The organisation supplied corresponds to an organisation that is closed. | | ORGANISATION_NOT_APPROPRIATE | The organisation supplied corresponds to an organisation that is not valid for the given request. | | DUPLICATE_SERVICE | Unique service value expected. | diff --git a/tests/sandbox/stu3/test_a031_change_shortlist.py b/tests/sandbox/stu3/test_a031_change_shortlist.py index 543da69ba..797734c7b 100644 --- a/tests/sandbox/stu3/test_a031_change_shortlist.py +++ b/tests/sandbox/stu3/test_a031_change_shortlist.py @@ -14,11 +14,25 @@ class TestChangeShortlist(SandboxTest): allowed_business_function_data = [ "REFERRING_CLINICIAN", "REFERRING_CLINICIAN_ADMIN", + "SERVICE_PROVIDER_CLINICIAN", + "SERVICE_PROVIDER_CLINICIAN_ADMIN", ] authorised_actor_data = Actor.all( required_business_functions=allowed_business_function_data ) + referring_actor_data = Actor.all( + required_business_functions=[ + "REFERRING_CLINICIAN", + "REFERRING_CLINICIAN_ADMIN", + ] + ) + service_provider_actor_data = Actor.all( + required_business_functions=[ + "SERVICE_PROVIDER_CLINICIAN", + "SERVICE_PROVIDER_CLINICIAN_ADMIN", + ] + ) testdata = [ ( @@ -31,6 +45,13 @@ class TestChangeShortlist(SandboxTest): ), ] + service_provider_testdata = [ + ( + "stu3/changeShortlist/requests/TriagedProviderToAction.json", + "stu3/changeShortlist/responses/TriagedProviderToAction.json", + ) + ] + @pytest.fixture def endpoint_url(self) -> str: return "FHIR/STU3/ReferralRequest/000000070000/$ers.changeShortlist" @@ -60,9 +81,34 @@ def call_endpoint( headers, ) - @pytest.mark.parametrize("actor", authorised_actor_data) + @pytest.mark.parametrize("actor", referring_actor_data) @pytest.mark.parametrize("requestJson,response", testdata) - def test_success( + def test_referrer_success( + self, + call_endpoint_url_with_request: Callable[ + [Actor, str, Dict[str, str]], Response + ], + load_json: Callable[[str], Dict[str, str]], + actor: Actor, + requestJson, + response, + ): + expected_response = load_json(response) + actual_response = call_endpoint_url_with_request(actor, requestJson) + + asserts.assert_status_code(200, actual_response.status_code) + asserts.assert_response(expected_response, actual_response) + + asserts.assert_json_response_headers( + actual_response, + additional={ + "etag": 'W/"3"', + }, + ) + + @pytest.mark.parametrize("actor", service_provider_actor_data) + @pytest.mark.parametrize("requestJson,response", service_provider_testdata) + def test_service_provider_success( self, call_endpoint_url_with_request: Callable[ [Actor, str, Dict[str, str]], Response