diff --git a/modules/carrefourbanque/backend.py b/modules/carrefourbanque/backend.py index 909634c9..b8d7060e 100644 --- a/modules/carrefourbanque/backend.py +++ b/modules/carrefourbanque/backend.py @@ -18,6 +18,7 @@ # along with weboob. If not, see . +from weboob.capabilities.base import find_object from weboob.capabilities.bank import ICapBank, AccountNotFound from weboob.tools.backend import BaseBackend, BackendConfig from weboob.tools.value import ValueBackendPassword @@ -35,8 +36,8 @@ class CarrefourBanqueBackend(BaseBackend, ICapBank): VERSION = '0.i' DESCRIPTION = u'Carrefour Banque' LICENSE = 'AGPLv3+' - CONFIG = BackendConfig(ValueBackendPassword('login', label=u'Référent client', masked=False), - ValueBackendPassword('password', label=u"Code d'accès", regexp='\d+')) + CONFIG = BackendConfig(ValueBackendPassword('login', label=u'Votre Identifiant Internet', masked=False), + ValueBackendPassword('password', label=u"Code d'accès", regexp=u'\d+')) BROWSER = CarrefourBanque def create_default_browser(self): @@ -44,26 +45,10 @@ class CarrefourBanqueBackend(BaseBackend, ICapBank): self.config['password'].get()) 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: - 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: - for tr in self.browser.iter_history(account): - if not tr._coming: - yield tr - - def iter_coming(self, account): - with self.browser: - for tr in self.browser.iter_history(account): - if tr._coming: - yield tr + return self.browser.iter_history(account) diff --git a/modules/carrefourbanque/browser.py b/modules/carrefourbanque/browser.py index 8968aefe..6b9eb91a 100644 --- a/modules/carrefourbanque/browser.py +++ b/modules/carrefourbanque/browser.py @@ -18,36 +18,23 @@ # along with weboob. If not, see . -import urllib +from weboob.tools.browser2 import LoginBrowser, URL, need_login +from weboob.tools.browser import BrowserIncorrectPassword -from weboob.tools.browser import BaseBrowser - -from .pages import LoginPage, HomePage, AccountsPage, TransactionsPage +from .pages import LoginPage, HomePage, TransactionsPage __all__ = ['CarrefourBanque'] -class CarrefourBanque(BaseBrowser): - PROTOCOL = 'https' - DOMAIN = 'services.carrefour-banque.fr' - ENCODING = 'iso-8859-15' - PAGES = {'https?://services.carrefour-banque.fr/s2pnet/publ/identification.do': LoginPage, - 'https?://services.carrefour-banque.fr/stscripts/run.stn/s2p/SommairePS2P': HomePage, - 'https?://services.carrefour-banque.fr/s2pnet/priv/disponible.do': AccountsPage, - 'https?://services.carrefour-banque.fr/s2pnet/priv/consult.do\?btnTelechargement': (TransactionsPage, 'raw'), - } +class CarrefourBanque(LoginBrowser): + BASEURL = 'https://www.carrefour-banque.fr' - def is_logged(self): - return self.page is not None and not self.is_on_page(LoginPage) + login = URL('/espace-client/connexion', LoginPage) + home = URL('/espace-client$', HomePage) + transactions = URL('/espace-client/carte-credit/solde-dernieres-operations.*', TransactionsPage) - def home(self): - if self.is_logged(): - self.location('/s2pnet/priv/disponible.do') - else: - self.login() - - def login(self): + def do_login(self): """ Attempt to log in. Note: this method does nothing if we are already logged in. @@ -55,41 +42,21 @@ class CarrefourBanque(BaseBrowser): assert isinstance(self.username, basestring) assert isinstance(self.password, basestring) - if self.is_logged(): - return + self.login.go() + self.page.enter_login(self.username) + self.page.enter_password(self.password) - args = {'login': '', - 'loginCBPASS': self.username.encode(self.ENCODING), - 'motPasse': self.password.encode(self.ENCODING), - 'testJS': 'true', - 'x': 8, - 'y': 4, - } - - self.location('https://services.carrefour-banque.fr/s2pnet/publ/identification.do', urllib.urlencode(args), no_login=True) - - assert self.is_on_page(LoginPage) - - # raises BrowserIncorrectPassword if no redirect form is found - self.page.redirect() + if not self.home.is_here(): + raise BrowserIncorrectPassword() + @need_login def get_accounts_list(self): - if not self.is_on_page(AccountsPage): - self.location('/s2pnet/priv/disponible.do') + self.home.stay_or_go() return self.page.get_list() - def get_account(self, id): - assert isinstance(id, basestring) - - l = self.get_accounts_list() - for a in l: - if a.id == id: - return a - - return None - + @need_login def iter_history(self, account): - self.location('/s2pnet/priv/consult.do?btnTelechargement') + self.location(account._link) - assert self.is_on_page(TransactionsPage) + assert self.transactions.is_here() return self.page.get_history(account) diff --git a/modules/carrefourbanque/pages.py b/modules/carrefourbanque/pages.py index 4647e952..dc89c1c3 100644 --- a/modules/carrefourbanque/pages.py +++ b/modules/carrefourbanque/pages.py @@ -18,102 +18,55 @@ # along with weboob. If not, see . -import datetime -from decimal import Decimal import re -from mechanize import FormNotFoundError -from weboob.tools.browser import BasePage, BrowserIncorrectPassword +from weboob.tools.browser2.page import HTMLPage, ListElement, ItemElement, method, LoggedPage +from weboob.tools.browser2.filters import Regexp, CleanText, CleanDecimal, Format, Link + from weboob.capabilities.bank import Account from weboob.tools.capabilities.bank.transactions import FrenchTransaction -__all__ = ['LoginPage', 'AccountsPage', 'TransactionsPage'] +__all__ = ['LoginPage', 'HomePage', 'TransactionsPage'] -class LoginPage(BasePage): - def redirect(self): - try: - self.browser.select_form(name='redirectEpargne') - self.browser.submit(nologin=True) - except FormNotFoundError: - raise BrowserIncorrectPassword() +class LoginPage(HTMLPage): + def enter_login(self, username): + form = self.get_form(nr=0) + form['name'] = username + form.submit() + + def enter_password(self, password): + form = self.get_form(nr=0) + form['pass'] = password + form.submit() -class HomePage(BasePage): - pass +class HomePage(LoggedPage, HTMLPage): + @method + class get_list(ListElement): + item_xpath = '//div[@class="three_contenu_table"]' + + class item(ItemElement): + klass = Account + + obj_id = Regexp(CleanText('./div[@class="carte_col_leftcol"]/p'), r'(\d+)') + obj_label = CleanText('./div[@class="carte_col_leftcol"]/h2') + obj_balance = CleanDecimal(Format('-%s', CleanText('.//div[@class="catre_col_one"]/h2'))) + obj_currency = FrenchTransaction.Currency('.//div[@class="catre_col_one"]/h2') + obj__link = Link('.//a[contains(@href, "solde-dernieres-operations")]') -class AccountsPage(BasePage): - def get_list(self): - div = self.document.xpath('//div[@id="descriptifdroite"]')[0] - - account = Account() - - account.id = re.search(u'(\d+)', div.xpath('.//div[@class="credithauttexte"]')[0].text).group(1) - account.label = u'Carte PASS' - account.balance = Decimal('0') - - for tr in div.xpath('.//table/tr'): - tds = tr.findall('td') - - if len(tds) < 3: - continue - - label = u''.join([txt.strip() for txt in tds[1].itertext()]) - value = u''.join([txt.strip() for txt in tds[2].itertext()]) - - if 'encours depuis le dernier' in label.lower(): - coming = u'-' + value - account.coming = Decimal(FrenchTransaction.clean_amount(coming)) - account.currency = account.get_currency(coming) - elif u'arrêté de compte' in label.lower(): - m = re.search(u'(\d+)/(\d+)/(\d+)', label) - if m: - account._outstanding_date = datetime.date(*reversed(map(int, m.groups()))) - break - - yield account +class Transaction(FrenchTransaction): + PATTERNS = [(re.compile(r'^(?P.*?) (?P
\d{2})/(?P\d{2})$'), FrenchTransaction.TYPE_CARD)] -class TransactionsPage(BasePage): - COL_DATE = 0 - COL_TEXT = 1 - COL_AMOUNT = 2 +class TransactionsPage(LoggedPage, HTMLPage): + @method + class get_history(Transaction.TransactionsElement): + head_xpath = '//table[@id="creditHistory"]//thead/tr/th' + item_xpath = '//table[@id="creditHistory"]/tbody/tr' - def get_history(self, account): - transactions = [] - last_order = None - - for tr in self.document.split('\n')[1:]: - cols = tr.split(';') - - if len(cols) < 4: - continue - - t = FrenchTransaction(0) - date = cols[self.COL_DATE] - raw = cols[self.COL_TEXT] - amount = cols[self.COL_AMOUNT] - - t.parse(date, re.sub(r'[ ]+', ' ', raw)) - - if t.raw.startswith('PRELEVEMENT ACHATS DIFFERES'): - t._coming = False - if last_order is None: - last_order = t.date - else: - t._coming = True - - t.set_amount(amount) - transactions.append(t) - - # go to the previous stop date before the last order - while last_order is not None and last_order.day != account._outstanding_date.day: - last_order = last_order - datetime.timedelta(days=1) - - for t in transactions: - if t.date <= last_order: - t._coming = False - - return iter(transactions) + class item(Transaction.TransactionElement): + obj_id = None + obj_type = Transaction.TYPE_CARD