Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
472 changes: 472 additions & 0 deletions layer/nrlf/core/constants.py

Large diffs are not rendered by default.

202 changes: 202 additions & 0 deletions layer/nrlf/core/tests/test_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -1522,3 +1522,205 @@ def test_validate_ssp_content_with_multiple_asids():
"diagnostics": "Multiple ASID identifiers provided. Only a single valid ASID identifier can be provided in the context.related.",
"expression": ["context.related"],
}


def test_validate_practiceSetting_no_coding():
validator = DocumentReferenceValidator()
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")

document_ref_data["context"]["practiceSetting"] = {
"text": "Description of the clinic"
}

result = validator.validate(document_ref_data)

assert result.is_valid is False
assert len(result.issues) == 1
assert result.issues[0].model_dump(exclude_none=True) == {
"severity": "error",
"code": "value",
"details": {
"coding": [
{
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
"code": "INVALID_RESOURCE",
"display": "Invalid validation of resource",
}
]
},
"diagnostics": "Invalid practice setting: must contain a Coding",
"expression": ["context.practiceSetting.coding"],
}


def test_validate_practiceSetting_coding_invalid_system():
validator = DocumentReferenceValidator()
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")

document_ref_data["context"]["practiceSetting"] = {
"coding": [
{
"system": "http://snoooooomed/sctfffffg",
"code": "788002001",
"display": "Adult mental health service",
}
]
}

result = validator.validate(document_ref_data)

assert result.is_valid is False
assert len(result.issues) == 1
assert result.issues[0].model_dump(exclude_none=True) == {
"severity": "error",
"code": "value",
"details": {
"coding": [
{
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
"code": "INVALID_RESOURCE",
"display": "Invalid validation of resource",
}
]
},
"diagnostics": "Invalid practice setting system: http://snoooooomed/sctfffffg Practice Setting system must be 'http://snomed.info/sct'",
"expression": ["context.practiceSetting.coding[0].system"],
}


def test_validate_practiceSetting_coding_invalid_code():
validator = DocumentReferenceValidator()
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")

document_ref_data["context"]["practiceSetting"] = {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "123",
"display": "Adult mental health service",
}
]
}

result = validator.validate(document_ref_data)

assert result.is_valid is False
assert len(result.issues) == 1
assert result.issues[0].model_dump(exclude_none=True) == {
"severity": "error",
"code": "value",
"details": {
"coding": [
{
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
"code": "INVALID_RESOURCE",
"display": "Invalid validation of resource",
}
]
},
"diagnostics": "Invalid practice setting code: 123 Practice Setting coding must be a member of value set https://fhir.nhs.uk/England/ValueSet/England-PracticeSetting",
"expression": ["context.practiceSetting.coding[0].code"],
}


def test_validate_practiceSetting_coding_missing_code():
validator = DocumentReferenceValidator()
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")

document_ref_data["context"]["practiceSetting"] = {
"coding": [
{
"system": "http://snomed.info/sct",
"display": "Adult mental health service",
}
]
}

result = validator.validate(document_ref_data)

assert result.is_valid is False
assert len(result.issues) == 1
assert result.issues[0].model_dump(exclude_none=True) == {
"severity": "error",
"code": "value",
"details": {
"coding": [
{
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
"code": "INVALID_RESOURCE",
"display": "Invalid validation of resource",
}
]
},
"diagnostics": "Invalid practice setting code: None Practice Setting coding must be a member of value set https://fhir.nhs.uk/England/ValueSet/England-PracticeSetting",
"expression": ["context.practiceSetting.coding[0].code"],
}


def test_validate_practiceSetting_coding_missing_display():
validator = DocumentReferenceValidator()
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")

document_ref_data["context"]["practiceSetting"] = {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "788002001",
}
]
}

result = validator.validate(document_ref_data)

assert result.is_valid is False
assert len(result.issues) == 1
assert result.issues[0].model_dump(exclude_none=True) == {
"severity": "error",
"code": "value",
"details": {
"coding": [
{
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
"code": "INVALID_RESOURCE",
"display": "Invalid validation of resource",
}
]
},
"diagnostics": "Invalid practice setting coding: display None does not match the expected display for 788002001 Practice Setting coding is bound to value set https://fhir.nhs.uk/England/ValueSet/England-PracticeSetting",
"expression": ["context.practiceSetting.coding[0]"],
}


