summaryrefslogtreecommitdiff
path: root/odoo/addons/base
diff options
context:
space:
mode:
authorRaf Geens <raf@odoo.com>2021-04-01 15:39:20 +0000
committerNicolas Lempereur <nle@odoo.com>2021-04-09 08:00:51 +0000
commit266a8e2a8abf936d5fbd45752ddf492d92e6a397 (patch)
treeabc4aae335fd72e87f16b1e65ad80d621e762e76 /odoo/addons/base
parentd050cf6d5891c06106aa68e2945e818cfd0b8455 (diff)
[FIX] base: Report which PDFs can't be read
PyPDF2 can't read some PDFs due to bugs, lack of fault-tolerance and not supporting some encryption schemes. When invoices are uploaded directly through the Invoices / Accounting app, that will fail for those files because it will try to read part of them. When invoices are uploaded through the Documents app, they're not read, which means the customer can end up in a situation where read and merge operations (like when printing a selection of original vendor bills) will fail. The structural solution for this is to replace PyPDF2 with a more capable library, like pikepdf: https://github.com/odoo/odoo/pull/64356 . This change is too impactful for stable, and there are compatibility concerns as well. A possible workaround is merging the PDFs we can and bundling the rest together in a zip file. This is possible on the level of just _merge_pdfs, but the PDF extension and mimetype are pretty hard-coded and the changes required to switch them to ZIP based on what happens in _merge_pdfs seem too impactful. Instead, this fix detects as early as possible if the PDFs can't be read and reports it to the user. The excluded PDFs can still be downloaded individually. In this way the user has a workaround and does not need to resort to trial and error to figure out which PDFs are causing the problem. Related tickets: 2359929, 2389679 closes odoo/odoo#68964 X-original-commit: 7a3fb09dbc68797522a3191a3358db296f279b36 Signed-off-by: Nicolas Lempereur (nle) <nle@odoo.com>
Diffstat (limited to 'odoo/addons/base')
-rw-r--r--odoo/addons/base/i18n/base.pot10
-rw-r--r--odoo/addons/base/models/ir_actions_report.py32
2 files changed, 41 insertions, 1 deletions
diff --git a/odoo/addons/base/i18n/base.pot b/odoo/addons/base/i18n/base.pot
index 6dd0694ecdf..adaf921547d 100644
--- a/odoo/addons/base/i18n/base.pot
+++ b/odoo/addons/base/i18n/base.pot
@@ -18821,6 +18821,16 @@ msgid ""
msgstr ""
#. module: base
+#: code:addons/base/models/ir_actions_report.py:0
+#, python-format
+msgid ""
+"Odoo is unable to merge the PDFs attached to the following records:\n"
+"%s\n"
+"\n"
+"Please exclude them from the selection to continue. It's possible to still retrieve those PDFs by selecting each of the affected records individually, which will avoid merging."
+msgstr ""
+
+#. module: base
#: model:ir.module.module,shortdesc:base.module_odoo_referral
msgid "Odoo referral program"
msgstr ""
diff --git a/odoo/addons/base/models/ir_actions_report.py b/odoo/addons/base/models/ir_actions_report.py
index 643f3f21bcf..b3d95eb5c32 100644
--- a/odoo/addons/base/models/ir_actions_report.py
+++ b/odoo/addons/base/models/ir_actions_report.py
@@ -690,6 +690,30 @@ class IrActionsReport(models.Model):
close_streams(streams)
return result
+ def _get_unreadable_pdfs(self, streams):
+ unreadable_streams = []
+
+ writer = PdfFileWriter()
+ for stream in streams:
+ try:
+ reader = PdfFileReader(stream)
+ writer.appendPagesFromReader(reader)
+ except utils.PdfReadError:
+ unreadable_streams.append(stream)
+
+ return unreadable_streams
+
+ def _raise_on_unreadable_pdfs(self, streams, stream_record):
+ unreadable_pdfs = self._get_unreadable_pdfs(streams)
+ if unreadable_pdfs:
+ records = [stream_record[s].name for s in unreadable_pdfs if s in stream_record]
+ raise UserError(_(
+ "Odoo is unable to merge the PDFs attached to the following records:\n"
+ "%s\n\n"
+ "Please exclude them from the selection to continue. It's possible to "
+ "still retrieve those PDFs by selecting each of the affected records "
+ "individually, which will avoid merging.") % "\n".join(records))
+
def _merge_pdfs(self, streams):
writer = PdfFileWriter()
for stream in streams:
@@ -741,6 +765,8 @@ class IrActionsReport(models.Model):
return self_sudo.with_context(context)._render_qweb_html(res_ids, data=data)[0]
save_in_attachment = OrderedDict()
+ # Maps the streams in `save_in_attachment` back to the records they came from
+ stream_record = dict()
if res_ids:
# Dispatch the records by ones having an attachment and ones requesting a call to
# wkhtmltopdf.
@@ -751,7 +777,9 @@ class IrActionsReport(models.Model):
for record_id in record_ids:
attachment = self_sudo.retrieve_attachment(record_id)
if attachment:
- save_in_attachment[record_id.id] = self_sudo._retrieve_stream_from_attachment(attachment)
+ stream = self_sudo._retrieve_stream_from_attachment(attachment)
+ save_in_attachment[record_id.id] = stream
+ stream_record[stream] = record_id
if not self_sudo.attachment_use or not attachment:
wk_record_ids += record_id
else:
@@ -763,6 +791,7 @@ class IrActionsReport(models.Model):
# - The report is not fully present in attachments.
if save_in_attachment and not res_ids:
_logger.info('The PDF report has been generated from attachments.')
+ self._raise_on_unreadable_pdfs(save_in_attachment.values(), stream_record)
return self_sudo._post_pdf(save_in_attachment), 'pdf'
if self.get_wkhtmltopdf_state() == 'install':
@@ -792,6 +821,7 @@ class IrActionsReport(models.Model):
set_viewport_size=context.get('set_viewport_size'),
)
if res_ids:
+ self._raise_on_unreadable_pdfs(save_in_attachment.values(), stream_record)
_logger.info('The PDF report has been generated for model: %s, records %s.' % (self_sudo.model, str(res_ids)))
return self_sudo._post_pdf(save_in_attachment, pdf_content=pdf_content, res_ids=html_ids), 'pdf'
return pdf_content, 'pdf'