[FIX] account: origianl bills with encrypted PDF
To reproduce ============ - Accounting > Vendor Bills > create a vendor bill and upload the pdf (attached on this ticket) - back to list view, select the created bill and print the original bills a user error is raised Problem ======= when trying to add the banner we read the PDF and we found out that it's encrypted so we raise the error Solution ======== if the PDF is encrypted, we log warning and carry on downloading the original bill. opw-3221796 closes odoo/odoo#118134 X-original-commit: 900418d9bc7bd260cac67769be77f8e818eed814 Signed-off-by: John Laterre (jol) <jol@odoo.com> Signed-off-by: abla001 <abla@odoo.com>
This commit is contained in:
@@ -2,9 +2,9 @@
|
||||
from collections import OrderedDict
|
||||
|
||||
try:
|
||||
from PyPDF2.errors import PdfStreamError
|
||||
from PyPDF2.errors import PdfStreamError, PdfReadError
|
||||
except ImportError:
|
||||
from PyPDF2.utils import PdfStreamError
|
||||
from PyPDF2.utils import PdfStreamError, PdfReadError
|
||||
|
||||
from odoo import models, _
|
||||
from odoo.exceptions import UserError
|
||||
@@ -36,7 +36,7 @@ class IrActionsReport(models.Model):
|
||||
record = self.env[attachment.res_model].browse(attachment.res_id)
|
||||
try:
|
||||
stream = pdf.add_banner(stream, record.name, logo=True)
|
||||
except (ValueError, PdfStreamError):
|
||||
except (ValueError, PdfStreamError, PdfReadError, TypeError):
|
||||
record._message_log(body=_(
|
||||
"There was an error when trying to add the banner to the original PDF.\n"
|
||||
"Please make sure the source file is valid."
|
||||
|
||||
@@ -38,3 +38,4 @@ from . import test_payment_term
|
||||
from . import test_account_payment_register
|
||||
from . import test_tour
|
||||
from . import test_early_payment_discount
|
||||
from . import test_ir_actions_report
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import base64
|
||||
import io
|
||||
|
||||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools import pdf
|
||||
from odoo.tests import tagged
|
||||
from odoo.tools import file_open
|
||||
|
||||
from PyPDF2 import PdfFileReader, PdfFileWriter
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestIrActionsReport(AccountTestInvoicingCommon):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.file = file_open('base/tests/minimal.pdf', 'rb').read()
|
||||
self.minimal_reader_buffer = io.BytesIO(self.file)
|
||||
self.minimal_pdf_reader = pdf.OdooPdfFileReader(self.minimal_reader_buffer)
|
||||
|
||||
def test_download_one_corrupted_pdf(self):
|
||||
"""
|
||||
PyPDF2 is not flawless. We can upload a PDF that can be previsualised but that cannot be merged by PyPDF2.
|
||||
In the case of "Print Original Bills", we want to be able to download the pdf from the list view.
|
||||
We test that, when selecting one record, it can be printed (downloaded) without error.
|
||||
"""
|
||||
attach_name = 'original_vendor_bill.pdf'
|
||||
|
||||
in_invoice_1 = self.env['account.move'].create({
|
||||
'move_type': 'in_invoice',
|
||||
'date': '2017-01-01',
|
||||
'invoice_date': '2017-01-01'
|
||||
})
|
||||
|
||||
in_invoice_1.message_main_attachment_id = self.env['ir.attachment'].create({
|
||||
'datas': base64.b64encode(self.file),
|
||||
'name': attach_name,
|
||||
'mimetype': 'application/pdf',
|
||||
'res_model': 'account.move',
|
||||
'res_id': in_invoice_1.id,
|
||||
})
|
||||
test_record_report = self.env['ir.actions.report'].with_context(force_report_rendering=True)._render_qweb_pdf('account.action_account_original_vendor_bill', res_ids=in_invoice_1.id)
|
||||
self.assertTrue(test_record_report, "The PDF should have been generated")
|
||||
|
||||
def test_download_one_encrypted_pdf(self):
|
||||
"""
|
||||
Same as test_download_one_corrupted_pdf
|
||||
but for encrypted pdf with no password and set encryption type to 5 (not known by PyPDF2)
|
||||
"""
|
||||
attach_name = 'original_vendor_bill.pdf'
|
||||
# we need to encrypt the file
|
||||
with file_open('base/tests/minimal.pdf', 'rb') as pdf_file:
|
||||
pdf_reader = PdfFileReader(pdf_file)
|
||||
pdf_writer = PdfFileWriter()
|
||||
for page_num in range(pdf_reader.getNumPages()):
|
||||
pdf_writer.addPage(pdf_reader.getPage(page_num))
|
||||
# Encrypt the PDF
|
||||
pdf_writer.encrypt('', use_128bit=True)
|
||||
# Get the binary
|
||||
output_buffer = io.BytesIO()
|
||||
pdf_writer.write(output_buffer)
|
||||
encrypted_file = output_buffer.getvalue()
|
||||
|
||||
# we need to change the encryption value from 4 to 5 to simulate an encryption not used by PyPDF2
|
||||
encrypt_start = encrypted_file.find(b'/Encrypt')
|
||||
encrypt_end = encrypted_file.find(b'>>', encrypt_start)
|
||||
encrypt_version = encrypted_file[encrypt_start : encrypt_end]
|
||||
encrypted_file = encrypted_file.replace(encrypt_version, encrypt_version.replace(b'4', b'5'))
|
||||
|
||||
in_invoice_1 = self.env['account.move'].create({
|
||||
'move_type': 'in_invoice',
|
||||
'date': '2017-01-01',
|
||||
'invoice_date': '2017-01-01'
|
||||
})
|
||||
|
||||
in_invoice_1.message_main_attachment_id = self.env['ir.attachment'].create({
|
||||
'datas': base64.b64encode(encrypted_file),
|
||||
'name': attach_name,
|
||||
'mimetype': 'application/pdf',
|
||||
'res_model': 'account.move',
|
||||
'res_id': in_invoice_1.id,
|
||||
})
|
||||
test_record_report = self.env['ir.actions.report'].with_context(force_report_rendering=True)._render_qweb_pdf('account.action_account_original_vendor_bill', res_ids=in_invoice_1.id)
|
||||
self.assertTrue(test_record_report, "The PDF should have been generated")
|
||||
|
||||
in_invoice_2 = in_invoice_1.copy()
|
||||
|
||||
in_invoice_2.message_main_attachment_id = self.env['ir.attachment'].create({
|
||||
'datas': base64.b64encode(self.file),
|
||||
'name': attach_name,
|
||||
'mimetype': 'application/pdf',
|
||||
'res_model': 'account.move',
|
||||
'res_id': in_invoice_2.id,
|
||||
})
|
||||
# trying to merge with a corrupted attachment should not work
|
||||
with self.assertRaises(UserError):
|
||||
self.env['ir.actions.report'].with_context(force_report_rendering=True)._render_qweb_pdf('account.action_account_original_vendor_bill', res_ids=[in_invoice_1.id, in_invoice_2.id])
|
||||
Reference in New Issue
Block a user