def test_validate_practiceSetting_coding_mismatch_code_and_display():
validator = DocumentReferenceValidator()
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")

document_ref_data["context"]["practiceSetting"] = {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "788002001",
"display": "Nephrology service",
}
]
}

result = validator.validate(document_ref_data)

assert result.is_valid is False
assert len(result.issues) == 1
assert result.issues[0].model_dump(exclude_none=True) == {
"severity": "error",
"code": "value",
"details": {
"coding": [
{
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
"code": "INVALID_RESOURCE",
"display": "Invalid validation of resource",
}
]
},
"diagnostics": "Invalid practice setting coding: display Nephrology service does not match the expected display for 788002001 Practice Setting coding is bound to value set https://fhir.nhs.uk/England/ValueSet/England-PracticeSetting",
"expression": ["context.practiceSetting.coding[0]"],
}
76 changes: 72 additions & 4 deletions layer/nrlf/core/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
from nrlf.core.constants import (
CATEGORY_ATTRIBUTES,
ODS_SYSTEM,
PRACTICE_SETTING_VALUE_SET_URL,
REQUIRED_CREATE_FIELDS,
SNOMED_PRACTICE_SETTINGS,
SNOMED_SYSTEM_URL,
TYPE_ATTRIBUTES,
TYPE_CATEGORIES,
Categories,
Expand Down Expand Up @@ -141,6 +144,7 @@ def validate(self, data: Dict[str, Any] | DocumentReference):
self._validate_category(resource)
self._validate_author(resource)
self._validate_type_category_mapping(resource)
self._validate_practiceSetting(resource)
if resource.content[0].extension:
self._validate_content_extension(resource)

Expand Down Expand Up @@ -566,7 +570,7 @@ def _validate_author(self, model: DocumentReference):
issue_code="invalid",
error_code="INVALID_RESOURCE",
diagnostics=f"Invalid author length: {len(model.author)} Author must only contain a single value",
field=f"author",
field="author",
)
return

Expand All @@ -578,7 +582,7 @@ def _validate_author(self, model: DocumentReference):
issue_code="invalid",
error_code="INVALID_IDENTIFIER_SYSTEM",
diagnostics=f"Invalid author system: '{identifier.system}' Author system must be '{ODS_SYSTEM}'",
field=f"author[0].identifier.system",
field="author[0].identifier.system",
)
return

Expand All @@ -587,7 +591,7 @@ def _validate_author(self, model: DocumentReference):
issue_code="value",
error_code="INVALID_RESOURCE",
diagnostics=f"Invalid author value: '{identifier.value}' Author value must be alphanumeric",
field=f"author[0].identifier.value",
field="author[0].identifier.value",
)
return

Expand All @@ -596,6 +600,70 @@ def _validate_author(self, model: DocumentReference):
issue_code="value",
error_code="INVALID_RESOURCE",
diagnostics=f"Invalid author value: '{identifier.value}' Author value must be less than 13 characters",
field=f"author[0].identifier.value",
field="author[0].identifier.value",
)
return

def _validate_practiceSetting(self, model: DocumentReference):
"""
Validate the practice setting field contains an appropriate coding system and code.
"""

if not (
practice_setting_coding := getattr(
model.context.practiceSetting, "coding", []
)
):
self.result.add_error(
issue_code="value",
error_code="INVALID_RESOURCE",
diagnostics="Invalid practice setting: must contain a Coding",
field="context.practiceSetting.coding",
)
return

if len(practice_setting_coding) != 1:
self.result.add_error(
issue_code="value",
error_code="INVALID_RESOURCE",
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",
)
return

if (
practice_setting_system := getattr(
practice_setting_coding[0], "system", None
)
) != SNOMED_SYSTEM_URL:
self.result.add_error(
issue_code="value",
error_code="INVALID_RESOURCE",
diagnostics=f"Invalid practice setting system: {practice_setting_system} Practice Setting system must be '{SNOMED_SYSTEM_URL}'",
field="context.practiceSetting.coding[0].system",
)
return

if (
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",
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",
)
return

if (
practice_setting_display := getattr(
practice_setting_coding[0], "display", None
)
) != SNOMED_PRACTICE_SETTINGS.get(practice_setting_value):
self.result.add_error(
issue_code="value",
error_code="INVALID_RESOURCE",
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]",
)
return
Loading