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 FormatError(FilterError): pass
[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