Skip to content

Commit d0cbf07

Browse files
authored
Merge branch 'master' into VED-1081-Remove-redundant-V2-V5-Identifier-Uplift-code
2 parents b338b0c + 3b9ed3b commit d0cbf07

23 files changed

Lines changed: 625 additions & 344 deletions

File tree

config/common/disease_mapping.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,19 @@
111111
}
112112
]
113113
},
114+
{
115+
"vacc_type": "HIBMENC",
116+
"diseases": [
117+
{
118+
"code": "709410003",
119+
"term": "Haemophilus influenzae type b infection"
120+
},
121+
{
122+
"code": "23511006",
123+
"term": "Meningococcal infectious disease"
124+
}
125+
]
126+
},
114127
{
115128
"vacc_type": "HPV",
116129
"diseases": [

config/dev/permissions_config.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"FLU.CRUDS",
6767
"HEPB.CRUDS",
6868
"HIB.CRUDS",
69+
"HIBMENC.CRUDS",
6970
"HPV.CRUDS",
7071
"MENACWY.CRUDS",
7172
"MENB.CRUDS",
@@ -90,6 +91,7 @@
9091
"FLU.CRUDS",
9192
"HEPB.CRUDS",
9293
"HIB.CRUDS",
94+
"HIBMENC.CRUDS",
9395
"HPV.CRUDS",
9496
"MENACWY.CRUDS",
9597
"MENB.CRUDS",
@@ -114,6 +116,7 @@
114116
"FLU.CRUDS",
115117
"HEPB.CRUDS",
116118
"HIB.CRUDS",
119+
"HIBMENC.CRUDS",
117120
"HPV.CRUDS",
118121
"MENACWY.CRUDS",
119122
"MENB.CRUDS",
@@ -179,14 +182,22 @@
179182
"supplier": "Test_App",
180183
"permissions": [
181184
"3IN1.CRUDS",
185+
"4IN1.CRUDS",
186+
"6IN1.CRUDS",
187+
"BCG.CRUDS",
182188
"COVID.CRUDS",
183189
"FLU.CRUDS",
190+
"HEPB.CRUDS",
191+
"HIB.CRUDS",
192+
"HIBMENC.CRUDS",
184193
"HPV.CRUDS",
185194
"MENACWY.CRUDS",
195+
"MENB.CRUDS",
186196
"MMR.CRUDS",
187197
"MMRV.CRUDS",
188198
"PERTUSSIS.CRUDS",
189199
"PNEUMOCOCCAL.CRUDS",
200+
"ROTAVIRUS.CRUDS",
190201
"RSV.CRUDS",
191202
"SHINGLES.CRUDS"
192203
]
@@ -195,14 +206,22 @@
195206
"supplier": "Postman_Auth",
196207
"permissions": [
197208
"3IN1.CRUDS",
209+
"4IN1.CRUDS",
210+
"6IN1.CRUDS",
211+
"BCG.CRUDS",
198212
"COVID.CRUDS",
199213
"FLU.CRUDS",
214+
"HEPB.CRUDS",
215+
"HIB.CRUDS",
216+
"HIBMENC.CRUDS",
200217
"HPV.CRUDS",
201218
"MENACWY.CRUDS",
219+
"MENB.CRUDS",
202220
"MMR.CRUDS",
203221
"MMRV.CRUDS",
204222
"PERTUSSIS.CRUDS",
205223
"PNEUMOCOCCAL.CRUDS",
224+
"ROTAVIRUS.CRUDS",
206225
"RSV.CRUDS",
207226
"SHINGLES.CRUDS"
208227
]

config/preprod/permissions_config.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"FLU.CRUDS",
6464
"HEPB.CRUDS",
6565
"HIB.CRUDS",
66+
"HIBMENC.CRUDS",
6667
"HPV.CRUDS",
6768
"MENACWY.CRUDS",
6869
"MENB.CRUDS",
@@ -87,6 +88,7 @@
8788
"FLU.CRUDS",
8889
"HEPB.CRUDS",
8990
"HIB.CRUDS",
91+
"HIBMENC.CRUDS",
9092
"HPV.CRUDS",
9193
"MENACWY.CRUDS",
9294
"MENB.CRUDS",
@@ -111,6 +113,7 @@
111113
"FLU.CRUDS",
112114
"HEPB.CRUDS",
113115
"HIB.CRUDS",
116+
"HIBMENC.CRUDS",
114117
"HPV.CRUDS",
115118
"MENACWY.CRUDS",
116119
"MENB.CRUDS",
@@ -132,14 +135,22 @@
132135
"supplier": "Test_App",
133136
"permissions": [
134137
"3IN1.CRUDS",
138+
"4IN1.CRUDS",
139+
"6IN1.CRUDS",
140+
"BCG.CRUDS",
135141
"COVID.CRUDS",
136142
"FLU.CRUDS",
143+
"HEPB.CRUDS",
144+
"HIB.CRUDS",
145+
"HIBMENC.CRUDS",
137146
"HPV.CRUDS",
138147
"MENACWY.CRUDS",
148+
"MENB.CRUDS",
139149
"MMR.CRUDS",
140150
"MMRV.CRUDS",
141151
"PERTUSSIS.CRUDS",
142152
"PNEUMOCOCCAL.CRUDS",
153+
"ROTAVIRUS.CRUDS",
143154
"RSV.CRUDS",
144155
"SHINGLES.CRUDS"
145156
]
@@ -148,14 +159,22 @@
148159
"supplier": "Postman_Auth",
149160
"permissions": [
150161
"3IN1.CRUDS",
162+
"4IN1.CRUDS",
163+
"6IN1.CRUDS",
164+
"BCG.CRUDS",
151165
"COVID.CRUDS",
152166
"FLU.CRUDS",
167+
"HEPB.CRUDS",
168+
"HIB.CRUDS",
169+
"HIBMENC.CRUDS",
153170
"HPV.CRUDS",
154171
"MENACWY.CRUDS",
172+
"MENB.CRUDS",
155173
"MMR.CRUDS",
156174
"MMRV.CRUDS",
157175
"PERTUSSIS.CRUDS",
158176
"PNEUMOCOCCAL.CRUDS",
177+
"ROTAVIRUS.CRUDS",
159178
"RSV.CRUDS",
160179
"SHINGLES.CRUDS"
161180
]

lambdas/ack_backend/src/update_ack_file.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
update_audit_table_item,
1717
)
1818
from common.clients import get_s3_client, logger
19+
from common.file_utils import get_file_key_without_ext
1920
from common.log_decorator import generate_and_send_logs
2021
from common.models.batch_constants import (
2122
ACK_BUCKET_NAME,
@@ -142,7 +143,7 @@ def complete_batch_file_process(
142143
start_time = time.time()
143144

144145
# finish CSV file
145-
file_key_without_ext = os.path.splitext(file_key)[0]
146+
file_key_without_ext = get_file_key_without_ext(file_key)
146147
ack_filename = f"{file_key_without_ext}_BusAck_{created_at_formatted_string}.csv"
147148

148149
move_file(ACK_BUCKET_NAME, f"{TEMP_ACK_DIR}/{ack_filename}", f"{COMPLETED_ACK_DIR}/{ack_filename}")
@@ -247,7 +248,7 @@ def obtain_current_json_ack_content(message_id: str, supplier: str, file_key: st
247248
logger.info("No existing JSON ack file found in S3 - creating new file")
248249

249250
ingestion_start_time = get_ingestion_start_time_by_message_id(message_id)
250-
raw_ack_filename = os.path.splitext(file_key)[0]
251+
raw_ack_filename = get_file_key_without_ext(file_key)
251252

252253
# Generate the initial fields
253254
return _make_ack_data_dict_identifier_information(
@@ -269,7 +270,7 @@ def update_csv_ack_file(
269270
ack_data_rows: list,
270271
) -> None:
271272
"""Updates the ack file with the new data row based on the given arguments"""
272-
file_key_without_ext = os.path.splitext(file_key)[0]
273+
file_key_without_ext = get_file_key_without_ext(file_key)
273274
ack_filename = f"{file_key_without_ext}_BusAck_{created_at_formatted_string}.csv"
274275
temp_ack_file_key = f"{TEMP_ACK_DIR}/{ack_filename}"
275276
accumulated_csv_content = obtain_current_csv_ack_content(temp_ack_file_key)
@@ -293,7 +294,7 @@ def update_json_ack_file(
293294
ack_data_rows: list,
294295
) -> None:
295296
"""Updates the ack file with the new data row based on the given arguments"""
296-
file_key_without_ext = os.path.splitext(file_key)[0]
297+
file_key_without_ext = get_file_key_without_ext(file_key)
297298
ack_filename = f"{file_key_without_ext}_BusAck_{created_at_formatted_string}.json"
298299
temp_ack_file_key = f"{TEMP_ACK_DIR}/{ack_filename}"
299300
ack_data_dict = obtain_current_json_ack_content(message_id, supplier, file_key, temp_ack_file_key)

lambdas/backend/src/controller/fhir_controller.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,15 +154,16 @@ def _get_immunization_by_identifier(self, search_params: dict[str, list[str]], s
154154
return create_response(200, prepared_search_bundle)
155155

156156
def _search_immunizations(self, search_params: dict[str, list[str]], supplier_system: str) -> dict:
157-
validated_search_params = validate_and_retrieve_search_params(search_params)
157+
result = validate_and_retrieve_search_params(search_params)
158158

159159
search_bundle = self.fhir_service.search_immunizations(
160-
validated_search_params.patient_identifier,
161-
validated_search_params.immunization_targets,
160+
result.params.patient_identifier,
161+
result.params.immunization_targets,
162162
supplier_system,
163-
validated_search_params.date_from,
164-
validated_search_params.date_to,
165-
validated_search_params.include,
163+
result.params.date_from,
164+
result.params.date_to,
165+
result.params.include,
166+
result.invalid_immunization_targets,
166167
)
167168

168169
if self._has_too_many_search_results(search_bundle):

lambdas/backend/src/controller/parameter_parser.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import datetime
2-
from dataclasses import dataclass
2+
from dataclasses import dataclass, field
33
from typing import Optional
44

55
from common.models.constants import RedisHashKeys
@@ -33,6 +33,12 @@ def __repr__(self):
3333
return str(self.__dict__)
3434

3535

36+
@dataclass
37+
class SearchParamsResult:
38+
params: SearchParams
39+
invalid_immunization_targets: list[str] = field(default_factory=list)
40+
41+
3642
def process_patient_identifier(identifier_params: dict[str, list[str]]) -> str:
3743
"""Validate and parse patient identifier parameter.
3844
@@ -65,10 +71,9 @@ def process_patient_identifier(identifier_params: dict[str, list[str]]) -> str:
6571
return nhs_number
6672

6773

68-
def process_immunization_target(imms_params: dict[str, list[str]]) -> set[str]:
69-
"""Validate and parse immunization target parameter.
70-
71-
:raises ParameterExceptionError:
74+
def process_immunization_target(imms_params: dict[str, list[str]]) -> tuple[list[str], list[str]]:
75+
"""Validate and parse immunization target parameter. Returns (valid_vaccine_types, invalid_vaccine_types).
76+
Raises ParameterExceptionError only when no values provided or all values are invalid.
7277
"""
7378
vaccine_types = [
7479
vaccine_type
@@ -81,24 +86,27 @@ def process_immunization_target(imms_params: dict[str, list[str]]) -> set[str]:
8186
f"Search parameter {ImmunizationSearchParameterName.IMMUNIZATION_TARGET} must have one or more values."
8287
)
8388

84-
valid_vaccine_types = get_redis_client().hkeys(RedisHashKeys.VACCINE_TYPE_TO_DISEASES_HASH_KEY)
85-
if any(x not in valid_vaccine_types for x in vaccine_types):
89+
valid_vaccine_types_set = set(get_redis_client().hkeys(RedisHashKeys.VACCINE_TYPE_TO_DISEASES_HASH_KEY))
90+
valid = [v for v in vaccine_types if v in valid_vaccine_types_set]
91+
invalid = [v for v in vaccine_types if v not in valid_vaccine_types_set]
92+
93+
if not valid:
8694
raise ParameterExceptionError(
8795
f"{ImmunizationSearchParameterName.IMMUNIZATION_TARGET} must be one or more of the following: "
88-
f"{', '.join(valid_vaccine_types)}"
96+
f"{', '.join(sorted(valid_vaccine_types_set))}"
8997
)
9098

91-
return set(vaccine_types)
99+
return valid, invalid
92100

93101

94-
def process_mandatory_params(params: dict[str, list[str]]) -> tuple[str, set[str]]:
95-
"""Validate mandatory params and return (patient_identifier, vaccine_types).
102+
def process_mandatory_params(params: dict[str, list[str]]) -> tuple[str, list[str], list[str]]:
103+
"""Validate mandatory params and return (patient_identifier, valid_vaccine_types, invalid_vaccine_types).
96104
Raises ParameterExceptionError for any validation error.
97105
"""
98106
patient_identifier = process_patient_identifier(params)
99-
vaccine_types = process_immunization_target(params)
107+
vaccine_types, invalid_vaccine_types = process_immunization_target(params)
100108

101-
return patient_identifier, vaccine_types
109+
return patient_identifier, vaccine_types, invalid_vaccine_types
102110

103111

104112
def process_optional_params(
@@ -146,11 +154,11 @@ def process_optional_params(
146154
return date_from, date_to, include
147155

148156

149-
def validate_and_retrieve_search_params(params: dict[str, list[str]]) -> SearchParams:
157+
def validate_and_retrieve_search_params(params: dict[str, list[str]]) -> SearchParamsResult:
150158
"""Validate and retrieve search parameters.
151159
:raises ParameterExceptionError:
152160
"""
153-
patient_identifier, vaccine_types = process_mandatory_params(params)
161+
patient_identifier, vaccine_types, invalid_vaccine_types = process_mandatory_params(params)
154162
date_from, date_to, include = process_optional_params(params)
155163

156164
if date_from and date_to and date_from > date_to:
@@ -159,7 +167,8 @@ def validate_and_retrieve_search_params(params: dict[str, list[str]]) -> SearchP
159167
f"{ImmunizationSearchParameterName.DATE_TO}"
160168
)
161169

162-
return SearchParams(patient_identifier, vaccine_types, date_from, date_to, include)
170+
search_params = SearchParams(patient_identifier, set(vaccine_types), date_from, date_to, include)
171+
return SearchParamsResult(params=search_params, invalid_immunization_targets=invalid_vaccine_types)
163172

164173

165174
def parse_search_params(search_params_in_req: dict[str, list[str]]) -> dict[str, list[str]]:

lambdas/backend/src/service/fhir_service.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ def search_immunizations(
198198
date_from: Optional[datetime.date],
199199
date_to: Optional[datetime.date],
200200
include: Optional[str],
201+
invalid_immunization_targets: Optional[list[str]] = None,
201202
) -> FhirBundle:
202203
"""
203204
Finds all instances of Immunization(s) for a specified patient for the given specified vaccine type(s).
@@ -262,6 +263,21 @@ def search_immunizations(
262263
)
263264
)
264265

266+
if invalid_immunization_targets:
267+
invalid_list = ", ".join(sorted(invalid_immunization_targets))
268+
entries.append(
269+
BundleEntry(
270+
resource=OperationOutcome.construct(
271+
**create_operation_outcome(
272+
resource_id=str(uuid.uuid4()),
273+
severity=Severity.warning,
274+
code=Code.invalid,
275+
diagnostics=f"Your search included invalid -immunization.target value(s) that were ignored: {invalid_list}. The search was performed using the valid value(s) only.",
276+
)
277+
)
278+
)
279+
)
280+
265281
return FhirBundle(
266282
type="searchset",
267283
entry=entries,

0 commit comments

Comments
 (0)