Skip to content

Commit acf80f7

Browse files
authored
VED-897 Follow-up: improve traceability in id sync without PID (#974)
1 parent 5926e92 commit acf80f7

File tree

3 files changed

+49
-14
lines changed

3 files changed

+49
-14
lines changed

lambdas/id_sync/src/ieds_db_operations.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
ieds_table = None
1212
BATCH_SIZE = 25 # DynamoDB TransactWriteItems max batch size
13+
PATIENT_KEY = "PatientPK"
14+
IDENTIFIER_KEY = "IdentifierPK"
1315

1416

1517
def get_ieds_table():
@@ -82,7 +84,7 @@ def paginate_items_for_patient_pk(patient_pk: str) -> list:
8284
while True:
8385
query_args = {
8486
"IndexName": "PatientGSI",
85-
"KeyConditionExpression": Key("PatientPK").eq(patient_pk),
87+
"KeyConditionExpression": Key(PATIENT_KEY).eq(patient_pk),
8688
}
8789
if last_evaluated_key:
8890
query_args["ExclusiveStartKey"] = last_evaluated_key
@@ -146,7 +148,7 @@ def build_transact_items(old_id: str, new_id: str, items_to_update: list) -> lis
146148
new_patient_pk = f"Patient#{new_id}"
147149

148150
for item in items_to_update:
149-
old_patient_pk = item.get("PatientPK", f"Patient#{old_id}")
151+
old_patient_pk = item.get(PATIENT_KEY, f"Patient#{old_id}")
150152

151153
transact_items.append(
152154
{
@@ -155,8 +157,8 @@ def build_transact_items(old_id: str, new_id: str, items_to_update: list) -> lis
155157
"Key": {
156158
"PK": {"S": item["PK"]},
157159
},
158-
"UpdateExpression": "SET PatientPK = :new_val",
159-
"ConditionExpression": "PatientPK = :expected_old",
160+
"UpdateExpression": f"SET {PATIENT_KEY} = :new_val",
161+
"ConditionExpression": f"{PATIENT_KEY} = :expected_old",
160162
"ExpressionAttributeValues": {
161163
":new_val": {"S": new_patient_pk},
162164
":expected_old": {"S": old_patient_pk},

lambdas/id_sync/src/record_processor.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from common.clients import logger
55
from exceptions.id_sync_exception import IdSyncException
66
from ieds_db_operations import (
7+
IDENTIFIER_KEY,
78
extract_patient_resource_from_item,
89
get_items_from_patient_id,
910
ieds_update_patient_id,
@@ -55,22 +56,26 @@ def process_nhs_number(nhs_number: str) -> Dict[str, Any]:
5556
logger.exception("process_nhs_number: failed to fetch ieds resources: %s", e)
5657
return make_status(str(e), status="error")
5758

58-
logger.info(
59-
"Fetched IEDS resources. IEDS count: %d",
60-
len(ieds_resources) if ieds_resources else 0,
61-
)
62-
6359
if not ieds_resources:
6460
logger.info("No IEDS records returned for NHS number")
6561
return make_status("No records returned for NHS Number")
6662

63+
logger.info("Fetched IEDS resources. IEDS count: %d", len(ieds_resources))
64+
6765
# Compare demographics from PDS to each IEDS item, keep only matching records
6866
matching_records = []
6967
discarded_count = 0
68+
7069
for detail in ieds_resources:
70+
immunisation_identifier = detail.get(IDENTIFIER_KEY)
71+
7172
if demographics_match(pds_patient_resource, detail):
73+
logger.info("Update required for imms identifier: %s. Demographic data matched", immunisation_identifier)
7274
matching_records.append(detail)
7375
else:
76+
logger.info(
77+
"No update required for imms identifier: %s. Demographic data did not match", immunisation_identifier
78+
)
7479
discarded_count += 1
7580

7681
if not matching_records:

lambdas/id_sync/tests/test_record_processor.py

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
22
import unittest
3-
from unittest.mock import patch
3+
from unittest.mock import call, patch
44

55
from exceptions.id_sync_exception import IdSyncException
66
from record_processor import process_record
@@ -12,6 +12,7 @@ class TestRecordProcessor(unittest.TestCase):
1212
"gender": "male",
1313
"birthDate": "1980-01-01",
1414
}
15+
MOCK_IMMUNISATION_IDENTIFIER_PK = {"IdentifierPK": "someSystem#12345"}
1516

1617
def setUp(self):
1718
"""Set up test fixtures and mocks"""
@@ -64,7 +65,10 @@ def test_process_record_success_update_required(self):
6465
pds_id = "9000000008"
6566
nhs_number = "9000000009"
6667

67-
test_sqs_record = {"body": json.dumps({"subject": nhs_number})}
68+
test_sqs_record = {
69+
"body": json.dumps({"subject": nhs_number, "id": "test-mns-event-id"}),
70+
"messageId": "test-sqs-message-id",
71+
}
6872

6973
# pds_get_patient_details should return details used by demographics_match
7074
self.mock_pds_get_patient_details.return_value = {
@@ -79,6 +83,7 @@ def test_process_record_success_update_required(self):
7983

8084
# Provide one IEDS item that will match demographics via demographics_match
8185
matching_item = {
86+
**self.MOCK_IMMUNISATION_IDENTIFIER_PK,
8287
"Resource": {
8388
"resourceType": "Immunization",
8489
"contained": [
@@ -90,7 +95,7 @@ def test_process_record_success_update_required(self):
9095
"birthDate": "1980-01-01",
9196
}
9297
],
93-
}
98+
},
9499
}
95100
self.mock_get_items_from_patient_id.return_value = [matching_item]
96101

@@ -103,13 +108,25 @@ def test_process_record_success_update_required(self):
103108
# Assert
104109
self.assertEqual(result, success_response)
105110
self.mock_pds_get_patient_details.assert_called_once_with(nhs_number)
111+
self.mock_logger.info.assert_has_calls(
112+
[
113+
call("Processing record with SQS messageId: %s", "test-sqs-message-id"),
114+
call("Processing MNS event with id: %s", "test-mns-event-id"),
115+
call("NHS Number has changed. Performing updates on relevant IEDS records"),
116+
call("Fetched IEDS resources. IEDS count: %d", 1),
117+
call("Update required for imms identifier: %s. Demographic data matched", "someSystem#12345"),
118+
]
119+
)
106120

107121
def test_process_record_demographics_mismatch_skips_update(self):
108122
"""If no IEDS item matches demographics, the update should be skipped"""
109123
# Arrange
110124
pds_id = "pds-1"
111125
nhs_number = "nhs-1"
112-
test_sqs_record = {"body": json.dumps({"subject": nhs_number})}
126+
test_sqs_record = {
127+
"body": json.dumps({"subject": nhs_number, "id": "test-mns-event-id"}),
128+
"messageId": "test-sqs-message-id",
129+
}
113130

114131
self.mock_pds_get_patient_details.return_value = {
115132
"name": [{"given": ["Alice"], "family": "Smith"}],
@@ -125,6 +142,7 @@ def test_process_record_demographics_mismatch_skips_update(self):
125142

126143
# IEDS items exist but do not match demographics
127144
non_matching_item = {
145+
**self.MOCK_IMMUNISATION_IDENTIFIER_PK,
128146
"Resource": {
129147
"resourceType": "Immunization",
130148
"contained": [
@@ -136,7 +154,7 @@ def test_process_record_demographics_mismatch_skips_update(self):
136154
"birthDate": "1990-01-01",
137155
}
138156
],
139-
}
157+
},
140158
}
141159
self.mock_get_items_from_patient_id.return_value = [non_matching_item]
142160

@@ -146,6 +164,16 @@ def test_process_record_demographics_mismatch_skips_update(self):
146164
# Assert
147165
self.assertEqual(result["status"], "success")
148166
self.assertEqual(result["message"], "No records matched PDS demographics; update skipped")
167+
self.mock_logger.info.assert_has_calls(
168+
[
169+
call("Processing record with SQS messageId: %s", "test-sqs-message-id"),
170+
call("Processing MNS event with id: %s", "test-mns-event-id"),
171+
call("NHS Number has changed. Performing updates on relevant IEDS records"),
172+
call("Fetched IEDS resources. IEDS count: %d", 1),
173+
call("No update required for imms identifier: %s. Demographic data did not match", "someSystem#12345"),
174+
call("No records matched PDS demographics: %d", 1),
175+
]
176+
)
149177

150178
def test_invalid_body_parsing_returns_error(self):
151179
"""When body is a malformed string, process_record should return an error"""

0 commit comments

Comments
 (0)