Skip to content

Commit 1bfb0a8

Browse files
authored
VED-235 Deliver imms as list (not string) (#407)
* Dose Amount, ACTION FLAG, Remove Array * check conversion
1 parent f1ef2ef commit 1bfb0a8

File tree

8 files changed

+203
-190
lines changed

8 files changed

+203
-190
lines changed

delta_backend/poetry.lock

Lines changed: 167 additions & 139 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

delta_backend/src/ConversionChecker.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
# Root and base type expression checker functions
44
import ExceptionMessages
55
from datetime import datetime,timedelta, timezone
6-
from zoneinfo import ZoneInfo
76
import re
87
from LookUpData import LookUpData
98

@@ -259,7 +258,7 @@ def _convertToDefaultTo(self, expressionRule, fieldName, fieldValue, summarise,
259258
try:
260259
if fieldValue == "":
261260
return expressionRule
262-
return fieldValue
261+
return str(fieldValue)
263262
except Exception as e:
264263
if report_unexpected_exception:
265264
message = ExceptionMessages.MESSAGES[ExceptionMessages.UNEXPECTED_EXCEPTION] % (e.__class__.__name__, e)

delta_backend/src/Converter.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
class Converter:
2020

2121
def __init__(self, fhir_data):
22-
self.imms = []
2322
self.converted = {}
2423
self.error_records = []
2524
self.fhir_data = fhir_data # Store JSON data directly
@@ -123,11 +122,10 @@ def runConversion(self, json_data, summarise=False, report_unexpected_exception=
123122
if error_records:
124123
error_summary = error_records
125124
else:
126-
error_summary = ""
125+
error_summary = []
127126
self.converted["CONVERSION_ERRORS"] = error_summary
128127

129-
self.imms.append(self.converted)
130-
return self.imms
128+
return self.converted
131129

132130
def getErrorRecords(self):
133131
return self.error_records

delta_backend/src/delta.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,12 @@ def handler(event, context):
6868
supplier_system = new_image["SupplierSystem"]["S"]
6969
if supplier_system not in ("DPSFULL", "DPSREDUCED"):
7070
operation = new_image["Operation"]["S"]
71-
if operation == "CREATE":
72-
operation = "NEW"
71+
action_flag = "NEW" if operation == "CREATE" else operation
7372
resource_json = json.loads(new_image["Resource"]["S"])
7473
FHIRConverter = Converter(json.dumps(resource_json))
7574
flat_json = FHIRConverter.runConversion(resource_json) # Get the flat JSON
7675
error_records = FHIRConverter.getErrorRecords()
77-
flat_json[0]["ACTION_FLAG"] = operation
76+
flat_json["ACTION_FLAG"] = action_flag
7877
response = delta_table.put_item(
7978
Item={
8079
"PK": str(uuid.uuid4()),
@@ -84,7 +83,7 @@ def handler(event, context):
8483
"SupplierSystem": supplier_system,
8584
"DateTimeStamp": approximate_creation_time.isoformat(),
8685
"Source": delta_source,
87-
"Imms": str(flat_json),
86+
"Imms": flat_json,
8887
"ExpiresAt": expiry_time_epoch,
8988
}
9089
)

delta_backend/tests/check_conversion.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@
3434

3535
# Convert JSON list of dicts to CSV
3636
if result:
37-
keys = result[0].keys()
37+
keys = result.keys()
3838
with open(csv_path, "w", newline="") as f:
3939
writer = csv.DictWriter(f, fieldnames=keys)
4040
writer.writeheader()
41-
writer.writerows(result)
41+
writer.writerow(result)
4242

4343
print("CSV saved to:", csv_path)
4444
print("JSON saved to:", json_path)

delta_backend/tests/test_convert_to_flat_json.py

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
import json
22
import unittest
3-
import os
4-
import time
5-
from datetime import datetime, timedelta
6-
from decimal import Decimal
73
from copy import deepcopy
8-
from unittest import TestCase
94
from unittest.mock import patch, Mock
105
from moto import mock_dynamodb, mock_sqs
11-
from boto3 import resource as boto3_resource, client as boto3_client
6+
from boto3 import resource as boto3_resource
127
from tests.utils_for_converter_tests import ValuesForTests, ErrorValuesForTests
13-
from botocore.config import Config
14-
from pathlib import Path
15-
from zoneinfo import ZoneInfo
168
from SchemaParser import SchemaParser
179
from Converter import Converter
1810
from ConversionChecker import ConversionChecker, RecordError
@@ -112,7 +104,7 @@ def get_event(event_name="INSERT", operation="operation", supplier="EMIS"):
112104
"""Returns test event data."""
113105
return ValuesForTests.get_event(event_name, operation, supplier)
114106

115-
def assert_dynamodb_record(self, operation_flag, items, expected_values, expected_imms, response):
107+
def assert_dynamodb_record(self, operation_flag, action_flag, items, expected_values, expected_imms, response):
116108
"""
117109
Asserts that a record with the expected structure exists in DynamoDB.
118110
Ignores dynamically generated fields like PK, DateTimeStamp, and ExpiresAt.
@@ -125,16 +117,17 @@ def assert_dynamodb_record(self, operation_flag, items, expected_values, expecte
125117
{k: v for k, v in item.items() if k not in ["PK", "DateTimeStamp", "ExpiresAt"]}
126118
for item in items
127119
if item.get("Operation") == operation_flag
120+
and item.get("Imms", {}).get("ACTION_FLAG") == action_flag
128121
]
129122

130123
self.assertGreater(len(filtered_items), 0, f"No matching item found for {operation_flag}")
131124

132125
imms_data = filtered_items[0]["Imms"]
133-
self.assertIsInstance(imms_data, str)
126+
self.assertIsInstance(imms_data, dict)
134127
self.assertGreater(len(imms_data), 0)
135128

136129
# Check Imms JSON structure matches exactly
137-
self.assertEqual(imms_data, str(expected_imms), "Imms data does not match expected JSON structure")
130+
self.assertEqual(imms_data, expected_imms, "Imms data does not match expected JSON structure")
138131

139132
for key, expected_value in expected_values.items():
140133
self.assertIn(key, filtered_items[0], f"{key} is missing")
@@ -169,7 +162,6 @@ def test_fhir_converter_json_error_scenario(self):
169162
errorRecords = FHIRConverter.getErrorRecords()
170163

171164
# Check if bad data creates error records
172-
print(f"Error Test Case, {len(errorRecords)}")
173165
self.assertTrue(len(errorRecords) > 0)
174166

175167
def test_handler_imms_convert_to_flat_json(self):
@@ -195,7 +187,12 @@ def test_handler_imms_convert_to_flat_json(self):
195187
expected_imms = ValuesForTests.get_expected_imms(test_case["EXPECTED_ACTION_FLAG"])
196188

197189
self.assert_dynamodb_record(
198-
test_case["EXPECTED_ACTION_FLAG"], items, expected_values, expected_imms, response
190+
test_case["Operation"],
191+
test_case["EXPECTED_ACTION_FLAG"],
192+
items,
193+
expected_values,
194+
expected_imms,
195+
response
199196
)
200197

201198
result = self.table.scan()
@@ -435,7 +432,6 @@ def test_convert_to_date(self, MockLookUpData):
435432

436433
# 7 Validate all error logs of various responses
437434
messages = [err["message"] for err in checker.errorRecords]
438-
print(f"Error Test Case, {messages}")
439435

440436
self.assertIn("Value is not a string", messages)
441437

@@ -486,7 +482,6 @@ def test_convert_to_date_time(self, MockLookUpData):
486482
self.assertEqual(result, "")
487483

488484
messages = [err["message"] for err in checker.errorRecords]
489-
print(f"Error Test Case, {messages}")
490485

491486
self.assertIn("Unexpected exception [ValueError]", messages[0])
492487
self.assertIn("Unsupported Format or offset", messages[1])
@@ -676,7 +671,7 @@ def _run_test(self, expected_forename):
676671
"""Helper function to run the test"""
677672
self.converter = Converter(json.dumps(request_json_data))
678673
flat_json = self.converter.runConversion(request_json_data, False, True)
679-
self.assertEqual(flat_json[0]["PERSON_FORENAME"], expected_forename)
674+
self.assertEqual(flat_json["PERSON_FORENAME"], expected_forename)
680675

681676
class TestPersonSurNameToFlatJson(unittest.TestCase):
682677

@@ -764,7 +759,7 @@ def _run_test_surname(self, expected_forename):
764759
"""Helper function to run the test"""
765760
self.converter = Converter(json.dumps(request_json_data))
766761
flat_json = self.converter.runConversion(request_json_data, False, True)
767-
self.assertEqual(flat_json[0]["PERSON_SURNAME"], expected_forename)
762+
self.assertEqual(flat_json["PERSON_SURNAME"], expected_forename)
768763

769764

770765
class TestPersonPostalCodeToFlatJson(unittest.TestCase):
@@ -853,7 +848,7 @@ def _run_postal_code_test(self, expected_postal_code):
853848
"""Helper function to run the test"""
854849
self.converter = Converter(json.dumps(request_json_data))
855850
flat_json = self.converter.runConversion(request_json_data, False, True)
856-
self.assertEqual(flat_json[0]["PERSON_POSTCODE"], expected_postal_code)
851+
self.assertEqual(flat_json["PERSON_POSTCODE"], expected_postal_code)
857852

858853

859854
class TestPersonSiteCodeToFlatJson(unittest.TestCase):
@@ -972,7 +967,7 @@ def _run_site_code_test(self, expected_site_code):
972967
"""Helper function to run the test"""
973968
self.converter = Converter(json.dumps(request_json_data))
974969
flat_json = self.converter.runConversion(request_json_data, False, True)
975-
self.assertEqual(flat_json[0].get("SITE_CODE"), expected_site_code)
970+
self.assertEqual(flat_json.get("SITE_CODE"), expected_site_code)
976971

977972

978973
class TestPersonSiteUriToFlatJson(unittest.TestCase):
@@ -1063,7 +1058,7 @@ def _run_site_uri_test(self, expected_site_code):
10631058
"""Helper function to run the test"""
10641059
self.converter = Converter(json.dumps(request_json_data))
10651060
flat_json = self.converter.runConversion(request_json_data, False, True)
1066-
self.assertEqual(flat_json[0].get("SITE_CODE_TYPE_URI"), expected_site_code)
1061+
self.assertEqual(flat_json.get("SITE_CODE_TYPE_URI"), expected_site_code)
10671062

10681063

10691064
class TestPractitionerForeNameToFlatJson(unittest.TestCase):
@@ -1179,7 +1174,7 @@ def _run_practitioner_test(self, expected_forename):
11791174
"""Helper function to run the test"""
11801175
self.converter = Converter(json.dumps(request_json_data))
11811176
flat_json = self.converter.runConversion(request_json_data, False, True)
1182-
self.assertEqual(flat_json[0]["PERFORMING_PROFESSIONAL_FORENAME"], expected_forename)
1177+
self.assertEqual(flat_json["PERFORMING_PROFESSIONAL_FORENAME"], expected_forename)
11831178

11841179

11851180
class TestPractitionerSurNameToFlatJson(unittest.TestCase):
@@ -1293,7 +1288,7 @@ def _run_test_practitioner_surname(self, expected_forename):
12931288
"""Helper function to run the test"""
12941289
self.converter = Converter(json.dumps(request_json_data))
12951290
flat_json = self.converter.runConversion(request_json_data, False, True)
1296-
self.assertEqual(flat_json[0]["PERFORMING_PROFESSIONAL_SURNAME"], expected_forename)
1291+
self.assertEqual(flat_json["PERFORMING_PROFESSIONAL_SURNAME"], expected_forename)
12971292

12981293
if __name__ == "__main__":
12991294
unittest.main()

delta_backend/tests/test_converter.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ def test_runConversion_success(self, mock_checker, mock_schema_parser, mock_fhir
7878

7979
result = converter.runConversion(json_data={"occurrenceDateTime": "2023-01-01T12:00:00"})
8080

81-
self.assertEqual(len(result), 1)
82-
self.assertIn("someFlatField", result[0])
83-
self.assertEqual(result[0]["someFlatField"], "converted_value")
81+
self.assertEqual(len(result), 2)
82+
self.assertIn("someFlatField", result)
83+
self.assertEqual(result["someFlatField"], "converted_value")
8484

8585
@patch('Converter.extract_person_names', return_value=("John", "Doe"))
8686
@patch('Converter.get_valid_address', return_value="12345")

delta_backend/tests/utils_for_converter_tests.py

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,7 @@ def get_event(event_name="INSERT", operation="CREATE", supplier="EMIS"):
167167
@staticmethod
168168
def get_expected_imms(expected_action_flag):
169169
"""Returns expected Imms JSON data with the given action flag."""
170-
return [
171-
{
170+
return {
172171
"NHS_NUMBER": "9000000009",
173172
"PERSON_FORENAME": "Sam",
174173
"PERSON_SURNAME": "Trailor",
@@ -203,12 +202,10 @@ def get_expected_imms(expected_action_flag):
203202
"INDICATION_CODE": "443684005",
204203
"LOCATION_CODE": "EC1111",
205204
"LOCATION_CODE_TYPE_URI": "https://fhir.nhs.uk/Id/ods-organization-code",
206-
"CONVERSION_ERRORS": ''
205+
"CONVERSION_ERRORS": []
207206
}
208-
]
209207

210-
expected_imms = [
211-
{
208+
expected_imms = {
212209
"NHS_NUMBER": "9000000009",
213210
"PERSON_FORENAME": "Sam",
214211
"PERSON_SURNAME": "Trailor",
@@ -243,12 +240,10 @@ def get_expected_imms(expected_action_flag):
243240
"INDICATION_CODE": "443684005",
244241
"LOCATION_CODE": "EC1111",
245242
"LOCATION_CODE_TYPE_URI": "https://fhir.nhs.uk/Id/ods-organization-code",
246-
"CONVERSION_ERRORS": ''
243+
"CONVERSION_ERRORS": []
247244
}
248-
]
249245

250-
expected_imms2 = [
251-
{
246+
expected_imms2 = {
252247
"NHS_NUMBER": "9000000009",
253248
"PERSON_FORENAME": "Sam",
254249
"PERSON_SURNAME": "Trailor",
@@ -283,9 +278,8 @@ def get_expected_imms(expected_action_flag):
283278
"INDICATION_CODE": "443684005",
284279
"LOCATION_CODE": "EC1111",
285280
"LOCATION_CODE_TYPE_URI": "https://fhir.nhs.uk/Id/ods-organization-code",
286-
"CONVERSION_ERRORS": ''
281+
"CONVERSION_ERRORS": []
287282
}
288-
]
289283

290284

291285
class ErrorValuesForTests:
@@ -437,6 +431,6 @@ def get_expected_imms_error_output(expected_action_flag):
437431
"INDICATION_CODE": "443684005",
438432
"LOCATION_CODE": "E712",
439433
"LOCATION_CODE_TYPE_URI": "https://fhir.nhs.uk/Id/ods-organization-code",
440-
"CONVERSION_ERRORS": ''
434+
"CONVERSION_ERRORS": []
441435
}
442436
]

0 commit comments

Comments
 (0)