# -*- coding: utf-8 -*- # Copyright(C) 2009-2012 Romain Bignon # Copyright(C) 2013-2015 Christophe Lampin # # 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 . import urllib import mechanize from datetime import datetime from weboob.deprecated.browser import Browser, BrowserIncorrectPassword, BrowserPasswordExpired from weboob.capabilities.bank import TransferError, Transfer from .perso.accounts_list import AccountsList, AccountPrelevement from .perso.transactions import AccountHistory, AccountComing from .perso.transfer import TransferPage, TransferConfirmPage, TransferCompletePage from .perso.login import LoginPage, ConfirmPage, InfoMessagePage from .perso.messages import MessagePage, MessagesPage __all__ = ['HelloBank'] class HelloBank(Browser): DOMAIN = 'client.hellobank.fr' PROTOCOL = 'https' ENCODING = None # refer to the HTML encoding PAGES = {'.*TableauBord.*': AccountsList, '.*type=folder.*': AccountHistory, '.*pageId=mouvementsavenir.*': AccountComing, '.*NS_AVEDP.*': AccountPrelevement, '.*NS_VIRDF.*': TransferPage, '.*NS_VIRDC.*': TransferConfirmPage, '.*/NS_VIRDA\?stp=(?P\d+).*': TransferCompletePage, '.*type=homeconnex.*': LoginPage, '.*layout=HomeConnexion.*': ConfirmPage, '.*SAF_CHM_VALID.*': ConfirmPage, '.*Action=DSP_MSG.*': InfoMessagePage, '.*Messages_recus.*': MessagesPage, '.*Lire_Message.*': MessagePage, } def __init__(self, *args, **kwargs): Browser.__init__(self, *args, **kwargs) def home(self): self.location('https://client.hellobank.fr/banque/portail/digitale/HomeConnexion?type=homeconnex') def is_logged(self): return not self.is_on_page(LoginPage) def login(self): assert isinstance(self.username, basestring) assert isinstance(self.password, basestring) assert self.password.isdigit() if not self.is_on_page(LoginPage): self.home() self.page.login(self.username, self.password) self.location('/NSFR?Action=DSP_VGLOBALE', no_login=True) if self.is_on_page(LoginPage): raise BrowserIncorrectPassword() def get_accounts_list(self): # We have to parse transfer page to get the IBAN numbers if not self.is_on_page(TransferPage): now = datetime.now() self.location('/NS_VIRDF?Origine=DSP_VIR&stp=%s' % now.strftime("%Y%m%d%H%M%S")) accounts = self.page.get_accounts() if len(accounts) == 0: self.logger.warning('no accounts') # oops, no accounts? check if we have not exhausted the allowed use # of this password for img in self.document.getroot().cssselect('img[align="middle"]'): if img.attrib.get('alt', '') == 'Changez votre code secret': raise BrowserPasswordExpired('Your password has expired') self.location('/NSFR?Action=DSP_VGLOBALE') return self.page.get_list(accounts) 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 def get_IBAN_from_account(self, account): self.go_to_history_page(account) return self.page.get_IBAN() def go_to_history_page(self,account): if account._link_id is None: raise NotImplementedError() if not self.is_on_page(AccountsList): self.location('/NSFR?Action=DSP_VGLOBALE') data = {'gt': 'homepage:basic-theme', 'externalIAId': 'IAStatements', 'cboFlowName': 'flow/iastatement', 'contractId': account._link_id, 'groupId': '-2', 'pastOrPendingOperations': 1, 'groupSelected':'-2', 'step': 'STAMENTS', 'pageId': 'releveoperations', 'sendEUD': 'true', } self.location('/udc', urllib.urlencode(data)) def go_to_coming_operations_page(self,account): if account._link_id is None: raise NotImplementedError() if not self.is_on_page(AccountsList): self.location('/NSFR?Action=DSP_VGLOBALE') data = {'gt': 'homepage:basic-theme', 'externalIAId': 'IAStatements', 'cboFlowName': 'flow/iastatement', 'contractId': account._link_id, 'groupId': '-2', 'pastOrPendingOperations': 2, 'groupSelected':'-2', 'step': 'STAMENTS', 'pageId': 'mouvementsavenir', 'sendEUD': 'true', } self.location('/udc', urllib.urlencode(data)) def iter_history(self, account): self.go_to_history_page(account) return self.page.iter_operations() def iter_coming_operations(self, account): self.go_to_coming_operations_page(account) return self.page.iter_coming_operations() def get_transfer_accounts(self): if not self.is_on_page(TransferPage): self.location('/NS_VIRDF') assert self.is_on_page(TransferPage) return self.page.get_accounts() def transfer(self, from_id, to_id, amount, reason=None): if not self.is_on_page(TransferPage): self.location('/NS_VIRDF') # Need to clean HTML before parse it html = self.response().get_data().replace("