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.

74 lines
2.7 KiB

  1. # Copyright 2020 Creu Blanca
  2. # Copyright 2020 Ecosoft Co., Ltd.
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  4. import logging
  5. from io import BytesIO
  6. from odoo import _, fields, models
  7. from odoo.exceptions import ValidationError
  8. from odoo.tools.safe_eval import safe_eval
  9. _logger = logging.getLogger(__name__)
  10. try:
  11. from PyPDF2 import PdfFileReader, PdfFileWriter
  12. except ImportError as err:
  13. _logger.debug(err)
  14. class IrActionsReport(models.Model):
  15. _inherit = "ir.actions.report"
  16. encrypt = fields.Selection(
  17. [("manual", "Manual Input Password"), ("auto", "Auto Generated Password")],
  18. string="Encryption",
  19. help="* Manual Input Password: allow user to key in password on the fly. "
  20. "This option available only on document print action.\n"
  21. "* Auto Generated Password: system will auto encrypt password when PDF "
  22. "created, based on provided python syntax.",
  23. )
  24. encrypt_password = fields.Char(
  25. help="Python code syntax to gnerate password.",
  26. )
  27. def _render_qweb_pdf(self, res_ids=None, data=None):
  28. document, ttype = super(IrActionsReport, self)._render_qweb_pdf(
  29. res_ids=res_ids, data=data
  30. )
  31. password = self._get_pdf_password(res_ids[:1])
  32. document = self._encrypt_pdf(document, password)
  33. return document, ttype
  34. def _get_pdf_password(self, res_id):
  35. encrypt_password = False
  36. if self.encrypt == "manual":
  37. # If use document print action, report_download() is called,
  38. # but that can't pass context (encrypt_password) here.
  39. # As such, file will be encrypted by report_download() again.
  40. # --
  41. # Following is used just in case when context is passed in.
  42. encrypt_password = self._context.get("encrypt_password", False)
  43. elif self.encrypt == "auto" and self.encrypt_password:
  44. obj = self.env[self.model].browse(res_id)
  45. try:
  46. encrypt_password = safe_eval(self.encrypt_password, {"object": obj})
  47. except Exception:
  48. raise ValidationError(
  49. _("Python code used for encryption password is invalid.\n%s")
  50. % self.encrypt_password
  51. )
  52. return encrypt_password
  53. def _encrypt_pdf(self, data, password):
  54. if not password:
  55. return data
  56. output_pdf = PdfFileWriter()
  57. in_buff = BytesIO(data)
  58. pdf = PdfFileReader(in_buff)
  59. output_pdf.appendPagesFromReader(pdf)
  60. output_pdf.encrypt(password)
  61. buff = BytesIO()
  62. output_pdf.write(buff)
  63. return buff.getvalue()
  64. def _get_readable_fields(self):
  65. return super()._get_readable_fields() | {"encrypt"}