Skip to content

Commit 20a606c

Browse files
committed
Add logic to uplift legacy identifiers
1 parent 45599b2 commit 20a606c

File tree

2 files changed

+168
-117
lines changed

2 files changed

+168
-117
lines changed

lambdas/recordprocessor/src/process_row.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
from convert_to_fhir_imms_resource import convert_to_fhir_imms_resource
66
from utils_for_recordprocessor import create_diagnostics_dictionary
77

8+
TPP_V2_SUPPLIER_IDENTIFIER_SYSTEM = "YGA"
9+
TPP_V5_SUPPLIER_IDENTIFIER_SYSTEM = "https://tpp-uk.com/Id/ve/vacc"
10+
EMIS_V2_SUPPLIER_IDENTIFIER_SYSTEM = "YGJ"
11+
EMIS_V5_SUPPLIER_IDENTIFIER_SYSTEM = "https://emishealth.com/identifiers/vacc"
12+
813

914
def process_row(target_disease: list, allowed_operations: set, row: dict) -> dict:
1015
"""
@@ -14,6 +19,18 @@ def process_row(target_disease: list, allowed_operations: set, row: dict) -> dic
1419
"""
1520
action_flag = (row.get("ACTION_FLAG") or "").upper()
1621
unique_id_uri = row.get("UNIQUE_ID_URI")
22+
23+
# This code the above constants can be safely removed once DPS carries out it's data migration to update legacy
24+
# identifiers as it should become redundant. However, it may be worth keeping in case legacy format identifiers are
25+
# received for some reason. Please see issue VED-904 for more information.
26+
if unique_id_uri == TPP_V2_SUPPLIER_IDENTIFIER_SYSTEM:
27+
unique_id_uri = TPP_V5_SUPPLIER_IDENTIFIER_SYSTEM
28+
row["UNIQUE_ID_URI"] = TPP_V5_SUPPLIER_IDENTIFIER_SYSTEM
29+
30+
if unique_id_uri == EMIS_V2_SUPPLIER_IDENTIFIER_SYSTEM:
31+
unique_id_uri = EMIS_V5_SUPPLIER_IDENTIFIER_SYSTEM
32+
row["UNIQUE_ID_URI"] = EMIS_V5_SUPPLIER_IDENTIFIER_SYSTEM
33+
1734
unique_id = row.get("UNIQUE_ID")
1835
local_id = f"{unique_id}^{unique_id_uri}"
1936

lambdas/recordprocessor/tests/test_process_row.py

Lines changed: 151 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -27,147 +27,145 @@
2727
s3_client = boto3_client("s3", region_name=REGION_NAME)
2828
ROW_DETAILS = MockFieldDictionaries.all_fields
2929
Allowed_Operations = {"CREATE", "UPDATE", "DELETE"}
30-
31-
32-
@mock_s3
33-
@patch.dict("os.environ", MOCK_ENVIRONMENT_DICT)
34-
class TestProcessRow(unittest.TestCase):
35-
"""Tests for process_row"""
36-
37-
def setUp(self) -> None:
38-
GenericSetUp(s3_client)
39-
40-
def tearDown(self) -> None:
41-
GenericTearDown(s3_client)
42-
43-
def test_process_row_success(self):
44-
"""
45-
Test that process_row gives the expected output.
46-
These tests check that the row is valid and matches the expected output.
47-
"""
48-
# set the expected output from 'process_row' in case of success
49-
expected_result = {
50-
"resourceType": "Immunization",
51-
"status": "completed",
52-
"protocolApplied": [
30+
expected_successful_result = {
31+
"resourceType": "Immunization",
32+
"status": "completed",
33+
"protocolApplied": [
34+
{
35+
"targetDisease": [
5336
{
54-
"targetDisease": [
37+
"coding": [
5538
{
56-
"coding": [
57-
{
58-
"system": "http://snomed.info/sct",
59-
"code": "55735004",
60-
"display": "Respiratory syncytial virus infection (disorder)",
61-
}
62-
]
39+
"system": "http://snomed.info/sct",
40+
"code": "55735004",
41+
"display": "Respiratory syncytial virus infection (disorder)",
6342
}
64-
],
65-
"doseNumberPositiveInt": 1,
43+
]
6644
}
6745
],
68-
"reasonCode": [{"coding": [{"system": "http://snomed.info/sct", "code": "1037351000000105"}]}],
69-
"recorded": "2024-09-04",
70-
"identifier": [{"value": "RSV_002", "system": "https://www.ravs.england.nhs.uk/"}],
71-
"patient": {"reference": "#Patient1"},
72-
"contained": [
73-
{
74-
"id": "Patient1",
75-
"resourceType": "Patient",
76-
"birthDate": "2008-02-17",
77-
"gender": "male",
78-
"address": [{"postalCode": "WD25 0DZ"}],
79-
"identifier": [
80-
{
81-
"system": "https://fhir.nhs.uk/Id/nhs-number",
82-
"value": "9732928395",
83-
}
84-
],
85-
"name": [{"family": "PEEL", "given": ["PHYLIS"]}],
86-
},
87-
{
88-
"resourceType": "Practitioner",
89-
"id": "Practitioner1",
90-
"name": [{"family": "O'Reilly", "given": ["Ellena"]}],
91-
},
92-
],
93-
"vaccineCode": {
94-
"coding": [
95-
{
96-
"system": "http://snomed.info/sct",
97-
"code": "42223111000001107",
98-
"display": "Quadrivalent influenza vaccine (split virion, inactivated)",
99-
}
100-
]
101-
},
102-
"manufacturer": {"display": "Sanofi Pasteur"},
103-
"expirationDate": "2024-09-15",
104-
"lotNumber": "BN92478105653",
105-
"extension": [
46+
"doseNumberPositiveInt": 1,
47+
}
48+
],
49+
"reasonCode": [{"coding": [{"system": "http://snomed.info/sct", "code": "1037351000000105"}]}],
50+
"recorded": "2024-09-04",
51+
"identifier": [{"value": "RSV_002", "system": "https://www.ravs.england.nhs.uk/"}],
52+
"patient": {"reference": "#Patient1"},
53+
"contained": [
54+
{
55+
"id": "Patient1",
56+
"resourceType": "Patient",
57+
"birthDate": "2008-02-17",
58+
"gender": "male",
59+
"address": [{"postalCode": "WD25 0DZ"}],
60+
"identifier": [
10661
{
107-
"url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-VaccinationProcedure",
108-
"valueCodeableConcept": {
109-
"coding": [
110-
{
111-
"system": "http://snomed.info/sct",
112-
"code": "956951000000104",
113-
"display": "RSV vaccination in pregnancy (procedure)",
114-
}
115-
]
116-
},
62+
"system": "https://fhir.nhs.uk/Id/nhs-number",
63+
"value": "9732928395",
11764
}
11865
],
119-
"occurrenceDateTime": "2024-09-04T18:33:25+00:00",
120-
"primarySource": True,
121-
"site": {
122-
"coding": [
123-
{
124-
"system": "http://snomed.info/sct",
125-
"code": "368209003",
126-
"display": "Right arm",
127-
}
128-
]
129-
},
130-
"route": {
66+
"name": [{"family": "PEEL", "given": ["PHYLIS"]}],
67+
},
68+
{
69+
"resourceType": "Practitioner",
70+
"id": "Practitioner1",
71+
"name": [{"family": "O'Reilly", "given": ["Ellena"]}],
72+
},
73+
],
74+
"vaccineCode": {
75+
"coding": [
76+
{
77+
"system": "http://snomed.info/sct",
78+
"code": "42223111000001107",
79+
"display": "Quadrivalent influenza vaccine (split virion, inactivated)",
80+
}
81+
]
82+
},
83+
"manufacturer": {"display": "Sanofi Pasteur"},
84+
"expirationDate": "2024-09-15",
85+
"lotNumber": "BN92478105653",
86+
"extension": [
87+
{
88+
"url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-VaccinationProcedure",
89+
"valueCodeableConcept": {
13190
"coding": [
13291
{
13392
"system": "http://snomed.info/sct",
134-
"code": "1210999013",
135-
"display": "Intradermal use",
93+
"code": "956951000000104",
94+
"display": "RSV vaccination in pregnancy (procedure)",
13695
}
13796
]
13897
},
139-
"doseQuantity": {
140-
"value": Decimal("0.3"),
141-
"unit": "Inhalation - unit of product usage",
98+
}
99+
],
100+
"occurrenceDateTime": "2024-09-04T18:33:25+00:00",
101+
"primarySource": True,
102+
"site": {
103+
"coding": [
104+
{
142105
"system": "http://snomed.info/sct",
143-
"code": "2622896019",
144-
},
145-
"performer": [
146-
{
147-
"actor": {
148-
"type": "Organization",
149-
"identifier": {
150-
"system": "https://fhir.nhs.uk/Id/ods-organization-code",
151-
"value": "RVVKC",
152-
},
153-
}
154-
},
155-
{"actor": {"reference": "#Practitioner1"}},
156-
],
157-
"location": {
106+
"code": "368209003",
107+
"display": "Right arm",
108+
}
109+
]
110+
},
111+
"route": {
112+
"coding": [
113+
{
114+
"system": "http://snomed.info/sct",
115+
"code": "1210999013",
116+
"display": "Intradermal use",
117+
}
118+
]
119+
},
120+
"doseQuantity": {
121+
"value": Decimal("0.3"),
122+
"unit": "Inhalation - unit of product usage",
123+
"system": "http://snomed.info/sct",
124+
"code": "2622896019",
125+
},
126+
"performer": [
127+
{
128+
"actor": {
129+
"type": "Organization",
158130
"identifier": {
159-
"value": "RJC02",
160131
"system": "https://fhir.nhs.uk/Id/ods-organization-code",
161-
}
162-
},
132+
"value": "RVVKC",
133+
},
134+
}
135+
},
136+
{"actor": {"reference": "#Practitioner1"}},
137+
],
138+
"location": {
139+
"identifier": {
140+
"value": "RJC02",
141+
"system": "https://fhir.nhs.uk/Id/ods-organization-code",
163142
}
143+
},
144+
}
145+
146+
147+
@mock_s3
148+
@patch.dict("os.environ", MOCK_ENVIRONMENT_DICT)
149+
class TestProcessRow(unittest.TestCase):
150+
"""Tests for process_row"""
164151

152+
def setUp(self) -> None:
153+
GenericSetUp(s3_client)
154+
155+
def tearDown(self) -> None:
156+
GenericTearDown(s3_client)
157+
158+
def test_process_row_success(self):
159+
"""
160+
Test that process_row gives the expected output.
161+
These tests check that the row is valid and matches the expected output.
162+
"""
165163
self.maxDiff = None
166164

167165
# call 'process_row' with required details
168166
imms_fhir_resource = process_row(TargetDiseaseElements.RSV, Allowed_Operations, ROW_DETAILS)
169167
# validate if the response with expected result
170-
self.assertDictEqual(imms_fhir_resource["fhir_json"], expected_result)
168+
self.assertDictEqual(imms_fhir_resource["fhir_json"], expected_successful_result)
171169

172170
def test_process_row_invalid_action_flag(self):
173171
"""
@@ -245,6 +243,42 @@ def test_process_row_missing_unique_id_uri(self):
245243
)
246244
self.assertEqual(response["diagnostics"]["statusCode"], 400)
247245

246+
def test_process_row_successfully_uplifts_legacy_TPP_uri(self):
247+
"""
248+
Test that process_row gives the expected output.
249+
These tests check that the row is valid and matches the expected output.
250+
"""
251+
legacy_TPP_row = deepcopy(ROW_DETAILS)
252+
legacy_TPP_row["UNIQUE_ID_URI"] = "YGA"
253+
254+
expected_successful_result_TPP = deepcopy(expected_successful_result)
255+
expected_successful_result_TPP["identifier"][0]["system"] = "https://tpp-uk.com/Id/ve/vacc"
256+
257+
self.maxDiff = None
258+
259+
# call 'process_row' with required details
260+
imms_fhir_resource = process_row(TargetDiseaseElements.RSV, Allowed_Operations, legacy_TPP_row)
261+
# validate if the response with expected result
262+
self.assertDictEqual(imms_fhir_resource["fhir_json"], expected_successful_result_TPP)
263+
264+
def test_process_row_successfully_uplifts_legacy_EMIS_uri(self):
265+
"""
266+
Test that process_row gives the expected output.
267+
These tests check that the row is valid and matches the expected output.
268+
"""
269+
legacy_EMIS_row = deepcopy(ROW_DETAILS)
270+
legacy_EMIS_row["UNIQUE_ID_URI"] = "YGJ"
271+
272+
expected_successful_result_EMIS = deepcopy(expected_successful_result)
273+
expected_successful_result_EMIS["identifier"][0]["system"] = "https://emishealth.com/identifiers/vacc"
274+
275+
self.maxDiff = None
276+
277+
# call 'process_row' with required details
278+
imms_fhir_resource = process_row(TargetDiseaseElements.RSV, Allowed_Operations, legacy_EMIS_row)
279+
# validate if the response with expected result
280+
self.assertDictEqual(imms_fhir_resource["fhir_json"], expected_successful_result_EMIS)
281+
248282

249283
if __name__ == "__main__":
250284
unittest.main()

0 commit comments

Comments
 (0)