From a9b2f5fe66aebcc1394ba6489fc745a6ecce82c1 Mon Sep 17 00:00:00 2001 From: Romain Bignon Date: Sun, 7 Dec 2014 16:20:51 +0100 Subject: [PATCH] support new website of bred --- modules/bred/bred/__init__.py | 3 + modules/bred/bred/browser.py | 114 ++++++++++++++++++++++++ modules/bred/dispobank/__init__.py | 3 + modules/bred/{ => dispobank}/browser.py | 15 ++-- modules/bred/{ => dispobank}/pages.py | 0 modules/bred/module.py | 30 +++---- 6 files changed, 140 insertions(+), 25 deletions(-) create mode 100644 modules/bred/bred/__init__.py create mode 100644 modules/bred/bred/browser.py create mode 100644 modules/bred/dispobank/__init__.py rename modules/bred/{ => dispobank}/browser.py (93%) rename modules/bred/{ => dispobank}/pages.py (100%) diff --git a/modules/bred/bred/__init__.py b/modules/bred/bred/__init__.py new file mode 100644 index 00000000..ee8b90cc --- /dev/null +++ b/modules/bred/bred/__init__.py @@ -0,0 +1,3 @@ +from .browser import BredBrowser + +__all__ = ['BredBrowser'] diff --git a/modules/bred/bred/browser.py b/modules/bred/bred/browser.py new file mode 100644 index 00000000..0ebd033c --- /dev/null +++ b/modules/bred/bred/browser.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2014 Romain Bignon +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + +from datetime import date +from decimal import Decimal + +from weboob.capabilities.bank import Account, Transaction +from weboob.exceptions import BrowserIncorrectPassword +from weboob.browser import DomainBrowser + + +__all__ = ['BredBrowser'] + + +class BredBrowser(DomainBrowser): + BASEURL = 'https://www.bred.fr' + + def __init__(self, accnum, login, password, *args, **kwargs): + super(BredBrowser, self).__init__(*args, **kwargs) + self.login = login + self.password = password + self.accnum = accnum + + self.do_login(login, password) + + def do_login(self, login, password): + self.location('/transactionnel/Authentication', data={'identifiant': login, 'password': password}) + + if 'erreur-pwd' in self.url: + raise BrowserIncorrectPassword() + + ACCOUNT_TYPES = {'000': Account.TYPE_CHECKING, + '999': Account.TYPE_MARKET, + '011': Account.TYPE_CARD, + '023': Account.TYPE_SAVINGS, + '078': Account.TYPE_SAVINGS, + '080': Account.TYPE_SAVINGS, + '027': Account.TYPE_SAVINGS, + '037': Account.TYPE_SAVINGS, + } + def get_accounts_list(self): + r = self.open('/transactionnel/services/rest/Account/accounts') + + for content in r.json()['content']: + if self.accnum != '00000000000' and content['numero'] != self.accnum: + continue + for poste in content['postes']: + a = Account() + a._number = content['numeroLong'] + a._nature = poste['codeNature'] + a._consultable = poste['consultable'] + a.id = '%s.%s' % (a._number, a._nature) + a.type = self.ACCOUNT_TYPES.get(poste['codeNature'], Account.TYPE_UNKNOWN) + + if poste['postePortefeuille']: + a.label = u'Portefeuille Titres' + a.balance = Decimal(poste['montantTitres']['valeur']) + a.currency = poste['montantTitres']['monnaie']['code'] + yield a + + if not 'libelle' in poste: + continue + + a.label = ' '.join([content['intitule'].strip(), poste['libelle'].strip()]) + a.balance = Decimal(poste['solde']['valeur']) + a.currency = poste['solde']['monnaie']['code'] + yield a + + def get_history(self, account): + if not account._consultable: + raise NotImplementedError() + + offset = 0 + next_page = True + while next_page: + r = self.open('/transactionnel/services/applications/operations/get/%(number)s/%(nature)s/00/%(currency)s/%(startDate)s/%(endDate)s/%(offset)s/%(limit)s' % + {'number': account._number, + 'nature': account._nature, + 'currency': account.currency, + 'startDate': '2000-01-01', + 'endDate': date.today().strftime('%Y-%m-%d'), + 'offset': offset, + 'limit': 50 + }) + next_page = False + offset += 50 + for op in r.json()['content']['operations']: + next_page = True + t = Transaction() + t.id = op['id'] + t.amount = Decimal(str(op['montant'])) + t.date = date.fromtimestamp(op.get('dateDebit', op.get('dateOperation'))/1000) + t.rdate = date.fromtimestamp(op.get('dateOperation', op.get('dateDebit'))/1000) + t.vdate = date.fromtimestamp(op.get('dateValeur', op.get('dateDebit', op.get('dateOperation')))/1000) + t.category = op['categorie'] + t.label = op['libelle'] + t.raw = ' '.join([op['libelle']] + op['details']) + yield t diff --git a/modules/bred/dispobank/__init__.py b/modules/bred/dispobank/__init__.py new file mode 100644 index 00000000..9824dd3f --- /dev/null +++ b/modules/bred/dispobank/__init__.py @@ -0,0 +1,3 @@ +from .browser import DispoBankBrowser + +__all__ = ['DispoBankBrowser'] diff --git a/modules/bred/browser.py b/modules/bred/dispobank/browser.py similarity index 93% rename from modules/bred/browser.py rename to modules/bred/dispobank/browser.py index a3a8fc50..2ba6c761 100644 --- a/modules/bred/browser.py +++ b/modules/bred/dispobank/browser.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2012 Romain Bignon +# Copyright(C) 2012-2014 Romain Bignon # # This file is part of weboob. # @@ -25,12 +25,12 @@ from weboob.deprecated.browser import Browser, BrowserIncorrectPassword from .pages import LoginPage, LoginResultPage, AccountsPage, EmptyPage, TransactionsPage -__all__ = ['BredBrowser'] +__all__ = ['DispoBankBrowser'] -class BredBrowser(Browser): +class DispoBankBrowser(Browser): PROTOCOL = 'https' - DOMAIN = 'www.bred.fr' + DOMAIN = 'www.dispobank.fr' CERTHASH = ['9b77dab9c84e1dc9e0798de561a6541ff15f038f60b36ca74c29be1def6c19a3', '375f1fed165d34aacaaf71674ab14ca6c1b38404cf748278714fde3c58385ff0', '0853a056453b56aea6a29085ef3f3721b18db2052aa8e84220720d44e0eb22af'] ENCODING = 'iso-8859-15' PAGES = {r'https://www.\w+.fr/mylittleform.*': LoginPage, @@ -50,10 +50,9 @@ class BredBrowser(Browser): } } - def __init__(self, website, accnum, *args, **kwargs): - self.accnum = accnum.replace(' ','').zfill(11) - self.DOMAIN = 'www.%s.fr' % website - self.website = website + def __init__(self, accnum, *args, **kwargs): + self.accnum = accnum + self.website = 'dispobank' Browser.__init__(self, *args, **kwargs) def is_logged(self): diff --git a/modules/bred/pages.py b/modules/bred/dispobank/pages.py similarity index 100% rename from modules/bred/pages.py rename to modules/bred/dispobank/pages.py diff --git a/modules/bred/module.py b/modules/bred/module.py index 1ad9d91a..2cbd579e 100644 --- a/modules/bred/module.py +++ b/modules/bred/module.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2012-2013 Romain Bignon +# Copyright(C) 2012-2014 Romain Bignon # # This file is part of weboob. # @@ -19,10 +19,12 @@ from weboob.capabilities.bank import CapBank, AccountNotFound +from weboob.capabilities.base import find_object from weboob.tools.backend import Module, BackendConfig from weboob.tools.value import ValueBackendPassword, Value -from .browser import BredBrowser +from .bred import BredBrowser +from .dispobank import DispoBankBrowser __all__ = ['BredModule'] @@ -41,28 +43,22 @@ class BredModule(Module, CapBank): choices={'bred': 'BRED', 'dispobank': 'DispoBank'}), Value('accnum', label=u'Numéro du compte bancaire (optionnel)', default='', masked=False) ) - BROWSER = BredBrowser + + BROWSERS = {'bred': BredBrowser, + 'dispobank': DispoBankBrowser, + } def create_default_browser(self): - return self.create_browser(self.config['website'].get(), - self.config['accnum'].get(), + self.BROWSER = self.BROWSERS[self.config['website'].get()] + return self.create_browser(self.config['accnum'].get().replace(' ','').zfill(11), self.config['login'].get(), self.config['password'].get()) def iter_accounts(self): - with self.browser: - for account in self.browser.get_accounts_list(): - yield account + return self.browser.get_accounts_list() def get_account(self, _id): - with self.browser: - account = self.browser.get_account(_id) - - if account: - return account - else: - raise AccountNotFound() + return find_object(self.browser.get_accounts_list(), id=_id, error=AccountNotFound) def iter_history(self, account): - with self.browser: - return self.browser.get_history(account) + return self.browser.get_history(account)