[ADD] account_qr_code_emv

- This is a bridge module to provide support for EMV Merchant-Presented
QR-code generation for Payment System.
- Other accounting localisation module will override _get_merchant_account_info
method to construct the qr code parameters. This module will help creating the
crc16 check sum to append in the qr code vals.

Part-of: odoo/odoo#120050
This commit is contained in:
Tommy (tong)
2023-05-15 11:41:26 +02:00
parent 58ca40b032
commit 373e023fe5
5 changed files with 143 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
@@ -0,0 +1,13 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'account_qr_code_emv',
'category': 'Accounting/Payment',
'version': '1.0',
'description': """
Bridge module addings support for EMV Merchant-Presented QR-code generation for Payment System.
""",
'author': 'Odoo SA',
'depends': ['account'],
'license': 'LGPL-3',
}
+51
View File
@@ -0,0 +1,51 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
CURRENCY_MAPPING = {
'ARS': '032',
'AUD': '036',
'BHD': '048',
'KHR': '116',
'CAD': '124',
'LKR': '144',
'CNY': '156',
'HRK': '191',
'CZK': '203',
'DKK': '208',
'HKD': '344',
'HUF': '348',
'ISK': '352',
'INR': '356',
'ILS': '376',
'JPY': '392',
'KRW': '410',
'KWD': '414',
'MYR': '458',
'MUR': '480',
'MXN': '484',
'NPR': '524',
'NZD': '554',
'NOK': '578',
'QAR': '634',
'RUB': '643',
'SAR': '682',
'SGD': '702',
'ZAR': '710',
'SEK': '752',
'CHF': '756',
'THB': '764',
'AED': '784',
'TND': '788',
'GBP': '826',
'USD': '840',
'TWD': '901',
'RSD': '941',
'RON': '946',
'TRY': '949',
'XOF': '952',
'XPF': '953',
'BGN': '975',
'EUR': '978',
'UAH': '980',
'PLN': '985',
'BRL': '986',
}
@@ -0,0 +1,3 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import res_bank
@@ -0,0 +1,73 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import _, api, models
from odoo.addons.account_qr_code_emv.const import CURRENCY_MAPPING
class ResPartnerBank(models.Model):
_inherit = 'res.partner.bank'
# 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 False
def _get_qr_vals(self, qr_method, amount, currency, debtor_partner, free_communication, structured_communication):
if qr_method == 'emv_qr':
merchant_account_info = self._get_merchant_account_info()
currency_code = CURRENCY_MAPPING[currency.name]
merchant_name = self.partner_id.name and self.partner_id.name[:25] or 'NA'
merchant_city = self.partner_id.city and self.partner_id.city[:15] or ''
qr_code_vals = [
'000201', # Payload Format Indicator
'010212', # Dynamic QR Codes
f'26{len(merchant_account_info):02}{merchant_account_info}', # Merchant Account Information
'52040000', # Merchant Category Code
f'5303{currency_code}', # Transaction Currency
f'54{len(str(amount)):02}{amount}', # Transaction Amount
f'5802{self.partner_id.country_code}', # Country Code
f'59{len(merchant_name):02}{merchant_name}', # Merchant Name
f'60{len(merchant_city):02}{merchant_city}', # Merchant City
'6304', # CRC16
]
crc = self._get_crc16(bytes(''.join(qr_code_vals), 'utf-8'))
qr_code_vals.append(format(crc, '04x').upper())
return qr_code_vals
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': ''.join(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.")
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