Newer
Older
##############################################################################
#
# Redner Odoo module
aronabencherif.diatta@xcg.africa
committed
# Copyright © 2016, 2024 XCG Consulting <https://xcg-consulting.fr>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import logging
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from ..redner import Redner
LANGUAGE_MJML_MUSTACHE = "text/mjml|mustache"
DEFAULT_LANGUAGE = LANGUAGE_MJML_MUSTACHE
class RednerTemplate(models.Model):
_name = "redner.template"
damien.habets
committed
_description = "Redner Template"
aronabencherif.diatta@xcg.africa
committed
use_redner = fields.Boolean(
string="Use redner",
default=True,
help="Indicate whether this redner template is synchronized with redner",
readonly=True,
)
name = fields.Char(
string="Name",
required=True,
help="This is a name of template mjml redner",
)
body = fields.Text(
string="Template remote Id",
translate=True,
help="Code for the mjml redner template must be added here",
)
slug = fields.Char(string="Slug")
active = fields.Boolean(
string="Active",
default=True,
help=(
"If unchecked, it will allow you to hide the "
"template without removing it."
),
)
is_mjml = fields.Boolean(
string="Is MJML",
default=True,
help="set to false if your template doesn't contain MJML",
)
detected_keywords = fields.Text(
string="Variables", readonly=True, compute="_compute_keywords"
selection=[
("text/html|mustache", "HTML + mustache"),
(LANGUAGE_MJML_MUSTACHE, "MJML + mustache"),
(
"application/vnd.oasis.opendocument.text|od+mustache",
"OpenDocument + mustache",
),
],
default="text/html|mustache",
required=True,
help="templating language",
)
redner_id = fields.Char(string="Redner ID", readonly=True)
locale_id = fields.Many2one(
comodel_name="res.lang",
string="Locale",
help="Optional translation language (ISO code).",
)
template_data = fields.Binary("Libreoffice Template")
@property
def redner(self):
"""Try to avoid Redner instance to be over created"""
# Bypass security rules when reading these configuration params. By
# default, only some administrators have access to that model.
config_model = self.env["ir.config_parameter"].sudo()
config_model.get_param("redner.api_key"),
config_model.get_param("redner.server_url"),
config_model.get_param("redner.account"),
int(config_model.get_param("redner.timeout", default="20")),
@api.model_create_multi
def create(self, vals_list):
"""Overwrite create to create redner template"""
for vals in vals_list:
# Prepare template params according to the selected language.
# Use template data field if the selected language is "od";
# otherwise the body field is used.
produces, language = vals.get("language", DEFAULT_LANGUAGE).split("|")
body, body_format = (
(vals.get("template_data", ""), "base64")
if language == "od+mustache"
else (vals.get("body"), "text")
)
aronabencherif.diatta@xcg.africa
committed
if not vals.get("use_redner"):
return super().create(vals_list)
# We depend on the API for consistency here
# So raised error should not result with a created template
vals["redner_id"] = self.redner.templates.account_template_add(
language=language,
body=body,
name=vals.get("name"),
produces=produces,
body_format=body_format,
version=fields.Datetime.to_string(fields.Datetime.now()),
)
def write(self, vals):
"""Overwrite write to update redner template"""
# Similar to the "send_to_rednerd_server" method; not worth factoring
# out.
# We depend on the API for consistency here
# So raised error should not result with an updated template
if "name" in vals:
self.ensure_one()
redner_id = self.redner_id
vals["redner_id"] = vals["name"]
produces, language = record.language.split("|")
(record.template_data.decode(), "base64")
if language == "od+mustache"
if "name" not in vals:
redner_id = record.redner_id
record.redner.templates.account_template_update(
template_id=redner_id,
language=language,
body=body,
body_format=body_format,
version=fields.Datetime.to_string(record.write_date),
_("Failed to update render template, %s") % e
) from e
def unlink(self):
"""Overwrite unlink to delete redner template"""
# We do NOT depend on the API for consistency here
# So raised error should not result block template deletion
try:
self.redner.templates.account_template_delete(self.redner_id)
except Exception:
pass
aronabencherif.diatta@xcg.africa
committed
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
def synchronize_template_with_redner(self):
"""This method is used to join a template without
redner with redner"""
self.ensure_one()
if not self.use_redner:
produces, language = self.language.split("|")
# Check if template data is of type bytes before decoding
if isinstance(self.template_data or "", bytes):
template_data = self.template_data.decode() # utf-8 by default
body, body_format = (
(template_data or "", "base64")
if language == "od+mustache"
else (self.body, "text")
)
# We depend on the API for consistency here
# So raised error should not result with a created template
redner_id = self.redner.templates.account_template_add(
language=language,
body=body,
name=self.name,
produces=produces,
body_format=body_format,
version=fields.Datetime.to_string(fields.Datetime.now()),
)
self.write({"redner_id": redner_id, "use_redner": True})
else:
raise ValidationError(_("Template has already been synced with redner !"))
def copy(self, default=None):
self.ensure_one()
default = dict(default or {}, name=_("%s (copy)") % self.name)
record.detected_keywords = "\n".join(record.template_varlist_fetch())
varlist = self.template_varlist_fetch()
for name in varlist:
while "." in name:
name = name[: name.rfind(".")]
if name not in varlist:
varlist.append(name)
varlist.sort()
return varlist
@api.model
def template_varlist_fetch(self):
"""Retrieve the list of variables present in the template."""
try:
if not self.redner_id:
return []
return self.redner.templates.account_template_varlist(self.redner_id)
logger.warning("Failed to fetch account template varlist: %s", e)
def send_to_rednerd_server(self):
"""Send templates to the rednerd server. Useful when you have
existing templates you want to register onto a new rednerd server (or
with a new user).
"""
for record in self:
# Similar to the "write" method override; not worth factoring out.
templates = record.redner.templates
produces, language = record.language.split("|")
(record.template_data.decode(), "base64")
if language == "od+mustache"
template_id=record.redner_id,
language=language,
body=body,
name=record.name,
version=fields.Datetime.to_string(record.write_date),
)
except ValidationError:
record.redner_id = templates.account_template_add(
language=language,
body=body,
name=record.name,
version=fields.Datetime.to_string(fields.Datetime.now()),