flectra/addons/base_iban/models/res_partner_bank.py

151 lines
6.6 KiB
Python

# -*- coding: utf-8 -*-
import re
from flectra import api, models, _
from flectra.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 """
return ' '.join([iban[i:i + 4] for i in range(0, len(iban), 4)])
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(_("No IBAN !"))
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.one
@api.depends('acc_number')
def _compute_acc_type(self):
try:
validate_iban(self.acc_number)
self.acc_type = 'iban'
except ValidationError:
super(ResPartnerBank, self)._compute_acc_type()
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_type') == 'iban') and vals.get('acc_number'):
vals['acc_number'] = pretty_iban(normalize_iban(vals['acc_number']))
return super(ResPartnerBank, self).create(vals)
@api.multi
def write(self, vals):
if (vals.get('acc_type') == 'iban') and vals.get('acc_number'):
vals['acc_number'] = pretty_iban(normalize_iban(vals['acc_number']))
return super(ResPartnerBank, self).write(vals)
@api.one
@api.constrains('acc_number')
def _check_iban(self):
if self.acc_type == 'iban':
validate_iban(self.acc_number)
# 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 C', # 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
'vg': 'VGkk BBBB CCCC CCCC CCCC CCCC', # Virgin Islands
'xk': 'XKkk BBBB CCCC CCCC CCCC', # Kosovo
}