Skip to content

Commit ed9fd52

Browse files
authored
Merge pull request #750 from NHSDigital/feature/kabo5-NRL519-validate-practice-setting
NRL-519 validate context.practiceSetting as in NRL2.8
2 parents 8ab94e2 + bfc1850 commit ed9fd52

File tree

13 files changed

+2840
-224
lines changed

13 files changed

+2840
-224
lines changed

layer/nrlf/core/constants.py

Lines changed: 472 additions & 0 deletions
Large diffs are not rendered by default.

layer/nrlf/core/tests/test_validators.py

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,3 +1522,205 @@ def test_validate_ssp_content_with_multiple_asids():
15221522
"diagnostics": "Multiple ASID identifiers provided. Only a single valid ASID identifier can be provided in the context.related.",
15231523
"expression": ["context.related"],
15241524
}
1525+
1526+
1527+
def test_validate_practiceSetting_no_coding():
1528+
validator = DocumentReferenceValidator()
1529+
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")
1530+
1531+
document_ref_data["context"]["practiceSetting"] = {
1532+
"text": "Description of the clinic"
1533+
}
1534+
1535+
result = validator.validate(document_ref_data)
1536+
1537+
assert result.is_valid is False
1538+
assert len(result.issues) == 1
1539+
assert result.issues[0].model_dump(exclude_none=True) == {
1540+
"severity": "error",
1541+
"code": "value",
1542+
"details": {
1543+
"coding": [
1544+
{
1545+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
1546+
"code": "INVALID_RESOURCE",
1547+
"display": "Invalid validation of resource",
1548+
}
1549+
]
1550+
},
1551+
"diagnostics": "Invalid practice setting: must contain a Coding",
1552+
"expression": ["context.practiceSetting.coding"],
1553+
}
1554+
1555+
1556+
def test_validate_practiceSetting_coding_invalid_system():
1557+
validator = DocumentReferenceValidator()
1558+
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")
1559+
1560+
document_ref_data["context"]["practiceSetting"] = {
1561+
"coding": [
1562+
{
1563+
"system": "http://snoooooomed/sctfffffg",
1564+
"code": "788002001",
1565+
"display": "Adult mental health service",
1566+
}
1567+
]
1568+
}
1569+
1570+
result = validator.validate(document_ref_data)
1571+
1572+
assert result.is_valid is False
1573+
assert len(result.issues) == 1
1574+
assert result.issues[0].model_dump(exclude_none=True) == {
1575+
"severity": "error",
1576+
"code": "value",
1577+
"details": {
1578+
"coding": [
1579+
{
1580+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
1581+
"code": "INVALID_RESOURCE",
1582+
"display": "Invalid validation of resource",
1583+
}
1584+
]
1585+
},
1586+
"diagnostics": "Invalid practice setting system: http://snoooooomed/sctfffffg Practice Setting system must be 'http://snomed.info/sct'",
1587+
"expression": ["context.practiceSetting.coding[0].system"],
1588+
}
1589+
1590+
1591+
def test_validate_practiceSetting_coding_invalid_code():
1592+
validator = DocumentReferenceValidator()
1593+
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")
1594+
1595+
document_ref_data["context"]["practiceSetting"] = {
1596+
"coding": [
1597+
{
1598+
"system": "http://snomed.info/sct",
1599+
"code": "123",
1600+
"display": "Adult mental health service",
1601+
}
1602+
]
1603+
}
1604+
1605+
result = validator.validate(document_ref_data)
1606+
1607+
assert result.is_valid is False
1608+
assert len(result.issues) == 1
1609+
assert result.issues[0].model_dump(exclude_none=True) == {
1610+
"severity": "error",
1611+
"code": "value",
1612+
"details": {
1613+
"coding": [
1614+
{
1615+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
1616+
"code": "INVALID_RESOURCE",
1617+
"display": "Invalid validation of resource",
1618+
}
1619+
]
1620+
},
1621+
"diagnostics": "Invalid practice setting code: 123 Practice Setting coding must be a member of value set https://fhir.nhs.uk/England/ValueSet/England-PracticeSetting",
1622+
"expression": ["context.practiceSetting.coding[0].code"],
1623+
}
1624+
1625+
1626+
def test_validate_practiceSetting_coding_missing_code():
1627+
validator = DocumentReferenceValidator()
1628+
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")
1629+
1630+
document_ref_data["context"]["practiceSetting"] = {
1631+
"coding": [
1632+
{
1633+
"system": "http://snomed.info/sct",
1634+
"display": "Adult mental health service",
1635+
}
1636+
]
1637+
}
1638+
1639+
result = validator.validate(document_ref_data)
1640+
1641+
assert result.is_valid is False
1642+
assert len(result.issues) == 1
1643+
assert result.issues[0].model_dump(exclude_none=True) == {
1644+
"severity": "error",
1645+
"code": "value",
1646+
"details": {
1647+
"coding": [
1648+
{
1649+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
1650+
"code": "INVALID_RESOURCE",
1651+
"display": "Invalid validation of resource",
1652+
}
1653+
]
1654+
},
1655+
"diagnostics": "Invalid practice setting code: None Practice Setting coding must be a member of value set https://fhir.nhs.uk/England/ValueSet/England-PracticeSetting",
1656+
"expression": ["context.practiceSetting.coding[0].code"],
1657+
}
1658+
1659+
1660+
def test_validate_practiceSetting_coding_missing_display():
1661+
validator = DocumentReferenceValidator()
1662+
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")
1663+
1664+
document_ref_data["context"]["practiceSetting"] = {
1665+
"coding": [
1666+
{
1667+
"system": "http://snomed.info/sct",
1668+
"code": "788002001",
1669+
}
1670+
]
1671+
}
1672+
1673+
result = validator.validate(document_ref_data)
1674+
1675+
assert result.is_valid is False
1676+
assert len(result.issues) == 1
1677+
assert result.issues[0].model_dump(exclude_none=True) == {
1678+
"severity": "error",
1679+
"code": "value",
1680+
"details": {
1681+
"coding": [
1682+
{
1683+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
1684+
"code": "INVALID_RESOURCE",
1685+
"display": "Invalid validation of resource",
1686+
}
1687+
]
1688+
},
1689+
"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",
1690+
"expression": ["context.practiceSetting.coding[0]"],
1691+
}
1692+
1693+
1694+
def test_validate_practiceSetting_coding_mismatch_code_and_display():
1695+
validator = DocumentReferenceValidator()
1696+
document_ref_data = load_document_reference_json("Y05868-736253002-Valid")
1697+
1698+
document_ref_data["context"]["practiceSetting"] = {
1699+
"coding": [
1700+
{
1701+
"system": "http://snomed.info/sct",
1702+
"code": "788002001",
1703+
"display": "Nephrology service",
1704+
}
1705+
]
1706+
}
1707+
1708+
result = validator.validate(document_ref_data)
1709+
1710+
assert result.is_valid is False
1711+
assert len(result.issues) == 1
1712+
assert result.issues[0].model_dump(exclude_none=True) == {
1713+
"severity": "error",
1714+
"code": "value",
1715+
"details": {
1716+
"coding": [
1717+
{
1718+
"system": "https://fhir.nhs.uk/ValueSet/Spine-ErrorOrWarningCode-1",
1719+
"code": "INVALID_RESOURCE",
1720+
"display": "Invalid validation of resource",
1721+
}
1722+
]
1723+
},
1724+
"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",
1725+
"expression": ["context.practiceSetting.coding[0]"],
1726+
}

layer/nrlf/core/validators.py

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
from nrlf.core.constants import (
1010
CATEGORY_ATTRIBUTES,
1111
ODS_SYSTEM,
12+
PRACTICE_SETTING_VALUE_SET_URL,
1213
REQUIRED_CREATE_FIELDS,
14+
SNOMED_PRACTICE_SETTINGS,
15+
SNOMED_SYSTEM_URL,
1316
TYPE_ATTRIBUTES,
1417
TYPE_CATEGORIES,
1518
Categories,
@@ -141,6 +144,7 @@ def validate(self, data: Dict[str, Any] | DocumentReference):
141144
self._validate_category(resource)
142145
self._validate_author(resource)
143146
self._validate_type_category_mapping(resource)
147+
self._validate_practiceSetting(resource)
144148
if resource.content[0].extension:
145149
self._validate_content_extension(resource)
146150

@@ -566,7 +570,7 @@ def _validate_author(self, model: DocumentReference):
566570
issue_code="invalid",
567571
error_code="INVALID_RESOURCE",
568572
diagnostics=f"Invalid author length: {len(model.author)} Author must only contain a single value",
569-
field=f"author",
573+
field="author",
570574
)
571575
return
572576

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

@@ -587,7 +591,7 @@ def _validate_author(self, model: DocumentReference):
587591
issue_code="value",
588592
error_code="INVALID_RESOURCE",
589593
diagnostics=f"Invalid author value: '{identifier.value}' Author value must be alphanumeric",
590-
field=f"author[0].identifier.value",
594+
field="author[0].identifier.value",
591595
)
592596
return
593597

