Skip to content
Snippets Groups Projects
Commit 93af15db authored by Abdelouahab (abla)'s avatar Abdelouahab (abla)
Browse files

[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#116987

Signed-off-by: default avatarJohn Laterre (jol) <jol@odoo.com>
parent 4af1c82e
No related branches found
No related tags found
No related merge requests found
# -*- coding: utf-8 -*-
from PyPDF2.utils import PdfStreamError
from PyPDF2.utils import PdfStreamError, PdfReadError
from odoo import models, _
from odoo.exceptions import UserError
......@@ -57,7 +57,7 @@ class IrActionsReport(models.Model):
record = self.env[attachment.res_model].browse(attachment.res_id)
try:
return 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."
......
......@@ -39,3 +39,4 @@ from . import test_account_incoming_supplier_invoice
from . import test_payment_term
from . import test_account_payment_register
from . import test_tour
from . import test_ir_actions_report
# -*- 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'
})
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.ref('account.action_account_original_vendor_bill').with_context(force_report_rendering=True)._render_qweb_pdf(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'
})
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.ref('account.action_account_original_vendor_bill').with_context(force_report_rendering=True)._render_qweb_pdf(in_invoice_1.id)
self.assertTrue(test_record_report, "The PDF should have been generated")
in_invoice_2 = in_invoice_1.copy()
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.ref('account.action_account_original_vendor_bill').with_context(force_report_rendering=True)._render_qweb_pdf(res_ids=[in_invoice_1.id, in_invoice_2.id])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment