2018-01-16 06:58:15 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
import re
|
|
|
|
|
2018-01-16 11:34:37 +01:00
|
|
|
from flectra import api, models, _
|
|
|
|
from flectra.exceptions import UserError, ValidationError
|
2018-01-16 06:58:15 +01:00
|
|
|
|
|
|
|
|
|
|
|
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
|
2018-04-05 10:25:40 +02:00
|
|
|
'by': 'BYkk BBBB AAAA CCCC CCCC CCCC CCCC', # Belarus
|
2018-01-16 06:58:15 +01:00
|
|
|
'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
|
|
|
|
}
|