Source code for woob.tools.capabilities.bank.investments
# Copyright(C) 2017 Jonathan Schmidt
#
# This file is part of woob.
#
# woob 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 3 of the License, or
# (at your option) any later version.
#
# woob 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 woob. If not, see <http://www.gnu.org/licenses/>.
from decimal import Decimal
import re
from woob.capabilities.base import NotAvailable
from woob.capabilities.bank.wealth import Investment
from woob.browser.filters.base import Filter, FilterError, debug
from woob.tools.log import getLogger
[docs]def is_isin_valid(isin):
"""
Méthode générale
Table de conversion des lettres en chiffres
A=10 B=11 C=12 D=13 E=14 F=15 G=16 H=17 I=18
J=19 K=20 L=21 M=22 N=23 O=24 P=25 Q=26 R=27
S=28 T=29 U=30 V=31 W=32 X=33 Y=34 Z=35
1 - Mettre de côté la clé, qui servira de référence à la fin de la vérification.
2 - Convertir toutes les lettres en nombres via la table de conversion ci-contre. Si le nombre obtenu est supérieur ou égal à 10, prendre les deux chiffres du nombre séparément (exemple : 27 devient 2 et 7).
3 - Pour chaque chiffre, multiplier sa valeur par deux si sa position est impaire en partant de la droite. Si le nombre obtenu est supérieur ou égal à 10, garder les deux chiffres du nombre séparément (exemple : 14 devient 1 et 4).
4 - Faire la somme de tous les chiffres.
5 - Soustraire cette somme de la dizaine supérieure ou égale la plus proche (exemples : si la somme vaut 22, la dizaine « supérieure ou égale » est 30, et la clé vaut donc 8 ; si la somme vaut 30, la dizaine « supérieure ou égale » est 30, et la clé vaut 0 ; si la somme vaut 31, la dizaine « supérieure ou égale » est 40, et la clé vaut 9).
6 - Comparer la valeur obtenue à la clé mise initialement de côté.
Étapes 1 et 2 :
F R 0 0 0 3 5 0 0 0 0 (+ 8 : clé)
15 27 0 0 0 3 5 0 0 0 0
Étape 3 : le traitement se fait sur des chiffres
1 5 2 7 0 0 0 3 5 0 0 0 0
I P I P I P I P I P I P I : position en partant de la droite (P = Pair, I = Impair)
2 1 2 1 2 1 2 1 2 1 2 1 2 : coefficient multiplicateur
2 5 4 7 0 0 0 3 10 0 0 0 0 : résultat
Étape 4 :
2 + 5 + 4 + 7 + 0 + 0 + 0 + 3 + (1 + 0)+ 0 + 0 + 0 + 0 = 22
Étapes 5 et 6 : 30 - 22 = 8 (valeur de la clé)
"""
if not isinstance(isin, str):
return False
if not re.match(r'^[A-Z]{2}[A-Z0-9]{9}\d$', isin):
return False
isin_in_digits = ''.join(str(ord(x) - ord('A') + 10) if not x.isdigit() else x for x in isin[:-1])
key = isin[-1:]
result = ''
for k, val in enumerate(isin_in_digits[::-1], start=1):
if k % 2 == 0:
result = ''.join((result, val))
else:
result = ''.join((result, str(int(val)*2)))
return str(sum(int(x) for x in result) + int(key))[-1] == '0'
[docs]def create_french_liquidity(valuation):
"""
Automatically fills a liquidity investment with label, code and code_type.
"""
if isinstance(valuation, Decimal) and valuation < 0:
getLogger('%s.create_French_liquidity' % __name__).warning("Liquidity has a negative value")
liquidity = Investment()
liquidity.label = "Liquidités"
liquidity.code = "XX-liquidity"
liquidity.code_type = NotAvailable
liquidity.valuation = valuation
return liquidity
# These filters can be used to set Investment.code
# and Investment.code_type without having to declare
# obj_code() and obj_code_type() methods in each module
[docs]class IsinCode(Filter):
"""
Returns the input only if it is a valid ISIN code.
"""
[docs] @debug()
def filter(self, code):
if is_isin_valid(code):
return code
return self.default_or_raise(FormatError('%r is not a valid ISIN code, no default value was set.' % code))
[docs]class IsinType(Filter):
"""
Returns Investment.CODE_TYPE_ISIN if the input is a valid ISIN code.
"""
[docs] @debug()
def filter(self, code):
if is_isin_valid(code):
return Investment.CODE_TYPE_ISIN
return NotAvailable