161 lines
7.0 KiB
Python
161 lines
7.0 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from werkzeug.urls import url_join
|
|
|
|
from odoo import api, models, fields, _
|
|
from odoo.exceptions import UserError, ValidationError
|
|
|
|
|
|
class WhatsAppTemplateVariable(models.Model):
|
|
_name = 'whatsapp.template.variable'
|
|
_description = 'WhatsApp Template Variable'
|
|
_order = 'line_type desc, name, id'
|
|
|
|
name = fields.Char(string="Placeholder", required=True)
|
|
button_id = fields.Many2one('whatsapp.template.button', ondelete='cascade')
|
|
wa_template_id = fields.Many2one(comodel_name='whatsapp.template', required=True, ondelete='cascade')
|
|
model = fields.Char(string="Model Name", related='wa_template_id.model')
|
|
|
|
line_type = fields.Selection([
|
|
('button', 'Button'),
|
|
('header', 'Header'),
|
|
('location', 'Location'),
|
|
('body', 'Body')], string="Variable location", required=True)
|
|
field_type = fields.Selection([
|
|
('user_name', 'User Name'),
|
|
('user_mobile', 'User Mobile'),
|
|
('free_text', 'Free Text'),
|
|
('portal_url', 'Portal Link'),
|
|
('field', 'Field of Model')], string="Type", default='free_text', required=True)
|
|
field_name = fields.Char(string="Field")
|
|
demo_value = fields.Char(string="Sample Value", default="Sample Value", required=True)
|
|
|
|
_sql_constraints = [
|
|
(
|
|
'name_type_template_unique',
|
|
'UNIQUE(name, line_type, wa_template_id, button_id)',
|
|
'Variable names must be unique for a given template'
|
|
),
|
|
]
|
|
|
|
@api.constrains("field_type", "demo_value", "button_id")
|
|
def _check_demo_values(self):
|
|
if self.filtered(lambda var: var.field_type == 'free_text' and not var.demo_value):
|
|
raise ValidationError(_('Free Text template variables must have a demo value.'))
|
|
|
|
@api.constrains("field_type", "field_name")
|
|
def _check_field_name(self):
|
|
is_system = self.env.user.has_group('base.group_system')
|
|
failing = self.browse()
|
|
to_check = self.filtered(lambda v: v.field_type == "field")
|
|
missing = to_check.filtered(lambda v: not v.field_name)
|
|
if missing:
|
|
raise ValidationError(
|
|
_("Field template variables %(var_names)s must be associated with a field.",
|
|
var_names=", ".join(missing.mapped("name")),
|
|
)
|
|
)
|
|
for variable in to_check:
|
|
model = self.env[variable.model]
|
|
if not is_system:
|
|
if not model.has_access('read'):
|
|
model_description = self.env['ir.model']._get(variable.model).display_name
|
|
raise ValidationError(
|
|
_("You can not select field of %(model)s.", model=model_description)
|
|
)
|
|
safe_fields = model._get_whatsapp_safe_fields() if hasattr(model, '_get_whatsapp_safe_fields') else []
|
|
if variable.field_name not in safe_fields:
|
|
raise ValidationError(
|
|
_("You are not allowed to use field %(field)s, contact your administrator.",
|
|
field=variable.field_name)
|
|
)
|
|
try:
|
|
model._find_value_from_field_path(variable.field_name)
|
|
except UserError:
|
|
failing += variable
|
|
if failing:
|
|
model_description = self.env['ir.model']._get(failing.mapped('model')[0]).display_name
|
|
raise ValidationError(
|
|
_("Variables %(field_names)s do not seem to be valid field path for model %(model_name)s.",
|
|
field_names=", ".join(failing.mapped("field_name")),
|
|
model_name=model_description,
|
|
)
|
|
)
|
|
|
|
@api.constrains('name')
|
|
def _check_name(self):
|
|
for variable in self:
|
|
if variable.line_type == 'location' and variable.name not in {'name', 'address', 'latitude', 'longitude'}:
|
|
raise ValidationError(
|
|
_("Location variable should be 'name', 'address', 'latitude' or 'longitude'. Cannot parse '%(placeholder)s'",
|
|
placeholder=variable.name))
|
|
elif variable.line_type == 'button' and variable.name != variable.button_id.name:
|
|
raise ValidationError(_("Dynamic button variable name must be the same as its respective button's name"))
|
|
elif variable.line_type in ('header', 'body') and not variable._extract_variable_index():
|
|
raise ValidationError(
|
|
_('Template variable should be in format {{number}}. Cannot parse "%(placeholder)s"',
|
|
placeholder=variable.name))
|
|
|
|
@api.constrains('button_id', 'line_type')
|
|
def _check_button_id(self):
|
|
for variable in self:
|
|
if variable.line_type == 'button' and not variable.button_id:
|
|
raise ValidationError(_('Button variables must be linked to a button.'))
|
|
|
|
@api.depends('line_type', 'name')
|
|
def _compute_display_name(self):
|
|
type_names = dict(self._fields["line_type"]._description_selection(self.env))
|
|
for variable in self:
|
|
type_name = type_names[variable.line_type or 'body']
|
|
variable.display_name = type_name if variable.line_type == 'header' else f'{type_name} - {variable.name}'
|
|
|
|
@api.onchange('model')
|
|
def _onchange_model_id(self):
|
|
self.field_name = False
|
|
|
|
@api.onchange('field_type')
|
|
def _onchange_field_type(self):
|
|
if self.field_type != 'field':
|
|
self.field_name = False
|
|
|
|
def _get_variables_value(self, record):
|
|
value_by_name = {}
|
|
user = self.env.user
|
|
for variable in self:
|
|
if variable.field_type == 'user_name':
|
|
value = user.name
|
|
elif variable.field_type == 'user_mobile':
|
|
value = user.mobile
|
|
elif variable.field_type == 'field':
|
|
value = variable._find_value_from_field_chain(record)
|
|
elif variable.field_type == 'portal_url':
|
|
portal_url = record._whatsapp_get_portal_url()
|
|
value = url_join(variable.get_base_url(), (portal_url or ''))
|
|
else:
|
|
value = variable.demo_value
|
|
|
|
value_str = value and str(value) or ''
|
|
if variable.button_id:
|
|
value_by_name[f"button-{variable.button_id.name}"] = value_str
|
|
else:
|
|
value_by_name[f"{variable.line_type}-{variable.name}"] = value_str
|
|
|
|
return value_by_name
|
|
|
|
# ------------------------------------------------------------
|
|
# TOOLS
|
|
# ------------------------------------------------------------
|
|
|
|
def _find_value_from_field_chain(self, record):
|
|
"""Get the value of field, returning display_name(s) if the field is a model."""
|
|
self.ensure_one()
|
|
return record.sudo(False)._find_value_from_field_path(self.field_name)
|
|
|
|
def _extract_variable_index(self):
|
|
""" Extract variable index, located between '{{}}' markers. """
|
|
self.ensure_one()
|
|
try:
|
|
return int(self.name.lstrip('{{').rstrip('}}'))
|
|
except ValueError:
|
|
return None
|