"""This module provides functionality to submit triggered sends to the Marketing Cloud API.""" from lambdacommon.common_config import logger import requests import config # noqa from src import utils from src.marketing_cloud_api.token import TokenManager from src.models import APIResponse from src.models import TriggeredSend from src.models import TriggeredSendBatchPayload def submit_triggered_send(triggered_send_info: TriggeredSend) -> tuple[requests.Response | None, str | None]: """Submit a triggered send to the Marketing Cloud API. Args: triggered_send_info (TriggeredSend): The triggered send information, including business unit ID and definition key. Returns: tuple: (response, error_message). If successful, response is the HTTP response object and error_message is None. If failed, response is None and error_message contains the error description. """ try: logger.debug(f'Getting access token for business unit {triggered_send_info.business_unit_id}') access_token = TokenManager().get_token(triggered_send_info.business_unit_id) except Exception as e: logger.exception(f'Failed to get token. Business Unit ID: {triggered_send_info.business_unit_id}') return None, str(e) url = config.MARKETING_CLOUD_TRIGGERED_SEND_API_URL_TEMPLATE.format( triggeredSendDefinitionId=triggered_send_info.triggered_send_definition_key) logger.debug(f'Submitting triggered send to URL: {url}') payload = TriggeredSendBatchPayload.from_input_model(triggered_send_info) headers = { 'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json' } try: logger.info(f'Submitting triggered send for business unit {triggered_send_info.business_unit_id}') if utils.is_triggered_send_enabled_for_business_unit_id(triggered_send_info.business_unit_id): response = requests.post(url, data=payload.model_dump_json(), headers=headers) logger.debug(f'Response status code: {response.status_code}') else: raise ValueError(f'Unsupported business unit ID: {triggered_send_info.business_unit_id}') return response, None except Exception as e: logger.exception('Failed to send Marketing Cloud API request') return None, str(e) def triggered_send_response_validation(response: requests.Response) -> tuple[APIResponse | None, str | None]: """Validate the response from the Marketing Cloud API triggered send request. This function checks if the HTTP response indicates success and parses the response body into a ResponsePayload object. It then validates that all responses in the payload are error-free and have a status of 'Queued'. Args: response (requests.Response): The HTTP response object returned from the Marketing Cloud API. Returns: tuple: (ResponsePayload or None, error_message or None). If validation succeeds, returns the parsed ResponsePayload and None for the error message. If validation fails, returns None or the ResponsePayload and an error message describing the failure. """ try: response.raise_for_status() except requests.RequestException as e: logger.error(f'HTTP error during response validation: {e}') return None, str(e) try: response_data = response.json() response_payload = APIResponse(**response_data) valid = all([not r.has_errors and r.messages == ['Queued'] for r in response_payload.responses]) if not valid: logger.error(f'Response validation failed: {response_payload}') return response_payload, 'Response validation failed' return response_payload, None except Exception as e: logger.error(f'Exception during response parsing/validation: {e}') return None, str(e)