Files
odoo_source/addons/account_qr_code_emv/models/res_bank.py
T
mhch-odoo 39df0141b9 [FIX] account_qr_code_emv: Improve Fallback error
At the moment, if EMV QR is selected on the invoice where the country does not support EMV QR an error is raised.

However, this error is also raised if EMV QR is selected but the bank account is not set. The following error is raise
`No EMV QR Code is available for the country of the account False.`
This commit adds a check to ensure the bank account is set and raise a better error message.

Task# 3868467

closes odoo/odoo#162500

X-original-commit: e6ca281b691e75dd9c12fb110f80f444c21729de
Signed-off-by: Nicolas Viseur (vin) <vin@odoo.com>
2024-04-19 02:27:25 +00:00

123 lines
6.3 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import re
from odoo import _, api, fields, models
from odoo.tools.misc import remove_accents
from odoo.addons.account_qr_code_emv.const import CURRENCY_MAPPING
class ResPartnerBank(models.Model):
_inherit = 'res.partner.bank'
country_code = fields.Char(related='partner_id.country_code', string="Country Code")
display_qr_setting = fields.Boolean(compute='_compute_display_qr_setting')
include_reference = fields.Boolean(string="Include Reference", help="Include the reference in the QR code.")
proxy_type = fields.Selection([('none', 'None')], string="Proxy Type", default='none')
proxy_value = fields.Char(string="Proxy Value")
@api.model
def _serialize(self, header, value):
if value is not None and value != '':
return f'{header:02}{len(str(value)):02}{value}'
else:
return ''
@api.model
def _remove_accents(self, string):
return remove_accents(string).replace('đ', 'd').replace('Đ', 'D')
@api.depends('country_code')
def _compute_display_qr_setting(self):
self.display_qr_setting = False
# CRC16 calculation with polynomial 0x1021 and initial value 0xFFFF
def _get_crc16(self, data, poly=0x1021, init=0xFFFF):
crc = init
for byte in data:
crc = crc ^ (byte << 8)
for __ in range(8):
if crc & 0x8000:
crc = (crc << 1) ^ poly
else:
crc = crc << 1
return crc & 0xFFFF
def _get_merchant_account_info(self):
return None, None
def _get_additional_data_field(self, comment):
return None
def _get_qr_code_vals_list(self, qr_method, amount, currency, debtor_partner, free_communication, structured_communication):
tag, merchant_account_info = self._get_merchant_account_info()
currency_code = CURRENCY_MAPPING[currency.name]
amount = amount.is_integer() and int(amount) or amount
merchant_name = self.partner_id.name and self._remove_accents(self.partner_id.name)[:25] or 'NA'
merchant_city = self.partner_id.city and self._remove_accents(self.partner_id.city)[:15] or ''
comment = structured_communication or free_communication or ''
comment = re.sub(r'/[^ A-Za-z0-9_@.\/#&+-]+/g', '', remove_accents(comment))
additional_data_field = self._get_additional_data_field(comment) if self.include_reference else None
return [
(0, '01'), # Payload Format Indicator
(1, '12'), # Dynamic QR Codes
(tag, merchant_account_info), # Merchant Account Information
(52, '0000'), # Merchant Category Code
(53, currency_code), # Transaction Currency
(54, amount), # Transaction Amount
(58, self.country_code), # Country Code
(59, merchant_name), # Merchant Name
(60, merchant_city), # Merchant City
(62, additional_data_field), # Additional Data Field
]
def _get_qr_vals(self, qr_method, amount, currency, debtor_partner, free_communication, structured_communication):
if qr_method == 'emv_qr':
qr_code_vals = self._get_qr_code_vals_list(qr_method, amount, currency, debtor_partner, free_communication, structured_communication)
qr_code_str = ''.join([self._serialize(*val) for val in qr_code_vals])
qr_code_str += '6304' # CRC16
crc = self._get_crc16(bytes(qr_code_str, 'utf-8'))
qr_code_str += format(crc, '04x').upper()
return qr_code_str
return super()._get_qr_vals(qr_method, amount, currency, debtor_partner, free_communication, structured_communication)
def _get_qr_code_generation_params(self, qr_method, amount, currency, debtor_partner, free_communication, structured_communication):
if qr_method == 'emv_qr':
return {
'barcode_type': 'QR',
'width': 128,
'height': 128,
'humanreadable': 1,
'value': self._get_qr_vals(qr_method, amount, currency, debtor_partner, free_communication, structured_communication),
}
return super()._get_qr_code_generation_params(qr_method, amount, currency, debtor_partner, free_communication, structured_communication)
def _check_for_qr_code_errors(self, qr_method, amount, currency, debtor_partner, free_communication, structured_communication):
if qr_method == 'emv_qr':
if not self._get_merchant_account_info():
return _("Missing Merchant Account Information.")
if not self.partner_id.city:
return _("Missing Merchant City.")
if not self.proxy_type:
return _("Missing Proxy Type.")
if not self.proxy_value:
return _("Missing Proxy Value.")
return super()._check_for_qr_code_errors(qr_method, amount, currency, debtor_partner, free_communication, structured_communication)
@api.model
def _get_available_qr_methods(self):
rslt = super()._get_available_qr_methods()
rslt.append(('emv_qr', _("EMV Merchant-Presented QR-code"), 30))
return rslt
def _get_error_messages_for_qr(self, qr_method, debtor_partner, currency):
""" Return an error for emv_qr if the account's country does no match any methods found in inheriting modules."""
if qr_method == 'emv_qr':
if not self:
return _("A bank account is required for EMV QR Code generation.")
return _("No EMV QR Code is available for the country of the account %(account_number)s.", account_number=self.acc_number)
return super()._get_error_messages_for_qr(qr_method, debtor_partner, currency)