From 69a1289eca79272efe7e53f8b3ad70de6df3d96a Mon Sep 17 00:00:00 2001 From: "Nasreddin Boulif (bon)" <bon@odoo.com> Date: Fri, 20 Aug 2021 16:25:34 +0000 Subject: [PATCH] [FIX] base,l10n_ch: Display all QR codes in QR bill Issue: When trying to print a Suisse QR bill, if multiple images are presents in document and they have a url as src, some pictures will not be displayed. (Same issue may occur with simple QR code) Cause: It's a known issue with wkhtmltopdf: https://github.com/odoo/odoo/commit/2949138a7d84cd6c925ea1745d62f25ef077bb8b Also, adding css class to body by js break wkhtmltopdf. Solution: Replace link by base64 image value (use a function to retrieve base64 image instead of image_url). Remove class 'l10n_ch_qr' added by js (no need since CSS file didacted to this report). extra: Alter some css for better rendering. opw-2620082 closes odoo/odoo#75408 Signed-off-by: oco-odoo <oco-odoo@users.noreply.github.com> --- addons/account/views/report_invoice.xml | 2 +- addons/l10n_ch/models/res_bank.py | 19 +++++++++++++-- addons/l10n_ch/report/swissqr_report.xml | 4 +--- .../static/src/scss/report_swissqr.scss | 8 +++---- .../views/payment_portal_templates.xml | 4 ++-- addons/website_sale/views/templates.xml | 2 +- odoo/addons/base/models/res_bank.py | 24 +++++++++++++++---- 7 files changed, 46 insertions(+), 17 deletions(-) diff --git a/addons/account/views/report_invoice.xml b/addons/account/views/report_invoice.xml index 59287c9e1e47..fcaf82dd91e6 100644 --- a/addons/account/views/report_invoice.xml +++ b/addons/account/views/report_invoice.xml @@ -184,7 +184,7 @@ <div id="qrcode" t-if="(o.company_id.qr_code) and (o.currency_id.name == 'EUR') and (o.partner_bank_id.acc_number != False)"> <p t-if="(o.partner_bank_id.qr_code_valid)"> <strong class="text-center">Scan me with your banking app.</strong><br /><br /> - <img class="border border-dark rounded" t-att-src="o.partner_bank_id.build_qr_code_url(o.residual,(o.reference) if (o.reference) else o.number)"/> + <img class="border border-dark rounded" t-att-src="o.partner_bank_id.build_qr_code_base64(o.residual,(o.reference) if (o.reference) else o.number)"/> </p> <p t-if="(o.partner_bank_id.qr_code_valid == False)"> <strong class="text-center">The SEPA QR Code informations are not set correctly.</strong><br /> diff --git a/addons/l10n_ch/models/res_bank.py b/addons/l10n_ch/models/res_bank.py index f97767f2e1eb..77e037a3a446 100644 --- a/addons/l10n_ch/models/res_bank.py +++ b/addons/l10n_ch/models/res_bank.py @@ -5,8 +5,11 @@ import re from odoo import api, fields, models, _ from odoo.tools.misc import mod10r +from odoo.tools.image import image_data_uri +import base64 import werkzeug.urls +import werkzeug.exceptions def _is_l10n_ch_postal(account_ref): """ Returns True iff the string account_ref is a valid postal account number, @@ -85,8 +88,7 @@ class ResPartnerBank(models.Model): else: return '' - @api.model - def build_swiss_code_url(self, amount, currency_name, not_used_anymore_1, debtor_partner, not_used_anymore_2, structured_communication, free_communication): + def build_swiss_code_vals(self, amount, currency_name, not_used_anymore_1, debtor_partner, not_used_anymore_2, structured_communication, free_communication): comment = "" if free_communication: comment = (free_communication[:137] + '...') if len(free_communication) > 140 else free_communication @@ -137,9 +139,22 @@ class ResPartnerBank(models.Model): comment, # Unstructured Message 'EPD', # Mandatory trailer part ] + return qr_code_vals + @api.model + def build_swiss_code_url(self, amount, currency_name, not_used_anymore_1, debtor_partner, not_used_anymore_2, structured_communication, free_communication): + qr_code_vals = self.build_swiss_code_vals(amount, currency_name, not_used_anymore_1, debtor_partner, not_used_anymore_2, structured_communication, free_communication) return '/report/barcode/?type=%s&value=%s&width=%s&height=%s&humanreadable=1' % ('QR_quiet', werkzeug.urls.url_quote_plus('\n'.join(qr_code_vals)), 256, 256) + @api.model + def build_swiss_code_base64(self, amount, currency_name, not_used_anymore_1, debtor_partner, not_used_anymore_2, structured_communication, free_communication): + qr_code_vals = self.build_swiss_code_vals(amount, currency_name, not_used_anymore_1, debtor_partner, not_used_anymore_2, structured_communication, free_communication) + try: + barcode = self.env['ir.actions.report'].barcode('QR_quiet', '\n'.join(qr_code_vals), width=256, height=256, humanreadable=1) + except (ValueError, AttributeError): + raise werkzeug.exceptions.HTTPException(description='Cannot convert into barcode.') + + return image_data_uri(base64.b64encode(barcode)) def _get_partner_address_lines(self, partner): """ Returns a tuple of two elements containing the address lines to use diff --git a/addons/l10n_ch/report/swissqr_report.xml b/addons/l10n_ch/report/swissqr_report.xml index ca4812ba6a4b..834b4625683e 100644 --- a/addons/l10n_ch/report/swissqr_report.xml +++ b/addons/l10n_ch/report/swissqr_report.xml @@ -21,8 +21,6 @@ <template id="l10n_ch_swissqr_template"> <t t-call="web.external_layout"> - <!-- add class to body tag --> - <script>document.body.className += " l10n_ch_qr";</script> <!-- add default margin for header (matching A4 European margin) --> <t t-set="report_header_style">padding-top:6.2mm; padding-left:8.2mm; padding-right:8.2mm;</t> @@ -78,7 +76,7 @@ <span class="swissqr_text title title_zone">Payment part</span><br/> </div> - <img class="swissqr" t-att-src="o.partner_bank_id.build_swiss_code_url(o.residual, o.currency_id.name, None, o.partner_id, None, o.reference, o.name or o.number)"/> + <img class="swissqr" t-att-src="o.partner_bank_id.build_swiss_code_base64(o.residual, o.currency_id.name, None, o.partner_id, None, o.reference, o.name or o.number)"/> <img class="ch_cross" src="/l10n_ch/static/src/img/CH-Cross_7mm.png"/> <div id="indications_zone" class="swissqr_column_right indication_zone"> diff --git a/addons/l10n_ch/static/src/scss/report_swissqr.scss b/addons/l10n_ch/static/src/scss/report_swissqr.scss index e7f245a5766e..96ca2e390f14 100644 --- a/addons/l10n_ch/static/src/scss/report_swissqr.scss +++ b/addons/l10n_ch/static/src/scss/report_swissqr.scss @@ -1,5 +1,5 @@ -body.l10n_ch_qr { - padding:0; +body { + padding: 0!important; /* Disable custom bakground */ .o_report_layout_background { @@ -10,7 +10,7 @@ body.l10n_ch_qr { .swissqr_title { position: absolute; padding: 15px; - padding-top: 150px; + padding-top: 200px; } .swissqr_content { @@ -19,7 +19,7 @@ body.l10n_ch_qr { .swissqr_receipt { position: absolute; - background_color: white; + background-color: white; border-color:black; border-width: 1pt 1pt 1pt 1pt; border-style: solid; diff --git a/addons/payment/views/payment_portal_templates.xml b/addons/payment/views/payment_portal_templates.xml index fafe80d28933..1a7b45fd5d4e 100644 --- a/addons/payment/views/payment_portal_templates.xml +++ b/addons/payment/views/payment_portal_templates.xml @@ -106,7 +106,7 @@ <div t-if="(tx.acquirer_id.qr_code == True) and (tx.currency_id.name == 'EUR')"> <div t-if="tx.acquirer_id.journal_id.bank_account_id.qr_code_valid"> <h3>Or scan me with your banking app.</h3> - <img class="border border-dark rounded" t-att-src="tx.acquirer_id.journal_id.bank_account_id.build_qr_code_url(tx.amount,tx.reference)"/> + <img class="border border-dark rounded" t-att-src="tx.acquirer_id.journal_id.bank_account_id.build_qr_code_base64(tx.amount,tx.reference)"/> </div> <div t-if="(tx.acquirer_id.journal_id.bank_account_id.qr_code_valid == False)"> <h3>The SEPA QR Code informations are not set correctly.</h3> @@ -145,7 +145,7 @@ <div t-if="(payment_tx_id.acquirer_id.qr_code == True) and (payment_tx_id.currency_id.name == 'EUR')"> <div t-if="payment_tx_id.acquirer_id.journal_id.bank_account_id.qr_code_valid"> <h3>Or scan me with your banking app.</h3> - <img class="border border-dark rounded" t-att-src="payment_tx_id.acquirer_id.journal_id.bank_account_id.build_qr_code_url(payment_tx_id.amount,payment_tx_id.reference)"/> + <img class="border border-dark rounded" t-att-src="payment_tx_id.acquirer_id.journal_id.bank_account_id.build_qr_code_base64(payment_tx_id.amount,payment_tx_id.reference)"/> </div> <div t-if="(payment_tx_id.acquirer_id.journal_id.bank_account_id.qr_code_valid == False)"> <h3>The SEPA QR Code informations are not set correctly.</h3> diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml index 0e78b6025724..f997f633268b 100644 --- a/addons/website_sale/views/templates.xml +++ b/addons/website_sale/views/templates.xml @@ -1632,7 +1632,7 @@ <div t-if="(payment_tx_id.acquirer_id.qr_code == True) and (payment_tx_id.acquirer_id.provider == 'transfer') and (payment_tx_id.currency_id.name == 'EUR')"> <div class="card-body" t-if="payment_tx_id.acquirer_id.journal_id.bank_account_id.qr_code_valid"> <h3>Or scan me with your banking app.</h3> - <img class="border border-dark rounded" t-att-src="payment_tx_id.acquirer_id.journal_id.bank_account_id.build_qr_code_url(order.amount_total,payment_tx_id.reference)"/> + <img class="border border-dark rounded" t-att-src="payment_tx_id.acquirer_id.journal_id.bank_account_id.build_qr_code_base64(order.amount_total,payment_tx_id.reference)"/> </div> <div class="card-body" t-if="payment_tx_id.acquirer_id.journal_id.bank_account_id.qr_code_valid == False"> <h3>The SEPA QR Code informations are not set correctly.</h3> diff --git a/odoo/addons/base/models/res_bank.py b/odoo/addons/base/models/res_bank.py index 9edafc3c1347..e6fa05e4e5b8 100644 --- a/odoo/addons/base/models/res_bank.py +++ b/odoo/addons/base/models/res_bank.py @@ -7,8 +7,11 @@ from collections.abc import Iterable from odoo import api, fields, models, _ from odoo.osv import expression from odoo.tools import pycompat +from odoo.tools.image import image_data_uri +import base64 import werkzeug.urls +import werkzeug.exceptions def sanitize_account_number(acc_number): if acc_number: @@ -127,15 +130,28 @@ class ResPartnerBank(models.Model): pos += 1 return super(ResPartnerBank, self)._search(args, offset, limit, order, count=count, access_rights_uid=access_rights_uid) - @api.model - def build_qr_code_url(self, amount, comment): + def build_qr_code_vals(self, amount, comment): communication = "" if comment: communication = (comment[:137] + '...') if len(comment) > 140 else comment - qr_code_string = 'BCD\n001\n1\nSCT\n%s\n%s\n%s\nEUR%s\n\n\n%s' % (self.bank_bic, self.company_id.name, self.acc_number, amount, communication) - qr_code_url = '/report/barcode/?type=%s&value=%s&width=%s&height=%s&humanreadable=1' % ('QR', werkzeug.url_quote_plus(qr_code_string), 128, 128) + qr_code_vals = 'BCD\n001\n1\nSCT\n%s\n%s\n%s\nEUR%s\n\n\n%s' % (self.bank_bic, self.company_id.name, self.acc_number, amount, communication) + return qr_code_vals + + @api.model + def build_qr_code_url(self, amount, comment): + qr_code_url = '/report/barcode/?type=%s&value=%s&width=%s&height=%s&humanreadable=1' % ('QR', + werkzeug.url_quote_plus(self.build_qr_code_vals(amount, comment)), 128, 128) return qr_code_url + @api.model + def build_qr_code_base64(self, amount, comment): + try: + barcode = self.env['ir.actions.report'].barcode('QR', self.build_qr_code_vals(amount, comment), width=128, height=128, humanreadable=1) + except (ValueError, AttributeError): + raise werkzeug.exceptions.HTTPException(description='Cannot convert into barcode.') + + return image_data_uri(base64.b64encode(barcode)) + @api.multi def _validate_qr_code_arguments(self): for bank in self: -- GitLab