diff --git a/kairon/events/definitions/message_broadcast.py b/kairon/events/definitions/message_broadcast.py index eaa7128e8..bcfbda8a5 100644 --- a/kairon/events/definitions/message_broadcast.py +++ b/kairon/events/definitions/message_broadcast.py @@ -55,7 +55,7 @@ def execute(self, event_id: Text, **kwargs): """ config = None reference_id = None - status = EVENT_STATUS.FAIL.value + status = EVENT_STATUS.INITIATED.value exception = None is_resend = kwargs.get('is_resend', "False") == "True" try: @@ -72,6 +72,7 @@ def execute(self, event_id: Text, **kwargs): except Exception as e: logger.exception(e) exception = str(e) + status = EVENT_STATUS.FAIL.value finally: time.sleep(5) MessageBroadcastProcessor.insert_status_received_on_channel_webhook(reference_id, config["name"], diff --git a/kairon/shared/channels/broadcast/whatsapp.py b/kairon/shared/channels/broadcast/whatsapp.py index 220899c45..6f0daecaf 100644 --- a/kairon/shared/channels/broadcast/whatsapp.py +++ b/kairon/shared/channels/broadcast/whatsapp.py @@ -89,10 +89,12 @@ def log(**kwargs): template_name = self.config['template_name'] language_code = self.config['language_code'] - raw_template = self.__get_template(template_name, language_code) + raw_template, template_exception = self.__get_template(template_name, language_code) + raw_template = raw_template if raw_template else [] MessageBroadcastProcessor.update_broadcast_logs_with_template( self.reference_id, self.event_id, raw_template=raw_template, - log_type=MessageBroadcastLogType.send.value, retry_count=0 + log_type=MessageBroadcastLogType.send.value, retry_count=0, + template_exception=template_exception ) def __send_using_configuration(self, recipients: List): @@ -105,7 +107,7 @@ def __send_using_configuration(self, recipients: List): namespace = template_config.get("namespace") lang = template_config["language"] template_params = self._get_template_parameters(template_config) - raw_template = self.__get_template(template_id, lang) + raw_template, template_exception = self.__get_template(template_id, lang) # if there's no template body, pass params as None for all recipients template_params = template_params * len(recipients) if template_params else [template_params] * len(recipients) @@ -128,7 +130,7 @@ def __send_using_configuration(self, recipients: List): self.bot, MessageBroadcastLogType.send.value, self.reference_id, api_response=response, status=status, recipient=recipient, template_params=t_params, template=raw_template, event_id=self.event_id, template_name=template_id, language_code=lang, namespace=namespace, - retry_count=0 + retry_count=0, template_exception=template_exception ) MessageBroadcastProcessor.add_event_log( self.bot, MessageBroadcastLogType.common.value, self.reference_id, failure_cnt=failure_cnt, total=total, @@ -151,6 +153,9 @@ def resend_broadcast(self): failure_cnt = 0 total = len(required_logs) skipped_count = len(broadcast_logs) - total + template_name = required_logs[0]["template_name"] + language_code = required_logs[0]["language_code"] + template, template_exception = self.__get_template(template_name, language_code) for log in required_logs: template_id = log["template_name"] @@ -158,7 +163,7 @@ def resend_broadcast(self): language_code = log["language_code"] components = log["template_params"] recipient = log["recipient"] - template = log["template"] + template = log.template if log.template else template response = channel_client.send_template_message(template_id, recipient, language_code, components, namespace) status = "Failed" if response.get("error") else "Success" @@ -169,7 +174,7 @@ def resend_broadcast(self): self.bot, MessageBroadcastLogType.resend.value, self.reference_id, api_response=response, status=status, recipient=recipient, template_params=components, template=template, event_id=self.event_id, template_name=template_id, language_code=language_code, namespace=namespace, - retry_count=retry_count, + retry_count=retry_count, template_exception=template_exception ) kwargs = { f"resend_count_{retry_count}": total, @@ -197,6 +202,16 @@ def __get_client(self): raise AppException(f"Whatsapp channel config not found!") def __get_template(self, name: Text, language: Text): - for template in BSP360Dialog(self.bot, self.user).list_templates(**{"business_templates.name": name}): - if template.get("language") == language: - return template.get("components") + template_exception = None + template = [] + try: + for template in BSP360Dialog(self.bot, self.user).list_templates(**{"business_templates.name": name}): + if template.get("language") == language: + template = template.get("components") + break + return template, template_exception + except Exception as e: + logger.exception(e) + template_exception = str(e) + return template, template_exception + diff --git a/kairon/shared/channels/whatsapp/bsp/dialog360.py b/kairon/shared/channels/whatsapp/bsp/dialog360.py index 82fc7c5df..edabccbe2 100644 --- a/kairon/shared/channels/whatsapp/bsp/dialog360.py +++ b/kairon/shared/channels/whatsapp/bsp/dialog360.py @@ -162,6 +162,9 @@ def list_templates(self, **kwargs): except DoesNotExist as e: logger.exception(e) raise AppException("Channel not found!") + except Exception as e: + logger.exception(e) + raise AppException(str(e)) @staticmethod def get_partner_auth_token(): diff --git a/kairon/shared/chat/broadcast/processor.py b/kairon/shared/chat/broadcast/processor.py index c7ebcf986..069df70e5 100644 --- a/kairon/shared/chat/broadcast/processor.py +++ b/kairon/shared/chat/broadcast/processor.py @@ -124,12 +124,12 @@ def get_reference_id_from_broadcasting_logs(event_id): @staticmethod def update_broadcast_logs_with_template(reference_id: Text, event_id: Text, raw_template: List[Dict], log_type: MessageBroadcastLogType, - retry_count: int = 0): + retry_count: int = 0, **kwargs): message_broadcast_logs = MessageBroadcastLogs.objects(reference_id=reference_id, event_id=event_id, log_type=log_type, retry_count=retry_count) - message_broadcast_logs.update(template=raw_template) + message_broadcast_logs.update(template=raw_template, **kwargs) @staticmethod def extract_message_ids_from_broadcast_logs(reference_id: Text, retry_count: int = 0): diff --git a/tests/unit_test/events/events_test.py b/tests/unit_test/events/events_test.py index 7b48ea48b..e92f040c6 100644 --- a/tests/unit_test/events/events_test.py +++ b/tests/unit_test/events/events_test.py @@ -1284,7 +1284,7 @@ def test_execute_message_broadcast_with_logs_modification(self, mock_is_exist, m 'contacts': [{'input': '+55123456789', 'status': 'valid', 'wa_id': '55123456789'}], 'messages': [{'id': 'wamid.HBgLMTIxMTU1NTc5NDcVAgARGBIyRkQxREUxRDJFQUJGMkQ3NDIZ', 'message_status': 'accepted'}]}, 'recipient': '918958030541', - 'template_params': None, 'template_name': 'brochure_pdf', + 'template_params': None, 'template_exception': None, 'template_name': 'brochure_pdf', 'language_code': 'hi', 'namespace': None, 'retry_count': 0, 'template': [ {'format': 'TEXT', 'text': 'Kisan Suvidha Program Follow-up', 'type': 'HEADER'}, { 'text': 'Hello! As a part of our Kisan Suvidha program, I am dedicated to supporting farmers like you in maximizing your crop productivity and overall yield.\n\nI wanted to reach out to inquire if you require any assistance with your current farming activities. Our team of experts, including our skilled agronomists, are here to lend a helping hand wherever needed.', @@ -1406,8 +1406,8 @@ def test_execute_message_broadcast_with_static_values(self, mock_is_exist, mock_ 'bot': 'test_execute_message_broadcast', 'status': 'Success', 'api_response': { 'contacts': [{'input': '+55123456789', 'status': 'valid', 'wa_id': '55123456789'}]}, 'recipient': '918958030541', 'template_params': None, "template": template, - 'template_name': 'brochure_pdf', 'language_code': 'hi', 'namespace': None, - 'retry_count': 0} + 'template_exception': None, 'template_name': 'brochure_pdf', 'language_code': 'hi', + 'namespace': None, 'retry_count': 0} settings = list(MessageBroadcastProcessor.list_settings(bot, status=False, name="one_time_schedule")) assert len(settings) == 1 @@ -1529,8 +1529,8 @@ def test_execute_message_broadcast_with_dynamic_values(self, mock_is_exist, mock {'type': 'document', 'document': { 'link': 'https://drive.google.com/uc?export=download&id=1GXQ43jilSDelRvy1kr3PNNpl1e21dRXm', 'filename': 'Brochure.pdf'}}]}], "template": template, - 'template_name': 'brochure_pdf', 'language_code': 'hi', 'namespace': None, - 'retry_count': 0} + 'template_exception': None, 'template_name': 'brochure_pdf', 'language_code': 'hi', + 'namespace': None, 'retry_count': 0} logs[0][0].pop("timestamp") assert logs[0][0] == {"event_id": event_id, 'reference_id': reference_id, 'log_type': 'send', 'bot': bot, 'status': 'Success', 'api_response': { @@ -1539,8 +1539,8 @@ def test_execute_message_broadcast_with_dynamic_values(self, mock_is_exist, mock {'type': 'document', 'document': { 'link': 'https://drive.google.com/uc?export=download&id=1GXQ43jilSDelRvy1kr3PNNpl1e21dRXm', 'filename': 'Brochure.pdf'}}]}], "template": template, - 'template_name': 'brochure_pdf', 'language_code': 'hi', 'namespace': None, - 'retry_count': 0} + 'template_exception': None, 'template_name': 'brochure_pdf', 'language_code': 'hi', + 'namespace': None, 'retry_count': 0} assert mock_send.call_args[0][1] == 'brochure_pdf' assert mock_send.call_args[0][2] in ['876543212345', '9876543210'] @@ -1849,8 +1849,8 @@ def test_execute_message_broadcast_evaluate_template_parameters(self, mock_is_ex 'contacts': [{'input': '+55123456789', 'status': 'valid', 'wa_id': '55123456789'}], 'messages': [{'id': 'wamid.HBgLMTIxMTU1NTc5NDcVAgARGBIyRkQxREUxRDJFQUJGMkQ3NDIZ'}]}, 'recipient': '918958030541', 'template_params': [{'body': 'Udit Pandey'}], - 'template_name': 'agronomy_support', 'language_code': 'hi', 'namespace': None, - 'retry_count': 0, + 'template_exception': None, 'template_name': 'agronomy_support', 'language_code': 'hi', + 'namespace': None, 'retry_count': 0, 'errors': [ {'code': 130472, 'title': "User's number is part of an experiment", 'message': "User's number is part of an experiment", @@ -2162,6 +2162,268 @@ def test_execute_message_broadcast_with_pyscript(self, mock_list_templates, mock ] } + @responses.activate + @mongomock.patch(servers=(('localhost', 27017),)) + @patch("kairon.shared.channels.whatsapp.bsp.dialog360.BSP360Dialog.get_partner_auth_token", autospec=True) + @patch("kairon.chat.handlers.channels.clients.whatsapp.dialog360.BSP360Dialog.send_template_message", + autospec=True) + @patch("kairon.shared.data.processor.MongoProcessor.get_bot_settings") + @patch("kairon.shared.chat.processor.ChatDataProcessor.get_channel_config") + @patch("kairon.shared.utils.Utility.is_exist", autospec=True) + @patch("kairon.shared.channels.whatsapp.bsp.dialog360.BSP360Dialog.list_templates", autospec=True) + def test_execute_message_broadcast_with_template_exception(self, mock_list_templates, mock_is_exist, + mock_channel_config, mock_get_bot_settings, + mock_send, mock_get_partner_auth_token): + + from datetime import datetime + from kairon.shared.chat.broadcast.data_objects import MessageBroadcastLogs + + bot = 'test_execute_message_broadcast_with_template_exception' + user = 'test_user' + script = """ + api_response = requests.get("http://kairon.local", headers={"api_key": "asdfghjkl", "access_key": "dsfghjkl"}) + api_response = api_response.json() + log(**api_response) + + components = [{'type': 'header', 'parameters': [{'type': 'document', 'document': { + 'link': 'https://drive.google.com/uc?export=download&id=1GXQ43jilSDelRvy1kr3PNNpl1e21dRXm', + 'filename': 'Brochure.pdf'}}]}] + i = 0 + for contact in api_response["contacts"]: + resp = send_msg("brochure_pdf", contact, components=components, namespace="13b1e228_4a08_4d19_a0da_cdb80bc76380") + log(i=i, contact=contact, whatsapp_response=resp) + """ + script = textwrap.dedent(script) + config = { + "name": "one_time_schedule", "broadcast_type": "dynamic", + "connector_type": "whatsapp", + "pyscript": script, + "retry_count": 0, + "template_name": "brochure_pdf", + "language_code": "hi" + } + template = [ + { + "format": "TEXT", + "text": "Kisan Suvidha Program Follow-up", + "type": "HEADER" + }, + { + "text": "Hello! As a part of our Kisan Suvidha program, I am dedicated to supporting farmers like you in maximizing your crop productivity and overall yield.\n\nI wanted to reach out to inquire if you require any assistance with your current farming activities. Our team of experts, including our skilled agronomists, are here to lend a helping hand wherever needed.", + "type": "BODY" + }, + { + "text": "reply with STOP to unsubscribe", + "type": "FOOTER" + }, + { + "buttons": [ + { + "text": "Connect to Agronomist", + "type": "QUICK_REPLY" + } + ], + "type": "BUTTONS" + } + ] + + template_exception = "Failed to load the template" + mock_list_templates.side_effect = Exception(template_exception) + + url = f"{Utility.environment['events']['server_url']}/api/events/execute/{EventClass.message_broadcast}?is_scheduled=False" + base_url = Utility.system_metadata["channels"]["whatsapp"]["business_providers"]["360dialog"][ + "waba_base_url"] + template_url = base_url + '/v1/configs/templates?filters={"business_templates.name": "brochure_pdf"}&sort=business_templates.name' + responses.add( + "POST", url, + json={"message": "Event Triggered!", "success": True, "error_code": 0, "data": None} + ) + responses.add( + "GET", "http://kairon.local", + match=[matchers.header_matcher({"api_key": "asdfghjkl", "access_key": "dsfghjkl"})], + json={"contacts": ["9876543210", "876543212345"]} + ) + responses.add( + "GET", template_url, + json={"waba_templates": [ + {"category": "MARKETING", "components": template, "name": "brochure_pdf", "language": "hi"}]} + ) + + mock_get_bot_settings.return_value = {"whatsapp": "360dialog", "notification_scheduling_limit": 4, + "dynamic_broadcast_execution_timeout": 21600} + mock_channel_config.return_value = { + "config": {"access_token": "shjkjhrefdfghjkl", "from_phone_number_id": "918958030415", + "waba_account_id": "asdfghjk"}} + mock_send.return_value = { + "contacts": [{"input": "+55123456789", "status": "valid", "wa_id": "55123456789"}]} + mock_get_partner_auth_token.return_value = None + + with patch.dict(Utility.environment["channels"]["360dialog"], {"partner_id": "sdfghjkjhgfddfghj"}): + event = MessageBroadcastEvent(bot, user) + event.validate() + event_id = event.enqueue(EventRequestType.trigger_async.value, config=config) + event.execute(event_id, is_resend="False") + + logs = MessageBroadcastProcessor.get_broadcast_logs(bot) + + assert len(logs[0]) == logs[1] == 1 + [log.pop("timestamp") for log in logs[0]] + reference_id = logs[0][0].get("reference_id") + expected_logs = [{"event_id": event_id, 'reference_id': reference_id, 'log_type': 'common', 'bot': bot, + 'status': 'Completed', + 'user': 'test_user', 'failure_cnt': 0, 'total': 0, + 'components': [{'type': 'header', 'parameters': [{'type': 'document', 'document': { + 'link': 'https://drive.google.com/uc?export=download&id=1GXQ43jilSDelRvy1kr3PNNpl1e21dRXm', + 'filename': 'Brochure.pdf'}}]}], 'i': 0, 'contact': '876543212345', + 'api_response': {'contacts': ['9876543210', '876543212345']}, + 'resp': { + 'contacts': [{'input': '+55123456789', 'status': 'valid', 'wa_id': '55123456789'}]}}] + for log in logs[0]: + if log.get("config"): + logged_config = log.pop("config") + assert log in expected_logs + + logged_config.pop("status") + logged_config.pop('pyscript_timeout') + logged_config.pop("timestamp") + logged_config.pop("_id") + assert logged_config.pop("template_config") == [] + assert logged_config == config + + timestamp = datetime.utcnow() + MessageBroadcastLogs( + **{ + "reference_id": reference_id, + "event_id": event_id, + "log_type": "send", + "bot": bot, + "status": "Success", + "template_name": "brochure_pdf", + "namespace": "54500467_f322_4595_becd_419af88spm4", + "language_code": "hi", + "errors": [], + "api_response": { + "messaging_product": "whatsapp", + "contacts": [ + { + "input": "9876543210", + "wa_id": "9876543210" + } + ], + "messages": [ + { + "id": "wamid.HBgLMTIxMTU1NTc5NDcVAgARGBIyRkQxREUxRDJFQUJGMkQ3NDIZ" + } + ] + }, + "recipient": "9876543210", + "template_params": [ + { + "type": "header", + "parameters": [ + { + "type": "document", + "document": { + "link": "https://drive.google.com/uc?export=download&id=1GXQ43jilSDelRvy1kr3PNNpl1e21dRXm", + "filename": "Brochure.pdf", + }, + } + ], + } + ], + "timestamp": timestamp, + "retry_count": 0 + } + ).save() + logs = MessageBroadcastProcessor.get_broadcast_logs(bot) + assert len(logs[0]) == logs[1] == 2 + logs[0][0].pop("timestamp") + reference_id = logs[0][0].get("reference_id") + logged_config = logs[0][0] + assert logged_config == { + 'reference_id': reference_id, + 'log_type': 'send', + 'bot': bot, + 'event_id': event_id, + 'status': 'Success', + 'template_name': 'brochure_pdf', + 'namespace': '54500467_f322_4595_becd_419af88spm4', + 'language_code': 'hi', + 'errors': [], + 'api_response': { + 'messaging_product': 'whatsapp', + 'contacts': [{'input': '9876543210', 'wa_id': '9876543210'}], + 'messages': [{'id': 'wamid.HBgLMTIxMTU1NTc5NDcVAgARGBIyRkQxREUxRDJFQUJGMkQ3NDIZ'}]}, + 'recipient': '9876543210', + 'template_params': [ + { + 'type': 'header', + 'parameters': [ + { + 'type': 'document', + 'document': { + 'link': 'https://drive.google.com/uc?export=download&id=1GXQ43jilSDelRvy1kr3PNNpl1e21dRXm', + 'filename': 'Brochure.pdf' + } + } + ] + } + ], + 'retry_count': 0 + } + MessageBroadcastProcessor.update_broadcast_logs_with_template(reference_id=reference_id, event_id=event_id, + raw_template=[], log_type="send", + retry_count=0, + template_exception=template_exception) + logs = MessageBroadcastProcessor.get_broadcast_logs(bot) + assert len(logs[0]) == logs[1] == 2 + logs[0][0].pop("timestamp") + reference_id = logs[0][0].get("reference_id") + logged_config = logs[0][0] + assert logged_config == { + 'reference_id': reference_id, + 'log_type': 'send', + 'bot': bot, + 'event_id': event_id, + 'status': 'Success', + 'template_name': 'brochure_pdf', + 'namespace': '54500467_f322_4595_becd_419af88spm4', + 'language_code': 'hi', + 'errors': [], + 'api_response': { + 'messaging_product': 'whatsapp', + 'contacts': [ + { + 'input': '9876543210', + 'wa_id': '9876543210' + } + ], + 'messages': [ + { + 'id': 'wamid.HBgLMTIxMTU1NTc5NDcVAgARGBIyRkQxREUxRDJFQUJGMkQ3NDIZ' + } + ] + }, + 'recipient': '9876543210', + 'template_params': [ + { + 'type': 'header', + 'parameters': [ + { + 'type': 'document', + 'document': { + 'link': 'https://drive.google.com/uc?export=download&id=1GXQ43jilSDelRvy1kr3PNNpl1e21dRXm', + 'filename': 'Brochure.pdf' + } + } + ] + } + ], + 'retry_count': 0, + 'template': [], + 'template_exception': 'Failed to load the template' + } + @responses.activate @patch("kairon.shared.data.processor.MongoProcessor.get_bot_settings") @patch("kairon.shared.chat.processor.ChatDataProcessor.get_channel_config") @@ -2581,7 +2843,7 @@ def test_execute_message_broadcast_with_resend_broadcast_with_static_values( {'text': 'Hello! As a part of our Kisan Suvidha program, I am dedicated to supporting farmers like you in maximizing your crop productivity and overall yield.\n\nI wanted to reach out to inquire if you require any assistance with your current farming activities. Our team of experts, including our skilled agronomists, are here to lend a helping hand wherever needed.', 'type': 'BODY'}, {'text': 'reply with STOP to unsubscribe', 'type': 'FOOTER'}, {'buttons': [{'text': 'Connect to Agronomist', 'type': 'QUICK_REPLY'}], 'type': 'BUTTONS'}], - 'event_id': event_id, 'template_name': 'brochure_pdf', 'language_code': 'hi', + 'event_id': event_id, 'template_exception': None, 'template_name': 'brochure_pdf', 'language_code': 'hi', 'namespace': '54500467_f322_4595_becd_419af88spm4', 'retry_count': 1, 'errors': []} logs[0][3].pop("timestamp") @@ -2940,7 +3202,7 @@ def test_execute_message_broadcast_with_resend_broadcast_with_dynamic_values( {'text': 'Hello! As a part of our Kisan Suvidha program, I am dedicated to supporting farmers like you in maximizing your crop productivity and overall yield.\n\nI wanted to reach out to inquire if you require any assistance with your current farming activities. Our team of experts, including our skilled agronomists, are here to lend a helping hand wherever needed.', 'type': 'BODY'}, {'text': 'reply with STOP to unsubscribe', 'type': 'FOOTER'}, {'buttons': [{'text': 'Connect to Agronomist', 'type': 'QUICK_REPLY'}], 'type': 'BUTTONS'}], - 'event_id': event_id, 'template_name': 'brochure_pdf', 'language_code': 'hi', + 'event_id': event_id, 'template_exception': None, 'template_name': 'brochure_pdf', 'language_code': 'hi', 'namespace': '54500467_f322_4595_becd_419af88spm4', 'retry_count': 1, 'errors': []} logs[0][3].pop("timestamp") @@ -2981,6 +3243,367 @@ def test_execute_message_broadcast_with_resend_broadcast_with_dynamic_values( } ] + @responses.activate + @mongomock.patch(servers=(('localhost', 27017),)) + @patch("kairon.shared.channels.whatsapp.bsp.dialog360.BSP360Dialog.get_partner_auth_token", autospec=True) + @patch("kairon.chat.handlers.channels.clients.whatsapp.dialog360.BSP360Dialog.send_template_message") + @patch("kairon.shared.data.processor.MongoProcessor.get_bot_settings") + @patch("kairon.shared.chat.processor.ChatDataProcessor.get_channel_config") + @patch("kairon.shared.utils.Utility.is_exist", autospec=True) + def test_execute_message_broadcast_with_resend_broadcast_without_template( + self, mock_is_exist, mock_channel_config, mock_get_bot_settings, mock_send, + mock_get_partner_auth_token + ): + from datetime import datetime, timedelta + from kairon.shared.chat.broadcast.data_objects import MessageBroadcastSettings, MessageBroadcastLogs + + bot = 'test_execute_message_broadcast_with_resend_broadcast_without_template' + user = 'test_user' + script = """ + contacts = ['919876543210','919012345678'] + + components = components = [{'type': 'header', 'parameters': [{'type': 'document', 'document': { + 'link': 'https://drive.google.com/uc?export=download&id=1GXQ43jilSDelRvy1kr3PNNpl1e21dRXm', + 'filename': 'Brochure.pdf'}}]}] + for contact in contacts: + resp = send_msg("brochure_pdf", contact, components=components, namespace="13b1e228_4a08_4d19_a0da_cdb80bc76380") + + log(contact=contact,whatsapp_response=resp) + """ + script = textwrap.dedent(script) + config = { + "name": "one_time_schedule", "broadcast_type": "dynamic", + "connector_type": "whatsapp", + "pyscript": script, + "bot": bot, + "user": user, + "status": False + } + template = [ + { + "format": "TEXT", + "text": "Kisan Suvidha Program Follow-up", + "type": "HEADER" + }, + { + "text": "Hello! As a part of our Kisan Suvidha program, I am dedicated to supporting farmers like you in maximizing your crop productivity and overall yield.\n\nI wanted to reach out to inquire if you require any assistance with your current farming activities. Our team of experts, including our skilled agronomists, are here to lend a helping hand wherever needed.", + "type": "BODY" + }, + { + "text": "reply with STOP to unsubscribe", + "type": "FOOTER" + }, + { + "buttons": [ + { + "text": "Connect to Agronomist", + "type": "QUICK_REPLY" + } + ], + "type": "BUTTONS" + } + ] + + url = f"{Utility.environment['events']['server_url']}/api/events/execute/{EventClass.message_broadcast}?is_scheduled=False" + base_url = Utility.system_metadata["channels"]["whatsapp"]["business_providers"]["360dialog"]["waba_base_url"] + template_url = base_url + '/v1/configs/templates?filters={"business_templates.name": "brochure_pdf"}&sort=business_templates.name' + responses.add( + "POST", url, + json={"message": "Event Triggered!", "success": True, "error_code": 0, "data": None} + ) + responses.add( + "GET", template_url, + json={"waba_templates": [ + {"category": "MARKETING", "components": template, "name": "agronomy_support", "language": "hi"}]} + ) + + mock_get_bot_settings.return_value = {"whatsapp": "360dialog", "notification_scheduling_limit": 4, + "dynamic_broadcast_execution_timeout": 21600} + mock_channel_config.return_value = { + "config": {"access_token": "shjkjhrefdfghjkl", "from_phone_number_id": "918958030415", + "waba_account_id": "asdfghjk"}} + mock_send.return_value = {"contacts": [{"input": "919876543210", "status": "valid", "wa_id": "55123456789"}], + "messages": [{"id": 'wamid.HBgMOTE5NTE1OTkxNjg1FQIAERgSODFFNEM0QkM5MEJBODM4MjIBB==', + "message_status": 'accepted'}]} + mock_get_partner_auth_token.return_value = None + + msg_broadcast_id = MessageBroadcastSettings(**config).save().id.__str__() + timestamp = datetime.utcnow() + MessageBroadcastLogs( + **{ + "reference_id": "667bed955bfdaf3466b19de1", + "log_type": "common", + "bot": bot, + "status": "Completed", + "user": "test_user", + "event_id": msg_broadcast_id, + "recipients": ["919876543210", "919012345678"], + "timestamp": timestamp, + + } + ).save() + timestamp = timestamp + timedelta(minutes=2) + MessageBroadcastLogs( + **{ + "reference_id": "667bed955bfdaf3466b19de1", + "log_type": "send", + "bot": bot, + "status": "Success", + "template_name": "brochure_pdf", + "template": [], + "namespace": "54500467_f322_4595_becd_419af88spm4", + "language_code": "hi", + "errors": [], + "api_response": { + "messaging_product": "whatsapp", + "contacts": [ + { + "input": "919012345678", + "wa_id": "919012345678" + } + ], + "messages": [ + { + "id": "wamid.HBgLMTIxMTU1NTc5NDcVAgARGBIyRkQxREUxRDJFQUJGMkQ3NDIZ" + } + ] + }, + "recipient": "919012345678", + "template_params": [ + { + "type": "header", + "parameters": [ + { + "type": "document", + "document": { + "link": "https://drive.google.com/uc?export=download&id=1GXQ43jilSDelRvy1kr3PNNpl1e21dRXm", + "filename": "Brochure.pdf", + }, + } + ], + } + ], + "timestamp": timestamp, + "retry_count": 0 + } + ).save() + timestamp = timestamp + timedelta(minutes=2) + MessageBroadcastLogs( + **{ + "reference_id": "667bed955bfdaf3466b19de1", + "log_type": "send", + "bot": bot, + "status": "Success", + "template_name": "brochure_pdf", + "template": [], + "namespace": "54500467_f322_4595_becd_419af88spm4", + "language_code": "hi", + "errors": [ + { + "code": 130472, + "title": "User's number is part of an experiment", + "message": "User's number is part of an experiment", + "error_data": { + "details": "Failed to send message because this user's phone number is part of an experiment" + }, + "href": "https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes/" + } + ], + "api_response": { + "messaging_product": "whatsapp", + "contacts": [ + { + "input": "919876543210", + "wa_id": "919876543210" + } + ], + "messages": [ + { + "id": "wamid.HBgMOTE5NTE1OTkxNjg1FQIAERgSODFFNEM0QkM5MEJBODM4MjI4AA==" + } + ] + }, + "recipient": "919876543210", + "template_params": [ + { + "type": "header", + "parameters": [ + { + "type": "document", + "document": { + "link": "https://drive.google.com/uc?export=download&id=1GXQ43jilSDelRvy1kr3PNNpl1e21dRXm", + "filename": "Brochure.pdf", + }, + } + ], + } + ], + "timestamp": timestamp, + "retry_count": 0 + } + ).save() + + ChannelLogs( + type=ChannelTypes.WHATSAPP.value, + status='sent', + data={'id': 'CONVERSATION_ID', 'expiration_timestamp': '1691598412', + 'origin': {'type': 'business_initated'}}, + initiator='business_initated', + message_id='wamid.HBgLMTIxMTU1NTc5NDcVAgARGBIyRkQxREUxRDJFQUJGMkQ3NDIZ', + campaign_id="667bed955bfdaf3466b19de1", + bot=bot, + user=user + ).save() + ChannelLogs( + type=ChannelTypes.WHATSAPP.value, + status='delivered', + data={'id': 'CONVERSATION_ID', 'expiration_timestamp': '1691598412', + 'origin': {'type': 'business_initated'}}, + initiator='business_initated', + message_id='wamid.HBgLMTIxMTU1NTc5NDcVAgARGBIyRkQxREUxRDJFQUJGMkQ3NDIZ', + campaign_id="667bed955bfdaf3466b19de1", + bot=bot, + user=user + ).save() + ChannelLogs( + type=ChannelTypes.WHATSAPP.value, + status='read', + data={'id': 'CONVERSATION_ID', 'expiration_timestamp': '1691598412', + 'origin': {'type': 'business_initated'}}, + initiator='business_initated', + message_id='wamid.HBgLMTIxMTU1NTc5NDcVAgARGBIyRkQxREUxRDJFQUJGMkQ3NDIZ', + campaign_id="667bed955bfdaf3466b19de1", + bot=bot, + user=user + ).save() + + ChannelLogs( + type=ChannelTypes.WHATSAPP.value, + status='sent', + data={'id': 'CONVERSATION_ID', 'expiration_timestamp': '1691598412', + 'origin': {'type': 'business_initated'}}, + initiator='business_initated', + message_id='wamid.HBgMOTE5NTE1OTkxNjg1FQIAERgSODFFNEM0QkM5MEJBODM4MjIBB==', + campaign_id="667bed955bfdaf3466b19de1", + bot=bot, + user=user + ).save() + ChannelLogs( + type=ChannelTypes.WHATSAPP.value, + status='delivered', + data={'id': 'CONVERSATION_ID', 'expiration_timestamp': '1691598412', + 'origin': {'type': 'business_initated'}}, + initiator='business_initated', + message_id='wamid.HBgMOTE5NTE1OTkxNjg1FQIAERgSODFFNEM0QkM5MEJBODM4MjIBB==', + campaign_id="667bed955bfdaf3466b19de1", + bot=bot, + user=user + ).save() + ChannelLogs( + type=ChannelTypes.WHATSAPP.value, + status='read', + data={'id': 'CONVERSATION_ID', 'expiration_timestamp': '1691598412', + 'origin': {'type': 'business_initated'}}, + initiator='business_initated', + message_id='wamid.HBgMOTE5NTE1OTkxNjg1FQIAERgSODFFNEM0QkM5MEJBODM4MjIBB==', + campaign_id="667bed955bfdaf3466b19de1", + bot=bot, + user=user + ).save() + + ChannelLogs( + type=ChannelTypes.WHATSAPP.value, + status='failed', + data={'id': 'CONVERSATION_ID', 'expiration_timestamp': '1691598412', + 'origin': {'type': 'business_initated'}}, + initiator='business_initated', + message_id='wamid.HBgMOTE5NTE1OTkxNjg1FQIAERgSODFFNEM0QkM5MEJBODM4MjI4AA==', + campaign_id="667bed955bfdaf3466b19de1", + errors=[ + { + "code": 130472, + "title": "User's number is part of an experiment", + "message": "User's number is part of an experiment", + "error_data": { + "details": "Failed to send message because this user's phone number is part of an experiment" + }, + "href": "https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes/" + } + ], + bot=bot, + user=user + ).save() + + with patch.dict(Utility.environment["channels"]["360dialog"], {"partner_id": "sdfghjkjhgfddfghj"}): + event = MessageBroadcastEvent(bot, user) + event.validate() + event_id = event.enqueue(EventRequestType.resend_broadcast.value, + msg_broadcast_id=msg_broadcast_id) + event.execute(event_id, is_resend="True") + + logs = MessageBroadcastProcessor.get_broadcast_logs(bot) + assert len(logs[0]) == logs[1] == 4 + logs[0][2].pop("timestamp") + reference_id = logs[0][2].get("reference_id") + logged_config = logs[0][2] + assert logged_config == { + 'reference_id': reference_id, 'log_type': 'resend', + 'bot': 'test_execute_message_broadcast_with_resend_broadcast_without_template', 'status': 'Success', + 'api_response': {'contacts': [{'input': '919876543210', 'status': 'valid', 'wa_id': '55123456789'}], + 'messages': [{'id': 'wamid.HBgMOTE5NTE1OTkxNjg1FQIAERgSODFFNEM0QkM5MEJBODM4MjIBB==', + 'message_status': 'accepted'}]}, + 'recipient': '919876543210', + 'template_params': [ + {'type': 'header', 'parameters': [ + {'type': 'document', + 'document': { + 'link': 'https://drive.google.com/uc?export=download&id=1GXQ43jilSDelRvy1kr3PNNpl1e21dRXm', + 'filename': 'Brochure.pdf'}}]}], + 'template': [{'format': 'TEXT', 'text': 'Kisan Suvidha Program Follow-up', 'type': 'HEADER'}, + {'text': 'Hello! As a part of our Kisan Suvidha program, I am dedicated to supporting farmers like you in maximizing your crop productivity and overall yield.\n\nI wanted to reach out to inquire if you require any assistance with your current farming activities. Our team of experts, including our skilled agronomists, are here to lend a helping hand wherever needed.', 'type': 'BODY'}, + {'text': 'reply with STOP to unsubscribe', 'type': 'FOOTER'}, + {'buttons': [{'text': 'Connect to Agronomist', 'type': 'QUICK_REPLY'}], 'type': 'BUTTONS'}], + 'event_id': event_id, 'template_exception': None, 'template_name': 'brochure_pdf', 'language_code': 'hi', + 'namespace': '54500467_f322_4595_becd_419af88spm4', 'retry_count': 1, 'errors': []} + + logs[0][3].pop("timestamp") + logs[0][3].get("config").pop("timestamp") + reference_id = logs[0][3].get("reference_id") + logs[0][3].pop("retry_1_timestamp") + logged_config = logs[0][3] + assert logged_config == { + 'reference_id': reference_id, 'log_type': 'common', + 'bot': 'test_execute_message_broadcast_with_resend_broadcast_without_template', 'status': 'Completed', + 'user': 'test_user', 'event_id': event_id, + 'recipients': ['919876543210', '919012345678'], + 'config': {'_id': event_id, 'name': 'one_time_schedule', 'connector_type': 'whatsapp', + 'broadcast_type': 'dynamic', 'template_config': [], + 'pyscript': '\ncontacts = [\'919876543210\',\'919012345678\']\n\ncomponents = components = [{\'type\': \'header\', \'parameters\': [{\'type\': \'document\', \'document\': {\n \'link\': \'https://drive.google.com/uc?export=download&id=1GXQ43jilSDelRvy1kr3PNNpl1e21dRXm\',\n \'filename\': \'Brochure.pdf\'}}]}]\nfor contact in contacts:\n resp = send_msg("brochure_pdf", contact, components=components, namespace="13b1e228_4a08_4d19_a0da_cdb80bc76380")\n\n log(contact=contact,whatsapp_response=resp) \n', + 'retry_count': 0, + 'bot': 'test_execute_message_broadcast_with_resend_broadcast_without_template', + 'user': 'test_user', 'status': False, 'pyscript_timeout': 21600}, + 'resend_count_1': 1, 'skipped_count_1': 0} + assert ChannelLogs.objects( + bot=bot, message_id='wamid.HBgMOTE5NTE1OTkxNjg1FQIAERgSODFFNEM0QkM5MEJBODM4MjIBB==', status="sent" + ).get().campaign_id == reference_id + + result = MessageBroadcastProcessor.get_channel_metrics(ChannelTypes.WHATSAPP.value, bot) + assert result == [ + { + 'campaign_metrics': [ + { + 'retry_count': 0, + 'statuses': {'delivered': 1, 'failed': 1, 'read': 1, 'sent': 1} + }, + { + 'retry_count': 1, + 'statuses': {'delivered': 1, 'read': 1, 'sent': 1} + } + ], + 'campaign_id': reference_id + } + ] + @responses.activate @mongomock.patch(servers=(('localhost', 27017),)) @patch("kairon.shared.channels.whatsapp.bsp.dialog360.BSP360Dialog.get_partner_auth_token", autospec=True) @@ -3376,7 +3999,7 @@ def test_execute_message_broadcast_with_resend_broadcast_with_meta_error_codes_t {'text': 'Hello! As a part of our Kisan Suvidha program, I am dedicated to supporting farmers like you in maximizing your crop productivity and overall yield.\n\nI wanted to reach out to inquire if you require any assistance with your current farming activities. Our team of experts, including our skilled agronomists, are here to lend a helping hand wherever needed.', 'type': 'BODY'}, {'text': 'reply with STOP to unsubscribe', 'type': 'FOOTER'}, {'buttons': [{'text': 'Connect to Agronomist', 'type': 'QUICK_REPLY'}], 'type': 'BUTTONS'}], - 'event_id': event_id, 'template_name': 'brochure_pdf', 'language_code': 'hi', + 'event_id': event_id, 'template_exception': None, 'template_name': 'brochure_pdf', 'language_code': 'hi', 'namespace': '54500467_f322_4595_becd_419af88spm4', 'retry_count': 1, 'errors': []} logs[0][4].pop("timestamp") @@ -3928,7 +4551,7 @@ def test_execute_message_broadcast_with_resend_broadcast_multiple_times( {'text': 'Hello! As a part of our Kisan Suvidha program, I am dedicated to supporting farmers like you in maximizing your crop productivity and overall yield.\n\nI wanted to reach out to inquire if you require any assistance with your current farming activities. Our team of experts, including our skilled agronomists, are here to lend a helping hand wherever needed.', 'type': 'BODY'}, {'text': 'reply with STOP to unsubscribe', 'type': 'FOOTER'}, {'buttons': [{'text': 'Connect to Agronomist', 'type': 'QUICK_REPLY'}], 'type': 'BUTTONS'}], - 'event_id': event_id, 'template_name': 'brochure_pdf', 'language_code': 'hi', + 'event_id': event_id, 'template_exception': None, 'template_name': 'brochure_pdf', 'language_code': 'hi', 'namespace': '54500467_f322_4595_becd_419af88spm4', 'retry_count': 2, 'errors': []} logs[0][5].pop("timestamp") @@ -4487,7 +5110,7 @@ def test_execute_message_broadcast_with_resend_broadcast_log_chat_history( 'type': 'BODY'}, {'text': 'reply with STOP to unsubscribe', 'type': 'FOOTER'}, {'buttons': [{'text': 'Connect to Agronomist', 'type': 'QUICK_REPLY'}], 'type': 'BUTTONS'}], - 'event_id': event_id, 'template_name': 'brochure_pdf', 'language_code': 'hi', + 'event_id': event_id, 'template_exception': None, 'template_name': 'brochure_pdf', 'language_code': 'hi', 'namespace': '54500467_f322_4595_becd_419af88spm4', 'retry_count': 2, 'errors': []} logs[0][5].pop("timestamp")