diff --git a/modules/creditcooperatif/module.py b/modules/creditcooperatif/module.py index 90611f13..2f694c23 100644 --- a/modules/creditcooperatif/module.py +++ b/modules/creditcooperatif/module.py @@ -56,17 +56,13 @@ class CreditCooperatifModule(Module, CapBank): strong_auth=self.config['auth_type'].get() == "strong") def iter_accounts(self): - with self.browser: - return self.browser.get_accounts_list() + return self.browser.get_accounts_list() def get_account(self, _id): - with self.browser: - return find_object(self.browser.get_accounts_list(), id=_id, error=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) def iter_coming(self, account): - with self.browser: - return self.browser.get_coming(account) + return self.browser.get_coming(account) diff --git a/modules/creditcooperatif/perso/browser.py b/modules/creditcooperatif/perso/browser.py index 6d590ad0..4d8e7122 100644 --- a/modules/creditcooperatif/perso/browser.py +++ b/modules/creditcooperatif/perso/browser.py @@ -17,68 +17,53 @@ # You should have received a copy of the GNU Affero General Public License # along with weboob. If not, see . -import urllib +from weboob.browser import LoginBrowser, URL, need_login +from weboob.exceptions import BrowserIncorrectPassword -from weboob.deprecated.browser import Browser, BrowserIncorrectPassword - -from .pages import LoginPage, LoggedPage, AccountsPage, TransactionsPage, TransactionsJSONPage, ComingTransactionsPage +from .pages import LoginPage, CreditLoggedPage, AccountsPage, TransactionsPage, TransactionsJSONPage, ComingTransactionsPage __all__ = ['CreditCooperatif'] -class CreditCooperatif(Browser): - PROTOCOL = 'https' - ENCODING = 'iso-8859-15' - DOMAIN = "www.credit-cooperatif.coop" - PAGES = {'https://www.credit-cooperatif.coop/portail/particuliers/login.do': LoginPage, - 'https://www.credit-cooperatif.coop/portail/particuliers/authentification.do': LoggedPage, - 'https://www.credit-cooperatif.coop/portail/particuliers/mescomptes/synthese.do': AccountsPage, - 'https://www.credit-cooperatif.coop/portail/particuliers/mescomptes/relevedesoperations.do': TransactionsPage, - 'https://www.credit-cooperatif.coop/portail/particuliers/mescomptes/relevedesoperationsjson.do': (TransactionsJSONPage, 'json'), - 'https://www.credit-cooperatif.coop/portail/particuliers/mescomptes/synthese/operationsencourslien.do': ComingTransactionsPage, - } +class CreditCooperatif(LoginBrowser): + BASEURL = "https://www.credit-cooperatif.coop" - def home(self): - self.location("/portail/particuliers/mescomptes/synthese.do") + loginpage = URL('/portail//particuliers/login.do', LoginPage) + loggedpage = URL('/portail/particuliers/authentification.do', CreditLoggedPage) + accountspage = URL('/portail/particuliers/mescomptes/synthese.do', AccountsPage) + transactionpage = URL('/portail/particuliers/mescomptes/relevedesoperations.do', TransactionsPage) + transactjsonpage = URL('/portail/particuliers/mescomptes/relevedesoperationsjson.do', TransactionsJSONPage) + comingpage = URL('/portail/particuliers/mescomptes/synthese/operationsencourslien.do', ComingTransactionsPage) - def is_logged(self): - return not self.is_on_page(LoginPage) - - def login(self): + def do_login(self): """ Attempt to log in. Note: this method does nothing if we are already logged in. """ - assert isinstance(self.username, basestring) assert isinstance(self.password, basestring) - if self.is_logged(): - return - - if not self.is_on_page(LoginPage): - self.home() - + self.loginpage.stay_or_go() self.page.login(self.username, self.password) - if self.is_on_page(LoggedPage): + if self.loggedpage.is_here(): error = self.page.get_error() - if error is not None: - raise BrowserIncorrectPassword(error) + if error is None: + return - if not self.is_logged(): - raise BrowserIncorrectPassword() + raise BrowserIncorrectPassword(error) + @need_login def get_accounts_list(self): - if not self.is_on_page(AccountsPage): - self.location('/portail/particuliers/mescomptes/synthese.do') + self.accountspage.stay_or_go() return self.page.get_list() + @need_login def get_history(self, account): data = {'accountExternalNumber': account.id} - self.location('/portail/particuliers/mescomptes/relevedesoperations.do', urllib.urlencode(data)) + self.transactionpage.go(data=data) data = {'iDisplayLength': 400, 'iDisplayStart': 0, @@ -87,15 +72,16 @@ class CreditCooperatif(Browser): 'sColumns': '', 'sEcho': 1, 'sSortDir_0': 'asc', - } - self.location('/portail/particuliers/mescomptes/relevedesoperationsjson.do', urllib.urlencode(data)) + } + self.transactjsonpage.go(data=data) return self.page.get_transactions() + @need_login def get_coming(self, account): data = {'accountExternalNumber': account.id} - self.location('/portail/particuliers/mescomptes/synthese/operationsencourslien.do', urllib.urlencode(data)) + self.comingpage.go(data=data) - assert self.is_on_page(ComingTransactionsPage) + assert self.comingpage.is_here() return self.page.get_transactions() diff --git a/modules/creditcooperatif/perso/pages.py b/modules/creditcooperatif/perso/pages.py index 008fd79a..845a25f8 100644 --- a/modules/creditcooperatif/perso/pages.py +++ b/modules/creditcooperatif/perso/pages.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2012 Kevin Pouget +# Copyright(C) 2012-2014 Kevin Pouget, Florent Fourcot # # This file is part of weboob. # @@ -18,26 +18,27 @@ # along with weboob. If not, see . -from decimal import Decimal import re from weboob.tools.json import json -from weboob.deprecated.browser import Page from weboob.capabilities.bank import Account from weboob.tools.capabilities.bank.transactions import FrenchTransaction +from weboob.browser.pages import HTMLPage, JsonPage, LoggedPage +from weboob.browser.filters.standard import Filter, Format, CleanText, CleanDecimal +from weboob.browser.elements import ListElement, ItemElement, method -class LoginPage(Page): +class LoginPage(HTMLPage): def login(self, login, password): - self.browser.select_form(predicate=lambda form: form.attrs.get('id', '') == 'AuthForm') - self.browser['j_username'] = login.encode('iso-8859-15') - self.browser['j_password'] = password.encode('iso-8859-15') - self.browser.submit(nologin=True) + form = self.get_form(xpath='//form[@id="AuthForm"]') + form['j_username'] = login.encode('iso-8859-15') + form['j_password'] = password.encode('iso-8859-15') + form.submit() -class LoggedPage(Page): +class CreditLoggedPage(HTMLPage): def get_error(self): - div = self.document.xpath('//div[@class="errorForm-msg"]') + div = self.doc.xpath('//div[@class="errorForm-msg"]') if len(div) == 0: return None @@ -45,24 +46,31 @@ class LoggedPage(Page): return re.sub('[\r\n\t\xa0]+', ' ', msg) -class AccountsPage(Page): - ACCOUNT_TYPES = {u'COMPTE NEF': Account.TYPE_CHECKING} +class AddType(Filter): + types = {u'COMPTE NEF': Account.TYPE_CHECKING, + u'CPTE A VUE': Account.TYPE_CHECKING, + u'LIVRET AGIR': Account.TYPE_SAVINGS} - def get_list(self): - for table in self.document.getroot().cssselect('table.table-synthese'): - account = Account() - labels = table.xpath('.//ul[@class="nClient"]/li') - account_type_str = table.xpath('.//h2[@class="tt_compte"]')[0].text.strip() + def filter(self, str_type): + for key, acc_type in self.types.items(): + if key == str_type: + return acc_type + return Account.TYPE_UNKNOWN - account.id = re.sub(u'[^0-9]', '', labels[-1].text) - account.label = u' '.join([account_type_str, labels[0].text.strip()]) - account.type = self.ACCOUNT_TYPES.get(account_type_str, Account.TYPE_UNKNOWN) - balance = table.xpath('.//td[@class="sum_solde"]//span')[-1].text - account.balance = Decimal(FrenchTransaction.clean_amount(balance)) - account.currency = account.get_currency(balance) +class AccountsPage(LoggedPage, HTMLPage): + @method + class get_list(ListElement): + item_xpath = '//table[has-class("table-synthese")]' - yield account + class item(ItemElement): + klass = Account + + obj_label = Format('%s %s', CleanText('.//h2[@class="tt_compte"][1]'), CleanText('.//ul[@class="nClient"]/li[1]')) + obj_id = CleanText('.//ul[@class="nClient"]/li[last()]', symbols=u'N°') + obj_type = AddType(CleanText('.//h2[@class="tt_compte"][1]')) + obj_balance = CleanDecimal('.//td[@class="sum_solde"]//span[last()]', replace_dots=True) + obj_currency = u'EUR' class Transaction(FrenchTransaction): @@ -79,7 +87,7 @@ class Transaction(FrenchTransaction): (re.compile('^(PRLV|PRELEVEMENT) (?P.*?)(- .*)?$'), FrenchTransaction.TYPE_ORDER), (re.compile('^CHEQUE.*'), FrenchTransaction.TYPE_CHECK), - (re.compile('^(AGIOS /|FRAIS) (?P.*)'),FrenchTransaction.TYPE_BANK), + (re.compile('^(AGIOS /|FRAIS) (?P.*)'), FrenchTransaction.TYPE_BANK), (re.compile('^ABONNEMENT (?P.*)'), FrenchTransaction.TYPE_BANK), (re.compile('^REMISE (?P.*)'), FrenchTransaction.TYPE_DEPOSIT), (re.compile('^(?P.*)( \d+)? QUITTANCE .*'), @@ -89,11 +97,11 @@ class Transaction(FrenchTransaction): ] -class TransactionsPage(Page): +class TransactionsPage(LoggedPage, HTMLPage): pass -class TransactionsJSONPage(Page): +class TransactionsJSONPage(LoggedPage, JsonPage): ROW_DATE = 0 ROW_TEXT = 2 ROW_CREDIT = -1 @@ -101,7 +109,7 @@ class TransactionsJSONPage(Page): def get_transactions(self): seen = set() - for tr in self.document['exportData'][1:]: + for tr in self.doc['exportData'][1:]: t = Transaction(0) t.parse(tr[self.ROW_DATE], tr[self.ROW_TEXT]) t.set_amount(tr[self.ROW_CREDIT], tr[self.ROW_DEBIT]) @@ -109,7 +117,7 @@ class TransactionsJSONPage(Page): yield t -class ComingTransactionsPage(Page): +class ComingTransactionsPage(LoggedPage, HTMLPage): ROW_REF = 0 ROW_TEXT = 1 ROW_DATE = 2 @@ -118,7 +126,7 @@ class ComingTransactionsPage(Page): def get_transactions(self): data = [] - for script in self.document.xpath('//script'): + for script in self.doc.xpath('//script'): txt = script.text if txt is None: continue