Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import logging
from odoo import api, fields, models
from odoo.tools import pycompat
from odoo.addons.mail.models.mail_template import *
_logger = logging.getLogger(__name__)
class IrActionsReport(models.Model):
"""
Inherit from ir.action.report to allow customizing the template
file.
"""
_inherit = "ir.actions.report"
report_type = fields.Selection(selection_add=[("redner", "redner")])
redner_tmpl_id = fields.Many2one(
comodel_name="redner.template",
string="Redner template",
domain=[("active", "=", True)],
)
redner_filetype = fields.Selection(
selection=[("html", "html"), ("pdf", "pdf")], string="Output Format"
)
substitution_ids = fields.One2many(
comodel_name="redner.substitution",
inverse_name="ir_actions_report_id",
string="Substitution",
)
@api.model
def render_post_process(self, html):
html = self._replace_local_links(html)
return html
@api.model
def render_template(
self, template_txt, model, res_ids, post_process=False
):
""" Render the given template text, replace mako expressions
``${expr}`` with the result of evaluating these expressions with
an evaluation context containing:
- ``user``: Model of the current user
- ``object``: record of the document record this mail is related to
- ``context``: the context passed to the mail composition wizard
:param str template_txt: the template text to render
:param str model: model name of the document record this mail is
related to.
:param int res_ids: list of ids of document records those mails are
related to.
"""
multi_mode = True
if isinstance(res_ids, pycompat.integer_types):
multi_mode = False
res_ids = [res_ids]
results = dict.fromkeys(res_ids, u"")
# try to load the template
try:
mako_env = (
mako_safe_template_env
if self.env.context.get("safe")
else mako_template_env
)
template = mako_env.from_string(tools.ustr(template_txt))
except Exception:
_logger.info(
"Failed to load template %r", template_txt, exc_info=True
)
return multi_mode and results or results[res_ids[0]]
# prepare template variables
records = self.env[model].browse(
it for it in res_ids if it
) # filter to avoid browsing [None]
res_to_rec = dict.fromkeys(res_ids, None)
for record in records:
res_to_rec[record.id] = record
variables = {
"format_date": lambda date, format=False, context=self._context: (
format_date(self.env, date, format)
),
"format_tz": (
lambda dt, tz=False, format=False, context=self._context: (
format_tz(self.env, dt, tz, format)
)
),
"format_amount": lambda amount, currency, context=self._context: (
format_amount(self.env, amount, currency)
),
"user": self.env.user,
"ctx": self._context, # context kw would clash with mako internals
}
for res_id, record in res_to_rec.items():
variables["object"] = record
try:
render_result = template.render(variables)
except Exception as e:
_logger.info(
"Failed to render template %r using values %r"
% (template, variables),
exc_info=True,
)
raise UserError(
_("Failed to render template %r using values %r")
% (template, variables)
+ "\n\n%s: %s" % (type(e).__name__, str(e))
)
if render_result == u"False":
render_result = u""
results[res_id] = render_result
if post_process:
for res_id, result in results.items():
results[res_id] = self.render_post_process(result)
return multi_mode and results or results[res_ids[0]]
@api.multi
def action_get_substitutions(self):
""" Call by: action button `Get Substitutions from Redner Report`
"""
self.ensure_one()
if self.redner_tmpl_id:
keywords = self.redner_tmpl_id.get_keywords()
# Get current substitutions
subs = self.substitution_ids.mapped("keyword") or []
values = []
for key in keywords:
# check to avoid duplicate keys
if key not in subs:
values.append((0, 0, {"keyword": key}))
self.write({"substitution_ids": values})
# remove obsolete keywords in substitutions model
if len(self.substitution_ids) > len(keywords):
deprecated_keys = self.substitution_ids.filtered(
lambda s: s.keyword not in keywords
)
if len(deprecated_keys) > 0:
deprecated_keys.unlink()
def _patch_report_values(self, res_id):
# get redner template values
import ipdb
ipdb.set_trace()
values_sent_to_redner = {}
for sub in self.substitution_ids:
value = self.render_template(sub.value, self.model, res_id)
if sub.deserialize:
value = ast.literal_eval(value)
values_sent_to_redner[sub.keyword] = value
try:
res = self.redner_tmpl_id.redner.templates.render(
self.redner_tmpl_id.redner_id, **values_sent_to_redner
)
except Exception as e:
if isinstance(e, ValidationError):
raise
raise ValidationError(
_(
"We received an unexpected error from redner server. "
"Please contact your administrator"
)
)
return res
def render_redner(self, res_ids, data):
self.ensure_one()
if self.report_type != "redner":
raise RuntimeError(
"redner rendition is only available on redner report.\n"
"(current: '{}', expected 'redner'".format(self.report_type)
)
res = {res_id: self._patch_report_values(res_id) for res_id in res_ids}
return True
def gen_report_download_filename(self, res_ids, data):
"""Override this function to change the name of the downloaded report
"""
self.ensure_one()
report = self.get_from_report_name(self.report_name, self.report_type)
if report.print_report_name and not len(res_ids) > 1:
obj = self.env[self.model].browse(res_ids)
return safe_eval(
report.print_report_name, {"object": obj, "time": time}
)
return "{}.{}".format(self.name, self.redner_filetype)