diff --git a/modules/bnporc/__init__.py b/modules/bnporc/__init__.py index 00adecdc3240babc5bf4b5825fd8ef3b50b160cc..00c9df3bccdf6ef35dd6ecf35e024e38a44533de 100644 --- a/modules/bnporc/__init__.py +++ b/modules/bnporc/__init__.py @@ -17,7 +17,6 @@ # You should have received a copy of the GNU Lesser General Public License # along with this weboob module. If not, see . - from .module import BNPorcModule __all__ = ['BNPorcModule'] diff --git a/modules/bnporc/company/browser.py b/modules/bnporc/company/browser.py index 1e1a5ff2317b247c39e2036350c48c4575f1626d..9e9f48cb7dff14f5c70cd156045977f9930ee87d 100644 --- a/modules/bnporc/company/browser.py +++ b/modules/bnporc/company/browser.py @@ -17,6 +17,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with this weboob module. If not, see . +# yapf-compatible + from __future__ import unicode_literals from datetime import date, timedelta @@ -28,7 +30,6 @@ from .pages import LoginPage, AccountsPage, HistoryPage - __all__ = ['BNPCompany'] @@ -49,7 +50,6 @@ def do_login(self): self.page.login(self.username, self.password) - @need_login def iter_accounts(self): self.accounts.go() @@ -74,10 +74,11 @@ def get_transactions(self, id_account, typeReleve, dateMin, dateMax='null'): @need_login def iter_history(self, account): - return self.get_transactions(account.id, - 'Comptable', - (date.today() - timedelta(days=90)).strftime('%Y%m%d'), - date.today().strftime('%Y%m%d')) + return self.get_transactions( + account.id, + 'Comptable', (date.today() - timedelta(days=90)).strftime('%Y%m%d'), + date.today().strftime('%Y%m%d') + ) @need_login def iter_documents(self, subscription): @@ -89,9 +90,7 @@ def iter_subscription(self): @need_login def iter_coming_operations(self, account): - return self.get_transactions(account.id, - 'Previsionnel', - (date.today().strftime('%Y%m%d'))) + return self.get_transactions(account.id, 'Previsionnel', (date.today().strftime('%Y%m%d'))) @need_login def iter_investment(self, account): diff --git a/modules/bnporc/company/pages.py b/modules/bnporc/company/pages.py index 631fbe3d4f64d04768c7faaa145efecd730d3068..97e776d01d09875d1d30ddd182909fd8ea368171 100644 --- a/modules/bnporc/company/pages.py +++ b/modules/bnporc/company/pages.py @@ -17,6 +17,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with this weboob module. If not, see . +# yapf-compatible + from __future__ import unicode_literals from io import BytesIO @@ -32,19 +34,20 @@ class BNPVirtKeyboard(MappedVirtKeyboard): - symbols = {'0': 'ff069462836e30a39c911034048f5bb3', - '1': '7969f04e4e82eaefa2ce7a9a23c26178', - '2': '1e6020f97ca1c3ce3da4f39ded15d67d', - '3': 'f84284b40aea93c24814e23e14e76cc8', - '4': '88bab262d4b344c0ef8f06ddd01adbcf', - '5': '0a270764fc5d8334bcb55053432b26cb', - '6': 'e6a4444a6c752cd3e655f2883e530080', - '7': '933d4ca5df6b2b3df2dea00a21a3fed6', - '8': ['f28b918777d21a5fde2bffb9899e2138', 'a97e6e27159084d50f8ef00548b70252'], - '9': 'be751b77af0d998ab4c2cfd38455b2a6', - } - - color=(0,0,0) + symbols = { + '0': 'ff069462836e30a39c911034048f5bb3', + '1': '7969f04e4e82eaefa2ce7a9a23c26178', + '2': '1e6020f97ca1c3ce3da4f39ded15d67d', + '3': 'f84284b40aea93c24814e23e14e76cc8', + '4': '88bab262d4b344c0ef8f06ddd01adbcf', + '5': '0a270764fc5d8334bcb55053432b26cb', + '6': 'e6a4444a6c752cd3e655f2883e530080', + '7': '933d4ca5df6b2b3df2dea00a21a3fed6', + '8': ['f28b918777d21a5fde2bffb9899e2138', 'a97e6e27159084d50f8ef00548b70252'], + '9': 'be751b77af0d998ab4c2cfd38455b2a6', + } + + color = (0, 0, 0) def __init__(self, basepage): img = basepage.doc.xpath('//img[@id="gridpass_img"]')[0] diff --git a/modules/bnporc/enterprise/browser.py b/modules/bnporc/enterprise/browser.py index dd2602188f019563b69d4a2addab15dece63a8fc..3860d54bcf888c3bbcc79d29ed0d09ed0ddd67e8 100644 --- a/modules/bnporc/enterprise/browser.py +++ b/modules/bnporc/enterprise/browser.py @@ -17,6 +17,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with this weboob module. If not, see . +# yapf-compatible + from __future__ import unicode_literals from datetime import datetime @@ -36,27 +38,37 @@ PasswordExpiredPage, TransactionPage, MarketPage, InvestPage, ) - __all__ = ['BNPEnterprise'] class BNPEnterprise(LoginBrowser): BASEURL = 'https://secure1.entreprises.bnpparibas.net' - login = URL('/sommaire/jsp/identification.jsp', - '/sommaire/generateImg', LoginPage) + login = URL('/sommaire/jsp/identification.jsp', '/sommaire/generateImg', LoginPage) auth = URL('/sommaire/PseMenuServlet', AuthPage) accounts = URL('/NCCPresentationWeb/e10_soldes/liste_soldes.do', AccountsPage) - account_history_view = URL('/NCCPresentationWeb/e10_soldes/init.do\?nccIdSelected=NCC_Soldes', - '/NCCPresentationWeb/e11_releve_op/init.do\?identifiant=(?P)' - '&typeSolde=(?P)&typeReleve=(?P)&typeDate=(?P)' - '&dateMin=(?P)&dateMax=(?P)&ajax=true', - '/NCCPresentationWeb/e11_releve_op/init.do', AccountHistoryViewPage) - account_coming_view = URL('/NCCPresentationWeb/m04_selectionCompteGroupe/init.do\?type=compte&identifiant=(?P)', AccountHistoryViewPage) - account_history = URL('/NCCPresentationWeb/e11_releve_op/listeOperations.do\?identifiant=(?P)&typeSolde=(?P)&typeReleve=(?P)&typeDate=(?P)&dateMin=(?P)&dateMax=(?P)&ajax=true', - '/NCCPresentationWeb/e11_releve_op/listeOperations.do', AccountHistoryPage) - account_coming = URL('/NCCPresentationWeb/e12_rep_cat_op/listOperations.do\?periode=date_valeur&identifiant=(?P)', - '/NCCPresentationWeb/e12_rep_cat_op/listOperations.do', AccountHistoryPage) + account_history_view = URL( + '/NCCPresentationWeb/e10_soldes/init.do\?nccIdSelected=NCC_Soldes', + '/NCCPresentationWeb/e11_releve_op/init.do\?identifiant=(?P)' + '&typeSolde=(?P)&typeReleve=(?P)&typeDate=(?P)' + '&dateMin=(?P)&dateMax=(?P)&ajax=true', + '/NCCPresentationWeb/e11_releve_op/init.do', + AccountHistoryViewPage + ) + account_coming_view = URL( + '/NCCPresentationWeb/m04_selectionCompteGroupe/init.do\?type=compte&identifiant=(?P)', + AccountHistoryViewPage + ) + account_history = URL( + '/NCCPresentationWeb/e11_releve_op/listeOperations.do\?identifiant=(?P)&typeSolde=(?P)&typeReleve=(?P)&typeDate=(?P)&dateMin=(?P)&dateMax=(?P)&ajax=true', + '/NCCPresentationWeb/e11_releve_op/listeOperations.do', + AccountHistoryPage + ) + account_coming = URL( + '/NCCPresentationWeb/e12_rep_cat_op/listOperations.do\?periode=date_valeur&identifiant=(?P)', + '/NCCPresentationWeb/e12_rep_cat_op/listOperations.do', + AccountHistoryPage + ) transaction_detail = URL(r'/NCCPresentationWeb/e21/getOptBDDF.do', TransactionPage) invest = URL(r'/opcvm/lister-composition/afficher.do', InvestPage) @@ -139,7 +151,11 @@ def _iter_history_base(self, account): # To avoid duplicated transactions we exit as soon a transaction is not within the expected timeframe for date in rrule(MONTHLY, dtstart=(datetime.now() - relativedelta(months=11)), until=datetime.now())[::-1]: - params = dict(identifiant=account.iban, type_solde='C', type_releve='Previsionnel', type_date='O', + params = dict( + identifiant=account.iban, + type_solde='C', + type_releve='Previsionnel', + type_date='O', date_min=(date + relativedelta(days=1) - relativedelta(months=1)).strftime(dformat), date_max=date.strftime(dformat) ) @@ -153,8 +169,9 @@ def _iter_history_base(self, account): continue if transaction.date > date: - self.logger.debug('transaction not within expected timeframe, stop iterating history: %r', - transaction.to_dict()) + self.logger.debug( + 'transaction not within expected timeframe, stop iterating history: %r', transaction.to_dict() + ) return yield transaction diff --git a/modules/bnporc/enterprise/pages.py b/modules/bnporc/enterprise/pages.py index b48ce343cd8e8ed27f7564940c7efdf97e783813..ecee52478e0f6c41653dc5e6e39919ef5edb4841 100644 --- a/modules/bnporc/enterprise/pages.py +++ b/modules/bnporc/enterprise/pages.py @@ -17,6 +17,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with this weboob module. If not, see . +# yapf-compatible + from __future__ import unicode_literals import re @@ -39,22 +41,24 @@ from weboob.capabilities import NotAvailable from weboob.exceptions import BrowserPasswordExpired, BrowserForbidden + def fromtimestamp(milliseconds): - return datetime.fromtimestamp(milliseconds/1000) + return datetime.fromtimestamp(milliseconds / 1000) class BNPVirtKeyboard(MappedVirtKeyboard): - symbols = {'0': '8adee734aaefb163fb008d26bb9b3a42', - '1': 'dad45ef18a75200030073ab102155e2f', - '2': '6cb4c69361f5ce32b68b477db98dd0fb', - '3': 'aa9f2d90c8112b84805d908938eefff7', - '4': '5aa9329aceab4318c2c96130915e87b7', - '5': 'd9fbfdf531ad888a9d79855536905d23', - '6': '50ce19be233ac07bebb59a16a3b9d4a7', - '7': '3a1f932237aab949fa6c59565823218b', - '8': 'd46cf28408db75caa915edb871ea573a', - '9': '87686fd75d283905d7651e1098db0882', - } + symbols = { + '0': '8adee734aaefb163fb008d26bb9b3a42', + '1': 'dad45ef18a75200030073ab102155e2f', + '2': '6cb4c69361f5ce32b68b477db98dd0fb', + '3': 'aa9f2d90c8112b84805d908938eefff7', + '4': '5aa9329aceab4318c2c96130915e87b7', + '5': 'd9fbfdf531ad888a9d79855536905d23', + '6': '50ce19be233ac07bebb59a16a3b9d4a7', + '7': '3a1f932237aab949fa6c59565823218b', + '8': 'd46cf28408db75caa915edb871ea573a', + '9': '87686fd75d283905d7651e1098db0882', + } color = (0, 0, 0) @@ -106,8 +110,8 @@ def on_load(self): class AccountsPage(LoggedPage, JsonPage): TYPES = { - 'Compte chèque': Account.TYPE_CHECKING, - 'Compte à vue': Account.TYPE_CHECKING, + 'Compte chèque': Account.TYPE_CHECKING, + 'Compte à vue': Account.TYPE_CHECKING, } @method @@ -121,9 +125,7 @@ def obj_id(self): return CleanText(Dict('numeroCompte'))(self)[2:] obj_balance = Eval( - lambda x, y: x / 10**y, - CleanDecimal(Dict('soldeComptable')), - CleanDecimal(Dict('decSoldeComptable')) + lambda x, y: x / 10 ** y, CleanDecimal(Dict('soldeComptable')), CleanDecimal(Dict('decSoldeComptable')) ) obj_label = CleanText(Dict('libelleCompte')) obj_currency = CleanText(Dict('deviseTenue')) @@ -133,9 +135,7 @@ def obj_type(self): return self.page.TYPES.get(Dict('libelleType')(self), Account.TYPE_UNKNOWN) def obj_coming(self): - page = self.page.browser.open( - BrowserURL('account_coming', identifiant=Field('iban'))(self) - ).page + page = self.page.browser.open(BrowserURL('account_coming', identifiant=Field('iban'))(self)).page nb_decimal = 0 if 'nb_dec' in Dict('infoOperationsAvenir/cumulTotal')(page.doc): @@ -144,7 +144,7 @@ def obj_coming(self): nb_decimal = Dict('infoOperationsAvenir/cumulTotal/nbDec') coming = Eval( - lambda x, y: x / 10**y, + lambda x, y: x / 10**y, # yapf: disable CleanDecimal(Dict('infoOperationsAvenir/cumulTotal/montant', default='0')), CleanDecimal(nb_decimal) )(page.doc) @@ -161,7 +161,6 @@ class get_profile(ItemElement): class BnpHistoryItem(ItemElement): - def obj_raw(self): if self.el.get('nature.libelle') and self.el.get('libelle'): return "%s %s" % ( @@ -195,10 +194,12 @@ def load_details(self): return url = self.page.browser.transaction_detail.build() - return self.page.browser.open(url, is_async=True, data={ - 'type_mvt': self.detail_type_mvt, - 'numero_mvt': Field('_trid')(self), - }) + return self.page.browser.open( + url, is_async=True, data={ + 'type_mvt': self.detail_type_mvt, + 'numero_mvt': Field('_trid')(self), + } + ) class AccountHistoryPage(LoggedPage, JsonPage): @@ -257,10 +258,10 @@ def obj_raw(self): def obj_type(self): type = self.page.TYPES.get(Dict('nature/codefamille')(self), Transaction.TYPE_UNKNOWN) - if ( - (type == Transaction.TYPE_CARD and re.search(r' RELEVE DU \d+\.', Field('raw')(self))) or - (type == Transaction.TYPE_UNKNOWN and re.search(r'FACTURE CARTE AFFAIRES \w{16} SUIVANT RELEVE DU \d{2}.\d{2}.\d{4}', Field('raw')(self))) - ): + if ((type == Transaction.TYPE_CARD and re.search(r' RELEVE DU \d+\.', Field('raw')(self))) or ( + type == Transaction.TYPE_UNKNOWN and + re.search(r'FACTURE CARTE AFFAIRES \w{16} SUIVANT RELEVE DU \d{2}.\d{2}.\d{4}', Field('raw')(self)) + )): return Transaction.TYPE_CARD_SUMMARY return type @@ -289,14 +290,9 @@ def obj_vdate(self): return fromtimestamp(Dict('dateValeur')(self)) def obj_amount(self): - decimal_nb = Dict('montant/nbDec', default=None)(self)\ - or Dict('montant/nb_dec')(self) + decimal_nb = (Dict('montant/nbDec', default=None)(self) or Dict('montant/nb_dec')(self)) - return Eval( - lambda x, y: x / 10**y, - CleanDecimal(Dict('montant/montant')), - decimal_nb - )(self) + return Eval(lambda x, y: x / 10 ** y, CleanDecimal(Dict('montant/montant')), decimal_nb)(self) obj__trid = Dict('id') @@ -328,11 +324,7 @@ def obj_amount(self): decimal_nb = Dict('montantMvmt/nbDec', default=None)(self)\ or Dict('montantMvmt/nb_dec')(self) - return Eval( - lambda x, y: x / 10**y, - CleanDecimal(Dict('montantMvmt/montant')), - decimal_nb - )(self) + return Eval(lambda x, y: x / 10 ** y, CleanDecimal(Dict('montantMvmt/montant')), decimal_nb)(self) obj__trid = Dict('idMouvement') @@ -343,14 +335,16 @@ class TransactionPage(LoggedPage, JsonPage): class MarketPage(LoggedPage, HTMLPage): TYPES = { - 'comptes de titres': Account.TYPE_MARKET, + 'comptes de titres': Account.TYPE_MARKET, } @method class iter_market_accounts(TableElement): def condition(self): - return not self.el.xpath('//table[@id="table-portefeuille"]//tr/td[contains(text(), "Aucun portefeuille à afficher") \ - or contains(text(), "No portfolio to display")]') + return not self.el.xpath( + '//table[@id="table-portefeuille"]//tr/td[contains(text(), "Aucun portefeuille à afficher") \ + or contains(text(), "No portfolio to display")]' + ) item_xpath = '//table[@id="table-portefeuille"]/tbody[@class="main-content"]/tr' head_xpath = '//table[@id="table-portefeuille"]/thead/tr/th/label' @@ -384,7 +378,9 @@ def get_token(self): def get_id(self, label): id_simple = re.search(r'[0-9]+', label).group(0) - for options in self.doc.xpath('//div[@class="filterbox-content hide"]//select[@id="numero-compte-titre"]//option'): + for options in self.doc.xpath( + '//div[@class="filterbox-content hide"]//select[@id="numero-compte-titre"]//option' + ): if id_simple in CleanText(options)(self.doc): return CleanText(options.xpath('./@value'))(self) @@ -404,7 +400,6 @@ class get_unique_market_account(ItemElement): obj__parent = CleanText('//h3/span[span[@class="info-cheque"]]', children=False) obj__unique = True - @method class iter_investment(TableElement): item_xpath = '//table[@class="csv-data-container hide"]//tr' @@ -416,13 +411,11 @@ class iter_investment(TableElement): col_unitvalue = 'Valeur de la part' col_valuation = 'Valorisation' col_diff = '+/- value' - """ Note: Pagination is not handled yet for investments, if we find a customer with more than 10 invests we might have to handle clicking on the button to get 50 invests per page or check if there is a link. """ - class item(ItemElement): klass = Investment @@ -432,7 +425,11 @@ class item(ItemElement): obj_unitvalue = CleanDecimal(TableCell('unitvalue'), replace_dots=True) obj_valuation = CleanDecimal(TableCell('valuation'), replace_dots=True) obj_diff = CleanDecimal(TableCell('diff'), replace_dots=True) - obj_code_type = lambda self: Investment.CODE_TYPE_ISIN if Field('code')(self) is not NotAvailable else NotAvailable + + def obj_code_type(self): + if Field('code')(self): + return Investment.CODE_TYPE_ISIN + return NotAvailable def obj_code(self): string = CleanText(TableCell('label'))(self) diff --git a/modules/bnporc/module.py b/modules/bnporc/module.py index e3c0cd431f91b1bcad7808ea09a79f83d4f012a0..1cad2e55201f7ea7cc43c17be4c5b654d98f92a7 100644 --- a/modules/bnporc/module.py +++ b/modules/bnporc/module.py @@ -17,6 +17,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with this weboob module. If not, see . +# yapf-compatible + from __future__ import unicode_literals import re @@ -42,11 +44,12 @@ from .company.browser import BNPCompany from .pp.browser import BNPPartPro, HelloBank - __all__ = ['BNPorcModule'] -class BNPorcModule(Module, CapBankWealth, CapBankTransferAddRecipient, CapMessages, CapContact, CapProfile, CapDocument): +class BNPorcModule( + Module, CapBankWealth, CapBankTransferAddRecipient, CapMessages, CapContact, CapProfile, CapDocument +): NAME = 'bnporc' MAINTAINER = u'Romain Bignon' EMAIL = 'romain@weboob.org' @@ -54,15 +57,22 @@ class BNPorcModule(Module, CapBankWealth, CapBankTransferAddRecipient, CapMessag LICENSE = 'LGPLv3+' DESCRIPTION = 'BNP Paribas' CONFIG = BackendConfig( - ValueBackendPassword('login', label=u'Numéro client', masked=False), - ValueBackendPassword('password', label=u'Code secret', regexp='^(\d{6})$'), - ValueBool('rotating_password', label=u'Automatically renew password every 100 connections', default=False), - ValueBool('digital_key', label=u'User with digital key have to add recipient with digital key', default=False), - Value('website', label='Type de compte', default='pp', - choices={'pp': 'Particuliers/Professionnels', - 'hbank': 'HelloBank', - 'ent': 'Entreprises', - 'ent2': 'Entreprises et PME (nouveau site)'})) + ValueBackendPassword('login', label=u'Numéro client', masked=False), + ValueBackendPassword('password', label=u'Code secret', regexp='^(\d{6})$'), + ValueBool('rotating_password', label=u'Automatically renew password every 100 connections', default=False), + ValueBool('digital_key', label=u'User with digital key have to add recipient with digital key', default=False), + Value( + 'website', + label='Type de compte', + default='pp', + choices={ + 'pp': 'Particuliers/Professionnels', + 'hbank': 'HelloBank', + 'ent': 'Entreprises', + 'ent2': 'Entreprises et PME (nouveau site)' + } + ) + ) STORAGE = {'seen': []} accepted_document_types = ( @@ -141,7 +151,9 @@ def init_transfer(self, transfer, **params): recipient = strict_find_object(self.iter_transfer_recipients(account.id), iban=transfer.recipient_iban) if not recipient: - recipient = strict_find_object(self.iter_transfer_recipients(account.id), id=transfer.recipient_id, error=RecipientNotFound) + recipient = strict_find_object( + self.iter_transfer_recipients(account.id), id=transfer.recipient_id, error=RecipientNotFound + ) assert account.id.isdigit() # quantize to show 2 decimals. diff --git a/modules/bnporc/pp/browser.py b/modules/bnporc/pp/browser.py index 6f6eaab5e7b631ce727d68990780e5bd9a1a4a08..8f2e257b9027ec5e1d9cbc43bddce07ae58e5212 100644 --- a/modules/bnporc/pp/browser.py +++ b/modules/bnporc/pp/browser.py @@ -17,6 +17,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with this weboob module. If not, see . +# yapf-compatible + from __future__ import unicode_literals from datetime import datetime @@ -34,7 +36,6 @@ from weboob.capabilities.profile import ProfileMissing from weboob.tools.decorators import retry from weboob.tools.capabilities.bank.transactions import sorted_transactions -from weboob.tools.json import json from weboob.browser.exceptions import ServerError from weboob.browser.elements import DataError from weboob.exceptions import BrowserIncorrectPassword, BrowserUnavailable @@ -56,47 +57,35 @@ __all__ = ['BNPPartPro', 'HelloBank'] -def JSON(data): - return ('json', data) - - -def isJSON(obj): - return type(obj) is tuple and obj and obj[0] == 'json' - - -class JsonBrowserMixin(object): - def open(self, *args, **kwargs): - if isJSON(kwargs.get('data')): - kwargs['data'] = json.dumps(kwargs['data'][1]) - if 'headers' not in kwargs: - kwargs['headers'] = {} - kwargs['headers']['Content-Type'] = 'application/json' - - return super(JsonBrowserMixin, self).open(*args, **kwargs) - - -class BNPParibasBrowser(JsonBrowserMixin, LoginBrowser, StatesMixin): +class BNPParibasBrowser(LoginBrowser, StatesMixin): TIMEOUT = 30.0 - login = URL(r'identification-wspl-pres/identification\?acceptRedirection=true×tamp=(?P\d+)', - r'SEEA-pa01/devServer/seeaserver', - r'https://mabanqueprivee.bnpparibas.net/fr/espace-prive/comptes-et-contrats\?u=%2FSEEA-pa01%2FdevServer%2Fseeaserver', - LoginPage) + login = URL( + r'identification-wspl-pres/identification\?acceptRedirection=true×tamp=(?P\d+)', + r'SEEA-pa01/devServer/seeaserver', + r'https://mabanqueprivee.bnpparibas.net/fr/espace-prive/comptes-et-contrats\?u=%2FSEEA-pa01%2FdevServer%2Fseeaserver', + LoginPage + ) - list_error_page = URL(r'https://mabanque.bnpparibas/rsc/contrib/document/properties/identification-fr-part-V1.json', ListErrorPage) + list_error_page = URL( + r'https://mabanque.bnpparibas/rsc/contrib/document/properties/identification-fr-part-V1.json', ListErrorPage + ) useless_page = URL(r'/fr/connexion/comptes-et-contrats', UselessPage) - con_threshold = URL(r'/fr/connexion/100-connexions', - r'/fr/connexion/mot-de-passe-expire', - r'/fr/espace-prive/100-connexions.*', - r'/fr/espace-pro/100-connexions-pro.*', - r'/fr/espace-pro/changer-son-mot-de-passe', - r'/fr/espace-client/100-connexions', - r'/fr/espace-prive/mot-de-passe-expire', - r'/fr/client/mdp-expire', - r'/fr/client/100-connexion', - r'/fr/systeme/page-indisponible', ConnectionThresholdPage) + con_threshold = URL( + r'/fr/connexion/100-connexions', + r'/fr/connexion/mot-de-passe-expire', + r'/fr/espace-prive/100-connexions.*', + r'/fr/espace-pro/100-connexions-pro.*', + r'/fr/espace-pro/changer-son-mot-de-passe', + r'/fr/espace-client/100-connexions', + r'/fr/espace-prive/mot-de-passe-expire', + r'/fr/client/mdp-expire', + r'/fr/client/100-connexion', + r'/fr/systeme/page-indisponible', + ConnectionThresholdPage + ) accounts = URL(r'udc-wspl/rest/getlstcpt', AccountsPage) loan_details = URL(r'caraccomptes-wspl/rpc/(?P.*)', LoanDetailsPage) ibans = URL(r'rib-wspl/rpc/comptes', AccountsIBANPage) @@ -109,7 +98,9 @@ class BNPParibasBrowser(JsonBrowserMixin, LoginBrowser, StatesMixin): lifeinsurances_detail = URL(r'mefav-wspl/rest/detailMouvement', LifeInsurancesDetailPage) natio_vie_pro = URL(r'/mefav-wspl/rest/natioViePro', NatioVieProPage) - capitalisation_page = URL(r'https://www.clients.assurance-vie.fr/servlets/helios.cinrj.htmlnav.runtime.FrontServlet', CapitalisationPage) + capitalisation_page = URL( + r'https://www.clients.assurance-vie.fr/servlets/helios.cinrj.htmlnav.runtime.FrontServlet', CapitalisationPage + ) market_list = URL(r'pe-war/rpc/SAVaccountDetails/get', MarketListPage) market_syn = URL(r'pe-war/rpc/synthesis/get', MarketSynPage) @@ -184,7 +175,7 @@ def change_pass(self, oldpass, newpass): @need_login def get_profile(self): - self.profile.go(data=JSON({})) + self.profile.go(json={}, method='POST') profile = self.page.get_profile() if profile: return profile @@ -192,13 +183,9 @@ def get_profile(self): def is_loan(self, account): return account.type in ( - Account.TYPE_LOAN, - Account.TYPE_MORTGAGE, - Account.TYPE_CONSUMER_CREDIT, - Account.TYPE_REVOLVING_CREDIT + Account.TYPE_LOAN, Account.TYPE_MORTGAGE, Account.TYPE_CONSUMER_CREDIT, Account.TYPE_REVOLVING_CREDIT ) - @need_login def iter_accounts(self): if self.accounts_list is None: @@ -208,12 +195,12 @@ def iter_accounts(self): ibans = self.page.get_ibans_dict() if self.ibans.is_here() else self.ibans.go().get_ibans_dict() # This page might be unavailable. try: - ibans.update(self.transfer_init.go(data=JSON({'modeBeneficiaire': '0'})).get_ibans_dict('Crediteur')) + ibans.update(self.transfer_init.go(json={'modeBeneficiaire': '0'}).get_ibans_dict('Crediteur')) except (TransferAssertionError, AttributeError): pass accounts = list(self.accounts.go().iter_accounts(ibans=ibans)) - self.market_syn.go(data=JSON({})) # do a post on the given URL + self.market_syn.go(json={}, method='POST') # do a post on the given URL market_accounts = self.page.get_list() # get the list of 'Comptes Titres' checked_accounts = set() for account in accounts: @@ -282,30 +269,32 @@ def iter_history(self, account, coming=False): return self.iter_lifeinsurance_history(account, coming) elif account.type in (account.TYPE_MARKET, Account.TYPE_PEA) and not coming: try: - self.market_list.go(data=JSON({})) + self.market_list.go(json={}, method='POST') except ServerError: self.logger.warning("An Internal Server Error occurred") return iter([]) for market_acc in self.page.get_list(): if account.number[-4:] == market_acc['securityAccountNumber'][-4:]: - self.page = self.market_history.go(data=JSON({ - "securityAccountNumber": market_acc['securityAccountNumber'], - })) + self.page = self.market_history.go( + json={ + "securityAccountNumber": market_acc['securityAccountNumber'], + } + ) return self.page.iter_history() return iter([]) else: if not self.card_to_transaction_type: self.list_detail_card.go() self.card_to_transaction_type = self.page.get_card_to_transaction_type() - data = JSON({ + data = { "ibanCrypte": account.id, "pastOrPending": 1, "triAV": 0, "startDate": (datetime.now() - relativedelta(years=1)).strftime('%d%m%Y'), "endDate": datetime.now().strftime('%d%m%Y') - }) + } try: - self.history.go(data=data) + self.history.go(json=data) except BrowserUnavailable: # old url is still used for certain connections bu we don't know which one is, # so the same HistoryPage is attained by the old url in another URL object @@ -320,17 +309,19 @@ def iter_history(self, account, coming=False): @need_login def iter_lifeinsurance_history(self, account, coming=False): - self.lifeinsurances_history.go(data=JSON({ + self.lifeinsurances_history.go(json={ "ibanCrypte": account.id, - })) + }) for tr in self.page.iter_history(coming): - page = self.lifeinsurances_detail.go(data=JSON({ - "ibanCrypte": account.id, - "idMouvement": tr._op.get('idMouvement'), - "ordreMouvement": tr._op.get('ordreMouvement'), - "codeTypeMouvement": tr._op.get('codeTypeMouvement'), - })) + page = self.lifeinsurances_detail.go( + json={ + "ibanCrypte": account.id, + "idMouvement": tr._op.get('idMouvement'), + "ordreMouvement": tr._op.get('ordreMouvement'), + "codeTypeMouvement": tr._op.get('codeTypeMouvement'), + } + ) tr.investments = list(page.iter_investments()) yield tr @@ -357,14 +348,14 @@ def iter_investment(self, account): else: # No capitalisation contract has yet been found in the API: assert account.type != account.TYPE_CAPITALISATION - self.lifeinsurances.go(data=JSON({ + self.lifeinsurances.go(json={ "ibanCrypte": account.id, - })) + }) return self.page.iter_investments() elif account.type in (account.TYPE_MARKET, account.TYPE_PEA): try: - self.market_list.go(data=JSON({})) + self.market_list.go(json={}, method='POST') except ServerError: self.logger.warning("An Internal Server Error occurred") return iter([]) @@ -372,9 +363,9 @@ def iter_investment(self, account): if account.number[-4:] == market_acc['securityAccountNumber'][-4:] and not account.iban: # Sometimes generate an Internal Server Error ... try: - self.market.go(data=JSON({ + self.market.go(json={ "securityAccountNumber": market_acc['securityAccountNumber'], - })) + }) except ServerError: self.logger.warning("An Internal Server Error occurred") break @@ -385,7 +376,11 @@ def iter_investment(self, account): @need_login def iter_recipients(self, origin_account_id): try: - if not origin_account_id in self.transfer_init.go(data=JSON({'modeBeneficiaire': '0'})).get_ibans_dict('Debiteur'): + if ( + not origin_account_id in self.transfer_init.go(json={ + 'modeBeneficiaire': '0' + }).get_ibans_dict('Debiteur') + ): raise NotImplementedError() except TransferAssertionError: return @@ -398,7 +393,7 @@ def iter_recipients(self, origin_account_id): yield recipient if self.page.can_transfer_to_recipients(origin_account_id): - for recipient in self.recipients.go(data=JSON({'type': 'TOUS'})).iter_recipients(): + for recipient in self.recipients.go(json={'type': 'TOUS'}).iter_recipients(): if recipient.iban not in seen: seen.add(recipient.iban) yield recipient @@ -425,7 +420,7 @@ def new_recipient(self, recipient, **params): # need to be on recipient page send sms or mobile notification # needed to get the phone number, enabling the possibility to send sms. # all users with validated phone number can receive sms code - self.recipients.go(data=JSON({'type': 'TOUS'})) + self.recipients.go(json={'type': 'TOUS'}) # check type of recipient activation type_activation = 'sms' @@ -439,10 +434,7 @@ def new_recipient(self, recipient, **params): if type_activation == 'sms': # post recipient data sending sms with same request data['typeEnvoi'] = 'SMS' - recipient = self.add_recip.go( - data=json.dumps(data), - headers={'Content-Type': 'application/json'} - ).get_recipient(recipient) + recipient = self.add_recip.go(json=data).get_recipient(recipient) self.rcpt_transfer_id = recipient._transfer_id self.need_reload_state = True raise AddRecipientStep(recipient, Value('code', label='Saisissez le code reçu par SMS.')) @@ -451,7 +443,11 @@ def new_recipient(self, recipient, **params): recipient.enabled_date = datetime.today() raise AddRecipientStep( recipient, - ValueBool('digital_key', label='Validez pour recevoir une demande sur votre application bancaire. La validation de votre bénéficiaire peut prendre plusieurs minutes.') + ValueBool( + 'digital_key', + label= + 'Validez pour recevoir une demande sur votre application bancaire. La validation de votre bénéficiaire peut prendre plusieurs minutes.' + ) ) @need_login @@ -464,7 +460,7 @@ def send_code(self, recipient, **params): data['typeActivation'] = 1 data['codeActivation'] = params['code'] self.rcpt_transfer_id = None - return self.activate_recip_sms.go(data=json.dumps(data), headers={'Content-Type': 'application/json'}).get_recipient(recipient) + return self.activate_recip_sms.go(json=data).get_recipient(recipient) @need_login def new_recipient_digital_key(self, recipient, data): @@ -473,7 +469,7 @@ def new_recipient_digital_key(self, recipient, data): """ # post recipient data, sending app notification with same request data['typeEnvoi'] = 'AF' - self.add_recip.go(data=json.dumps(data), headers={'Content-Type': 'application/json'}) + self.add_recip.go(json=data) recipient = self.page.get_recipient(recipient) # prepare data for polling @@ -483,15 +479,12 @@ def new_recipient_digital_key(self, recipient, data): polling_data['idTransaction'] = recipient._id_transaction polling_data['typeActivation'] = 2 - timeout = time.time() + 300.00 # float(second), like bnp website + timeout = time.time() + 300.00 # float(second), like bnp website # polling while time.time() < timeout: - time.sleep(5) # like website - self.activate_recip_digital_key.go( - data = json.dumps(polling_data), - headers = {'Content-Type': 'application/json'} - ) + time.sleep(5) # like website + self.activate_recip_digital_key.go(json=polling_data) if self.page.is_recipient_validated(): break else: @@ -520,11 +513,11 @@ def init_transfer(self, account, recipient, amount, reason, exec_date): raise TransferInvalidRecipient(message="Le bénéficiaire sélectionné n'est pas activé") data = self.prepare_transfer(account, recipient, amount, reason, exec_date) - return self.validate_transfer.go(data=JSON(data)).handle_response(account, recipient, amount, reason) + return self.validate_transfer.go(json=data).handle_response(account, recipient, amount, reason) @need_login def execute_transfer(self, transfer): - self.register_transfer.go(data=JSON({'referenceVirement': transfer.id})) + self.register_transfer.go(json={'referenceVirement': transfer.id}) return self.page.handle_response(transfer) @need_login @@ -575,7 +568,9 @@ def iter_documents(self, subscription): data['ikpiPersonne'] = subscription._iduser self.document_research.go(json=data) - for doc in self.page.iter_documents(sub_id=subscription.id, sub_number=subscription._number, baseurl=self.BASEURL): + for doc in self.page.iter_documents( + sub_id=subscription.id, sub_number=subscription._number, baseurl=self.BASEURL + ): if doc.id not in id_docs: yield doc diff --git a/modules/bnporc/pp/document_pages.py b/modules/bnporc/pp/document_pages.py index e4a02e7ff11c4002db83c9d0d910ceb8db394ecf..35517ebcc1e29dce8ecc65aa3df5f45efa8e696d 100644 --- a/modules/bnporc/pp/document_pages.py +++ b/modules/bnporc/pp/document_pages.py @@ -17,6 +17,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with this weboob module. If not, see . +# yapf-compatible + from __future__ import unicode_literals import re @@ -73,13 +75,15 @@ def condition(self): def obj_label(self): if 'ibanCrypte' in self.el: - return '%s %s N° %s' % (Dict('dateDoc')(self), Dict('libelleSousFamille')(self), Dict('numeroCompteAnonymise')(self)) + return '%s %s N° %s' % ( + Dict('dateDoc')(self), Dict('libelleSousFamille')(self), Dict('numeroCompteAnonymise')(self) + ) else: return '%s %s N° %s' % (Dict('dateDoc')(self), Dict('libelleSousFamille')(self), Dict('idContrat')(self)) def obj_url(self): keys_to_copy = { - 'idDocument' :'idDoc', + 'idDocument': 'idDoc', 'dateDocument': 'dateDoc', 'idLocalisation': 'idLocalisation', 'viDocDocument': 'viDocDocument', diff --git a/modules/bnporc/pp/pages.py b/modules/bnporc/pp/pages.py index 882e6dcc37622810e7cddb4c32a38e47130c8ba1..1b39f69f963f03b2b299ca613b5d90f60d742d43 100644 --- a/modules/bnporc/pp/pages.py +++ b/modules/bnporc/pp/pages.py @@ -17,6 +17,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with this weboob module. If not, see . +# yapf-compatible + from __future__ import unicode_literals from collections import Counter @@ -60,7 +62,6 @@ class TransferAssertionError(Exception): class ConnectionThresholdPage(HTMLPage): NOT_REUSABLE_PASSWORDS_COUNT = 3 """BNP disallows to reuse one of the three last used passwords.""" - def make_date(self, yy, m, d): current = datetime.now().year if yy > current - 2000: @@ -109,8 +110,10 @@ def looks_legit(self, password): def on_load(self): msg = ( - CleanText('//div[@class="confirmation"]//span[span]')(self.doc) or - CleanText('//p[contains(text(), "Vous avez atteint la date de fin de vie de votre code secret")]')(self.doc) + CleanText('//div[@class="confirmation"]//span[span]')(self.doc) + or CleanText('//p[contains(text(), "Vous avez atteint la date de fin de vie de votre code secret")]')( + self.doc + ) ) self.logger.warning('Password expired.') @@ -154,16 +157,18 @@ def cast(x, typ, default=None): class BNPKeyboard(GridVirtKeyboard): color = (0x1f, 0x27, 0x28) margin = 3, 3 - symbols = {'0': '43b2227b92e0546d742a1f087015e487', - '1': '2914e8cc694de26756096d0d0d4c6e0f', - '2': 'aac54304a7bb850805d29f54557be366', - '3': '0376d9f8419efee42e253d195a152547', - '4': '3719595f15b1ac1c5a73d84aa290b5f6', - '5': '617597f07a6530479927536671485439', - '6': '4f5dce7bd0d9213fdae54b79bb8dd33a', - '7': '49e07fa52b9bcee798f3a663f86e6cc1', - '8': 'c60b723b3d95a46416b34c2cbefba3ed', - '9': 'a13b8c3617a7bf854590833ddfb97f1f'} + symbols = { + '0': '43b2227b92e0546d742a1f087015e487', + '1': '2914e8cc694de26756096d0d0d4c6e0f', + '2': 'aac54304a7bb850805d29f54557be366', + '3': '0376d9f8419efee42e253d195a152547', + '4': '3719595f15b1ac1c5a73d84aa290b5f6', + '5': '617597f07a6530479927536671485439', + '6': '4f5dce7bd0d9213fdae54b79bb8dd33a', + '7': '49e07fa52b9bcee798f3a663f86e6cc1', + '8': 'c60b723b3d95a46416b34c2cbefba3ed', + '9': 'a13b8c3617a7bf854590833ddfb97f1f' + } def __init__(self, browser, image): symbols = list('%02d' % x for x in range(1, 11)) @@ -191,7 +196,7 @@ def render_template(tmpl, **values): @staticmethod def generate_token(length=11): chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz' - return ''.join((chars[randint(0, len(chars)-1)] for _ in range(length))) + return ''.join((chars[randint(0, len(chars) - 1)] for _ in range(length))) def build_doc(self, text): try: @@ -222,7 +227,7 @@ def on_load(self): websiteUnavailable_codes = [207, 1000, 1001] if error in wrongpass_codes: raise BrowserIncorrectPassword(msg) - elif error == 21: # "Ce service est momentanément indisponible. Veuillez renouveler votre demande ultérieurement." -> In reality, account is blocked because of too much wrongpass + elif error == 21: # "Ce service est momentanément indisponible. Veuillez renouveler votre demande ultérieurement." -> In reality, account is blocked because of too much wrongpass raise ActionNeeded(u"Compte bloqué") elif error in actionNeeded_codes: raise ActionNeeded(msg) @@ -244,10 +249,12 @@ def login(self, username, password): target = self.browser.BASEURL + 'SEEA-pa01/devServer/seeaserver' user_agent = self.browser.session.headers.get('User-Agent') or '' - auth = self.render_template(self.get('data.authTemplate'), - idTelematique=username, - password=vk.get_string_code(password), - clientele=user_agent) + auth = self.render_template( + self.get('data.authTemplate'), + idTelematique=username, + password=vk.get_string_code(password), + clientele=user_agent + ) # XXX useless? csrf = self.generate_token() @@ -292,8 +299,12 @@ def condition(self): klass = Person def parse(self, el): - if not Dict(self.item_path + 'etatCivil/prenom')(el).strip() and not Dict(self.item_path + 'etatCivil/nom')(el).strip(): + if ( + not Dict(self.item_path + 'etatCivil/prenom')(el).strip() + and not Dict(self.item_path + 'etatCivil/nom')(el).strip() + ): raise ProfileMissing() + obj_name = Format('%s %s', Dict(item_path + 'etatCivil/prenom'), Dict(item_path + 'etatCivil/nom')) obj_spouse_name = Dict(item_path + 'etatCivil/nomMarital', default=NotAvailable) obj_birth_date = Date(Dict(item_path + 'etatCivil/dateNaissance'), dayfirst=True) @@ -446,10 +457,15 @@ def on_load(self): raise TransferAssertionError('%s, code=%s' % (message_code[0], message_code[1])) def get_ibans_dict(self, account_type): - return dict([(a['ibanCrypte'], a['iban']) for a in self.path('data.infoVirement.listeComptes%s.*' % account_type)]) + return dict([(a['ibanCrypte'], a['iban']) + for a in self.path('data.infoVirement.listeComptes%s.*' % account_type)]) def can_transfer_to_recipients(self, origin_account_id): - return next(a['eligibleVersBenef'] for a in self.path('data.infoVirement.listeComptesDebiteur.*') if a['ibanCrypte'] == origin_account_id) == '1' + return next( + a['eligibleVersBenef'] + for a in self.path('data.infoVirement.listeComptesDebiteur.*') + if a['ibanCrypte'] == origin_account_id + ) == '1' @method class transferable_on(DictElement): @@ -492,10 +508,15 @@ def obj_bank_name(self): return Dict('nomBanque')(self) or NotAvailable def obj_enabled_at(self): - return datetime.now().replace(microsecond=0) if Dict('libelleStatut')(self) == u'Activé' else (datetime.now() + timedelta(days=5)).replace(microsecond=0) + if Dict('libelleStatut')(self) == u'Activé': + return datetime.now().replace(microsecond=0) + return (datetime.now() + timedelta(days=5)).replace(microsecond=0) def has_digital_key(self): - return Dict('data/infoBeneficiaire/authentForte')(self.doc) and Dict('data/infoBeneficiaire/nomDeviceAF', default=False)(self.doc) + return ( + Dict('data/infoBeneficiaire/authentForte')(self.doc) + and Dict('data/infoBeneficiaire/nomDeviceAF', default=False)(self.doc) + ) class ValidateTransferPage(BNPPage): @@ -566,27 +587,45 @@ def handle_response(self, transfer): class Transaction(FrenchTransaction): - PATTERNS = [(re.compile(u'^(?PCHEQUE)(?P.*)'), FrenchTransaction.TYPE_CHECK), - (re.compile('^(?PFACTURE CARTE) DU (?P
\d{2})(?P\d{2})(?P\d{2}) (?P.*?)( CA?R?T?E? ?\d*X*\d*)?$'), - FrenchTransaction.TYPE_CARD), - (re.compile('^(?P(PRELEVEMENT|TELEREGLEMENT|TIP)) (?P.*)'), - FrenchTransaction.TYPE_ORDER), - (re.compile('^(?PPRLV( EUROPEEN)? SEPA) (?P.*?)( MDT/.*?)?( ECH/\d+)?( ID .*)?$'), - FrenchTransaction.TYPE_ORDER), - (re.compile('^(?PECHEANCEPRET)(?P.*)'), FrenchTransaction.TYPE_LOAN_PAYMENT), - (re.compile('^(?PRETRAIT DAB) (?P
\d{2})/(?P\d{2})/(?P\d{2})( (?P\d+)H(?P\d+))?( \d+)? (?P.*)'), - FrenchTransaction.TYPE_WITHDRAWAL), - (re.compile('^(?PVIR(EMEN)?T? (RECU |FAVEUR )?(TIERS )?)\w+ \d+/\d+ \d+H\d+ \w+ (?P.*)$'), - FrenchTransaction.TYPE_TRANSFER), - (re.compile('^(?PVIR(EMEN)?T? (EUROPEEN )?(SEPA )?(RECU |FAVEUR |EMIS )?(TIERS )?)(/FRM |/DE |/MOTIF |/BEN )?(?P.*?)(/.+)?$'), - FrenchTransaction.TYPE_TRANSFER), - (re.compile('^(?PREMBOURST) CB DU (?P
\d{2})(?P\d{2})(?P\d{2}) (?P.*)'), - FrenchTransaction.TYPE_PAYBACK), - (re.compile('^(?PREMBOURST)(?P.*)'), FrenchTransaction.TYPE_PAYBACK), - (re.compile('^(?PCOMMISSIONS)(?P.*)'), FrenchTransaction.TYPE_BANK), - (re.compile('^(?P(?PREMUNERATION).*)'), FrenchTransaction.TYPE_BANK), - (re.compile('^(?PREMISE CHEQUES)(?P.*)'), FrenchTransaction.TYPE_DEPOSIT), - ] + PATTERNS = [ + (re.compile(u'^(?PCHEQUE)(?P.*)'), FrenchTransaction.TYPE_CHECK), + ( + re.compile( + '^(?PFACTURE CARTE) DU (?P
\d{2})(?P\d{2})(?P\d{2}) (?P.*?)( CA?R?T?E? ?\d*X*\d*)?$' + ), + FrenchTransaction.TYPE_CARD + ), + (re.compile('^(?P(PRELEVEMENT|TELEREGLEMENT|TIP)) (?P.*)'), FrenchTransaction.TYPE_ORDER), + ( + re.compile('^(?PPRLV( EUROPEEN)? SEPA) (?P.*?)( MDT/.*?)?( ECH/\d+)?( ID .*)?$'), + FrenchTransaction.TYPE_ORDER + ), + (re.compile('^(?PECHEANCEPRET)(?P.*)'), FrenchTransaction.TYPE_LOAN_PAYMENT), + ( + re.compile( + '^(?PRETRAIT DAB) (?P
\d{2})/(?P\d{2})/(?P\d{2})( (?P\d+)H(?P\d+))?( \d+)? (?P.*)' + ), + FrenchTransaction.TYPE_WITHDRAWAL + ), + ( + re.compile('^(?PVIR(EMEN)?T? (RECU |FAVEUR )?(TIERS )?)\w+ \d+/\d+ \d+H\d+ \w+ (?P.*)$'), + FrenchTransaction.TYPE_TRANSFER + ), + ( + re.compile( + '^(?PVIR(EMEN)?T? (EUROPEEN )?(SEPA )?(RECU |FAVEUR |EMIS )?(TIERS )?)(/FRM |/DE |/MOTIF |/BEN )?(?P.*?)(/.+)?$' + ), + FrenchTransaction.TYPE_TRANSFER + ), + ( + re.compile('^(?PREMBOURST) CB DU (?P
\d{2})(?P\d{2})(?P\d{2}) (?P.*)'), + FrenchTransaction.TYPE_PAYBACK + ), + (re.compile('^(?PREMBOURST)(?P.*)'), FrenchTransaction.TYPE_PAYBACK), + (re.compile('^(?PCOMMISSIONS)(?P.*)'), FrenchTransaction.TYPE_BANK), + (re.compile('^(?P(?PREMUNERATION).*)'), FrenchTransaction.TYPE_BANK), + (re.compile('^(?PREMISE CHEQUES)(?P.*)'), FrenchTransaction.TYPE_DEPOSIT), + ] class HistoryPage(BNPPage): @@ -631,11 +670,15 @@ def iter_history(self): 'category': op.get('categorie'), 'amount': self.one('montant.montant', op), }) - tr.parse(raw=CleanText().filter(op.get('libelleOperation')), - date=parse_french_date(op.get('dateOperation')), - vdate=parse_french_date(self.one('montant.valueDate', op))) - - raw_is_summary = re.match(r'FACTURE CARTE SELON RELEVE DU\b|FACTURE CARTE CARTE AFFAIRES \d{4}X{8}\d{4} SUIVANT\b', tr.raw) + tr.parse( + raw=CleanText().filter(op.get('libelleOperation')), + date=parse_french_date(op.get('dateOperation')), + vdate=parse_french_date(self.one('montant.valueDate', op)) + ) + + raw_is_summary = re.match( + r'FACTURE CARTE SELON RELEVE DU\b|FACTURE CARTE CARTE AFFAIRES \d{4}X{8}\d{4} SUIVANT\b', tr.raw + ) if tr.type == Transaction.TYPE_CARD and raw_is_summary: tr.type = Transaction.TYPE_CARD_SUMMARY tr.deleted = True @@ -658,8 +701,7 @@ def iter_coming(self): parse_with_patterns(tr.raw, tr, Transaction.PATTERNS) if tr.type == Transaction.TYPE_CARD: - tr.type = self.browser.card_to_transaction_type.get(op.get('keyCarte'), - Transaction.TYPE_DEFERRED_CARD) + tr.type = self.browser.card_to_transaction_type.get(op.get('keyCarte'), Transaction.TYPE_DEFERRED_CARD) yield tr @@ -708,11 +750,13 @@ def iter_history(self, coming): 'type': Transaction.TYPE_BANK, '_state': op.get('statut'), 'amount': op.get('montantNet'), - }) + }) - tr.parse(date=parse_french_date(op.get('dateSaisie')), - vdate = parse_french_date(op.get('dateEffet')) if op.get('dateEffet') else None, - raw='%s %s' % (op.get('libelleMouvement'), op.get('canalSaisie') or '')) + tr.parse( + date=parse_french_date(op.get('dateSaisie')), + vdate=parse_french_date(op.get('dateEffet')) if op.get('dateEffet') else None, + raw='%s %s' % (op.get('libelleMouvement'), op.get('canalSaisie') or '') + ) tr._op = op if not tr.amount: @@ -732,10 +776,10 @@ class NatioVieProPage(BNPPage): # This form is required to go to the capitalisation contracts page. def get_params(self): params = { - 'app': 'BNPNET', - 'hageGroup': 'consultationBnpnet', - 'init': 'true', - 'multiInit': 'false', + 'app': 'BNPNET', + 'hageGroup': 'consultationBnpnet', + 'init': 'true', + 'multiInit': 'false', } params['a0'] = self.doc['data']['nationVieProInfos']['a0'] # The number of "p" keys may vary (p0, p1, p2 ... up to p13 or more) @@ -754,13 +798,13 @@ def has_contracts(self): # To be completed with other account labels and types seen on the "Assurance Vie" space: ACCOUNT_TYPES = { - 'BNP Paribas Multiplacements': Account.TYPE_LIFE_INSURANCE, - 'BNP Paribas Multihorizons': Account.TYPE_LIFE_INSURANCE, - 'BNP Paribas Libertéa Privilège': Account.TYPE_LIFE_INSURANCE, - 'BNP Paribas Avenir Retraite': Account.TYPE_LIFE_INSURANCE, - 'BNP Paribas Multiciel Privilège': Account.TYPE_CAPITALISATION, - 'Plan Epargne Retraite Particulier': Account.TYPE_PERP, - "Plan d'Épargne Retraite des Particuliers": Account.TYPE_PERP, + 'BNP Paribas Multiplacements': Account.TYPE_LIFE_INSURANCE, + 'BNP Paribas Multihorizons': Account.TYPE_LIFE_INSURANCE, + 'BNP Paribas Libertéa Privilège': Account.TYPE_LIFE_INSURANCE, + 'BNP Paribas Avenir Retraite': Account.TYPE_LIFE_INSURANCE, + 'BNP Paribas Multiciel Privilège': Account.TYPE_CAPITALISATION, + 'Plan Epargne Retraite Particulier': Account.TYPE_PERP, + "Plan d'Épargne Retraite des Particuliers": Account.TYPE_PERP, } @method @@ -812,7 +856,9 @@ def get_params(self, account): # The investments vdate is out of the investments table and is the same for all investments: def get_vdate(self): - return parse_french_date(CleanText('//table[tr[th[text()[contains(., "Date de valorisation")]]]]/tr[2]/td[2]')(self.doc)) + return parse_french_date( + CleanText('//table[tr[th[text()[contains(., "Date de valorisation")]]]]/tr[2]/td[2]')(self.doc) + ) @method class iter_investments(TableElement): @@ -832,6 +878,7 @@ class item(ItemElement): obj_label = CleanText(TableCell('label')) obj_valuation = CleanDecimal(TableCell('valuation'), replace_dots=True) obj_portfolio_share = Eval(lambda x: x / 100, CleanDecimal(TableCell('portfolio_share'), replace_dots=True)) + # There is no "unitvalue" information available on the "Assurances Vie" space. def obj_quantity(self): @@ -889,7 +936,7 @@ def iter_history(self): 'amount': op.get('movementAmount'), 'date': datetime.fromtimestamp(op.get('movementDate') / 1000), 'label': op.get('operationName'), - }) + }) tr.investments = [] inv = Investment() @@ -916,7 +963,9 @@ class item(ItemElement): obj_mobile = CleanText(Dict('data/mobile'), replace=[(' ', '')]) obj_fax = CleanText(Dict('data/fax'), replace=[(' ', '')]) obj_agency = Dict('data/agence') - obj_address = Format('%s %s %s', Dict('data/adresseAgence'), Dict('data/codePostalAgence'), Dict('data/villeAgence')) + obj_address = Format( + '%s %s %s', Dict('data/adresseAgence'), Dict('data/codePostalAgence'), Dict('data/villeAgence') + ) class AddRecipPage(BNPPage): diff --git a/modules/bnporc/test.py b/modules/bnporc/test.py index 0ef44256084a55453b6cb3c8341dbbef28ecb4c1..8d054f47fd5a9ba08ccd8ee4804b4186fb36189e 100644 --- a/modules/bnporc/test.py +++ b/modules/bnporc/test.py @@ -17,7 +17,6 @@ # You should have received a copy of the GNU Lesser General Public License # along with this weboob module. If not, see . - from weboob.tools.test import BackendTest from random import choice