OCA reporting engine fork for dev and update.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
6.6 KiB

  1. # Copyright 2014 Guewen Baconnier (Camptocamp SA)
  2. # Copyright 2013-2014 Nicolas Bessi (Camptocamp SA)
  3. # Copyright 2020 NextERP Romania SRL
  4. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  5. from lxml import etree
  6. from odoo import _, api, fields, models
  7. from odoo.exceptions import ValidationError
  8. from odoo.tools.safe_eval import safe_eval
  9. class CommentTemplate(models.AbstractModel):
  10. _name = "comment.template"
  11. _description = (
  12. "base.comment.template to put header and footer "
  13. "in reports based on created comment templates"
  14. )
  15. def get_comment_template_records(
  16. self, position="before_lines", company_id=False, partner_id=False
  17. ):
  18. self.ensure_one()
  19. if not company_id:
  20. company_id = self.env.company.id
  21. present_model_id = self.env["ir.model"].search([("model", "=", self._name)])
  22. default_dom = [
  23. ("model_ids", "in", present_model_id.id),
  24. ("position", "=", position),
  25. ]
  26. lang = False
  27. if partner_id and "partner_id" in self._fields:
  28. default_dom += [
  29. "|",
  30. ("partner_ids", "=", False),
  31. ("partner_ids", "in", partner_id),
  32. ]
  33. lang = self.env["res.partner"].browse(partner_id).lang
  34. if company_id and "company_id" in self._fields:
  35. if partner_id and "partner_id" in self._fields:
  36. default_dom.insert(-3, "&")
  37. default_dom += [
  38. "|",
  39. ("company_id", "=", company_id),
  40. ("company_id", "=", False),
  41. ]
  42. templates = self.env["base.comment.template"].search(
  43. default_dom, order="priority"
  44. )
  45. if lang:
  46. templates = templates.with_context({"lang": lang})
  47. return templates
  48. def get_comment_template(
  49. self, position="before_lines", company_id=False, partner_id=False
  50. ):
  51. """ Method that is called from report xml and is returning the
  52. position template as a html if exists
  53. """
  54. self.ensure_one()
  55. templates = self.get_comment_template_records(
  56. position=position, company_id=company_id, partner_id=partner_id
  57. )
  58. template = False
  59. if templates:
  60. for templ in templates:
  61. if self in self.search(safe_eval(templ.domain or "[]")):
  62. template = templ
  63. break
  64. if not template:
  65. return ""
  66. return self.env["mail.template"]._render_template(
  67. template.text, self._name, self.id, post_process=True
  68. )
  69. class BaseCommentTemplate(models.Model):
  70. """Comment templates printed on reports"""
  71. _name = "base.comment.template"
  72. _description = "Comments Template"
  73. active = fields.Boolean(default=True)
  74. position = fields.Selection(
  75. string="Position on document",
  76. selection=[("before_lines", "Before lines"), ("after_lines", "After lines")],
  77. required=True,
  78. default="before_lines",
  79. help="This field allows to select the position of the comment on reports.",
  80. )
  81. name = fields.Char(
  82. string="Name",
  83. translate=True,
  84. required=True,
  85. help="Name/description of this comment template",
  86. )
  87. text = fields.Html(
  88. string="Template",
  89. translate=True,
  90. required=True,
  91. sanitize=False,
  92. help="This is the text template that will be inserted into reports.",
  93. )
  94. company_id = fields.Many2one(
  95. "res.company",
  96. string="Company",
  97. ondelete="cascade",
  98. index=True,
  99. help="If set, the comment template will be available only for the selected "
  100. "company.",
  101. )
  102. partner_ids = fields.Many2many(
  103. comodel_name="res.partner",
  104. string="Partner",
  105. ondelete="cascade",
  106. help="If set, the comment template will be available only for the selected "
  107. "partner.",
  108. )
  109. model_ids = fields.Many2many(
  110. comodel_name="ir.model",
  111. string="IR Model",
  112. ondelete="cascade",
  113. required=True,
  114. help="This comment template will be available on this models. "
  115. "You can see here only models allowed to set the coment template.",
  116. )
  117. domain = fields.Char(
  118. "Filter Domain",
  119. required=True,
  120. default="[]",
  121. help="This comment template will be available only for objects "
  122. "that satisfy the condition",
  123. )
  124. priority = fields.Integer(
  125. default=10, copy=False, help="the highest priority = the smallest number",
  126. )
  127. @api.constrains("domain", "priority", "model_ids", "position")
  128. def _check_partners_in_company_id(self):
  129. templates = self.search([])
  130. for record in self:
  131. other_template_same_models_and_priority = templates.filtered(
  132. lambda t: t.priority == record.priority
  133. and set(record.model_ids).intersection(record.model_ids)
  134. and t.domain == record.domain
  135. and t.position == record.position
  136. and t.id != record.id
  137. )
  138. if other_template_same_models_and_priority:
  139. raise ValidationError(
  140. _(
  141. "There are other records with same models, priority, "
  142. "domain and position."
  143. )
  144. )
  145. @api.model
  146. def fields_view_get(
  147. self, view_id=None, view_type="form", toolbar=False, submenu=False
  148. ):
  149. # modify the form view of base_commnent_template
  150. # Add domain on model_id to get only models that have a report set
  151. # and those whom have inherited this model
  152. res = super().fields_view_get(
  153. view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu
  154. )
  155. if view_type == "form":
  156. doc = etree.XML(res["arch"])
  157. for node in doc.xpath("//field[@name='model_ids']"):
  158. report_models = self.env["ir.actions.report"].search([]).mapped("model")
  159. model_ids = (
  160. self.env["ir.model"]
  161. .search(
  162. [
  163. ("model", "in", report_models),
  164. ("is_comment_template", "=", True),
  165. "!",
  166. ("name", "=like", "ir.%"),
  167. ]
  168. )
  169. .ids
  170. )
  171. model_filter = "[('id','in'," + str(model_ids) + ")]"
  172. node.set("domain", model_filter)
  173. res["arch"] = etree.tostring(doc, encoding="unicode")
  174. return res