# Part of Odoo. See LICENSE file for full copyright and licensing details. from datetime import datetime from odoo.addons.base.tests.test_ir_cron import CronMixinCase from odoo.addons.test_whatsapp.tests.common import WhatsAppFullCase from odoo.addons.whatsapp.tests.common import MockIncomingWhatsApp, WhatsAppCommon from odoo.tests import tagged, users @tagged('wa_composer') class WhatsAppComposerCase(WhatsAppCommon): @classmethod def setUpClass(cls): super().setUpClass() # test records for sending messages cls.test_base_records = cls.env['whatsapp.test.base'].create([ { 'country_id': cls.env.ref('base.in').id, 'name': 'Recipient-IN', 'phone': "+91 12345 67891", }, { 'country_id': cls.env.ref('base.be').id, 'name': 'Recipient-BE', 'phone': "0456001122", } ]) # templates (considered as approved) cls.template_basic, cls.template_dynamic, cls.template_dynamic_cplx = cls.env['whatsapp.template'].create([ { 'body': 'Hello World', 'model_id': cls.env['ir.model']._get_id('whatsapp.test.base'), 'name': 'Test-basic', 'status': 'approved', 'wa_account_id': cls.whatsapp_account.id, }, { 'body': 'Hello {{1}}', 'model_id': cls.env['ir.model']._get_id('whatsapp.test.base'), 'name': 'Test-dynamic', 'status': 'approved', 'variable_ids': [ (5, 0, 0), (0, 0, {'name': '{{1}}', 'line_type': 'body', 'field_type': 'field', 'demo_value': 'Customer', 'field_name': 'name'}), ], 'wa_account_id': cls.whatsapp_account.id, }, { 'body': '''Hello I am {{1}}, Here my mobile number: {{2}}, You are coming from {{3}}. Welcome to {{4}} office''', 'model_id': cls.env['ir.model']._get_id('whatsapp.test.base'), 'name': 'Test-dynamic-complex', 'status': 'approved', 'variable_ids': [ (5, 0, 0), (0, 0, {'name': "{{1}}", 'line_type': "body", 'field_type': "user_name", 'demo_value': "Jigar"}), (0, 0, {'name': "{{2}}", 'line_type': "body", 'field_type': "user_mobile", 'demo_value': "+91 12345 12345"}), (0, 0, {'name': "{{3}}", 'line_type': "body", 'field_type': "field", 'demo_value': "sample country", 'field_name': 'country_id'}), (0, 0, {'name': "{{4}}", 'line_type': "body", 'field_type': "free_text", 'demo_value': "Odoo In"}), ], 'wa_account_id': cls.whatsapp_account.id, } ]) @tagged('wa_composer') class WhatsAppComposerRendering(WhatsAppComposerCase, WhatsAppFullCase, CronMixinCase, MockIncomingWhatsApp): """ Test rendering based on various templates, notably using static or dynamic content, headers, ... """ def test_assert_initial_data(self): """ Ensure base data for tests, to ease understanding them """ self.assertEqual(self.company_admin.country_id, self.env.ref('base.us')) self.assertEqual(self.user_admin.country_id, self.env.ref('base.be')) @users('employee') def test_composer_tpl_base(self): """ Test basic sending, with template, without rendering """ template = self.template_basic.with_user(self.env.user) test_record = self.test_base_records[0] composer = self._instanciate_wa_composer_from_records(template, test_record) with self.mockWhatsappGateway(): composer.action_send_whatsapp_template() self.assertWAMessageFromRecord( test_record, fields_values={ 'body': f'
{template.body}
', }, ) @users('employee') def test_composer_tpl_base_rendering(self): """ Test sending with template and rendering """ free_text = 'Odoo In' template = self.template_dynamic_cplx.with_user(self.env.user) test_record = self.test_base_records[0] composer = self._instanciate_wa_composer_from_records(template, test_record) with self.mockWhatsappGateway(): composer.action_send_whatsapp_template() self.assertWAMessageFromRecord( test_record, fields_values={ 'body': f'Hello I am {self.env.user.name},
Here my mobile number: {self.env.user.mobile},'
f'
You are coming from {test_record.country_id.name}.
Welcome to {free_text} office
Hello, your dates are here {expected_formatted_date}
', }, ) @users('employee') def test_composer_tpl_base_rendering_selection(self): """ Specific case involving selections """ # template setup self.template_basic.write({ 'body': 'Base model is here ({{1}}) and selection through m2o is here ({{2}})', 'variable_ids': [ (5, 0, 0), (0, 0, { 'name': '{{1}}', 'line_type': 'body', 'field_type': 'field', 'demo_value': 'Selection Demo Value 1', 'field_name': 'selection_field' }), (0, 0, { 'name': '{{2}}', 'line_type': 'body', 'field_type': 'field', 'demo_value': 'Selection Demo Value 4', 'field_name': 'selection_id.selection_field' }) ], }) test_template = self.template_basic.with_user(self.env.user) # record setup with selection field test_selection = self.env['whatsapp.test.selection'].create({ 'selection_field': 'selection_key_4', }) test_base_selection_id = self.env['whatsapp.test.base'].create({ "country_id": self.env.ref("base.be").id, "name": "Recipient-IN", "phone": "+91 12345 67891", "selection_id": test_selection.id, }) # Check whether selection field values are sent and not keys composer = self._instanciate_wa_composer_from_records(test_template, test_base_selection_id) with self.mockWhatsappGateway(): composer.action_send_whatsapp_template() self.assertWAMessageFromRecord( test_base_selection_id, fields_values={ 'body': 'Base model is here (Selection Value 1) and selection through m2o is here (Selection Value 4)
', }, ) @users('employee') def test_composer_tpl_header_attachments(self): """ Send a template with a header attachment set through the composer.""" doc_attach_clone = self.document_attachment.copy({'name': 'pdf_clone.pdf'}) self.template_dynamic.write({ 'header_attachment_ids': [(6, 0, self.document_attachment.ids)], 'header_type': 'document', }) test_record = self.test_base_records[0].with_env(self.env) composer = self._instanciate_wa_composer_from_records(self.template_dynamic, test_record) composer.attachment_id = doc_attach_clone with self.mockWhatsappGateway(): composer.action_send_whatsapp_template() self.assertWAMessageFromRecord( test_record, attachment_values={ 'name': 'pdf_clone.pdf', }, fields_values={ 'body': f'Hello {test_record.name}
', }, ) @users('employee') def test_composer_tpl_header_report_resend(self): """ In case of resend and reports, it has to be generated again, so it deserves its own test. """ # template setup with report self.template_basic.write({ 'header_type': 'document', 'report_id': self.test_wa_base_report.id, }) test_template = self.template_basic.with_user(self.env.user) test_record = self.test_base_records[0].with_env(self.env) composer = self._instanciate_wa_composer_from_records(test_template, test_record) with self.mockWhatsappGateway(): composer.action_send_whatsapp_template() self.assertWAMessageFromRecord( test_record, attachment_values={ 'name': f'TestReport for {test_record.name}.html', }, fields_values={ 'body': 'Hello World
', }, ) message = self._new_wa_msg old_attachment_ids = message.mail_message_id.attachment_ids # fail the message using the webhook self._receive_message_update( account=self.whatsapp_account, display_phone_number=self.test_base_records[0].phone, extra_value={ "statuses": [{ "id": message.msg_uid, "status": "failed", "errors": [{ "code": 131000, "title": "Message failed to send due to an unknown error." }], }], }, ) # retry the failed message with self.capture_triggers('whatsapp.ir_cron_send_whatsapp_queue') as capt: message.button_resend() self.assertEqual(len(capt.records), 1) with self.mockWhatsappGateway(): message._send_message() self._assertWAMessage( message, attachment_values={ 'name': f'TestReport for {test_record.name}.html', }, fields_values={ 'body': 'Hello World
', }, ) self.assertFalse(old_attachment_ids.exists()) self.assertTrue(message.mail_message_id.attachment_ids) @users('employee') def test_composer_tpl_header_various(self): """ Test sending with rendering, including header """ sample_text = 'Header Free Text' base_variable_ids = [ (0, 0, {'name': '{{1}}', 'line_type': 'body', 'field_type': 'field', 'demo_value': 'Customer', 'field_name': 'name'}), ] for header_type, template_upd_values, exp_att_values, exp_field_values in zip( ( 'text', 'text', 'text', 'text', 'image', 'video', 'document', 'document', 'document', 'location', ), ( # text {'header_text': 'Header World'}, {'header_text': 'Header {{1}}', 'variable_ids': [ (5, 0), (0, 0, {'name': '{{1}}', 'line_type': 'header', 'field_type': 'free_text', 'demo_value': sample_text}) ] + base_variable_ids, }, {'header_text': 'Header {{1}}', 'variable_ids': [ (5, 0), (0, 0, {'name': '{{1}}', 'line_type': 'header', 'field_type': 'user_name', 'demo_value': sample_text}) ] + base_variable_ids, }, {'header_text': 'Header {{1}}', 'variable_ids': [ (5, 0), (0, 0, {'name': '{{1}}', 'line_type': 'header', 'field_type': 'user_mobile', 'demo_value': sample_text}) ] + base_variable_ids, }, # image {'header_attachment_ids': [(6, 0, self.image_attachment.ids)]}, # video {'header_attachment_ids': [(6, 0, self.video_attachment.ids)]}, # document {'header_attachment_ids': [(6, 0, self.document_attachment.ids)]}, {'report_id': self.test_wa_base_report.id}, { 'header_attachment_ids': [(6, 0, self.document_attachment.ids)], 'report_id': self.test_wa_base_report.id, }, # location {'variable_ids': [ (0, 0, {'name': 'name', 'line_type': 'location', 'demo_value': 'LocName'}), (0, 0, {'name': 'address', 'line_type': 'location', 'demo_value': 'Gandhinagar, Gujarat'}), (0, 0, {'name': 'latitude', 'line_type': 'location', 'demo_value': '23.192985'}), (0, 0, {'name': 'longitude', 'line_type': 'location', 'demo_value': '72.6366633'})], }, ), ( # text {}, {}, {}, {}, # image {'name': self.image_attachment.name, 'datas': self.image_attachment.datas}, # video {'name': self.video_attachment.name, 'datas': self.video_attachment.datas}, # document {'name': self.document_attachment.name, 'datas': self.document_attachment.datas}, { 'name': f'TestReport for {self.test_base_records[0].name}.html', 'raw': b'External report for %s
External report for %s
Header World
Hello {self.test_base_records[0].name}
'}, {'body': f'Header {sample_text}
Hello {self.test_base_records[0].name}
'}, {'body': f'Header {self.env.user.name}
Hello {self.test_base_records[0].name}
'}, {'body': f'Header {self.env.user.mobile}
Hello {self.test_base_records[0].name}
'}, # image {}, # video {}, # document {}, {}, {}, # location {}, ), ): with self.subTest(header_type=header_type): self.template_dynamic.write({ 'header_attachment_ids': [(5, 0, 0)], 'header_type': header_type, 'report_id': False, **template_upd_values, }) template = self.template_dynamic.with_user(self.env.user) composer = self._instanciate_wa_composer_from_records(template, self.test_base_records[0]) with self.mockWhatsappGateway(): composer.action_send_whatsapp_template() fields_values = { 'body': f'Hello {self.test_base_records[0].name}
', } fields_values.update(**(exp_field_values or {})) self.assertWAMessageFromRecord( self.test_base_records[0], attachment_values=exp_att_values, fields_values=fields_values, )