diff --git a/AUTHORS b/AUTHORS index 3787d4f7603180807e35056a51635e550d6f5b49..3a574756381598feb0e27c07a314bb203938a086 100644 --- a/AUTHORS +++ b/AUTHORS @@ -53,6 +53,9 @@ Xavier Guerrin Gabriel Kerneis * Boursorama module maintainer. +Kevin Pouget + * CreditCooperatif module maintainer. + Gilles Quenot * Fortuneo module maintainer. diff --git a/modules/creditcooperatif/backend.py b/modules/creditcooperatif/backend.py index f00a7d3c4ad89f685d5fbfd164b69ca788cb3318..13b6c5c14e3b57452112edace18c915c598d555f 100644 --- a/modules/creditcooperatif/backend.py +++ b/modules/creditcooperatif/backend.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2012 Kevin Pouget, based on Romain Bignon work +# Copyright(C) 2012 Kevin Pouget # # This file is part of weboob. # @@ -20,7 +20,6 @@ from weboob.capabilities.bank import ICapBank, AccountNotFound from weboob.tools.backend import BaseBackend, BackendConfig -from weboob.tools.ordereddict import OrderedDict from weboob.tools.value import ValueBackendPassword, Value from .browser import CreditCooperatif @@ -36,18 +35,18 @@ class CreditCooperatifBackend(BaseBackend, ICapBank): VERSION = '0.e' DESCRIPTION = u'Credit Cooperatif French bank website' LICENSE = 'AGPLv3+' - auth_type = {"weak" : "Code confidentiel", + auth_type = {"weak" : "Code confidentiel", "strong": "Sesame"} CONFIG = BackendConfig(Value('auth_type', label='Authentication type', choices=auth_type, default="strong"), ValueBackendPassword('login', label='Account ID', masked=False), - ValueBackendPassword('pin', label='One time pin')) - + ValueBackendPassword('password', label='Password or one time pin')) + BROWSER = CreditCooperatif - + def create_default_browser(self): return self.create_browser(self.config['login'].get(), - self.config['pin'].get(), - self.config['auth_type'].get() == "strong") + self.config['password'].get(), + strong_auth=self.config['auth_type'].get() == "strong") def iter_accounts(self): with self.browser: @@ -65,7 +64,7 @@ def get_account(self, _id): def iter_history(self, account): with self.browser: return self.browser.get_history(account) - + def iter_coming(self, account): with self.browser: return self.browser.get_coming(account) diff --git a/modules/creditcooperatif/browser.py b/modules/creditcooperatif/browser.py index a89c090011c0202410a2d8fa9aa649b62a916b27..58723b6e269ad7fb5e7ee3160540b6a113adb6df 100644 --- a/modules/creditcooperatif/browser.py +++ b/modules/creditcooperatif/browser.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2012 Romain Bignon +# Copyright(C) 2012 Kevin Pouget # # This file is part of weboob. # @@ -17,9 +17,6 @@ # You should have received a copy of the GNU Affero General Public License # along with weboob. If not, see . - -import urllib - from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword from .pages import LoginPage, AccountsPage, TransactionsPage, ComingTransactionsPage @@ -37,18 +34,17 @@ class CreditCooperatif(BaseBrowser): 'https://www.coopanet.com/banque/cpt/cpt/situationcomptes.do\?lnkReleveAction=X&numeroExterne=.*': TransactionsPage, 'https://www.coopanet.com/banque/cpt/cpt/relevecompte.do\?tri_page=.*': TransactionsPage, 'https://www.coopanet.com/banque/cpt/cpt/situationcomptes.do\?lnkOpCB=X&numeroExterne=.*': ComingTransactionsPage - } - + } + def __init__(self, *args, **kwargs): - #catch and remove the third/last arg - self.strong_auth = args[-1] - BaseBrowser.__init__(self, *args[:-1], **kwargs) + self.strong_auth = kwargs.pop('strong_auth', False) + BaseBrowser.__init__(self, *args, **kwargs) def home(self): self.location("/banque/sso/") assert self.is_on_page(LoginPage) - + def is_logged(self): return not self.is_on_page(LoginPage) @@ -86,13 +82,13 @@ def get_account(self, id): return a return None - + def get_history(self, account): self.location('/banque/cpt/cpt/situationcomptes.do?lnkReleveAction=X&numeroExterne='+ account.id) - + while 1: assert self.is_on_page(TransactionsPage) - + for tr in self.page.get_history(): yield tr @@ -101,7 +97,7 @@ def get_history(self, account): return self.location(next_url) - + def get_coming(self, account): self.location('/banque/cpt/cpt/situationcomptes.do?lnkOpCB=X&numeroExterne='+ account.id) diff --git a/modules/creditcooperatif/pages.py b/modules/creditcooperatif/pages.py index f5678abb79738b1c6cd4d8910a9ef0b6946f44bd..cf221ed82064dd26956ed724ad59d504a55a4132 100644 --- a/modules/creditcooperatif/pages.py +++ b/modules/creditcooperatif/pages.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2012 Kevin Pouget, based on Romain Bignon work +# Copyright(C) 2012 Kevin Pouget # # This file is part of weboob. # @@ -18,9 +18,9 @@ # along with weboob. If not, see . -from urlparse import urlsplit, parse_qsl from decimal import Decimal import re +import time from weboob.tools.browser import BasePage from weboob.capabilities.bank import Account @@ -33,7 +33,7 @@ class LoginPage(BasePage): def login(self, login, pin, strong_auth): form_nb = 1 if strong_auth else 0 indentType = "RENFORCE" if strong_auth else "MDP" - + self.browser.select_form(name='loginCoForm', nr=form_nb) self.browser['codeUtil'] = login self.browser['motPasse'] = pin @@ -43,13 +43,13 @@ def login(self, login, pin, strong_auth): class AccountsPage(BasePage): ACCOUNT_TYPES = {u'COMPTE NEF': Account.TYPE_CHECKING} - + CPT_ROW_ID = 0 CPT_ROW_NAME = 1 CPT_ROW_NATURE = 2 CPT_ROW_BALANCE = 3 CPT_ROW_ENCOURS = 4 - + def is_error(self): for par in self.document.xpath('//p[@class=acctxtnoirlien]'): if par.text is not None and u"La page demandée ne peut pas être affichée." in par.text: @@ -60,20 +60,20 @@ def is_error(self): def get_list(self): for trCompte in self.document.xpath('//table[@id="compte"]/tbody/tr'): tds = trCompte.findall('td') - + account = Account() - + account.id = tds[self.CPT_ROW_ID].text.strip() account.label = tds[self.CPT_ROW_NAME].text.strip() - + account_type_str = "".join([td.text for td in tds[self.CPT_ROW_NATURE].xpath('.//td[@class="txt"]')]).strip() - + account.type = self.ACCOUNT_TYPES.get(account_type_str, Account.TYPE_UNKNOWN) - + account.balance = Decimal(FrenchTransaction.clean_amount(tds[self.CPT_ROW_BALANCE].find("a").text)) account.coming = Decimal(FrenchTransaction.clean_amount( tds[self.CPT_ROW_ENCOURS].find("a").text)) yield account - + return class Transaction(FrenchTransaction): @@ -115,17 +115,17 @@ def get_history(self): def get_content(td): ret = "".join([ttd.text if ttd.text else "" for ttd in td.xpath(".//td")]) return ret.replace(u"\xa0", " ").strip() - + date = get_content(tds[self.TR_DATE]) raw = get_content(tds[self.TR_TEXT]) - + debit = get_content(tds[self.TR_DEBIT]) credit = get_content(tds[self.TR_CREDIT]) t = Transaction(date+""+raw) t.parse(date, re.sub(r'[ ]+', ' ', raw)) t.set_amount(credit, debit) - + yield t class ComingTransactionsPage(BasePage): @@ -133,12 +133,12 @@ class ComingTransactionsPage(BasePage): COM_TR_DATE = 1 COM_TR_TEXT = 2 COM_TR_VALUE = 3 - + def get_history(self): comment = None for tr in self.document.xpath('//table[@id="operation"]/tbody/tr'): tds = tr.findall('td') - + def get_content(td): ret = td.text return ret.replace(u"\xa0", " ").strip() @@ -148,7 +148,7 @@ def get_content(td): if comment is None: comment = get_content(tds[self.COM_TR_COMMENT]) raw = "%s (%s) " % (raw, comment) - + debit = get_content(tds[self.COM_TR_VALUE]) date = get_content(tds[self.COM_TR_DATE]) @@ -156,12 +156,11 @@ def get_content(td): #date is 'JJ/MM'. add '/YYYY' date += comment[comment.rindex("/"):] else: - import time date += "/%d" % time.localtime().tm_year - + t = Transaction(date+""+raw) t.parse(date, re.sub(r'[ ]+', ' ', raw)) t.set_amount("", debit) - + yield t diff --git a/modules/creditcooperatif/test.py b/modules/creditcooperatif/test.py index 7611f03fa4d0788391b2bc217d2bef1491c4879d..1ba65654cf33af9155bf805f113b5422a3ba3d3b 100644 --- a/modules/creditcooperatif/test.py +++ b/modules/creditcooperatif/test.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2012 Kevin Pouget, based on Romain Bignon +# Copyright(C) 2012 Kevin Pouget # # This file is part of weboob. #