diff --git a/api/producer/createDocumentReference/create_document_reference.py b/api/producer/createDocumentReference/create_document_reference.py index 020f84d80..500bfa97d 100644 --- a/api/producer/createDocumentReference/create_document_reference.py +++ b/api/producer/createDocumentReference/create_document_reference.py @@ -73,7 +73,7 @@ def _check_permissions( ods_code_parts=metadata.ods_code_parts, custodian_parts=custodian_parts, ) - return SpineErrorResponse.BAD_REQUEST( + return SpineErrorResponse.UNPROCESSABLE_ENTITY( diagnostics="The custodian of the provided DocumentReference does not match the expected ODS code for this organisation", expression="custodian.identifier.value", ) @@ -201,10 +201,11 @@ def _raise_operation_outcome_error(diagnostics, idx): """ raise OperationOutcomeError( severity="error", - code="invalid", - details=SpineErrorConcept.from_code("BAD_REQUEST"), + code="business-rule", + details=SpineErrorConcept.from_code("UNPROCESSABLE_ENTITY"), diagnostics=diagnostics, expression=[f"relatesTo[{idx}].target.identifier.value"], + status_code="422", ) @@ -236,7 +237,7 @@ def handler( if not result.is_valid: logger.log(LogReference.PROCREATE002) - return Response.from_issues(issues=result.issues, statusCode="400") + return Response.from_issues(issues=result.issues, statusCode="422") core_model = _create_core_model(result.resource, metadata) if error_response := _check_permissions(core_model, metadata): diff --git a/api/producer/createDocumentReference/tests/test_create_document_reference.py b/api/producer/createDocumentReference/tests/test_create_document_reference.py index a9c85d796..27dfdac68 100644 --- a/api/producer/createDocumentReference/tests/test_create_document_reference.py +++ b/api/producer/createDocumentReference/tests/test_create_document_reference.py @@ -191,7 +191,7 @@ def test_create_document_reference_without_related_value_exception( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -203,12 +203,12 @@ def test_create_document_reference_without_related_value_exception( "issue": [ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_IDENTIFIER_VALUE", - "display": "Invalid identifier value", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -397,7 +397,7 @@ def test_create_document_reference_invalid_resource(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -408,12 +408,12 @@ def test_create_document_reference_invalid_resource(): "issue": [ { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ], @@ -438,7 +438,7 @@ def test_create_document_reference_with_no_custodian(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -449,12 +449,12 @@ def test_create_document_reference_with_no_custodian(): "issue": [ { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ], @@ -563,7 +563,7 @@ def test_create_document_reference_invalid_custodian_id(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -575,12 +575,12 @@ def test_create_document_reference_invalid_custodian_id(): "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -607,7 +607,7 @@ def test_create_document_reference_invalid_pointer_type(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -619,12 +619,12 @@ def test_create_document_reference_invalid_pointer_type(): "issue": [ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -701,7 +701,7 @@ def test_create_document_reference_invalid_category_type(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -713,12 +713,12 @@ def test_create_document_reference_invalid_category_type(): "issue": [ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -795,7 +795,7 @@ def test_create_document_reference_no_relatesto_target(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -807,12 +807,12 @@ def test_create_document_reference_no_relatesto_target(): "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -844,7 +844,7 @@ def test_create_document_reference_invalid_relatesto_target_producer_id(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -856,12 +856,12 @@ def test_create_document_reference_invalid_relatesto_target_producer_id(): "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -896,7 +896,7 @@ def test_create_document_reference_invalid_relatesto_not_exists(repository): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -908,12 +908,12 @@ def test_create_document_reference_invalid_relatesto_not_exists(repository): "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -957,7 +957,7 @@ def test_create_document_reference_invalid_relatesto_nhs_number( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -969,12 +969,12 @@ def test_create_document_reference_invalid_relatesto_nhs_number( "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -1021,7 +1021,7 @@ def test_create_document_reference_invalid_relatesto_type( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -1033,12 +1033,12 @@ def test_create_document_reference_invalid_relatesto_type( "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -1068,7 +1068,7 @@ def test_create_document_reference_with_no_context_related_for_ssp_url( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -1080,12 +1080,12 @@ def test_create_document_reference_with_no_context_related_for_ssp_url( "issue": [ { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -1122,7 +1122,7 @@ def test_create_document_reference_with_no_asid_in_for_ssp_url( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -1134,12 +1134,12 @@ def test_create_document_reference_with_no_asid_in_for_ssp_url( "issue": [ { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -1176,7 +1176,7 @@ def test_create_document_reference_with_invalid_asid_for_ssp_url( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -1188,12 +1188,12 @@ def test_create_document_reference_with_invalid_asid_for_ssp_url( "issue": [ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_IDENTIFIER_VALUE", - "display": "Invalid identifier value", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -1356,7 +1356,7 @@ def test_create_document_reference_supersede_fails_without_toggle( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -1368,12 +1368,12 @@ def test_create_document_reference_supersede_fails_without_toggle( "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] diff --git a/api/producer/updateDocumentReference/tests/test_update_document_reference.py b/api/producer/updateDocumentReference/tests/test_update_document_reference.py index d2f06b669..9d9de5017 100644 --- a/api/producer/updateDocumentReference/tests/test_update_document_reference.py +++ b/api/producer/updateDocumentReference/tests/test_update_document_reference.py @@ -420,7 +420,7 @@ def test_update_document_reference_id_mismatch(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -431,12 +431,12 @@ def test_update_document_reference_id_mismatch(): "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -462,7 +462,7 @@ def test_update_document_reference_invalid_resource(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -473,12 +473,12 @@ def test_update_document_reference_invalid_resource(): "issue": [ { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -605,7 +605,7 @@ def test_update_document_reference_immutable_fields(repository): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -616,12 +616,12 @@ def test_update_document_reference_immutable_fields(repository): "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -701,7 +701,7 @@ def test_update_document_reference_with_no_context_related_for_ssp_url(repositor body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -712,12 +712,12 @@ def test_update_document_reference_with_no_context_related_for_ssp_url(repositor "issue": [ { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -755,7 +755,7 @@ def test_create_document_reference_with_no_asid_in_for_ssp_url( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -767,12 +767,12 @@ def test_create_document_reference_with_no_asid_in_for_ssp_url( "issue": [ { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -810,7 +810,7 @@ def test_create_document_reference_with_invalid_asid_for_ssp_url( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -822,12 +822,12 @@ def test_create_document_reference_with_invalid_asid_for_ssp_url( "issue": [ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_IDENTIFIER_VALUE", - "display": "Invalid identifier value", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] diff --git a/api/producer/updateDocumentReference/update_document_reference.py b/api/producer/updateDocumentReference/update_document_reference.py index 1f7400ee7..c6f3e9bb1 100644 --- a/api/producer/updateDocumentReference/update_document_reference.py +++ b/api/producer/updateDocumentReference/update_document_reference.py @@ -41,7 +41,7 @@ def handler( if body.id != path.id: logger.log(LogReference.PROUPDATE001, body_id=body.id, path_id=path.id) - return SpineErrorResponse.BAD_REQUEST( + return SpineErrorResponse.UNPROCESSABLE_ENTITY( diagnostics="The document id in the path does not match the document id in the body" ) @@ -52,7 +52,7 @@ def handler( if not result.is_valid: logger.log(LogReference.PROUPDATE003) - return Response.from_issues(statusCode="400", issues=result.issues) + return Response.from_issues(statusCode="422", issues=result.issues) update_time = create_fhir_instant() document_reference = _set_update_time_fields( @@ -118,7 +118,7 @@ def handler( for field in immutable_fields: if getattr(result.resource, field) != getattr(existing_resource, field): logger.log(LogReference.PROUPDATE006, field=field) - return SpineErrorResponse.BAD_REQUEST( + return SpineErrorResponse.UNPROCESSABLE_ENTITY( diagnostics=f"The field '{field}' is immutable and cannot be updated", expression=field, ) diff --git a/api/producer/upsertDocumentReference/tests/test_upsert_document_reference.py b/api/producer/upsertDocumentReference/tests/test_upsert_document_reference.py index 35a087f55..479dbe95a 100644 --- a/api/producer/upsertDocumentReference/tests/test_upsert_document_reference.py +++ b/api/producer/upsertDocumentReference/tests/test_upsert_document_reference.py @@ -210,7 +210,7 @@ def test_upsert_document_reference_invalid_category_type(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -222,12 +222,12 @@ def test_upsert_document_reference_invalid_category_type(): "issue": [ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -416,7 +416,7 @@ def test_upsert_document_reference_invalid_resource(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -427,12 +427,12 @@ def test_upsert_document_reference_invalid_resource(): "issue": [ { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ], @@ -539,7 +539,7 @@ def test_upsert_document_reference_invalid_producer_id(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -551,12 +551,12 @@ def test_upsert_document_reference_invalid_producer_id(): "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -580,7 +580,7 @@ def test_upsert_document_reference_with_no_custodian(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -591,12 +591,12 @@ def test_upsert_document_reference_with_no_custodian(): "issue": [ { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ], @@ -623,7 +623,7 @@ def test_upsert_document_reference_invalid_custodian_id(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -635,12 +635,12 @@ def test_upsert_document_reference_invalid_custodian_id(): "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -667,7 +667,7 @@ def test_upsert_document_reference_invalid_pointer_type(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -679,12 +679,12 @@ def test_upsert_document_reference_invalid_pointer_type(): "issue": [ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -762,7 +762,7 @@ def test_upsert_document_reference_no_relatesto_target(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -774,12 +774,12 @@ def test_upsert_document_reference_no_relatesto_target(): "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -811,7 +811,7 @@ def test_upsert_document_reference_invalid_relatesto_target_producer_id(): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -823,12 +823,12 @@ def test_upsert_document_reference_invalid_relatesto_target_producer_id(): "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -863,7 +863,7 @@ def test_upsert_document_reference_invalid_relatesto_not_exists(repository): body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -875,12 +875,12 @@ def test_upsert_document_reference_invalid_relatesto_not_exists(repository): "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -982,7 +982,7 @@ def test_upsert_document_reference_invalid_relatesto_nhs_number( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -994,12 +994,12 @@ def test_upsert_document_reference_invalid_relatesto_nhs_number( "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -1046,7 +1046,7 @@ def test_upsert_document_reference_invalid_relatesto_type( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -1058,12 +1058,12 @@ def test_upsert_document_reference_invalid_relatesto_type( "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -1093,7 +1093,7 @@ def test_upsert_document_reference_with_no_context_related_for_ssp_url( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -1105,12 +1105,12 @@ def test_upsert_document_reference_with_no_context_related_for_ssp_url( "issue": [ { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -1147,7 +1147,7 @@ def test_upsert_document_reference_with_no_asid_in_for_ssp_url( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -1159,12 +1159,12 @@ def test_upsert_document_reference_with_no_asid_in_for_ssp_url( "issue": [ { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -1201,7 +1201,7 @@ def test_upsert_document_reference_with_invalid_asid_for_ssp_url( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -1213,12 +1213,12 @@ def test_upsert_document_reference_with_invalid_asid_for_ssp_url( "issue": [ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { - "code": "INVALID_IDENTIFIER_VALUE", - "display": "Invalid identifier value", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] @@ -1379,7 +1379,7 @@ def test_upsert_document_reference_supersede_fails_without_toggle( body = result.pop("body") assert result == { - "statusCode": "400", + "statusCode": "422", "headers": default_response_headers(), "isBase64Encoded": False, } @@ -1391,12 +1391,12 @@ def test_upsert_document_reference_supersede_fails_without_toggle( "issue": [ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { - "code": "BAD_REQUEST", - "display": "Bad request", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", } ] diff --git a/api/producer/upsertDocumentReference/upsert_document_reference.py b/api/producer/upsertDocumentReference/upsert_document_reference.py index 42348e3be..d818b2561 100644 --- a/api/producer/upsertDocumentReference/upsert_document_reference.py +++ b/api/producer/upsertDocumentReference/upsert_document_reference.py @@ -71,7 +71,7 @@ def _check_permissions( ods_code_parts=metadata.ods_code_parts, custodian_parts=custodian_parts, ) - return SpineErrorResponse.BAD_REQUEST( + return SpineErrorResponse.UNPROCESSABLE_ENTITY( diagnostics="The custodian of the provided DocumentReference does not match the expected ODS code for this organisation", expression="custodian.identifier.value", ) @@ -204,10 +204,11 @@ def _raise_operation_outcome_error(diagnostics, idx): """ raise OperationOutcomeError( severity="error", - code="invalid", - details=SpineErrorConcept.from_code("BAD_REQUEST"), + code="business-rule", + details=SpineErrorConcept.from_code("UNPROCESSABLE_ENTITY"), diagnostics=diagnostics, expression=[f"relatesTo[{idx}].target.identifier.value"], + status_code="422", ) @@ -228,7 +229,7 @@ def handler( if not result.is_valid: logger.log(LogReference.PROUPSERT002) - return Response.from_issues(issues=result.issues, statusCode="400") + return Response.from_issues(issues=result.issues, statusCode="422") core_model = _create_core_model(result.resource, metadata) @@ -238,7 +239,7 @@ def handler( ods_code_parts=metadata.ods_code_parts, producer_id=core_model.producer_id, ) - return SpineErrorResponse.BAD_REQUEST( + return SpineErrorResponse.UNPROCESSABLE_ENTITY( diagnostics="The id of the provided DocumentReference does not include the expected ODS code for this organisation" ) diff --git a/layer/nrlf/core/codes.py b/layer/nrlf/core/codes.py index dba6e927b..a1f6767b3 100644 --- a/layer/nrlf/core/codes.py +++ b/layer/nrlf/core/codes.py @@ -45,7 +45,6 @@ class SpineErrorConcept(_CodeableConcept): _SYSTEM = "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1" _TEXT_MAP = { "ACCESS DENIED": "Access has been denied to process this request", - "INVALID_RESOURCE": "Invalid validation of resource", "NO_RECORD_FOUND": "No record found", "INVALID_NHS_NUMBER": "Invalid NHS number", "INVALID_CODE_SYSTEM": "Invalid code system", @@ -56,7 +55,6 @@ class SpineErrorConcept(_CodeableConcept): "INVALID_PARAMETER": "Invalid parameter", "MESSAGE_NOT_WELL_FORMED": "Message not well formed", "MISSING_OR_INVALID_HEADER": "There is a required header missing or invalid", - "INVALID_IDENTIFIER_SYSTEM": "Invalid identifier system", - "INVALID_CODE_VALUE": "Invalid code value", "INVALID_IDENTIFIER_VALUE": "Invalid identifier value", + "UNPROCESSABLE_ENTITY": "Unprocessable Entity", } diff --git a/layer/nrlf/core/response.py b/layer/nrlf/core/response.py index 3372923b3..8a11ed9bd 100644 --- a/layer/nrlf/core/response.py +++ b/layer/nrlf/core/response.py @@ -235,6 +235,27 @@ def BAD_REQUEST( statusCode="400", ) + @classmethod + def UNPROCESSABLE_ENTITY( + cls, diagnostics: str = "Unprocessable Entity", expression: str | None = None + ) -> "Response": + return cls.from_issues( + issues=[ + producer_model.OperationOutcomeIssue( + severity="error", + code="business-rule", + details=SpineErrorConcept.from_code("UNPROCESSABLE_ENTITY"), + diagnostics=diagnostics, + expression=( + [producer_model.ExpressionItem(root=expression)] + if expression + else None + ), + ) + ], + statusCode="422", + ) + @classmethod def AUTHOR_CREDENTIALS_ERROR( cls, diagnostics: str, expression: str | None = None diff --git a/layer/nrlf/core/tests/test_codes.py b/layer/nrlf/core/tests/test_codes.py index 44daf354f..ff154feef 100644 --- a/layer/nrlf/core/tests/test_codes.py +++ b/layer/nrlf/core/tests/test_codes.py @@ -66,6 +66,7 @@ def test_nrl_response_concept_from_code(code, expected_text): ("BAD_REQUEST", "Bad request"), ("AUTHOR_CREDENTIALS_ERROR", "Author credentials error"), ("DUPLICATE_REJECTED", "Create would lead to creation of a duplicate resource"), + ("UNPROCESSABLE_ENTITY", "Unprocessable Entity"), ], ) def test_spine_error_concept_from_code(code, expected_text): diff --git a/layer/nrlf/core/tests/test_pydantic_errors.py b/layer/nrlf/core/tests/test_pydantic_errors.py index 033961446..79171841b 100644 --- a/layer/nrlf/core/tests/test_pydantic_errors.py +++ b/layer/nrlf/core/tests/test_pydantic_errors.py @@ -24,8 +24,8 @@ def test_validate_content_missing_attachment(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -52,8 +52,8 @@ def test_validate_content_missing_content_type(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -80,8 +80,8 @@ def test_validate_content_missing_format(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -111,8 +111,8 @@ def test_validate_content_multiple_content_stability_extensions(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -141,8 +141,8 @@ def test_validate_content_invalid_content_stability_code(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -171,8 +171,8 @@ def test_validate_content_invalid_content_stability_display(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -203,8 +203,8 @@ def test_validate_content_invalid_content_stability_system(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -232,8 +232,8 @@ def test_validate_content_invalid_content_stability_url(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -263,8 +263,8 @@ def test_validate_content_empty_content_stability_coding(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -294,8 +294,8 @@ def test_validate_content_missing_content_stability_coding(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -340,8 +340,8 @@ def test_validate_multiple_codings(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -368,8 +368,8 @@ def test_validate_missing_coding(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -404,8 +404,8 @@ def test_validate_empty_strings(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -440,8 +440,8 @@ def test_validate_whitespace_strings(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -470,8 +470,8 @@ def test_validate_no_coding_where_mandatory(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -518,8 +518,8 @@ def test_validate_missing_system_from_coding_where_mandatory(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -553,8 +553,8 @@ def test_validate_missing_code_from_coding_where_mandatory(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -588,8 +588,8 @@ def test_validate_missing_display_from_coding_where_mandatory(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, diff --git a/layer/nrlf/core/tests/test_validators.py b/layer/nrlf/core/tests/test_validators.py index 8c5c36e0f..288cb7b16 100644 --- a/layer/nrlf/core/tests/test_validators.py +++ b/layer/nrlf/core/tests/test_validators.py @@ -184,8 +184,8 @@ def test_document_reference_validator_parse_invalid(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -199,8 +199,8 @@ def test_document_reference_validator_parse_invalid(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -235,13 +235,13 @@ def test_validate_document_reference_missing_fields(): assert len(result.issues) == 3 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -293,8 +293,8 @@ def test_validate_document_reference_extra_fields(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -321,8 +321,8 @@ def test_validate_document_reference_extra_fields_content(): "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "BAD_REQUEST", + "display": "Bad request", } ] }, @@ -344,13 +344,13 @@ def test_validate_identifiers_no_custodian_identifier(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -372,13 +372,13 @@ def test_validate_identifiers_no_subject_identifier(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -410,13 +410,13 @@ def test_validate_category_too_many_category(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -479,13 +479,13 @@ def test_validate_category_coding_display_mismatch( assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -511,13 +511,13 @@ def test_validate_category_coding_invalid_code(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -547,13 +547,13 @@ def test_validate_category_coding_invalid_system(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -583,13 +583,13 @@ def test_validate_type_coding_invalid_code(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -619,13 +619,13 @@ def test_validate_type_coding_invalid_system(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -680,13 +680,13 @@ def test_validate_type_coding_display_mismatch(type_str: str, display: str): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -715,13 +715,13 @@ def test_validate_author_too_many_authors(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -748,13 +748,13 @@ def test_validate_author_system_invalid(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_IDENTIFIER_SYSTEM", - "display": "Invalid identifier system", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -781,13 +781,13 @@ def test_validate_author_value_invalid(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -814,13 +814,13 @@ def test_validate_author_value_too_long(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -843,13 +843,13 @@ def test_validate_identifiers_invalid_systems(): assert len(result.issues) == 2 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_IDENTIFIER_SYSTEM", - "display": "Invalid identifier system", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -858,13 +858,13 @@ def test_validate_identifiers_invalid_systems(): } assert result.issues[1].model_dump(exclude_none=True) == { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_IDENTIFIER_SYSTEM", - "display": "Invalid identifier system", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -916,13 +916,13 @@ def test_validate_relates_to_invalid_code(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_CODE_VALUE", - "display": "Invalid code value", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -943,13 +943,13 @@ def test_validate_relates_to_no_target_identifier(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_IDENTIFIER_VALUE", - "display": "Invalid identifier value", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1001,13 +1001,13 @@ def test_validate_ssp_content_without_any_context_related(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1035,13 +1035,13 @@ def test_validate_asid_with_no_ssp_content(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_IDENTIFIER_VALUE", - "display": "Invalid identifier value", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1071,13 +1071,13 @@ def test_validate_ssp_content_without_asid_in_context_related(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "required", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1102,13 +1102,13 @@ def test_validate_ssp_content_with_invalid_asid_value(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_IDENTIFIER_VALUE", - "display": "Invalid identifier value", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1154,13 +1154,13 @@ def test_validate_ssp_content_with_invalid_asid_value_and_multiple_related(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_IDENTIFIER_VALUE", - "display": "Invalid identifier value", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1193,13 +1193,13 @@ def test_validate_ssp_content_with_multiple_asids(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1225,13 +1225,13 @@ def test_validate_content_format_invalid_code_for_unstructured_document(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1253,13 +1253,13 @@ def test_validate_content_format_invalid_code_for_contact_details(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1288,13 +1288,13 @@ def test_validate_practiceSetting_coding_invalid_system(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1323,13 +1323,13 @@ def test_validate_practiceSetting_coding_invalid_code(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1358,13 +1358,13 @@ def test_validate_practiceSetting_coding_mismatch_code_and_display(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1397,13 +1397,13 @@ def test_validate_content_extension_invalid_code_and_display_mismatch(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1426,13 +1426,13 @@ def test_validate_content_invalid_content_type(): assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, @@ -1500,13 +1500,13 @@ def test_validate_nrl_format_code_display_mismatch( assert len(result.issues) == 1 assert result.issues[0].model_dump(exclude_none=True) == { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource", + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity", } ] }, diff --git a/layer/nrlf/core/validators.py b/layer/nrlf/core/validators.py index 588845797..efe8bd433 100644 --- a/layer/nrlf/core/validators.py +++ b/layer/nrlf/core/validators.py @@ -114,7 +114,7 @@ def parse(cls, data: Dict[str, Any]): ) raise ParseError.from_validation_error( exc, - details=SpineErrorConcept.from_code("INVALID_RESOURCE"), + details=SpineErrorConcept.from_code("BAD_REQUEST"), msg="Failed to parse DocumentReference resource", ) from None @@ -164,8 +164,8 @@ def _validate_required_fields(self, model: DocumentReference): for field in REQUIRED_CREATE_FIELDS: if not getattr(model, field, None): self.result.add_error( - issue_code="required", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"The required field '{field}' is missing", field=field, ) @@ -179,8 +179,8 @@ def _validate_identifiers(self, model: DocumentReference): if not (custodian_identifier := getattr(model.custodian, "identifier", None)): self.result.add_error( - issue_code="required", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics="Custodian must have an identifier", field="custodian.identifier", ) @@ -188,8 +188,8 @@ def _validate_identifiers(self, model: DocumentReference): if not (subject_identifier := getattr(model.subject, "identifier", None)): self.result.add_error( - issue_code="required", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics="Subject must have an identifier", field="subject.identifier", ) @@ -200,16 +200,16 @@ def _validate_identifiers(self, model: DocumentReference): != "https://fhir.nhs.uk/Id/ods-organization-code" ): self.result.add_error( - issue_code="invalid", - error_code="INVALID_IDENTIFIER_SYSTEM", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics="Provided custodian identifier system is not the ODS system (expected: 'https://fhir.nhs.uk/Id/ods-organization-code')", field="custodian.identifier.system", ) if subject_identifier.system != "https://fhir.nhs.uk/Id/nhs-number": self.result.add_error( - issue_code="invalid", - error_code="INVALID_IDENTIFIER_SYSTEM", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=( "Provided subject identifier system is not the NHS number system " "(expected 'https://fhir.nhs.uk/Id/nhs-number')" @@ -239,8 +239,8 @@ def _validate_relates_to(self, model: DocumentReference): "summarizes", ]: self.result.add_error( - issue_code="value", - error_code="INVALID_CODE_VALUE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid relatesTo code: {relates_to.code}", field=f"relatesTo[{index}].code", ) @@ -250,8 +250,8 @@ def _validate_relates_to(self, model: DocumentReference): relates_to.target.identifier and relates_to.target.identifier.value ): self.result.add_error( - issue_code="required", - error_code="INVALID_IDENTIFIER_VALUE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics="relatesTo code 'replaces' must have a target identifier", field=f"relatesTo[{index}].target.identifier.value", ) @@ -264,8 +264,8 @@ def _validate_asid(self, asid_references: list): if len(asid_references) > 1: self.result.add_error( - issue_code="invalid", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics="Multiple ASID identifiers provided. Only a single valid ASID identifier can be provided in the context.related.", field="context.related", ) @@ -275,8 +275,8 @@ def _validate_asid(self, asid_references: list): asid_value = getattr(asid_reference.identifier, "value") or "" if not match(r"^\d{12}$", asid_value): self.result.add_error( - issue_code="value", - error_code="INVALID_IDENTIFIER_VALUE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid ASID value '{asid_value}'. A single ASID consisting of 12 digits can be provided in the context.related field.", field=f"context.related[{idx}].identifier.value", ) @@ -317,8 +317,8 @@ def _validate_ssp_asid(self, model: DocumentReference): if ssp_content and not does_related_exist: self.result.add_error( - issue_code="required", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics="Missing context.related. It must be provided and contain a single valid ASID identifier when content contains an SSP URL", field="context.related", ) @@ -326,8 +326,8 @@ def _validate_ssp_asid(self, model: DocumentReference): if ssp_content and does_related_exist and not does_asid_exist: self.result.add_error( - issue_code="required", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics="Missing ASID identifier. context.related must contain a single valid ASID identifier when content contains an SSP URL", field="context.related", ) @@ -341,8 +341,8 @@ def _validate_type(self, model: DocumentReference): if len(model.type.coding) > 1: self.result.add_error( - issue_code="invalid", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid type coding length: {len(model.type.coding)} Type Coding must only contain a single value", field="type.coding", ) @@ -351,8 +351,8 @@ def _validate_type(self, model: DocumentReference): coding = model.type.coding[0] if coding.system not in ["http://snomed.info/sct", "https://nicip.nhs.uk"]: self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid type system: {coding.system} Type system must be either 'http://snomed.info/sct' or 'https://nicip.nhs.uk'", field="type.coding[0].system", ) @@ -361,8 +361,8 @@ def _validate_type(self, model: DocumentReference): type_id = f"{coding.system}|{coding.code}" if type_id not in TYPE_ATTRIBUTES.keys(): self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid type code: {coding.code} Type must be a member of the England-NRLRecordType value set (https://fhir.nhs.uk/England/CodeSystem/England-NRLRecordType)", field="type.coding[0].code", ) @@ -371,8 +371,8 @@ def _validate_type(self, model: DocumentReference): type_attributes = TYPE_ATTRIBUTES.get(type_id, {}) if coding.display != type_attributes.get("display"): self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"type code '{coding.code}' must have a display value of '{type_attributes.get('display')}'", field="type.coding[0].display", ) @@ -385,8 +385,8 @@ def _validate_category(self, model: DocumentReference): if len(model.category) > 1: self.result.add_error( - issue_code="invalid", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid category length: {len(model.category)} Category must only contain a single value", field=f"category", ) @@ -396,8 +396,8 @@ def _validate_category(self, model: DocumentReference): if len(model.category[0].coding) > 1: self.result.add_error( - issue_code="invalid", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid category coding length: {len(model.category[0].coding)} Category Coding must only contain a single value", field=f"category[0].coding", ) @@ -406,8 +406,8 @@ def _validate_category(self, model: DocumentReference): coding = model.category[0].coding[0] if coding.system != "http://snomed.info/sct": self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid category system: {coding.system} Category system must be 'http://snomed.info/sct'", field="category[0].coding[0].system", ) @@ -416,8 +416,8 @@ def _validate_category(self, model: DocumentReference): category_id = f"{coding.system}|{coding.code}" if category_id not in CATEGORY_ATTRIBUTES.keys(): self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid category code: {coding.code} Category must be a member of the England-NRLRecordCategory value set (https://fhir.nhs.uk/England/CodeSystem/England-NRLRecordCategory)", field="category[0].coding[0].code", ) @@ -426,8 +426,8 @@ def _validate_category(self, model: DocumentReference): category_attributes = CATEGORY_ATTRIBUTES.get(category_id, {}) if coding.display != category_attributes.get("display"): self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"category code '{coding.code}' must have a display value of '{category_attributes.get('display')}'", field="category[0].coding[0].display", ) @@ -449,8 +449,8 @@ def _validate_type_category_mapping(self, model: DocumentReference): type_category = TYPE_CATEGORIES.get(type_id) if type_category != category_id: self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"The Category code of the provided document '{category_id}' must match the allowed category for pointer type '{type_id}' with a category value of '{type_category}'", field="category.coding[0].code", ) @@ -468,8 +468,8 @@ def _validate_content_format(self, model: DocumentReference): and content.format.code != "urn:nhs-ic:record-contact" ): self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid content format code: {content.format.code} format code must be 'urn:nhs-ic:record-contact' for Contact details attachments.", field=f"content[{i}].format.code", ) @@ -478,8 +478,8 @@ def _validate_content_format(self, model: DocumentReference): and content.format.code != "urn:nhs-ic:unstructured" ): self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid content format code: {content.format.code} format code must be 'urn:nhs-ic:unstructured' for Unstructured Document attachments.", field=f"content[{i}].format.code", ) @@ -495,8 +495,8 @@ def _validate_content_extension(self, model: DocumentReference): coding = content.extension[0].valueCodeableConcept.coding[0] if coding.code != coding.display.lower(): self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid content extension display: {coding.display} Extension display must be the same as code either 'Static' or 'Dynamic'", field=f"content[{i}].extension[0].valueCodeableConcept.coding[0].display", ) @@ -510,8 +510,8 @@ def _validate_author(self, model: DocumentReference): if len(model.author) > 1: self.result.add_error( - issue_code="invalid", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid author length: {len(model.author)} Author must only contain a single value", field="author", ) @@ -522,8 +522,8 @@ def _validate_author(self, model: DocumentReference): if identifier.system != ODS_SYSTEM: self.result.add_error( - issue_code="invalid", - error_code="INVALID_IDENTIFIER_SYSTEM", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid author system: '{identifier.system}' Author system must be '{ODS_SYSTEM}'", field="author[0].identifier.system", ) @@ -531,8 +531,8 @@ def _validate_author(self, model: DocumentReference): if not identifier.value.isalnum(): self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid author value: '{identifier.value}' Author value must be alphanumeric", field="author[0].identifier.value", ) @@ -540,8 +540,8 @@ def _validate_author(self, model: DocumentReference): if len(identifier.value) > 12: self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid author value: '{identifier.value}' Author value must be less than 13 characters", field="author[0].identifier.value", ) @@ -558,8 +558,8 @@ def _validate_practiceSetting(self, model: DocumentReference): ) ): self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics="Invalid practice setting: must contain a Coding", field="context.practiceSetting.coding", ) @@ -567,8 +567,8 @@ def _validate_practiceSetting(self, model: DocumentReference): if len(practice_setting_coding) != 1: self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid practice setting coding length: {len(model.context.practiceSetting.coding)} Practice Setting Coding must only contain a single value", field="context.practiceSetting.coding", ) @@ -580,8 +580,8 @@ def _validate_practiceSetting(self, model: DocumentReference): ) ) != SNOMED_SYSTEM_URL: self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid practice setting system: {practice_setting_system} Practice Setting system must be '{SNOMED_SYSTEM_URL}'", field="context.practiceSetting.coding[0].system", ) @@ -591,8 +591,8 @@ def _validate_practiceSetting(self, model: DocumentReference): practice_setting_value := getattr(practice_setting_coding[0], "code", None) ) not in SNOMED_PRACTICE_SETTINGS: self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid practice setting code: {practice_setting_value} Practice Setting coding must be a member of value set {PRACTICE_SETTING_VALUE_SET_URL}", field="context.practiceSetting.coding[0].code", ) @@ -604,8 +604,8 @@ def _validate_practiceSetting(self, model: DocumentReference): ) ) != SNOMED_PRACTICE_SETTINGS.get(practice_setting_value): self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid practice setting coding: display {practice_setting_display} does not match the expected display for {practice_setting_value} Practice Setting coding is bound to value set {PRACTICE_SETTING_VALUE_SET_URL}", field="context.practiceSetting.coding[0]", ) @@ -625,8 +625,8 @@ def _validate_content(self, model: DocumentReference): for i, content in enumerate(model.content): if content.attachment.contentType not in ["application/pdf", "text/html"]: self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid contentType: {content.attachment.contentType}. Must be 'application/pdf' or 'text/html'", field=f"content[{i}].attachment.contentType", ) @@ -637,8 +637,8 @@ def _validate_content(self, model: DocumentReference): expected_display = format_code_display_map.get(format_code) if expected_display and format_display != expected_display: self.result.add_error( - issue_code="value", - error_code="INVALID_RESOURCE", + issue_code="business-rule", + error_code="UNPROCESSABLE_ENTITY", diagnostics=f"Invalid display for format code '{format_code}'. Expected '{expected_display}'", field=f"content[{i}].format.display", ) diff --git a/tests/features/producer/createDocumentReference-failure.feature b/tests/features/producer/createDocumentReference-failure.feature index 1510543a0..a24174aa0 100644 --- a/tests/features/producer/createDocumentReference-failure.feature +++ b/tests/features/producer/createDocumentReference-failure.feature @@ -25,19 +25,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios | custodian | N0TANGY | | author | HAR1 | | url | https://example.org/my-doc.pdf | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "BAD_REQUEST", - "display": "Bad request" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -97,19 +97,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios } } """ - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_IDENTIFIER_SYSTEM", - "display": "Invalid identifier system" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -134,19 +134,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios } }] """ - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -171,19 +171,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios } }] """ - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_IDENTIFIER_SYSTEM", - "display": "Invalid identifier system" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -222,19 +222,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios | author | HAR1 | | url | https://example.org/newdoc.pdf | | supercedes | N0TANGY-111-UnauthSupersedeTest | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "invalid", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "BAD_REQUEST", - "display": "Bad request" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -382,19 +382,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios | custodian | X26 | | author | HAR1 | | url | https://example.org/my-doc.pdf | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -441,19 +441,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios } ] """ - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -504,19 +504,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios } ] """ - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -555,19 +555,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios | custodian | ANGY1 | | author | HAR1 | | url | https://example.org/my-doc.pdf | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -591,19 +591,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios | custodian | ANGY1 | | author | HAR1 | | url | https://example.org/my-doc.pdf | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -631,19 +631,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios | custodian | ANGY1 | | author | HAR1 | | url | https://example.org/my-doc.pdf | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -675,19 +675,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios | author | HAR1 | | url | https://example.org/my-doc.pdf | | practiceSetting | 12345 | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -716,7 +716,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios } } """ - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue Scenario: Missing content @@ -824,19 +824,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios | author | HAR1 | | url | https://example.org/my-doc.pdf | | contentType | application/invalid | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -882,19 +882,19 @@ Feature: Producer - createDocumentReference - Failure Scenarios } ] """ - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, diff --git a/tests/features/producer/updateDocumentReference-failure.feature b/tests/features/producer/updateDocumentReference-failure.feature index 4dd5ea87c..44be4a1d4 100644 --- a/tests/features/producer/updateDocumentReference-failure.feature +++ b/tests/features/producer/updateDocumentReference-failure.feature @@ -213,19 +213,19 @@ Feature: Producer - updateDocumentReference - Failure Scenarios ] } """ - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -284,19 +284,19 @@ Feature: Producer - updateDocumentReference - Failure Scenarios ] } """ - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, diff --git a/tests/features/producer/upsertDocumentReference-failure.feature b/tests/features/producer/upsertDocumentReference-failure.feature index b86cdf60c..e34457f05 100644 --- a/tests/features/producer/upsertDocumentReference-failure.feature +++ b/tests/features/producer/upsertDocumentReference-failure.feature @@ -16,19 +16,19 @@ Feature: Producer - upsertDocumentReference - Failure Scenarios | custodian | X26 | | author | HAR1 | | url | https://example.org/my-doc.pdf | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -94,19 +94,19 @@ Feature: Producer - upsertDocumentReference - Failure Scenarios | custodian | ANGY1 | | author | HAR1 | | url | https://example.org/my-doc.pdf | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -132,19 +132,19 @@ Feature: Producer - upsertDocumentReference - Failure Scenarios | custodian | ANGY1 | | author | HAR1 | | url | https://example.org/my-doc.pdf | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -171,19 +171,19 @@ Feature: Producer - upsertDocumentReference - Failure Scenarios | custodian | X26 | | author | HAR1 | | url | https://example.org/my-doc.pdf | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -212,19 +212,19 @@ Feature: Producer - upsertDocumentReference - Failure Scenarios | custodian | ANGY1 | | author | HAR1 | | url | https://example.org/my-doc.pdf | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -346,19 +346,19 @@ Feature: Producer - upsertDocumentReference - Failure Scenarios | author | HAR1 | | url | https://example.org/my-doc.pdf | | contentType | application/invalid | - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] }, @@ -404,19 +404,19 @@ Feature: Producer - upsertDocumentReference - Failure Scenarios } ] """ - Then the response status code is 400 + Then the response status code is 422 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: """ { "severity": "error", - "code": "value", + "code": "business-rule", "details": { "coding": [ { "system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1", - "code": "INVALID_RESOURCE", - "display": "Invalid validation of resource" + "code": "UNPROCESSABLE_ENTITY", + "display": "Unprocessable Entity" } ] },