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