@@ -596,6 +600,70 @@ def _validate_author(self, model: DocumentReference):
596600
issue_code="value",
597601
error_code="INVALID_RESOURCE",
598602
diagnostics=f"Invalid author value: '{identifier.value}' Author value must be less than 13 characters",
599-
field=f"author[0].identifier.value",
603+
field="author[0].identifier.value",
604+
)
605+
return
606+
607+
def _validate_practiceSetting(self, model: DocumentReference):
608+
"""
609+
Validate the practice setting field contains an appropriate coding system and code.
610+
"""
611+
612+
if not (
613+
practice_setting_coding := getattr(
614+
model.context.practiceSetting, "coding", []
615+
)
616+
):
617+
self.result.add_error(
618+
issue_code="value",
619+
error_code="INVALID_RESOURCE",
620+
diagnostics="Invalid practice setting: must contain a Coding",
621+
field="context.practiceSetting.coding",
622+
)
623+
return
624+
625+
if len(practice_setting_coding) != 1:
626+
self.result.add_error(
627+
issue_code="value",
628+
error_code="INVALID_RESOURCE",
629+
diagnostics=f"Invalid practice setting coding length: {len(model.context.practiceSetting.coding)} Practice Setting Coding must only contain a single value",
630+
field="context.practiceSetting.coding",
631+
)
632+
return
633+
634+
if (
635+
practice_setting_system := getattr(
636+
practice_setting_coding[0], "system", None
637+
)
638+
) != SNOMED_SYSTEM_URL:
639+
self.result.add_error(
640+
issue_code="value",
641+
error_code="INVALID_RESOURCE",
642+
diagnostics=f"Invalid practice setting system: {practice_setting_system} Practice Setting system must be '{SNOMED_SYSTEM_URL}'",
643+
field="context.practiceSetting.coding[0].system",
644+
)
645+
return
646+
647+
if (
648+
practice_setting_value := getattr(practice_setting_coding[0], "code", None)
649+
) not in SNOMED_PRACTICE_SETTINGS:
650+
self.result.add_error(
651+
issue_code="value",
652+
error_code="INVALID_RESOURCE",
653+
diagnostics=f"Invalid practice setting code: {practice_setting_value} Practice Setting coding must be a member of value set {PRACTICE_SETTING_VALUE_SET_URL}",
654+
field="context.practiceSetting.coding[0].code",
655+
)
656+
return
657+
658+
if (
659+
practice_setting_display := getattr(
660+
practice_setting_coding[0], "display", None
661+
)
662+
) != SNOMED_PRACTICE_SETTINGS.get(practice_setting_value):
663+
self.result.add_error(
664+
issue_code="value",
665+
error_code="INVALID_RESOURCE",
666+
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}",
667+
field="context.practiceSetting.coding[0]",
600668
)
601669
return

0 commit comments

Comments
 (0)