11"""Functions for uploading the data to the ack file"""
22
33from io import BytesIO , StringIO
4- from typing import Optional
54
65from audit_table import change_audit_table_status_to_processed
76from botocore .exceptions import ClientError
87from common .clients import get_s3_client , logger
9- from constants import ACK_HEADERS , get_ack_bucket_name , get_source_bucket_name
10- from logging_decorators import upload_ack_file_logging_decorator
11- from utils_for_ack_lambda import get_row_count
8+ from constants import (
9+ ACK_HEADERS ,
10+ BATCH_FILE_ARCHIVE_DIR ,
11+ BATCH_FILE_PROCESSING_DIR ,
12+ COMPLETED_ACK_DIR ,
13+ TEMP_ACK_DIR ,
14+ get_ack_bucket_name ,
15+ get_source_bucket_name ,
16+ )
17+ from logging_decorators import complete_batch_file_process_logging_decorator
1218
1319
1420def create_ack_data (
@@ -46,6 +52,35 @@ def create_ack_data(
4652 }
4753
4854
55+ @complete_batch_file_process_logging_decorator
56+ def complete_batch_file_process (
57+ message_id : str ,
58+ supplier : str ,
59+ vaccine_type : str ,
60+ created_at_formatted_string : str ,
61+ file_key : str ,
62+ total_ack_rows_processed : int ,
63+ ) -> dict :
64+ """Mark the batch file as processed. This involves moving the ack and original file to destinations and updating
65+ the audit table status"""
66+ ack_filename = f"{ file_key .replace ('.csv' , f'_BusAck_{ created_at_formatted_string } .csv' )} "
67+
68+ move_file (get_ack_bucket_name (), f"{ TEMP_ACK_DIR } /{ ack_filename } " , f"{ COMPLETED_ACK_DIR } /{ ack_filename } " )
69+ move_file (
70+ get_source_bucket_name (), f"{ BATCH_FILE_PROCESSING_DIR } /{ file_key } " , f"{ BATCH_FILE_ARCHIVE_DIR } /{ file_key } "
71+ )
72+
73+ change_audit_table_status_to_processed (file_key , message_id )
74+
75+ return {
76+ "message_id" : message_id ,
77+ "file_key" : file_key ,
78+ "supplier" : supplier ,
79+ "vaccine_type" : vaccine_type ,
80+ "row_count" : total_ack_rows_processed ,
81+ }
82+
83+
4984def obtain_current_ack_content (temp_ack_file_key : str ) -> StringIO :
5085 """Returns the current ack file content if the file exists, or else initialises the content with the ack headers."""
5186 try :
@@ -66,76 +101,27 @@ def obtain_current_ack_content(temp_ack_file_key: str) -> StringIO:
66101 return accumulated_csv_content
67102
68103
69- @upload_ack_file_logging_decorator
70- def upload_ack_file (
71- temp_ack_file_key : str ,
72- message_id : str ,
73- supplier : str ,
74- vaccine_type : str ,
75- accumulated_csv_content : StringIO ,
76- ack_data_rows : list ,
77- archive_ack_file_key : str ,
104+ def update_ack_file (
78105 file_key : str ,
79- ) -> Optional [dict ]:
80- """Adds the data row to the uploaded ack file"""
106+ created_at_formatted_string : str ,
107+ ack_data_rows : list ,
108+ ) -> None :
109+ """Updates the ack file with the new data row based on the given arguments"""
110+ ack_filename = f"{ file_key .replace ('.csv' , f'_BusAck_{ created_at_formatted_string } .csv' )} "
111+ temp_ack_file_key = f"{ TEMP_ACK_DIR } /{ ack_filename } "
112+ archive_ack_file_key = f"{ COMPLETED_ACK_DIR } /{ ack_filename } "
113+ accumulated_csv_content = obtain_current_ack_content (temp_ack_file_key )
114+
81115 for row in ack_data_rows :
82116 data_row_str = [str (item ) for item in row .values ()]
83117 cleaned_row = "|" .join (data_row_str ).replace (" |" , "|" ).replace ("| " , "|" ).strip ()
84118 accumulated_csv_content .write (cleaned_row + "\n " )
85- csv_file_like_object = BytesIO (accumulated_csv_content .getvalue ().encode ("utf-8" ))
86119
120+ csv_file_like_object = BytesIO (accumulated_csv_content .getvalue ().encode ("utf-8" ))
87121 ack_bucket_name = get_ack_bucket_name ()
88- source_bucket_name = get_source_bucket_name ()
89122
90123 get_s3_client ().upload_fileobj (csv_file_like_object , ack_bucket_name , temp_ack_file_key )
91-
92- row_count_source = get_row_count (source_bucket_name , f"processing/{ file_key } " )
93- row_count_destination = get_row_count (ack_bucket_name , temp_ack_file_key )
94- # TODO: Should we check for > and if so what handling is required
95- if row_count_destination == row_count_source :
96- move_file (ack_bucket_name , temp_ack_file_key , archive_ack_file_key )
97- move_file (source_bucket_name , f"processing/{ file_key } " , f"archive/{ file_key } " )
98-
99- # Update the audit table
100- change_audit_table_status_to_processed (file_key , message_id )
101-
102- # Ingestion of this file is complete
103- result = {
104- "message_id" : message_id ,
105- "file_key" : file_key ,
106- "supplier" : supplier ,
107- "vaccine_type" : vaccine_type ,
108- "row_count" : row_count_source - 1 ,
109- }
110- else :
111- result = None
112124 logger .info ("Ack file updated to %s: %s" , ack_bucket_name , archive_ack_file_key )
113- return result
114-
115-
116- def update_ack_file (
117- file_key : str ,
118- message_id : str ,
119- supplier : str ,
120- vaccine_type : str ,
121- created_at_formatted_string : str ,
122- ack_data_rows : list ,
123- ) -> None :
124- """Updates the ack file with the new data row based on the given arguments"""
125- ack_filename = f"{ file_key .replace ('.csv' , f'_BusAck_{ created_at_formatted_string } .csv' )} "
126- temp_ack_file_key = f"TempAck/{ ack_filename } "
127- archive_ack_file_key = f"forwardedFile/{ ack_filename } "
128- accumulated_csv_content = obtain_current_ack_content (temp_ack_file_key )
129- upload_ack_file (
130- temp_ack_file_key ,
131- message_id ,
132- supplier ,
133- vaccine_type ,
134- accumulated_csv_content ,
135- ack_data_rows ,
136- archive_ack_file_key ,
137- file_key ,
138- )
139125
140126
141127def move_file (bucket_name : str , source_file_key : str , destination_file_key : str ) -> None :
0 commit comments