1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
# at_02.py - functions for handling AT-02 (SEPA Creditor identifier)
#
# Copyright (C) 2014-2016 Sergi Almacellas Abellana
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
"""SEPA Identifier of the Creditor (AT-02).
This identifier is indicated in the ISO 20022 data element `Creditor Scheme
Identification`. The creditor can be a legal entity, or an association that
is not a legal entity, or a person.
The first two digits contain the ISO country code, the next two are check
digits for the ISO 7064 Mod 97, 10 checksum, the next tree contain the
Creditor Business Code (or `ZZZ` if no business code used) and the remainder
contains the country-specific identifier.
>>> validate('ES 23 ZZZ 47690558N')
'ES23ZZZ47690558N'
>>> validate('ES2300047690558N')
'ES2300047690558N'
>>> compact('ES++()+23ZZZ4//7690558N')
'ES23ZZZ47690558N'
>>> calc_check_digits('ESXXZZZ47690558N')
'23'
"""
from stdnum.exceptions import *
from stdnum.iso7064 import mod_97_10
from stdnum.util import clean
# the valid characters we have
_alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
def compact(number):
"""Convert the AT-02 number to the minimal representation. This strips
the number of any valid separators and removes invalid characters."""
return clean(number, ' -/?:().m\'+"').strip().upper()
def _to_base10(number):
"""Prepare the number to its base10 representation so it can be checked
with the ISO 7064 Mod 97, 10 algorithm. That means excluding positions 5
to 7 and moving the first four digits to the end."""
return ''.join(str(_alphabet.index(x)) for x in number[7:] + number[:4])
def validate(number):
"""Check if the number provided is a valid AT-02."""
number = compact(number)
try:
test_number = _to_base10(number)
except Exception: # noqa: B902
raise InvalidFormat()
# ensure that checksum is valid
mod_97_10.validate(test_number)
return number
def is_valid(number):
"""Check if the number provided is a valid AT-02."""
try:
return bool(validate(number))
except ValidationError:
return False
def calc_check_digits(number):
"""Calculate the check digits that should be put in the number to make it
valid. Check digits in the supplied number are ignored."""
number = compact(number)
# replace check digits with placeholders
number = ''.join((number[:2], '00', number[4:]))
return mod_97_10.calc_check_digits(_to_base10(number)[:-2])
|