44from io import StringIO , BytesIO
55from typing import Union
66from botocore .exceptions import ClientError
7- from constants import ACK_HEADERS , SOURCE_BUCKET_NAME , ACK_BUCKET_NAME , FILE_NAME_PROC_LAMBDA_NAME
8- from audit_table import change_audit_table_status_to_processed , get_next_queued_file_details
7+ from audit_table import change_audit_table_status_to_processed
98from clients import s3_client , logger , lambda_client
10- from utils_for_ack_lambda import get_row_count
9+ from audit_table import change_audit_table_status_to_processed , get_next_queued_file_details
10+ from constants import (
11+ ACK_HEADERS ,
12+ get_source_bucket_name ,
13+ get_ack_bucket_name ,
14+ COMPLETED_ACK_DIR ,
15+ TEMP_ACK_DIR ,
16+ BATCH_FILE_PROCESSING_DIR ,
17+ BATCH_FILE_ARCHIVE_DIR ,
18+ FILE_NAME_PROC_LAMBDA_NAME
19+ )
20+ from logging_decorators import complete_batch_file_process_logging_decorator
1121
1222
1323def create_ack_data (
@@ -45,11 +55,45 @@ def create_ack_data(
4555 }
4656
4757
58+ @complete_batch_file_process_logging_decorator
59+ def complete_batch_file_process (
60+ message_id : str ,
61+ supplier : str ,
62+ vaccine_type : str ,
63+ supplier_queue : str ,
64+ created_at_formatted_string : str ,
65+ file_key : str ,
66+ total_ack_rows_processed : int ,
67+ ) -> dict :
68+ """Mark the batch file as processed. This involves moving the ack and original file to destinations and updating
69+ the audit table status"""
70+ ack_filename = f"{ file_key .replace ('.csv' , f'_BusAck_{ created_at_formatted_string } .csv' )} "
71+
72+ move_file (get_ack_bucket_name (), f"{ TEMP_ACK_DIR } /{ ack_filename } " , f"{ COMPLETED_ACK_DIR } /{ ack_filename } " )
73+ move_file (
74+ get_source_bucket_name (), f"{ BATCH_FILE_PROCESSING_DIR } /{ file_key } " , f"{ BATCH_FILE_ARCHIVE_DIR } /{ file_key } "
75+ )
76+
77+ change_audit_table_status_to_processed (file_key , message_id )
78+
79+ next_queued_file_details = get_next_queued_file_details (supplier_queue )
80+ if next_queued_file_details :
81+ invoke_filename_lambda (next_queued_file_details ["filename" ], next_queued_file_details ["message_id" ])
82+
83+ return {
84+ "message_id" : message_id ,
85+ "file_key" : file_key ,
86+ "supplier" : supplier ,
87+ "vaccine_type" : vaccine_type ,
88+ "row_count" : total_ack_rows_processed ,
89+ }
90+
91+
4892def obtain_current_ack_content (temp_ack_file_key : str ) -> StringIO :
4993 """Returns the current ack file content if the file exists, or else initialises the content with the ack headers."""
5094 try :
5195 # If ack file exists in S3 download the contents
52- existing_ack_file = s3_client .get_object (Bucket = ACK_BUCKET_NAME , Key = temp_ack_file_key )
96+ existing_ack_file = s3_client .get_object (Bucket = get_ack_bucket_name () , Key = temp_ack_file_key )
5397 existing_content = existing_ack_file ["Body" ].read ().decode ("utf-8" )
5498 except ClientError as error :
5599 # If ack file does not exist in S3 create a new file containing the headers only
@@ -65,60 +109,27 @@ def obtain_current_ack_content(temp_ack_file_key: str) -> StringIO:
65109 return accumulated_csv_content
66110
67111
68- def upload_ack_file (
69- temp_ack_file_key : str ,
70- message_id : str ,
71- supplier_queue : str ,
72- accumulated_csv_content : StringIO ,
73- ack_data_rows : list ,
74- archive_ack_file_key : str ,
75- file_key : str ,
76- ) -> None :
77- """Adds the data row to the uploaded ack file"""
78- for row in ack_data_rows :
79- data_row_str = [str (item ) for item in row .values ()]
80- cleaned_row = "|" .join (data_row_str ).replace (" |" , "|" ).replace ("| " , "|" ).strip ()
81- accumulated_csv_content .write (cleaned_row + "\n " )
82- csv_file_like_object = BytesIO (accumulated_csv_content .getvalue ().encode ("utf-8" ))
83- s3_client .upload_fileobj (csv_file_like_object , ACK_BUCKET_NAME , temp_ack_file_key )
84-
85- row_count_source = get_row_count (SOURCE_BUCKET_NAME , f"processing/{ file_key } " )
86- row_count_destination = get_row_count (ACK_BUCKET_NAME , temp_ack_file_key )
87- # TODO: Should we check for > and if so what handling is required
88- if row_count_destination == row_count_source :
89- move_file (ACK_BUCKET_NAME , temp_ack_file_key , archive_ack_file_key )
90- move_file (SOURCE_BUCKET_NAME , f"processing/{ file_key } " , f"archive/{ file_key } " )
91-
92- # Update the audit table and invoke the filename lambda with next file in the queue (if one exists)
93- change_audit_table_status_to_processed (file_key , message_id )
94- next_queued_file_details = get_next_queued_file_details (supplier_queue )
95- if next_queued_file_details :
96- invoke_filename_lambda (next_queued_file_details ["filename" ], next_queued_file_details ["message_id" ])
97-
98- logger .info ("Ack file updated to %s: %s" , ACK_BUCKET_NAME , archive_ack_file_key )
99-
100-
101112def update_ack_file (
102113 file_key : str ,
103- message_id : str ,
104- supplier_queue : str ,
105114 created_at_formatted_string : str ,
106115 ack_data_rows : list ,
107116) -> None :
108117 """Updates the ack file with the new data row based on the given arguments"""
109118 ack_filename = f"{ file_key .replace ('.csv' , f'_BusAck_{ created_at_formatted_string } .csv' )} "
110- temp_ack_file_key = f"TempAck /{ ack_filename } "
111- archive_ack_file_key = f"forwardedFile /{ ack_filename } "
119+ temp_ack_file_key = f"{ TEMP_ACK_DIR } /{ ack_filename } "
120+ archive_ack_file_key = f"{ COMPLETED_ACK_DIR } /{ ack_filename } "
112121 accumulated_csv_content = obtain_current_ack_content (temp_ack_file_key )
113- upload_ack_file (
114- temp_ack_file_key ,
115- message_id ,
116- supplier_queue ,
117- accumulated_csv_content ,
118- ack_data_rows ,
119- archive_ack_file_key ,
120- file_key ,
121- )
122+
123+ for row in ack_data_rows :
124+ data_row_str = [str (item ) for item in row .values ()]
125+ cleaned_row = "|" .join (data_row_str ).replace (" |" , "|" ).replace ("| " , "|" ).strip ()
126+ accumulated_csv_content .write (cleaned_row + "\n " )
127+
128+ csv_file_like_object = BytesIO (accumulated_csv_content .getvalue ().encode ("utf-8" ))
129+ ack_bucket_name = get_ack_bucket_name ()
130+
131+ s3_client .upload_fileobj (csv_file_like_object , ack_bucket_name , temp_ack_file_key )
132+ logger .info ("Ack file updated to %s: %s" , ack_bucket_name , archive_ack_file_key )
122133
123134
124135def move_file (bucket_name : str , source_file_key : str , destination_file_key : str ) -> None :
@@ -135,7 +146,7 @@ def invoke_filename_lambda(file_key: str, message_id: str) -> None:
135146 try :
136147 lambda_payload = {
137148 "Records" : [
138- {"s3" : {"bucket" : {"name" : SOURCE_BUCKET_NAME }, "object" : {"key" : file_key }}, "message_id" : message_id }
149+ {"s3" : {"bucket" : {"name" : get_source_bucket_name () }, "object" : {"key" : file_key }}, "message_id" : message_id }
139150 ]
140151 }
141152 lambda_client .invoke (
0 commit comments