Skip to content

Commit da80901

Browse files
committed
Add pre-validation for NHS number system in immunization services
- Implemented a new pre-validation method to ensure that patient identifiers use the NHS number system. - Added unit tests to verify that both creation and update of immunization records reject invalid patient identifier systems. - Updated existing tests to reflect changes in validation logic for patient identifiers.
1 parent 5c34807 commit da80901

3 files changed

Lines changed: 73 additions & 5 deletions

File tree

lambdas/recordforwarder/tests/service/test_fhir_batch_service.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,29 @@ def test_create_immunization_post_validation_error(self):
9797
self.assertTrue(expected_msg in error.exception.message)
9898
self.mock_repo.create_immunization.assert_not_called()
9999

100+
def test_create_immunization_invalid_patient_identifier_system(self):
101+
"""it should reject create when the patient identifier system is not the NHS number URI"""
102+
103+
imms = create_covid_immunization_dict_no_id()
104+
patient = next(resource for resource in imms["contained"] if resource["resourceType"] == "Patient")
105+
patient["identifier"][0]["system"] = "https://1234/Id/nhs-number"
106+
patient["identifier"][0]["value"] = "ABCD"
107+
108+
with self.assertRaises(CustomValidationError) as error:
109+
self.pre_validate_fhir_service.create_immunization(
110+
immunization=imms,
111+
supplier_system="test_supplier",
112+
vax_type="test_vax",
113+
table=self.mock_table,
114+
imms_pk=None,
115+
)
116+
117+
self.assertIn(
118+
"contained[?(@.resourceType=='Patient')].identifier[0].system must equal",
119+
error.exception.message,
120+
)
121+
self.mock_repo.create_immunization.assert_not_called()
122+
100123

101124
class TestUpdateImmunizationBatchService(TestFhirBatchServiceBase):
102125
def setUp(self):
@@ -169,6 +192,29 @@ def test_update_immunization_post_validation_error(self):
169192
self.assertTrue(expected_msg in error.exception.message)
170193
self.mock_repo.update_immunization.assert_not_called()
171194

195+
def test_update_immunization_invalid_patient_identifier_system(self):
196+
"""it should reject update when the patient identifier system is not the NHS number URI"""
197+
198+
imms = create_covid_immunization_dict_no_id()
199+
patient = next(resource for resource in imms["contained"] if resource["resourceType"] == "Patient")
200+
patient["identifier"][0]["system"] = "https://1234/Id/nhs-number"
201+
patient["identifier"][0]["value"] = "ABCD"
202+
203+
with self.assertRaises(CustomValidationError) as error:
204+
self.pre_validate_fhir_service.update_immunization(
205+
immunization=imms,
206+
supplier_system="test_supplier",
207+
vax_type="test_vax",
208+
table=self.mock_table,
209+
imms_pk=None,
210+
)
211+
212+
self.assertIn(
213+
"contained[?(@.resourceType=='Patient')].identifier[0].system must equal",
214+
error.exception.message,
215+
)
216+
self.mock_repo.update_immunization.assert_not_called()
217+
172218

173219
class TestDeleteImmunizationBatchService(unittest.TestCase):
174220
def setUp(self):

lambdas/shared/src/common/models/fhir_immunization_pre_validators.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def validate(self):
4646
self.pre_validate_patient_identifier_extension,
4747
self.pre_validate_patient_identifier,
4848
self.pre_validate_patient_identifier_system,
49+
self.pre_validate_patient_identifier_nhs_system,
4950
self.pre_validate_patient_identifier_value,
5051
self.pre_validate_patient_name,
5152
self.pre_validate_patient_name_given,
@@ -286,6 +287,21 @@ def pre_validate_patient_identifier_system(self, values: dict) -> None:
286287
except (KeyError, IndexError):
287288
pass
288289

290+
def pre_validate_patient_identifier_nhs_system(self, values: dict) -> None:
291+
"""
292+
Pre-validate that, if the contained Patient has an identifier system,
293+
it uses the NHS number system.
294+
"""
295+
field_location = "contained[?(@.resourceType=='Patient')].identifier[0].system"
296+
try:
297+
field_value = [x for x in values["contained"] if x.get("resourceType") == "Patient"][0]["identifier"][0][
298+
"system"
299+
]
300+
if field_value != Urls.NHS_NUMBER:
301+
raise ValueError(f"{field_location} must equal '{Urls.NHS_NUMBER}'")
302+
except (KeyError, IndexError):
303+
pass
304+
289305
def pre_validate_patient_identifier_value(self, values: dict) -> None:
290306
"""
291307
Pre-validate that, if the contained Patient has an NHS-number identifier,

lambdas/shared/tests/test_common/test_immunization_pre_validator.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -470,17 +470,23 @@ def test_pre_validate_patient_identifier_value(self):
470470
],
471471
)
472472

473-
def test_pre_validate_patient_identifier_value_accepts_non_nhs_identifier(self):
474-
"""Test pre_validate_patient_identifier_value ignores non-NHS patient identifiers"""
475-
valid_json_data = deepcopy(self.json_data)
476-
valid_json_data["contained"][1]["identifier"] = [
473+
def test_pre_validate_patient_identifier_rejects_non_nhs_identifier_system(self):
474+
"""Test pre_validate_patient_identifier rejects non-NHS patient identifier systems"""
475+
invalid_json_data = deepcopy(self.json_data)
476+
invalid_json_data["contained"][1]["identifier"] = [
477477
{
478478
"system": "https://someother.codeableconcept.com/",
479479
"value": "TVC15",
480480
}
481481
]
482482

483-
self.assertIsNone(self.validator.validate(valid_json_data))
483+
with self.assertRaises(ValueError) as error:
484+
self.validator.validate(invalid_json_data)
485+
486+
self.assertIn(
487+
"contained[?(@.resourceType=='Patient')].identifier[0].system must equal '",
488+
str(error.exception),
489+
)
484490

485491
def test_pre_validate_patient_identifier_system(self):
486492
"""Test pre_validate_patient_identifier_system accepts valid values and rejects invalid values"""

0 commit comments

Comments
 (0)