Newer
Older
from odoo import _, api, fields, models
from odoo.exceptions import AccessError, ValidationError
from odoo.tools.safe_eval import safe_eval
from odoo.addons.redner.utils.formats import Formats
_logger = logging.getLogger(__name__)
class IrActionsReport(models.Model):
"""
Inherit from ir.action.report to allow customizing the template
file.
"""
_inherit = "ir.actions.report"
@api.constrains("redner_filetype", "report_type")
def _check_redner_filetype(self):
for report in self:
if report.report_type == "redner" and not report.redner_filetype:
raise ValidationError(
_("Field 'Output Format' is required for Redner report")
)
@api.constrains("redner_filetype", "attachment")
def _check_redner_attachment(self):
for report in self:
if report.report_type == "redner" and report.attachment:
ext = ".{ftype}".format(ftype=report.redner_filetype)
if ext not in report.attachment:
raise ValidationError(
_(
"The output format cannot be different from the "
'extension defined in "Save as attachment prefix".'
)
)
@api.model
def _get_redner_filetypes(self):
formats = Formats()
names = formats.get_known_format_names()
selections = []
for name in names:
description = name
if formats.get_format(name).native:
description = description + " " + _("(Native)")
selections.append((name, description))
return selections
report_type = fields.Selection(selection_add=[("redner", "redner")])
redner_multi_in_one = fields.Boolean(
damien.habets
committed
string="Multiple Records in a Single Redner Report",
help="If you execute a report on several records, "
"by default Odoo will generate a ZIP file that contains as many "
"files as selected records. If you enable this option, Odoo will "
"generate instead a single report for the selected records.",
)
redner_filetype = fields.Selection(
damien.habets
committed
selection="_get_redner_filetypes", string="Redner Output Format"
)
is_redner_native_format = fields.Boolean(
compute="_compute_is_redner_native_format"
)
redner_tmpl_id = fields.Many2one(
comodel_name="redner.template",
string="Redner template",
domain=[("active", "=", True)],
)
substitution_ids = fields.One2many(
comodel_name="redner.substitution",
inverse_name="ir_actions_report_id",
string="Substitution",
)
@api.depends("report_type", "redner_filetype")
def _compute_is_redner_native_format(self):
fmt = Formats()
for rec in self:
rec.is_redner_native_format = False
if not rec.report_type == "redner" or not rec.redner_filetype:
continue
filetype = rec.redner_filetype
rec.is_redner_native_format = fmt.get_format(filetype).native
"""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 get_report_metadata(self):
self.ensure_one()
metadata_values = {}
pformat = self.paperformat_id
if not pformat:
return metadata_values
# Get print-paper-size values
if pformat.format and pformat.orientation:
metadata_values["print-paper-size"] = "%s %s" % (
pformat.format,
pformat.orientation,
)
elif pformat.format and not pformat.orientation:
metadata_values["print-paper-size"] = "%s" % pformat.format
# Get print-paper-margin values: top | right | bottom | left
metadata_values["print-paper-margin"] = "%s %s %s %s" % (
pformat.margin_top,
pformat.margin_right,
pformat.margin_bottom,
pformat.margin_left,
)
return metadata_values
def get_report_data(self, res_id):
if not res_id:
return {}
conv = self.substitution_ids.filtered(
lambda r: r.depth == 0
).build_converter()
instance = self.env[self.model].browse(res_id)
return conv.odoo_to_message(instance)
@api.model
def get_from_report_name(self, report_name, report_type):
return self.search(
[
("report_name", "=", report_name),
("report_type", "=", report_type),
]
)
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)
)
return (
self.env["redner.report"]
.create({"ir_actions_report_id": self.id})
.create_report(res_ids, data)
)
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)
def _get_attachments(self, res_ids):
"""Return the report already generated for the given res_ids"""
self.ensure_one()
save_in_attachment = {}
if res_ids:
# Dispatch the records by ones having an attachment
Model = self.env[self.model]
record_ids = Model.browse(res_ids)
if self.attachment:
for record_id in record_ids:
attachment_id = self.retrieve_attachment(record_id)
if attachment_id:
save_in_attachment[record_id.id] = attachment_id
return save_in_attachment
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
239
240
241
242
243
244
245
246
247
def postprocess_redner_report(self, record, buffer):
"""Handle post processing during the report generation.
The basic behavior consists to create a new attachment containing
the document base64 encoded.
"""
self.ensure_one()
attachment_name = safe_eval(
self.attachment, {"object": record, "time": time}
)
if not attachment_name:
return None
if not attachment_name.endswith(
".{filetype}".format(filetype=self.redner_filetype)
):
return None
attachment_vals = {
"name": attachment_name,
"datas": base64.encodestring(buffer.getvalue()),
"res_model": self.model,
"res_id": record.id,
"type": "binary",
}
try:
self.env["ir.attachment"].create(attachment_vals)
except AccessError:
_logger.info(
"Cannot save report %r as attachment", attachment_vals["name"]
)
else:
_logger.info(
"The document %s is now saved in the database",
attachment_vals["name"],
)
return buffer