# -*- coding: utf-8 -*- # Copyright(C) 2010-2011 Nicolas Duhamel # # 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 os from datetime import datetime, timedelta from weboob.browser import LoginBrowser, URL, need_login from weboob.browser.browsers import StatesMixin from weboob.browser.exceptions import ServerError from weboob.capabilities.base import NotAvailable from weboob.exceptions import BrowserIncorrectPassword, BrowserBanned, NoAccountsException, BrowserUnavailable from weboob.tools.compat import urlsplit, urlunsplit, parse_qsl from .pages import ( LoginPage, Initident, CheckPassword, repositionnerCheminCourant, BadLoginPage, AccountDesactivate, AccountList, AccountHistory, CardsList, UnavailablePage, AccountRIB, Advisor, TransferChooseAccounts, CompleteTransfer, TransferConfirm, TransferSummary, CreateRecipient, ValidateRecipient, ValidateCountry, ConfirmPage, RcptSummary ) from .pages.accounthistory import ( LifeInsuranceInvest, LifeInsuranceHistory, LifeInsuranceHistoryInv, RetirementHistory, SavingAccountSummary, CachemireCatalogPage, ) from .pages.accountlist import MarketLoginPage, UselessPage, ProfilePage from .pages.pro import RedirectPage, ProAccountsList, ProAccountHistory, DownloadRib, RibPage from .pages.mandate import MandateAccountsList, PreMandate, PreMandateBis, MandateLife, MandateMarket from .linebourse_browser import LinebourseBrowser from weboob.capabilities.bank import TransferError, Account, Recipient, AddRecipientStep from weboob.tools.value import Value __all__ = ['BPBrowser', 'BProBrowser'] class BPBrowser(LoginBrowser, StatesMixin): BASEURL = 'https://voscomptesenligne.labanquepostale.fr' STATE_DURATION = 5 # FIXME beware that '.*' in start of URL() won't match all domains but only under BASEURL login_page = URL(r'.*wsost/OstBrokerWeb/loginform.*', LoginPage) repositionner_chemin_courant = URL(r'.*authentification/repositionnerCheminCourant-identif.ea', repositionnerCheminCourant) init_ident = URL(r'.*authentification/initialiser-identif.ea', Initident) check_password = URL(r'.*authentification/verifierMotDePasse-identif.ea', r'/voscomptes/canalXHTML/securite/authentification/verifierPresenceCompteOK-identif.ea', r'.*//voscomptes/identification/motdepasse.jsp', CheckPassword) redirect_page = URL(r'.*voscomptes/identification/identification.ea.*', r'.*voscomptes/synthese/3-synthese.ea', RedirectPage) par_accounts_checking = URL('/voscomptes/canalXHTML/comptesCommun/synthese_ccp/afficheSyntheseCCP-synthese_ccp.ea', AccountList) par_accounts_savings_and_invests = URL('/voscomptes/canalXHTML/comptesCommun/synthese_ep/afficheSyntheseEP-synthese_ep.ea', AccountList) par_accounts_loan = URL('/voscomptes/canalXHTML/pret/encours/consulterPrets-encoursPrets.ea', '/voscomptes/canalXHTML/pret/encours/detaillerPretPartenaireListe-encoursPrets.ea', '/voscomptes/canalXHTML/pret/encours/detaillerOffrePretImmoListe-encoursPrets.ea', '/voscomptes/canalXHTML/pret/encours/detaillerOffrePretConsoListe-encoursPrets.ea', '/voscomptes/canalXHTML/pret/creditRenouvelable/init-consulterCreditRenouvelable.ea', '/voscomptes/canalXHTML/pret/encours/rechercherPret-encoursPrets.ea', AccountList) accounts_rib = URL(r'.*voscomptes/canalXHTML/comptesCommun/imprimerRIB/init-imprimer_rib.ea.*', '/voscomptes/canalXHTML/comptesCommun/imprimerRIB/init-selection_rib.ea', AccountRIB) saving_summary = URL(r'/voscomptes/canalXHTML/assurance/vie/reafficher-assuranceVie.ea(\?numContrat=(?P\w+))?', r'/voscomptes/canalXHTML/assurance/retraiteUCEuro/afficher-assuranceRetraiteUCEuros.ea(\?numContrat=(?P\w+))?', r'/voscomptes/canalXHTML/assurance/retraitePoints/reafficher-assuranceRetraitePoints.ea(\?numContrat=(?P\w+))?', r'/voscomptes/canalXHTML/assurance/prevoyance/reafficher-assurancePrevoyance.ea(\?numContrat=(?P\w+))?', SavingAccountSummary) lifeinsurance_invest = URL(r'/voscomptes/canalXHTML/assurance/retraiteUCEuro/afficherSansDevis-assuranceRetraiteUCEuros.ea\?numContrat=(?P\w+)', LifeInsuranceInvest) lifeinsurance_invest2 = URL(r'/voscomptes/canalXHTML/assurance/vie/valorisation-assuranceVie.ea\?numContrat=(?P\w+)', LifeInsuranceInvest) lifeinsurance_history = URL(r'/voscomptes/canalXHTML/assurance/vie/historiqueVie-assuranceVie.ea\?numContrat=(?P\w+)', LifeInsuranceHistory) lifeinsurance_hist_inv = URL(r'/voscomptes/canalXHTML/assurance/vie/detailMouvement-assuranceVie.ea\?idMouvement=(?P\w+)', r'/voscomptes/canalXHTML/assurance/vie/detailMouvementHermesBompard-assuranceVie.ea\?idMouvement=(\w+)', LifeInsuranceHistoryInv) lifeinsurance_cachemire_catalog = URL(r'https://www.labanquepostale.fr/particuliers/bel_particuliers/assurance/accueil_cachemire.html', CachemireCatalogPage) market_login = URL(r'/voscomptes/canalXHTML/bourse/aiguillage/oicFormAutoPost.jsp', MarketLoginPage) useless = URL(r'https://labanquepostale.offrebourse.com/ReroutageSJR', UselessPage) retirement_hist = URL(r'/voscomptes/canalXHTML/assurance/retraitePoints/historiqueRetraitePoint-assuranceRetraitePoints.ea(\?numContrat=(?P\w+))?', r'/voscomptes/canalXHTML/assurance/retraiteUCEuro/historiqueMouvements-assuranceRetraiteUCEuros.ea(\?numContrat=(?P\w+))?', r'/voscomptes/canalXHTML/assurance/prevoyance/consulterHistorique-assurancePrevoyance.ea(\?numContrat=(?P\w+))?', RetirementHistory) par_account_checking_history = URL('/voscomptes/canalXHTML/CCP/releves_ccp/init-releve_ccp.ea\?typeRecherche=10&compte.numero=(?P.*)', '/voscomptes/canalXHTML/CCP/releves_ccp/afficher-releve_ccp.ea', AccountHistory) deferred_card_history = URL(r'/voscomptes/canalXHTML/CB/releveCB/init-mouvementsCarteDD.ea\?compte.numero=(?P\w+)&indexCarte=(?P\d+)&typeListe=(?P\d+)', AccountHistory) deferred_card_history_multi = URL(r'/voscomptes/canalXHTML/CB/releveCB/preparerRecherche-mouvementsCarteDD.ea\?compte.numero=(?P\w+)&indexCarte=(?P\d+)&typeListe=(?P\d+)', AccountHistory) # &typeRecherche=10 par_account_checking_coming = URL('/voscomptes/canalXHTML/CCP/releves_ccp_encours/preparerRecherche-releve_ccp_encours.ea\?compte.numero=(?P.*)&typeRecherche=1', '/voscomptes/canalXHTML/CB/releveCB/init-mouvementsCarteDD.ea\?compte.numero=(?P.*)&typeListe=1&typeRecherche=10', AccountHistory) par_account_savings_and_invests_history = URL('/voscomptes/canalXHTML/CNE/releveCNE/init-releve_cne.ea\?typeRecherche=10&compte.numero=(?P.*)', '/voscomptes/canalXHTML/CNE/releveCNE/releveCNE-releve_cne.ea', AccountHistory) cards_list = URL('/voscomptes/canalXHTML/CB/releveCB/init-mouvementsCarteDD.ea\?compte.numero=(?P\w+)$', r'.*CB/releveCB/init-mouvementsCarteDD.ea.*', CardsList) transfer_choose = URL(r'/voscomptes/canalXHTML/virement/mpiaiguillage/init-saisieComptes.ea', TransferChooseAccounts) transfer_complete = URL(r'/voscomptes/canalXHTML/virement/mpiaiguillage/soumissionChoixComptes-saisieComptes.ea', r'/voscomptes/canalXHTML/virement/virementSafran_national/init-creerVirementNational.ea', r'/voscomptes/canalXHTML/virement/virementSafran_sepa/init-creerVirementSepa.ea', CompleteTransfer) transfer_confirm = URL(r'/voscomptes/canalXHTML/virement/virementSafran_pea/validerVirementPea-virementPea.ea', r'/voscomptes/canalXHTML/virement/virementSafran_sepa/valider-creerVirementSepa.ea', r'/voscomptes/canalXHTML/virement/virementSafran_sepa/valider-virementSepa.ea', r'/voscomptes/canalXHTML/virement/virementSafran_sepa/confirmerInformations-virementSepa.ea', r'/voscomptes/canalXHTML/virement/virementSafran_national/valider-creerVirementNational.ea', r'/voscomptes/canalXHTML/virement/virementSafran_national/validerVirementNational-virementNational.ea', TransferConfirm) transfer_summary = URL(r'/voscomptes/canalXHTML/virement/virementSafran_national/confirmerVirementNational-virementNational.ea', r'/voscomptes/canalXHTML/virement/virementSafran_pea/confirmerInformations-virementPea.ea', r'/voscomptes/canalXHTML/virement/virementSafran_sepa/confirmer-creerVirementSepa.ea', r'/voscomptes/canalXHTML/virement/virementSafran_national/confirmer-creerVirementNational.ea', r'/voscomptes/canalXHTML/virement/virementSafran_sepa/confirmerInformations-virementSepa.ea', TransferSummary) create_recipient = URL(r'/voscomptes/canalXHTML/virement/mpiGestionBeneficiairesVirementsCreationBeneficiaire/init-creationBeneficiaire.ea', CreateRecipient) validate_country = URL(r'/voscomptes/canalXHTML/virement/mpiGestionBeneficiairesVirementsCreationBeneficiaire/validationSaisiePaysBeneficiaire-creationBeneficiaire.ea', ValidateCountry) validate2_recipient = URL(r'/voscomptes/canalXHTML/virement/mpiGestionBeneficiairesVirementsCreationBeneficiaire/valider-creationBeneficiaire.ea', ValidateRecipient) rcpt_code = URL(r'/voscomptes/canalXHTML/virement/mpiGestionBeneficiairesVirementsCreationBeneficiaire/validerRecapBeneficiaire-creationBeneficiaire.ea', ConfirmPage) rcpt_summary = URL(r'/voscomptes/canalXHTML/virement/mpiGestionBeneficiairesVirementsCreationBeneficiaire/finalisation-creationBeneficiaire.ea', RcptSummary) badlogin = URL(r'https://transverse.labanquepostale.fr/.*ost/messages\.CVS\.html\?param=0x132120c8.*', # still valid? r'https://transverse.labanquepostale.fr/xo_/messages/message.html\?param=0x132120c8.*', BadLoginPage) disabled_account = URL(r'.*ost/messages\.CVS\.html\?param=0x132120cb.*', r'.*/message\.html\?param=0x132120c.*', r'https://transverse.labanquepostale.fr/xo_/messages/message.html\?param=0x132120cb.*', AccountDesactivate) unavailable = URL(r'https?://.*.labanquepostale.fr/delestage.html', r'https://transverse.labanquepostale.fr/xo_/messages/message.html\?param=delestage', UnavailablePage) rib_dl = URL(r'.*/voscomptes/rib/init-rib.ea', DownloadRib) rib = URL(r'.*/voscomptes/rib/preparerRIB-rib.*', RibPage) advisor = URL(r'/ws_q45/Q45/canalXHTML/commun/authentification/init-identif.ea\?origin=particuliers&codeMedia=0004&entree=HubHome', r'/ws_q45/Q45/canalXHTML/desktop/home/init-home.ea', Advisor) login_url = 'https://voscomptesenligne.labanquepostale.fr/wsost/OstBrokerWeb/loginform?TAM_OP=login&' \ 'ERROR_CODE=0x00000000&URL=%2Fvoscomptes%2FcanalXHTML%2Fidentif.ea%3Forigin%3Dparticuliers' pre_mandate = URL(r'/voscomptes/canalXHTML/sso/commun/init-integration.ea\?partenaire=procapital', PreMandate) pre_mandate_bis = URL(r'https://www.gestion-sous-mandat.labanquepostale-gestionprivee.fr/lbpgp/secure/main.html', PreMandateBis) mandate_accounts_list = URL(r'https://www.gestion-sous-mandat.labanquepostale-gestionprivee.fr/lbpgp/secure/accounts_list.html', MandateAccountsList) mandate_market = URL(r'https://www.gestion-sous-mandat.labanquepostale-gestionprivee.fr/lbpgp/secure_account/selectedAccountDetail.html', MandateMarket) mandate_life = URL(r'https://www.gestion-sous-mandat.labanquepostale-gestionprivee.fr/lbpgp/secure_main/asvContratClient.html', r'https://www.gestion-sous-mandat.labanquepostale-gestionprivee.fr/lbpgp/secure_ajax/asvSupportsDetail.html', MandateLife) profile = URL('/voscomptes/canalXHTML/donneesPersonnelles/consultationDonneesPersonnellesSB490A/init-consulterDonneesPersonnelles.ea', ProfilePage) accounts = None def __init__(self, *args, **kwargs): self.weboob = kwargs.pop('weboob') super(BPBrowser, self).__init__(*args, **kwargs) dirname = self.responses_dirname if dirname: dirname += '/bourse' self.linebourse = LinebourseBrowser('https://labanquepostale.offrebourse.com/', logger=self.logger, responses_dirname=dirname, weboob=self.weboob, proxy=self.PROXIES) self.recipient_form = None def load_state(self, state): if 'recipient_form' in state and state['recipient_form'] is not None: super(BPBrowser, self).load_state(state) self.logged = True def deinit(self): super(BPBrowser, self).deinit() self.linebourse.deinit() def location(self, url, **kwargs): try: return super(BPBrowser, self).location(url, **kwargs) except ServerError as err: if "/../" not in err.response.url: raise # this shit website includes ".." in an absolute url in the Location header # requests passes it verbatim, and the site can't handle it self.logger.debug('site has "/../" in their url, fixing url manually') parts = list(urlsplit(err.response.url)) parts[2] = os.path.abspath(parts[2]) return self.location(urlunsplit(parts)) def do_login(self): self.location(self.login_url) self.page.login(self.username, self.password) if self.redirect_page.is_here() and self.page.check_for_perso(): raise BrowserIncorrectPassword(u"L'identifiant utilisé est celui d'un compte de Particuliers.") if self.badlogin.is_here(): raise BrowserIncorrectPassword() if self.disabled_account.is_here(): raise BrowserBanned() @need_login def get_accounts_list(self): if self.accounts is None: accounts = [] to_check = [] self.par_accounts_checking.go() pages = [self.par_accounts_checking, self.par_accounts_savings_and_invests, self.par_accounts_loan] no_accounts = 0 for page in pages: page.go() assert page.is_here(), "AccountList type page not reached" if self.page.no_accounts: no_accounts += 1 continue for account in self.page.iter_accounts(): if account.type == Account.TYPE_LOAN: self.location(account.url) if 'CreditRenouvelable' not in account.url: for loan in self.page.iter_loans(): loan.currency = account.currency accounts.append(loan) student_loan = self.page.get_student_loan() if student_loan: # Number of headers and item elements are the same assert len(student_loan._heads) == len(student_loan._items) student_loan.currency = account.currency accounts.append(student_loan) else: for loan in self.page.iter_revolving_loans(): loan.currency = account.currency accounts.append(loan) else: accounts.append(account) if account.type == Account.TYPE_CHECKING and account._has_cards: to_check.append(account) if self.page.has_mandate_management_space: self.location(self.page.mandate_management_space_link()) for mandate_account in self.page.iter_accounts(): accounts.append(mandate_account) for account in to_check: accounts.extend(self.iter_cards(account)) to_check = [] self.accounts = accounts # if we are sure there is no accounts on the all visited pages, # it is legit. if no_accounts == len(pages): raise NoAccountsException() return self.accounts def iter_cards(self, account): self.deferred_card_history.go(accountId=account.id, type=0, cardIndex=0) if self.cards_list.is_here(): self.logger.debug('multiple cards for account %r', account) for card in self.page.get_cards(parent_id=account.id): card.parent = account yield card else: self.logger.debug('single card for account %r', account) self.logger.debug('parsing %r', self.url) card = self.page.get_single_card(parent_id=account.id) card.parent = account yield card @need_login def get_history(self, account): # TODO scrap pdf to get history of mandate accounts if 'gestion-sous-mandat' in account.url: return [] if account.type in (account.TYPE_PEA, account.TYPE_MARKET): self.go_linebourse(account) return self.linebourse.iter_history(account.id) if account.type == Account.TYPE_LOAN: return [] if account.type == Account.TYPE_CARD: return (tr for tr in self.iter_card_transactions(account) if not tr._coming) else: self.location(account.url) history = {Account.TYPE_CHECKING: self.par_account_checking_history, Account.TYPE_SAVINGS: self.par_account_savings_and_invests_history, Account.TYPE_MARKET: self.par_account_savings_and_invests_history }.get(account.type) if history is not None: history.go(accountId=account.id) # TODO be smarter by avoid fetching all, sorting all and returning all if only coming were desired if hasattr(self.page, 'iter_transactions') and self.page.has_transactions(): return self.page.iter_transactions() return [] @need_login def go_linebourse(self, account): self.location(account.url) self.market_login.go() self.linebourse.session.cookies.update(self.session.cookies) self.par_accounts_checking.go() def _get_coming_transactions(self, account): if account.type == Account.TYPE_CHECKING: self.location(account.url) self.par_account_checking_coming.go(accountId=account.id) if self.par_account_checking_coming.is_here() and self.page.has_transactions(): for tr in self.page.iter_transactions(coming=True): yield tr @need_login def get_coming(self, account): if 'gestion-sous-mandat' in account.url: return [] if account.type == Account.TYPE_CHECKING: return self._get_coming_transactions(account) elif account.type == Account.TYPE_CARD: transactions = [] for tr in self.iter_card_transactions(account): if tr._coming: transactions.append(tr) return transactions return [] @need_login def iter_card_transactions(self, account): def iter_transactions(link, urlobj): self.location(link) assert urlobj.is_here() ncard = self.page.params['cardIndex'] self.logger.debug('handling card %s for account %r', ncard, account) for t in range(6): try: urlobj.go(accountId=account.parent.id, type=t, cardIndex=ncard) except BrowserUnavailable: self.logger.debug("deferred card history stop at %s", t) break if urlobj.is_here(): for tr in self.page.get_history(deferred=True): yield tr assert account.type == Account.TYPE_CARD for tr in iter_transactions(account.url, self.deferred_card_history_multi): yield tr @need_login def iter_investment(self, account): if 'gestion-sous-mandat' in account.url: return self.location(account.url).page.iter_investments() if account.type in (account.TYPE_PEA, account.TYPE_MARKET): self.go_linebourse(account) return self.linebourse.iter_investment(account.id) if account.type != Account.TYPE_LIFE_INSURANCE: return iter([]) investments = [] self.lifeinsurance_invest.go(id=account.id) assert self.lifeinsurance_invest.is_here() if not self.page.has_error(): investments = list(self.page.iter_investments()) if not investments: self.lifeinsurance_invest2.go(id=account.id) investments = list(self.page.iter_investments()) if self.page.get_cachemire_link(): # fetch ISIN codes for cachemire invests self.lifeinsurance_cachemire_catalog.go() product_codes = self.page.product_codes for inv in investments: inv.code = product_codes.get(inv.label.upper(), NotAvailable) return investments @need_login def iter_recipients(self, account_id): return self.transfer_choose.stay_or_go().iter_recipients(account_id=account_id) @need_login def init_transfer(self, account, recipient, amount, transfer): self.transfer_choose.stay_or_go() self.page.init_transfer(account.id, recipient._value) assert self.transfer_complete.is_here() self.page.complete_transfer(amount, transfer) return self.page.handle_response(account, recipient, amount, transfer.label) @need_login def execute_transfer(self, transfer, code=None): if not self.transfer_confirm.is_here(): raise TransferError('Case not handled.') self.page.confirm() # Should only happen if double auth. if self.transfer_confirm.is_here(): self.page.double_auth(transfer) return self.page.handle_response(transfer) def build_recipient(self, recipient): r = Recipient() r.iban = recipient.iban r.id = recipient.iban r.label = recipient.label r.category = recipient.category r.enabled_at = datetime.now().replace(microsecond=0) + timedelta(days=5) r.currency = u'EUR' r.bank_name = recipient.bank_name return r def post_code(self, code): data = {} for k, v in self.recipient_form.items(): if k != 'url': data[k] = v data['codeOTPSaisi'] = code self.location(self.recipient_form['url'], data=data) @need_login def new_recipient(self, recipient, is_bp_account=False, **kwargs): if 'code' in kwargs: assert self.rcpt_code.is_here() self.post_code(kwargs['code']) self.recipient_form = None assert self.rcpt_summary.is_here() return self.build_recipient(recipient) self.create_recipient.go().choose_country(recipient, is_bp_account) self.page.populate(recipient) if self.page.is_bp_account(): return self.new_recipient(recipient, is_bp_account=True, **kwargs) # send sms self.location(self.page.get_confirm_link()) self.page.set_browser_form() raise AddRecipientStep(self.build_recipient(recipient), Value('code', label='Veuillez saisir votre code de validation')) @need_login def get_advisor(self): return iter([self.advisor.go().get_advisor()]) @need_login def get_profile(self): return self.profile.go().get_profile() class BProBrowser(BPBrowser): login_url = "https://banqueenligne.entreprises.labanquepostale.fr/wsost/OstBrokerWeb/loginform?TAM_OP=login&ERROR_CODE=0x00000000&URL=%2Fws_q47%2Fvoscomptes%2Fidentification%2Fidentification.ea%3Forigin%3Dprofessionnels" accounts_and_loans_url = None pro_accounts_list = URL(r'.*voscomptes/synthese/synthese.ea', ProAccountsList) pro_history = URL(r'.*voscomptes/historique(ccp|cne)/(\d+-)?historique(ccp|cne).*', ProAccountHistory) useless2 = URL(r'.*/voscomptes/bourseenligne/lancementBourseEnLigne-bourseenligne.ea\?numCompte=(?P\d+)', UselessPage) market_login = URL(r'.*/voscomptes/bourseenligne/oicformautopost.jsp', MarketLoginPage) BASEURL = 'https://banqueenligne.entreprises.labanquepostale.fr' def set_variables(self): v = urlsplit(self.url) version = v.path.split('/')[1] self.base_url = 'https://banqueenligne.entreprises.labanquepostale.fr/%s' % version self.accounts_url = self.base_url + '/voscomptes/synthese/synthese.ea' def go_linebourse(self, account): self.location(account.url) self.location('../bourseenligne/oicformautopost.jsp') self.linebourse.session.cookies.update(self.session.cookies) self.location(self.accounts_url) @need_login def get_history(self, account): if account.type in (account.TYPE_PEA, account.TYPE_MARKET): self.go_linebourse(account) return self.linebourse.iter_history(account.id) transactions = [] v = urlsplit(account.url) args = dict(parse_qsl(v.query)) args['typeRecherche'] = 10 self.location(v.path, params=args) for tr in self.page.iter_history(): transactions.append(tr) transactions.sort(key=lambda tr: tr.rdate, reverse=True) return transactions def _get_coming_transactions(self, account): return [] @need_login def get_accounts_list(self): if self.accounts is None: self.set_variables() accounts = [] ids = set() self.location(self.accounts_url) assert self.pro_accounts_list.is_here() for account in self.page.get_accounts_list(): ids.add(account.id) accounts.append(account) if self.accounts_and_loans_url: self.location(self.accounts_and_loans_url) assert self.pro_accounts_list.is_here() for account in self.page.get_accounts_list(): if account.id not in ids: ids.add(account.id) accounts.append(account) for acc in accounts: self.location('%s/voscomptes/rib/init-rib.ea' % self.base_url) value = self.page.get_rib_value(acc.id) if value: self.location('%s/voscomptes/rib/preparerRIB-rib.ea?%s' % (self.base_url, value)) if self.rib.is_here(): acc.iban = self.page.get_iban() self.accounts = accounts return self.accounts @need_login def get_profile(self): acc = self.get_accounts_list()[0] self.location('%s/voscomptes/rib/init-rib.ea' % self.base_url) value = self.page.get_rib_value(acc.id) if value: self.location('%s/voscomptes/rib/preparerRIB-rib.ea?%s' % (self.base_url, value)) if self.rib.is_here(): return self.page.get_profile()