diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/base_iban/models | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/base_iban/models')
| -rw-r--r-- | addons/base_iban/models/__init__.py | 4 | ||||
| -rw-r--r-- | addons/base_iban/models/res_partner_bank.py | 174 |
2 files changed, 178 insertions, 0 deletions
diff --git a/addons/base_iban/models/__init__.py b/addons/base_iban/models/__init__.py new file mode 100644 index 00000000..20f3eefa --- /dev/null +++ b/addons/base_iban/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import res_partner_bank
\ No newline at end of file diff --git a/addons/base_iban/models/res_partner_bank.py b/addons/base_iban/models/res_partner_bank.py new file mode 100644 index 00000000..72c9d77d --- /dev/null +++ b/addons/base_iban/models/res_partner_bank.py @@ -0,0 +1,174 @@ +# -*- coding: utf-8 -*- + +import re + +from odoo import api, fields, models, _ +from odoo.exceptions import UserError, ValidationError + + +def normalize_iban(iban): + return re.sub('[\W_]', '', iban or '') + +def pretty_iban(iban): + """ return iban in groups of four characters separated by a single space """ + try: + validate_iban(iban) + iban = ' '.join([iban[i:i + 4] for i in range(0, len(iban), 4)]) + except ValidationError: + pass + return iban + +def get_bban_from_iban(iban): + """ Returns the basic bank account number corresponding to an IBAN. + Note : the BBAN is not the same as the domestic bank account number ! + The relation between IBAN, BBAN and domestic can be found here : http://www.ecbs.org/iban.htm + """ + return normalize_iban(iban)[4:] + +def validate_iban(iban): + iban = normalize_iban(iban) + if not iban: + raise ValidationError(_("There is no IBAN code.")) + + country_code = iban[:2].lower() + if country_code not in _map_iban_template: + raise ValidationError(_("The IBAN is invalid, it should begin with the country code")) + + iban_template = _map_iban_template[country_code] + if len(iban) != len(iban_template.replace(' ', '')): + raise ValidationError(_("The IBAN does not seem to be correct. You should have entered something like this %s\n" + "Where B = National bank code, S = Branch code, C = Account No, k = Check digit") % iban_template) + + check_chars = iban[4:] + iban[:4] + digits = int(''.join(str(int(char, 36)) for char in check_chars)) # BASE 36: 0..9,A..Z -> 0..35 + if digits % 97 != 1: + raise ValidationError(_("This IBAN does not pass the validation check, please verify it.")) + + +class ResPartnerBank(models.Model): + _inherit = "res.partner.bank" + + @api.model + def _get_supported_account_types(self): + rslt = super(ResPartnerBank, self)._get_supported_account_types() + rslt.append(('iban', _('IBAN'))) + return rslt + + @api.model + def retrieve_acc_type(self, acc_number): + try: + validate_iban(acc_number) + return 'iban' + except ValidationError: + return super(ResPartnerBank, self).retrieve_acc_type(acc_number) + + def get_bban(self): + if self.acc_type != 'iban': + raise UserError(_("Cannot compute the BBAN because the account number is not an IBAN.")) + return get_bban_from_iban(self.acc_number) + + @api.model + def create(self, vals): + if vals.get('acc_number'): + try: + validate_iban(vals['acc_number']) + vals['acc_number'] = pretty_iban(normalize_iban(vals['acc_number'])) + except ValidationError: + pass + return super(ResPartnerBank, self).create(vals) + + def write(self, vals): + if vals.get('acc_number'): + try: + validate_iban(vals['acc_number']) + vals['acc_number'] = pretty_iban(normalize_iban(vals['acc_number'])) + except ValidationError: + pass + return super(ResPartnerBank, self).write(vals) + + @api.constrains('acc_number') + def _check_iban(self): + for bank in self: + if bank.acc_type == 'iban': + validate_iban(bank.acc_number) + + def check_iban(self, iban=''): + try: + validate_iban(iban) + return True + except ValidationError: + return False + +# Map ISO 3166-1 -> IBAN template, as described here : +# http://en.wikipedia.org/wiki/International_Bank_Account_Number#IBAN_formats_by_country +_map_iban_template = { + 'ad': 'ADkk BBBB SSSS CCCC CCCC CCCC', # Andorra + 'ae': 'AEkk BBBC CCCC CCCC CCCC CCC', # United Arab Emirates + 'al': 'ALkk BBBS SSSK CCCC CCCC CCCC CCCC', # Albania + 'at': 'ATkk BBBB BCCC CCCC CCCC', # Austria + 'az': 'AZkk BBBB CCCC CCCC CCCC CCCC CCCC', # Azerbaijan + 'ba': 'BAkk BBBS SSCC CCCC CCKK', # Bosnia and Herzegovina + 'be': 'BEkk BBBC CCCC CCXX', # Belgium + 'bg': 'BGkk BBBB SSSS DDCC CCCC CC', # Bulgaria + 'bh': 'BHkk BBBB CCCC CCCC CCCC CC', # Bahrain + 'br': 'BRkk BBBB BBBB SSSS SCCC CCCC CCCT N', # Brazil + 'by': 'BYkk BBBB AAAA CCCC CCCC CCCC CCCC', # Belarus + 'ch': 'CHkk BBBB BCCC CCCC CCCC C', # Switzerland + 'cr': 'CRkk BBBC CCCC CCCC CCCC CC', # Costa Rica + 'cy': 'CYkk BBBS SSSS CCCC CCCC CCCC CCCC', # Cyprus + 'cz': 'CZkk BBBB SSSS SSCC CCCC CCCC', # Czech Republic + 'de': 'DEkk BBBB BBBB CCCC CCCC CC', # Germany + 'dk': 'DKkk BBBB CCCC CCCC CC', # Denmark + 'do': 'DOkk BBBB CCCC CCCC CCCC CCCC CCCC', # Dominican Republic + 'ee': 'EEkk BBSS CCCC CCCC CCCK', # Estonia + 'es': 'ESkk BBBB SSSS KKCC CCCC CCCC', # Spain + 'fi': 'FIkk BBBB BBCC CCCC CK', # Finland + 'fo': 'FOkk CCCC CCCC CCCC CC', # Faroe Islands + 'fr': 'FRkk BBBB BGGG GGCC CCCC CCCC CKK', # France + 'gb': 'GBkk BBBB SSSS SSCC CCCC CC', # United Kingdom + 'ge': 'GEkk BBCC CCCC CCCC CCCC CC', # Georgia + 'gi': 'GIkk BBBB CCCC CCCC CCCC CCC', # Gibraltar + 'gl': 'GLkk BBBB CCCC CCCC CC', # Greenland + 'gr': 'GRkk BBBS SSSC CCCC CCCC CCCC CCC', # Greece + 'gt': 'GTkk BBBB MMTT CCCC CCCC CCCC CCCC', # Guatemala + 'hr': 'HRkk BBBB BBBC CCCC CCCC C', # Croatia + 'hu': 'HUkk BBBS SSSC CCCC CCCC CCCC CCCC', # Hungary + 'ie': 'IEkk BBBB SSSS SSCC CCCC CC', # Ireland + 'il': 'ILkk BBBS SSCC CCCC CCCC CCC', # Israel + 'is': 'ISkk BBBB SSCC CCCC XXXX XXXX XX', # Iceland + 'it': 'ITkk KBBB BBSS SSSC CCCC CCCC CCC', # Italy + 'jo': 'JOkk BBBB NNNN CCCC CCCC CCCC CCCC CC', # Jordan + 'kw': 'KWkk BBBB CCCC CCCC CCCC CCCC CCCC CC', # Kuwait + 'kz': 'KZkk BBBC CCCC CCCC CCCC', # Kazakhstan + 'lb': 'LBkk BBBB CCCC CCCC CCCC CCCC CCCC', # Lebanon + 'li': 'LIkk BBBB BCCC CCCC CCCC C', # Liechtenstein + 'lt': 'LTkk BBBB BCCC CCCC CCCC', # Lithuania + 'lu': 'LUkk BBBC CCCC CCCC CCCC', # Luxembourg + 'lv': 'LVkk BBBB CCCC CCCC CCCC C', # Latvia + 'mc': 'MCkk BBBB BGGG GGCC CCCC CCCC CKK', # Monaco + 'md': 'MDkk BBCC CCCC CCCC CCCC CCCC', # Moldova + 'me': 'MEkk BBBC CCCC CCCC CCCC KK', # Montenegro + 'mk': 'MKkk BBBC CCCC CCCC CKK', # Macedonia + 'mr': 'MRkk BBBB BSSS SSCC CCCC CCCC CKK', # Mauritania + 'mt': 'MTkk BBBB SSSS SCCC CCCC CCCC CCCC CCC', # Malta + 'mu': 'MUkk BBBB BBSS CCCC CCCC CCCC CCCC CC', # Mauritius + 'nl': 'NLkk BBBB CCCC CCCC CC', # Netherlands + 'no': 'NOkk BBBB CCCC CCK', # Norway + 'pk': 'PKkk BBBB CCCC CCCC CCCC CCCC', # Pakistan + 'pl': 'PLkk BBBS SSSK CCCC CCCC CCCC CCCC', # Poland + 'ps': 'PSkk BBBB XXXX XXXX XCCC CCCC CCCC C', # Palestinian + 'pt': 'PTkk BBBB SSSS CCCC CCCC CCCK K', # Portugal + 'qa': 'QAkk BBBB CCCC CCCC CCCC CCCC CCCC C', # Qatar + 'ro': 'ROkk BBBB CCCC CCCC CCCC CCCC', # Romania + 'rs': 'RSkk BBBC CCCC CCCC CCCC KK', # Serbia + 'sa': 'SAkk BBCC CCCC CCCC CCCC CCCC', # Saudi Arabia + 'se': 'SEkk BBBB CCCC CCCC CCCC CCCC', # Sweden + 'si': 'SIkk BBSS SCCC CCCC CKK', # Slovenia + 'sk': 'SKkk BBBB SSSS SSCC CCCC CCCC', # Slovakia + 'sm': 'SMkk KBBB BBSS SSSC CCCC CCCC CCC', # San Marino + 'tn': 'TNkk BBSS SCCC CCCC CCCC CCCC', # Tunisia + 'tr': 'TRkk BBBB BRCC CCCC CCCC CCCC CC', # Turkey + 'ua': 'UAkk BBBB BBCC CCCC CCCC CCCC CCCC C', # Ukraine + 'vg': 'VGkk BBBB CCCC CCCC CCCC CCCC', # Virgin Islands + 'xk': 'XKkk BBBB CCCC CCCC CCCC', # Kosovo +} |
