odoo-addon-mail-gateway-whatsapp 16.0.1.0.0.11__py3-none-any.whl → 16.0.1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. odoo/addons/mail_gateway_whatsapp/README.rst +13 -1
  2. odoo/addons/mail_gateway_whatsapp/__init__.py +1 -0
  3. odoo/addons/mail_gateway_whatsapp/__manifest__.py +4 -1
  4. odoo/addons/mail_gateway_whatsapp/i18n/mail_gateway_whatsapp.pot +590 -0
  5. odoo/addons/mail_gateway_whatsapp/models/__init__.py +1 -0
  6. odoo/addons/mail_gateway_whatsapp/models/mail_gateway.py +61 -1
  7. odoo/addons/mail_gateway_whatsapp/models/mail_gateway_whatsapp.py +24 -3
  8. odoo/addons/mail_gateway_whatsapp/models/mail_whatsapp_template.py +193 -0
  9. odoo/addons/mail_gateway_whatsapp/readme/CONFIGURE.rst +1 -0
  10. odoo/addons/mail_gateway_whatsapp/readme/CONTRIBUTORS.rst +3 -0
  11. odoo/addons/mail_gateway_whatsapp/readme/ROADMAP.rst +4 -0
  12. odoo/addons/mail_gateway_whatsapp/security/ir.model.access.csv +2 -0
  13. odoo/addons/mail_gateway_whatsapp/security/security.xml +8 -0
  14. odoo/addons/mail_gateway_whatsapp/static/description/index.html +41 -19
  15. odoo/addons/mail_gateway_whatsapp/tests/__init__.py +1 -0
  16. odoo/addons/mail_gateway_whatsapp/tests/test_mail_gateway_whatsapp.py +75 -1
  17. odoo/addons/mail_gateway_whatsapp/tests/test_mail_whatsapp_template.py +170 -0
  18. odoo/addons/mail_gateway_whatsapp/tools/__init__.py +1 -0
  19. odoo/addons/mail_gateway_whatsapp/tools/const.py +75 -0
  20. odoo/addons/mail_gateway_whatsapp/views/mail_gateway.xml +28 -0
  21. odoo/addons/mail_gateway_whatsapp/views/mail_whatsapp_template_views.xml +154 -0
  22. odoo/addons/mail_gateway_whatsapp/wizards/__init__.py +1 -0
  23. odoo/addons/mail_gateway_whatsapp/wizards/mail_compose_gateway_message.py +30 -0
  24. odoo/addons/mail_gateway_whatsapp/wizards/mail_compose_gateway_message.xml +31 -0
  25. odoo/addons/mail_gateway_whatsapp/wizards/whatsapp_composer.py +53 -1
  26. odoo/addons/mail_gateway_whatsapp/wizards/whatsapp_composer.xml +11 -1
  27. {odoo_addon_mail_gateway_whatsapp-16.0.1.0.0.11.dist-info → odoo_addon_mail_gateway_whatsapp-16.0.1.1.0.dist-info}/METADATA +14 -2
  28. {odoo_addon_mail_gateway_whatsapp-16.0.1.0.0.11.dist-info → odoo_addon_mail_gateway_whatsapp-16.0.1.1.0.dist-info}/RECORD +30 -21
  29. {odoo_addon_mail_gateway_whatsapp-16.0.1.0.0.11.dist-info → odoo_addon_mail_gateway_whatsapp-16.0.1.1.0.dist-info}/WHEEL +1 -1
  30. {odoo_addon_mail_gateway_whatsapp-16.0.1.0.0.11.dist-info → odoo_addon_mail_gateway_whatsapp-16.0.1.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,170 @@
1
+ # Copyright 2024 Tecnativa - Carlos López
2
+ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3
+
4
+ import json
5
+ from unittest.mock import patch
6
+
7
+ import requests
8
+
9
+ from odoo.exceptions import UserError
10
+ from odoo.tests.common import tagged
11
+
12
+ from odoo.addons.mail_gateway.tests.common import MailGatewayTestCase
13
+
14
+
15
+ @tagged("-at_install", "post_install")
16
+ class TestMailWhatsAppTemplate(MailGatewayTestCase):
17
+ @classmethod
18
+ def setUpClass(cls):
19
+ super().setUpClass()
20
+ cls.gateway = cls.env["mail.gateway"].create(
21
+ {
22
+ "name": "gateway",
23
+ "gateway_type": "whatsapp",
24
+ "token": "token",
25
+ "whatsapp_security_key": "key",
26
+ "webhook_secret": "MY-SECRET",
27
+ "member_ids": [(4, cls.env.user.id)],
28
+ }
29
+ )
30
+ cls.new_template_response_data = {
31
+ "id": "018273645",
32
+ "status": "APPROVED",
33
+ }
34
+ cls.new_template_full_response_data = {
35
+ "name": "new_template",
36
+ "parameter_format": "POSITIONAL",
37
+ "components": [
38
+ {"type": "HEADER", "format": "TEXT", "text": "Header 1"},
39
+ {"type": "BODY", "text": "Body 1"},
40
+ {"type": "FOOTER", "text": "Footer changed"},
41
+ ],
42
+ "language": "es",
43
+ "status": "APPROVED",
44
+ "category": "MARKETING",
45
+ "id": "018273645",
46
+ }
47
+ cls.template_1_data = {
48
+ "name": "test_odoo_1",
49
+ "parameter_format": "POSITIONAL",
50
+ "components": [
51
+ {"type": "HEADER", "format": "TEXT", "text": "Header 1"},
52
+ {"type": "BODY", "text": "Body 1"},
53
+ {"type": "FOOTER", "text": "Footer 1"},
54
+ ],
55
+ "language": "es",
56
+ "status": "APPROVED",
57
+ "category": "MARKETING",
58
+ "id": "1234567890",
59
+ }
60
+ cls.template_2_data = {
61
+ "name": "test_with_buttons",
62
+ "parameter_format": "POSITIONAL",
63
+ "components": [
64
+ {"type": "HEADER", "format": "TEXT", "text": "Header 2"},
65
+ {"type": "BODY", "text": "Body 2"},
66
+ {
67
+ "type": "BUTTONS",
68
+ "buttons": [{"type": "QUICK_REPLY", "text": "Button 1"}],
69
+ },
70
+ ],
71
+ "language": "es",
72
+ "status": "APPROVED",
73
+ "category": "MARKETING",
74
+ "sub_category": "CUSTOM",
75
+ "id": "0987654321",
76
+ }
77
+ cls.templates_download = {
78
+ "data": [cls.template_1_data, cls.template_2_data],
79
+ }
80
+
81
+ def _make_meta_requests(self, url, json_data, status_code=200):
82
+ """
83
+ Simulate a fake request to the Meta API:
84
+ :param json_data: Dictionary with the json data to return
85
+ :param status_code: Status code expected
86
+ :returns requests.Response object
87
+ """
88
+ response = requests.Response()
89
+ response.status_code = status_code
90
+ response._content = json.dumps(json_data).encode()
91
+ response.url = url
92
+ response.headers["Content-Type"] = "application/json"
93
+ return response
94
+
95
+ def test_download_templates(self):
96
+ def _patch_request_post(url, *args, **kwargs):
97
+ if "message_templates" in url:
98
+ return self._make_meta_requests(url, self.templates_download)
99
+ return original_get(url, *args, **kwargs)
100
+
101
+ with self.assertRaisesRegex(
102
+ UserError, "WhatsApp Account is required to import templates"
103
+ ):
104
+ self.gateway.button_import_whatsapp_template()
105
+ self.gateway.whatsapp_account_id = "123456"
106
+ original_get = requests.get
107
+ with patch.object(requests, "get", _patch_request_post):
108
+ self.gateway.button_import_whatsapp_template()
109
+ self.assertEqual(self.gateway.whatsapp_template_count, 2)
110
+ template_1 = self.gateway.whatsapp_template_ids.filtered(
111
+ lambda t: t.template_uid == "1234567890"
112
+ )
113
+ self.assertTrue(template_1.is_supported)
114
+ self.assertEqual(template_1.template_name, "test_odoo_1")
115
+ self.assertEqual(template_1.category, "marketing")
116
+ self.assertEqual(template_1.language, "es")
117
+ self.assertEqual(template_1.state, "approved")
118
+ self.assertEqual(template_1.header, "Header 1")
119
+ self.assertEqual(template_1.body, "Body 1")
120
+ self.assertEqual(template_1.footer, "Footer 1")
121
+ template_2 = self.gateway.whatsapp_template_ids.filtered(
122
+ lambda t: t.template_uid == "0987654321"
123
+ )
124
+ self.assertFalse(template_2.is_supported)
125
+ self.assertEqual(template_2.template_name, "test_with_buttons")
126
+ self.assertEqual(template_2.category, "marketing")
127
+ self.assertEqual(template_2.language, "es")
128
+ self.assertEqual(template_2.state, "approved")
129
+ self.assertEqual(template_2.header, "Header 2")
130
+ self.assertEqual(template_2.body, "Body 2")
131
+ self.assertFalse(template_2.footer)
132
+ self.assertFalse(template_2.is_supported)
133
+
134
+ def test_export_template(self):
135
+ def _patch_request_post(url, *args, **kwargs):
136
+ if "message_templates" in url:
137
+ return self._make_meta_requests(url, self.new_template_response_data)
138
+ return original_post(url, *args, **kwargs)
139
+
140
+ def _patch_request_get(url, *args, **kwargs):
141
+ if "018273645" in url:
142
+ return self._make_meta_requests(
143
+ url, self.new_template_full_response_data
144
+ )
145
+ return original_get(url, *args, **kwargs)
146
+
147
+ original_post = requests.post
148
+ original_get = requests.get
149
+ self.gateway.whatsapp_account_id = "123456"
150
+ new_template = self.env["mail.whatsapp.template"].create(
151
+ {
152
+ "name": "New template",
153
+ "category": "marketing",
154
+ "language": "es",
155
+ "header": "Header 1",
156
+ "body": "Body 1",
157
+ "gateway_id": self.gateway.id,
158
+ }
159
+ )
160
+ self.assertEqual(new_template.template_name, "new_template")
161
+ with patch.object(requests, "post", _patch_request_post):
162
+ new_template.button_export_template()
163
+ self.assertTrue(new_template.template_uid)
164
+ self.assertTrue(new_template.is_supported)
165
+ self.assertFalse(new_template.footer)
166
+ self.assertEqual(new_template.state, "approved")
167
+ # sync templates, footer should be updated
168
+ with patch.object(requests, "get", _patch_request_get):
169
+ new_template.button_sync_template()
170
+ self.assertEqual(new_template.footer, "Footer changed")
@@ -0,0 +1 @@
1
+ from . import const
@@ -0,0 +1,75 @@
1
+ # https://developers.facebook.com/docs/whatsapp/business-management-api/message-templates/supported-languages # noqa: B950
2
+ # res.lang not matching with supported languages(iso codes)
3
+ supported_languages = [
4
+ ("af", "Afrikaans"),
5
+ ("sq", "Albanian"),
6
+ ("ar", "Arabic"),
7
+ ("az", "Azerbaijani"),
8
+ ("bn", "Bengali"),
9
+ ("bg", "Bulgarian"),
10
+ ("ca", "Catalan"),
11
+ ("zh_CN", "Chinese (CHN)"),
12
+ ("zh_HK", "Chinese (HKG)"),
13
+ ("zh_TW", "Chinese (TAI)"),
14
+ ("hr", "Croatian"),
15
+ ("cs", "Czech"),
16
+ ("da", "Danish"),
17
+ ("nl", "Dutch"),
18
+ ("en", "English"),
19
+ ("en_GB", "English (UK)"),
20
+ ("en_US", "English (US)"),
21
+ ("et", "Estonian"),
22
+ ("fil", "Filipino"),
23
+ ("fi", "Finnish"),
24
+ ("fr", "French"),
25
+ ("ka", "Georgian"),
26
+ ("de", "German"),
27
+ ("el", "Greek"),
28
+ ("gu", "Gujarati"),
29
+ ("ha", "Hausa"),
30
+ ("he", "Hebrew"),
31
+ ("hi", "Hindi"),
32
+ ("hu", "Hungarian"),
33
+ ("id", "Indonesian"),
34
+ ("ga", "Irish"),
35
+ ("it", "Italian"),
36
+ ("ja", "Japanese"),
37
+ ("kn", "Kannada"),
38
+ ("kk", "Kazakh"),
39
+ ("rw_RW", "Kinyarwanda"),
40
+ ("ko", "Korean"),
41
+ ("ky_KG", "Kyrgyz (Kyrgyzstan)"),
42
+ ("lo", "Lao"),
43
+ ("lv", "Latvian"),
44
+ ("lt", "Lithuanian"),
45
+ ("mk", "Macedonian"),
46
+ ("ms", "Malay"),
47
+ ("ml", "Malayalam"),
48
+ ("mr", "Marathi"),
49
+ ("nb", "Norwegian"),
50
+ ("fa", "Persian"),
51
+ ("pl", "Polish"),
52
+ ("pt_BR", "Portuguese (BR)"),
53
+ ("pt_PT", "Portuguese (POR)"),
54
+ ("pa", "Punjabi"),
55
+ ("ro", "Romanian"),
56
+ ("ru", "Russian"),
57
+ ("sr", "Serbian"),
58
+ ("sk", "Slovak"),
59
+ ("sl", "Slovenian"),
60
+ ("es", "Spanish"),
61
+ ("es_AR", "Spanish (ARG)"),
62
+ ("es_ES", "Spanish (SPA)"),
63
+ ("es_MX", "Spanish (MEX)"),
64
+ ("sw", "Swahili"),
65
+ ("sv", "Swedish"),
66
+ ("ta", "Tamil"),
67
+ ("te", "Telugu"),
68
+ ("th", "Thai"),
69
+ ("tr", "Turkish"),
70
+ ("uk", "Ukrainian"),
71
+ ("ur", "Urdu"),
72
+ ("uz", "Uzbek"),
73
+ ("vi", "Vietnamese"),
74
+ ("zu", "Zulu"),
75
+ ]
@@ -7,7 +7,35 @@
7
7
  <field name="model">mail.gateway</field>
8
8
  <field name="inherit_id" ref="mail_gateway.mail_gateway_form_view" />
9
9
  <field name="arch" type="xml">
10
+ <xpath expr="//header" position="inside">
11
+ <button
12
+ type="object"
13
+ name="button_import_whatsapp_template"
14
+ string="Download Templates"
15
+ attrs="{'invisible': [('gateway_type', '!=', 'whatsapp')]}"
16
+ icon="fa-download"
17
+ />
18
+ </xpath>
19
+ <xpath expr="//div[@name='button_box']" position="inside">
20
+ <button
21
+ type="action"
22
+ name="%(mail_gateway_whatsapp.action_mail_whatsapp_template_gateway)d"
23
+ attrs="{'invisible': [('gateway_type', '!=', 'whatsapp')]}"
24
+ class="oe_stat_button"
25
+ icon="fa-whatsapp"
26
+ >
27
+ <field
28
+ name="whatsapp_template_count"
29
+ string="Templates"
30
+ widget="statinfo"
31
+ />
32
+ </button>
33
+ </xpath>
10
34
  <field name="webhook_user_id" position="after">
35
+ <field
36
+ name="whatsapp_account_id"
37
+ attrs="{'invisible': [('gateway_type', '!=', 'whatsapp')]}"
38
+ />
11
39
  <field
12
40
  name="whatsapp_security_key"
13
41
  attrs="{'invisible': [('gateway_type', '!=', 'whatsapp')]}"
@@ -0,0 +1,154 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <odoo>
3
+
4
+ <record id="view_mail_whatsapp_template_tree" model="ir.ui.view">
5
+ <field name="name">view.mail.whatsapp.template.tree</field>
6
+ <field name="model">mail.whatsapp.template</field>
7
+ <field name="arch" type="xml">
8
+ <tree decoration-danger="not is_supported and template_uid">
9
+ <field name="name" />
10
+ <field name="template_name" />
11
+ <field name="template_uid" optional="show" />
12
+ <field name="category" />
13
+ <field name="language" />
14
+ <field name="gateway_id" />
15
+ <field
16
+ name="company_id"
17
+ options="{'no_create': True}"
18
+ groups="base.group_multi_company"
19
+ />
20
+ <field
21
+ name="state"
22
+ decoration-success="state == 'approved'"
23
+ decoration-danger="state == 'rejected'"
24
+ widget="badge"
25
+ />
26
+ <field name="is_supported" optional="show" />
27
+ </tree>
28
+ </field>
29
+ </record>
30
+
31
+ <record id="view_mail_whatsapp_template_form" model="ir.ui.view">
32
+ <field name="name">view.mail.whatsapp.template.form</field>
33
+ <field name="model">mail.whatsapp.template</field>
34
+ <field name="arch" type="xml">
35
+ <form>
36
+ <header>
37
+ <button
38
+ string="Export Template"
39
+ name="button_export_template"
40
+ type="object"
41
+ class="oe_highlight"
42
+ attrs="{'invisible': [('template_uid', '!=', False)]}"
43
+ />
44
+ <button
45
+ string="Sync Template"
46
+ name="button_sync_template"
47
+ type="object"
48
+ attrs="{'invisible': [('template_uid', '=', False)]}"
49
+ />
50
+ <button
51
+ string="Back to draft"
52
+ name="button_back2draft"
53
+ type="object"
54
+ attrs="{'invisible': [('state', '=', 'draft')]}"
55
+ />
56
+ <field
57
+ name="state"
58
+ widget="statusbar"
59
+ statusbar_visible="draft,pending,approved"
60
+ />
61
+ </header>
62
+ <div
63
+ class="alert alert-danger"
64
+ role="alert"
65
+ attrs="{'invisible': ['|',('is_supported', '=', True), ('template_uid', '=', False)]}"
66
+ >
67
+ This template is not supported because has <strong
68
+ >variables</strong> or <strong>buttons</strong>.
69
+ </div>
70
+ <sheet>
71
+ <div class="oe_title">
72
+ <label for="name" />
73
+ <h1>
74
+ <field
75
+ name="name"
76
+ placeholder="Name"
77
+ attrs="{'readonly': [('state', '!=', 'draft')]}"
78
+ />
79
+ </h1>
80
+ </div>
81
+ <group>
82
+ <group>
83
+ <field
84
+ name="gateway_id"
85
+ attrs="{'readonly': [('state', '!=', 'draft')]}"
86
+ options="{'no_create': True}"
87
+ />
88
+ <field
89
+ name="category"
90
+ attrs="{'readonly': [('state', '!=', 'draft')]}"
91
+ />
92
+ <field
93
+ name="language"
94
+ attrs="{'readonly': [('state', '!=', 'draft')]}"
95
+ />
96
+ </group>
97
+ <group>
98
+ <field
99
+ name="header"
100
+ attrs="{'readonly': [('state', '!=', 'draft')]}"
101
+ />
102
+ <field
103
+ name="footer"
104
+ attrs="{'readonly': [('state', '!=', 'draft')]}"
105
+ />
106
+ <field name="template_name" />
107
+ <field name="template_uid" />
108
+ <field
109
+ name="company_id"
110
+ options="{'no_create': True}"
111
+ groups="base.group_multi_company"
112
+ />
113
+ <field name="is_supported" invisible="1" />
114
+ </group>
115
+ </group>
116
+ <notebook>
117
+ <page name="body" string="Body">
118
+ <field
119
+ name="body"
120
+ attrs="{'readonly': [('state', '!=', 'draft')]}"
121
+ />
122
+ </page>
123
+ </notebook>
124
+ </sheet>
125
+ </form>
126
+ </field>
127
+ </record>
128
+
129
+ <record id="view_mail_whatsapp_template_search" model="ir.ui.view">
130
+ <field name="name">view.mail.whatsapp.template.search</field>
131
+ <field name="model">mail.whatsapp.template</field>
132
+ <field name="arch" type="xml">
133
+ <search>
134
+ <field name="name" />
135
+ <field name="gateway_id" />
136
+ <filter
137
+ name="group_by_state"
138
+ string="State"
139
+ context="{'group_by': 'state'}"
140
+ />
141
+ </search>
142
+ </field>
143
+ </record>
144
+
145
+ <record id="action_mail_whatsapp_template_gateway" model="ir.actions.act_window">
146
+ <field name="name">WhatsApp Templates</field>
147
+ <field name="type">ir.actions.act_window</field>
148
+ <field name="res_model">mail.whatsapp.template</field>
149
+ <field name="view_mode">tree,form</field>
150
+ <field name="domain">[('gateway_id', '=', active_id)]</field>
151
+ <field name="context">{'default_gateway_id': active_id}</field>
152
+ </record>
153
+
154
+ </odoo>
@@ -1 +1,2 @@
1
+ from . import mail_compose_gateway_message
1
2
  from . import whatsapp_composer
@@ -0,0 +1,30 @@
1
+ # Copyright 2024 Tecnativa - Carlos López
2
+ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3
+
4
+ import markupsafe
5
+
6
+ from odoo import api, fields, models
7
+
8
+
9
+ class MailComposeGatewayMessage(models.TransientModel):
10
+ _inherit = "mail.compose.gateway.message"
11
+
12
+ whatsapp_template_id = fields.Many2one(
13
+ "mail.whatsapp.template",
14
+ domain="""[
15
+ ('state', '=', 'approved'),
16
+ ('is_supported', '=', True)
17
+ ]""",
18
+ )
19
+
20
+ @api.onchange("whatsapp_template_id")
21
+ def onchange_whatsapp_template_id(self):
22
+ if self.whatsapp_template_id:
23
+ self.body = markupsafe.Markup(self.whatsapp_template_id.body)
24
+
25
+ def _action_send_mail(self, auto_commit=False):
26
+ if self.whatsapp_template_id:
27
+ self = self.with_context(whatsapp_template_id=self.whatsapp_template_id.id)
28
+ return super(MailComposeGatewayMessage, self)._action_send_mail(
29
+ auto_commit=auto_commit
30
+ )
@@ -0,0 +1,31 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <!-- Copyright 2024 Tecnativa - Carlos López
3
+ License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
4
+ <odoo>
5
+
6
+ <record model="ir.ui.view" id="mail_compose_gateway_message_form_view">
7
+ <field name="model">mail.compose.gateway.message</field>
8
+ <field
9
+ name="inherit_id"
10
+ ref="mail_gateway.mail_compose_gateway_message_form_view"
11
+ />
12
+ <field name="arch" type="xml">
13
+ <xpath expr="//field[@name='wizard_channel_ids']" position="after">
14
+ <field
15
+ name="whatsapp_template_id"
16
+ options="{'no_create': True, 'no_open': True}"
17
+ />
18
+ </xpath>
19
+ <xpath expr="//field[@name='template_id']" position="attributes">
20
+ <attribute
21
+ name="attrs"
22
+ >{'invisible': [('whatsapp_template_id', '!=', False)]}</attribute>
23
+ </xpath>
24
+ <xpath expr="//field[@name='attachment_ids']" position="attributes">
25
+ <attribute
26
+ name="attrs"
27
+ >{'invisible': [('whatsapp_template_id', '!=', False)]}</attribute>
28
+ </xpath>
29
+ </field>
30
+ </record>
31
+ </odoo>
@@ -1,5 +1,7 @@
1
1
  # Copyright 2022 CreuBlanca
2
+ # Copyright 2024 Tecnativa - Carlos López
2
3
  # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
4
+ from datetime import datetime
3
5
 
4
6
  from odoo import _, api, fields, models
5
7
  from odoo.exceptions import UserError
@@ -17,7 +19,57 @@ class WhatsappComposer(models.TransientModel):
17
19
  gateway_id = fields.Many2one(
18
20
  "mail.gateway", domain=[("gateway_type", "=", "whatsapp")], required=True
19
21
  )
22
+ template_id = fields.Many2one(
23
+ "mail.whatsapp.template",
24
+ domain="""[
25
+ ('gateway_id', '=', gateway_id),
26
+ ('state', '=', 'approved'),
27
+ ('is_supported', '=', True)
28
+ ]""",
29
+ )
20
30
  body = fields.Text("Message")
31
+ is_required_template = fields.Boolean(compute="_compute_is_required_template")
32
+
33
+ @api.depends("res_model", "res_id", "number_field_name", "gateway_id")
34
+ def _compute_is_required_template(self):
35
+ MailMessage = self.env["mail.message"]
36
+ for wizard in self:
37
+ if (
38
+ not wizard.res_model
39
+ or not wizard.gateway_id
40
+ or not wizard.number_field_name
41
+ ):
42
+ wizard.is_required_template = False
43
+ continue
44
+ record = self.env[wizard.res_model].browse(wizard.res_id)
45
+ is_required_template = True
46
+ channel = record._whatsapp_get_channel(
47
+ wizard.number_field_name, wizard.gateway_id
48
+ )
49
+ if channel:
50
+ last_message = MailMessage.search(
51
+ [
52
+ ("gateway_type", "=", "whatsapp"),
53
+ ("model", "=", channel._name),
54
+ ("res_id", "=", channel.id),
55
+ ],
56
+ order="date desc",
57
+ limit=1,
58
+ )
59
+ if last_message:
60
+ delta = (datetime.now() - last_message.date).total_seconds() / 3600
61
+ if delta < 24.0:
62
+ is_required_template = False
63
+ wizard.is_required_template = is_required_template
64
+
65
+ @api.onchange("gateway_id")
66
+ def onchange_gateway_id(self):
67
+ self.template_id = False
68
+
69
+ @api.onchange("template_id")
70
+ def onchange_template_id(self):
71
+ if self.template_id:
72
+ self.body = self.template_id.body
21
73
 
22
74
  @api.model
23
75
  def default_get(self, fields):
@@ -33,7 +85,7 @@ class WhatsappComposer(models.TransientModel):
33
85
  if not record:
34
86
  return
35
87
  channel = record._whatsapp_get_channel(self.number_field_name, self.gateway_id)
36
- channel.message_post(
88
+ channel.with_context(whatsapp_template_id=self.template_id.id).message_post(
37
89
  body=self.body, subtype_xmlid="mail.mt_comment", message_type="comment"
38
90
  )
39
91
 
@@ -13,11 +13,21 @@
13
13
  name="gateway_id"
14
14
  attrs="{'invisible': [('find_gateway', '=', False)]}"
15
15
  />
16
+ <field
17
+ name="template_id"
18
+ attrs="{'required': [('is_required_template', '=', True)]}"
19
+ options="{'no_create': True, 'no_open': True}"
20
+ />
16
21
  <field name="find_gateway" invisible="1" />
17
22
  <field name="res_model" invisible="1" />
18
23
  <field name="res_id" invisible="1" />
19
24
  <field name="number_field_name" invisible="1" />
20
- <field name="body" />
25
+ <field name="is_required_template" invisible="1" />
26
+ <field
27
+ name="body"
28
+ attrs="{'readonly': [('template_id', '!=', False)]}"
29
+ force_save="1"
30
+ />
21
31
  </group>
22
32
  <footer>
23
33
  <button
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: odoo-addon-mail_gateway_whatsapp
3
- Version: 16.0.1.0.0.11
3
+ Version: 16.0.1.1.0
4
4
  Summary: Set a gateway for whatsapp
5
5
  Home-page: https://github.com/OCA/social
6
6
  Author: Creu Blanca, Dixmit, Odoo Community Association (OCA)
@@ -24,7 +24,7 @@ Mail Whatsapp Gateway
24
24
  !! This file is generated by oca-gen-addon-readme !!
25
25
  !! changes will be overwritten. !!
26
26
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
27
- !! source digest: sha256:7e8914aa79754fb57cdfe774336f8ffe4c6784994839b64e09cf393ed7c2aa4a
27
+ !! source digest: sha256:70475641a2c7498a1ee67811eadb397e33c33435cdd2efb8edce729026ad09c4
28
28
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
29
29
 
30
30
  .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
@@ -79,6 +79,7 @@ In order to make it you must follow this steps:
79
79
 
80
80
  * Use the Meta App authentication key as `Token` field
81
81
  * Use the Meta App Phone Number ID as `Whatsapp from Phone` field
82
+ * Use the Meta Account Business ID as `Whatsapp account` field (only if you need sync templates)
82
83
  * Write your own `Webhook key`
83
84
  * Use the Application Secret Key on `Whatsapp Security Key`. It will be used in order to validate the data
84
85
  * Press the `Integrate Webhook Key`. In this case, it will not integrate it, we need to make it manually
@@ -96,6 +97,14 @@ Usage
96
97
  2. Wait until someone starts a conversation.
97
98
  3. Now you will be able to respond and receive messages to this person.
98
99
 
100
+ Known issues / Roadmap
101
+ ======================
102
+
103
+ **WhatsApp templates**
104
+
105
+ * Add support for `Variables`
106
+ * Add support for `Buttons`
107
+
99
108
  Bug Tracker
100
109
  ===========
101
110
 
@@ -120,6 +129,9 @@ Contributors
120
129
 
121
130
  * Olga Marco <olga.marco@creublanca.es>
122
131
  * Enric Tobella <etobella@creublanca.es>
132
+ * `Tecnativa <https://www.tecnativa.com>`_:
133
+
134
+ * Carlos Lopez
123
135
 
124
136
  Other credits
125
137
  ~~~~~~~~~~~~~