diff --git a/modules/bnporc/company/browser.py b/modules/bnporc/company/browser.py index a38ea186..4eb1aee3 100644 --- a/modules/bnporc/company/browser.py +++ b/modules/bnporc/company/browser.py @@ -17,8 +17,11 @@ # You should have received a copy of the GNU Affero General Public License # along with weboob. If not, see . +from datetime import date, timedelta + from weboob.browser import LoginBrowser, URL, need_login -from weboob.exceptions import BrowserIncorrectPassword +from weboob.capabilities.base import find_object +from weboob.capabilities.bank import AccountNotFound from .pages import LoginPage, AccountsPage, HistoryPage @@ -31,7 +34,7 @@ class BNPCompany(LoginBrowser): login = URL('/sommaire/jsp/identification.jsp', LoginPage) accounts = URL('/NCCPresentationWeb/e10_soldes/liste_soldes.do', AccountsPage) - history = URL('/NCCPresentationWeb/m04_selectionCompteGroupe/init.do?type=compte&identifiant=', HistoryPage) + history = URL('/NCCPresentationWeb/e11_releve_op/listeOperations.do', HistoryPage) def do_login(self): assert isinstance(self.username, basestring) @@ -43,8 +46,6 @@ class BNPCompany(LoginBrowser): self.page.login(self.username, self.password) - if self.login.is_here(): - raise BrowserIncorrectPassword() @need_login def get_accounts_list(self): @@ -53,15 +54,50 @@ class BNPCompany(LoginBrowser): @need_login def get_account(self, _id): - pass + return find_object(self.get_accounts_list(), id=_id, error=AccountNotFound) + + def get_transactions(self, id_account, typeReleve, dateMin, dateMax='null'): + self.open('https://secure1.entreprises.bnpparibas.net/NCCPresentationWeb/e11_releve_op/init.do?e10=true') + params = {} + params['identifiant'] = id_account + params['typeSole'] = 'C' + params['typeReleve'] = typeReleve + params['typeDate'] = 'O' + params['ajax'] = 'true' + params['dateMin'] = dateMin + params['dateMax'] = dateMax + self.history.go(params=params) + return self.page.iter_history() @need_login def iter_history(self, account): - pass + 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_coming_operations(self, account): - pass + return self.get_transactions(account.id, + 'Previsionnel', + (date.today().strftime('%Y%m%d'))) + @need_login def iter_investment(self, account): raise NotImplementedError() + + @need_login + def get_transfer_accounts(self): + raise NotImplementedError() + + @need_login + def transfer(self, account, to, amount, reason): + raise NotImplementedError() + + @need_login + def iter_threads(self): + raise NotImplementedError() + + @need_login + def get_thread(self, thread): + raise NotImplementedError() diff --git a/modules/bnporc/company/pages.py b/modules/bnporc/company/pages.py index ce4ba828..6180436f 100644 --- a/modules/bnporc/company/pages.py +++ b/modules/bnporc/company/pages.py @@ -20,11 +20,13 @@ from StringIO import StringIO import hashlib from decimal import Decimal +from datetime import datetime from weboob.capabilities.bank import Account +from weboob.exceptions import BrowserIncorrectPassword +from weboob.tools.capabilities.bank.transactions import FrenchTransaction from weboob.browser.pages import HTMLPage, JsonPage, LoggedPage from weboob.tools.captcha.virtkeyboard import MappedVirtKeyboard, VirtKeyboardError -from weboob.tools.json import json class BNPVirtKeyboard(MappedVirtKeyboard): @@ -89,20 +91,71 @@ class LoginPage(HTMLPage): form['gridpass_hidden_input'] = vk.get_string_code(password) form.submit() + def on_load(self): + if self.doc.xpath('//p[contains(text(), "Your identification is wrong.")]'): + raise BrowserIncorrectPassword("Your identification is wrong.") -class AccountsPage(JsonPage, LoggedPage): +class AccountsPage(LoggedPage, JsonPage): + FAMILY_TO_TYPE = { + u"Compte chèque": Account.TYPE_CHECKING, + } + def iter_accounts(self): for f in self.path('tableauSoldes.listeGroupes'): for g in f: for a in g.get('listeComptes'): yield Account.from_dict({ 'id': a.get('numeroCompte'), + 'type': self.FAMILY_TO_TYPE.get(a.get('libelleType')) or Account.TYPE_UNKNOWN, 'label': '%s %s' % (a.get('libelleType'), a.get('libelleTitulaire')), 'currency': a.get('deviseTenue'), 'balance': Decimal(a.get('soldeComptable')) / 100, 'coming': Decimal(a.get('soldePrevisionnel')) / 100, }) -class HistoryPage(JsonPage, LoggedPage): - pass + +class HistoryPage(LoggedPage, JsonPage): + CODE_TO_TYPE = { + "AUTOP": FrenchTransaction.TYPE_UNKNOWN, # Autres opérations, + "BOURS": FrenchTransaction.TYPE_BANK, # Bourse / Titres, + "CARTE": FrenchTransaction.TYPE_CARD, # Cartes, + "CHEQU": FrenchTransaction.TYPE_CHECK, # Chèques, + "CREDD": FrenchTransaction.TYPE_UNKNOWN, # Crédits documentaires, + "CREDI": FrenchTransaction.TYPE_UNKNOWN, # Crédits, + "EFFET": FrenchTransaction.TYPE_UNKNOWN, # Effets, + "ESPEC": FrenchTransaction.TYPE_UNKNOWN, # Espèces, + "FACCB": FrenchTransaction.TYPE_UNKNOWN, # Factures / Retraits cartes, + "ICHEQ": FrenchTransaction.TYPE_UNKNOWN, # Impayés chèques, + "IEFFE": FrenchTransaction.TYPE_UNKNOWN, # Impayés et incidents effets, + "IMPAY": FrenchTransaction.TYPE_UNKNOWN, # Impayés et rejets, + "IPRLV": FrenchTransaction.TYPE_UNKNOWN, # Impayés prélèvements, TIP et télérèglements, + "PRLVT": FrenchTransaction.TYPE_UNKNOWN, # Prélèvements, TIP et télérèglements, + "REMCB": FrenchTransaction.TYPE_UNKNOWN, # Remises cartes, + "RJVIR": FrenchTransaction.TYPE_ORDER, # Rejets de virements, + "VIREM": FrenchTransaction.TYPE_ORDER, # Virements, + "VIRIT": FrenchTransaction.TYPE_ORDER, # Virements internationaux, + "VIRSP": FrenchTransaction.TYPE_ORDER, # Virements européens, + "VIRTR": FrenchTransaction.TYPE_ORDER, # Virements de trésorerie, + "VIRXX": FrenchTransaction.TYPE_ORDER, # Autres virements + } + + def one(self, path, context=None): + try: + return list(self.path(path, context))[0] + except IndexError: + return None + + def iter_history(self): + for op in self.get('mouvementsBDDF'): + codeFamille = self.one('nature.codefamille', op) + tr = FrenchTransaction.from_dict({ + 'id': op.get('id'), + 'type': self.CODE_TO_TYPE.get(codeFamille) or FrenchTransaction.TYPE_UNKNOWN, + 'category': self.one('nature.libelle', op), + 'raw': ' '.join(op.get('libelle').split()) or op.get('nature')['libelle'], + 'date': datetime.fromtimestamp(op.get('dateOperation') / 1000), + 'vdate': datetime.fromtimestamp(op.get('dateValeur') / 1000), + 'amount': Decimal(self.one('montant.montant', op)) / 100, + }) + yield tr diff --git a/modules/bnporc/module.py b/modules/bnporc/module.py index 854b6c5c..bd5239ed 100644 --- a/modules/bnporc/module.py +++ b/modules/bnporc/module.py @@ -74,8 +74,6 @@ class BNPorcModule(Module, CapBank, CapMessages): yield account def get_account(self, _id): - if not _id.isdigit(): - raise AccountNotFound() account = self.browser.get_account(_id) if account: return account