[FIX] [base, account_edi_facturx]: Fix pdf export

There is an issue when exporting pdf using edi documents created before
the PDF/A commit. With the subtype now included, the system would try
to use the subtype given by the ir.attachment which would not be formated
as expected by the pdf file format.

The attachment may get neutered by the ORM, so we may have to force
the mimetype when embedding it.

This fix in two parts will allow to force a subtype when adding an
attachment into a pdf, as well as parse the subtype of ir.attachment
to give them the right format.

xxx/xxx should become /xxx#2Fxxx

opw-2714040

closes odoo/odoo#81898

X-original-commit: 880d7a1c8474a3bee4fd05474788fbd4a63f4ae7
Signed-off-by: Laurent Smet <las@odoo.com>
This commit is contained in:
Nicolas (vin)
2021-12-24 13:11:50 +00:00
parent 9ffb0143d0
commit 08e9798d74
2 changed files with 26 additions and 15 deletions
@@ -36,7 +36,7 @@ class AccountEdiFormat(models.Model):
if not edi_document.attachment_id:
return
pdf_writer.embed_odoo_attachment(edi_document.attachment_id)
pdf_writer.embed_odoo_attachment(edi_document.attachment_id, subtype='application/xml')
if not pdf_writer.is_pdfa and str2bool(self.env['ir.config_parameter'].sudo().get_param('edi.use_pdfa', 'False')):
try:
pdf_writer.convert_to_pdfa()
@@ -75,7 +75,7 @@ class AccountEdiFormat(models.Model):
return self.env['ir.attachment'].create({
'name': 'factur-x.xml',
'raw': xml_content.encode(),
'mimetype': '/application#2Fxml'
'mimetype': 'application/xml'
})
def _is_facturx(self, filename, tree):
+24 -13
View File
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import io
import re
from datetime import datetime
from hashlib import md5
@@ -18,6 +19,8 @@ from odoo.tools.misc import file_open
_logger = getLogger(__name__)
DEFAULT_PDF_DATETIME_FORMAT = "D:%Y%m%d%H%M%S+00'00'"
REGEX_SUBTYPE_UNFORMATED = re.compile(r'^\w+/[\w-]+$')
REGEX_SUBTYPE_FORMATED = re.compile(r'^/\w+#2F[\w-]+$')
# make sure values are unwrapped by calling the specialized __getitem__
@@ -95,16 +98,16 @@ class OdooPdfFileReader(PdfFileReader):
try:
file_path = self.trailer["/Root"].get("/Names", {}).get("/EmbeddedFiles", {}).get("/Names")
if not file_path:
return []
for i in range(0, len(file_path), 2):
attachment = file_path[i+1].getObject()
yield (attachment["/F"], attachment["/EF"]["/F"].getObject().getData())
except Exception:
# malformed pdf (i.e. invalid xref page)
return []
if not file_path:
return []
for i in range(0, len(file_path), 2):
attachment = file_path[i+1].getObject()
yield (attachment["/F"], attachment["/EF"]["/F"].getObject().getData())
class OdooPdfFileWriter(PdfFileWriter):
@@ -117,21 +120,29 @@ class OdooPdfFileWriter(PdfFileWriter):
self._reader = None
self.is_pdfa = False
def addAttachment(self, name, data, subtype=""):
def addAttachment(self, name, data, subtype=None):
"""
Add an attachment to the pdf. Supports adding multiple attachment, while respecting PDF/A rules.
:param name: The name of the attachement
:param data: The data of the attachement
:param subtype: The mime-type of the attachement. This is required by PDF/A, but not essential otherwise.
It should take the form of "/xxx%2Fxxx". E.g. for "text/xml": "/text%2Fxml"
It should take the form of "/xxx#2Fxxx". E.g. for "text/xml": "/text#2Fxml"
"""
if subtype == 'application/xml':
subtype = '/application#2Fxml'
adapted_subtype = subtype
if subtype:
# If we receive the subtype in an 'unformated' (mimetype) format, we'll try to convert it to a pdf-valid one
if REGEX_SUBTYPE_UNFORMATED.match(subtype):
adapted_subtype = '/' + subtype.replace('/', '#2F')
if not REGEX_SUBTYPE_FORMATED.match(adapted_subtype):
# The subtype still does not match the correct format, so we will not add it to the document
_logger.warning("Attempt to add an attachment with the incorrect subtype '%s'. The subtype will be ignored.", subtype)
adapted_subtype = ''
attachment = self._create_attachment_object({
'filename': name,
'content': data,
'subtype': subtype,
'subtype': adapted_subtype,
})
if self._root_object.get('/Names') and self._root_object['/Names'].get('/EmbeddedFiles'):
names_array = self._root_object["/Names"]["/EmbeddedFiles"]["/Names"]
@@ -163,9 +174,9 @@ class OdooPdfFileWriter(PdfFileWriter):
NameObject("/AF"): attachment_array
})
def embed_odoo_attachment(self, attachment):
def embed_odoo_attachment(self, attachment, subtype=None):
assert attachment, "embed_odoo_attachment cannot be called without attachment."
self.addAttachment(attachment.name, attachment.raw, attachment.mimetype)
self.addAttachment(attachment.name, attachment.raw, subtype=subtype or attachment.mimetype)
def cloneReaderDocumentRoot(self, reader):
super().cloneReaderDocumentRoot(reader)