# -*- coding: utf-8 -*- # Copyright(C) 2012-2014 Vincent Paredes # # This file is part of a weboob module. # # This weboob module is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This weboob module 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this weboob module. If not, see . from __future__ import unicode_literals from requests.exceptions import ConnectTimeout from weboob.browser import LoginBrowser, URL, need_login from weboob.exceptions import BrowserIncorrectPassword, BrowserUnavailable, ActionNeeded, BrowserPasswordExpired from .pages import LoginPage, BillsPage from .pages.login import ManageCGI, HomePage, PasswordPage from .pages.bills import ( SubscriptionsPage, SubscriptionsApiPage, BillsApiProPage, BillsApiParPage, ContractsPage, ) from .pages.profile import ProfilePage from weboob.browser.exceptions import ClientError, ServerError from weboob.tools.compat import basestring from weboob.tools.decorators import retry __all__ = ['OrangeBillBrowser'] class OrangeBillBrowser(LoginBrowser): BASEURL = 'https://espaceclientv3.orange.fr' home_page = URL(r'https://businesslounge.orange.fr/$', HomePage) loginpage = URL( r'https://login.orange.fr/\?service=sosh&return_url=https://www.sosh.fr/', r'https://login.orange.fr/front/login', LoginPage, ) password_page = URL(r'https://login.orange.fr/front/password', PasswordPage) contracts = URL(r'https://espaceclientpro.orange.fr/api/contracts\?page=1&nbcontractsbypage=15', ContractsPage) subscriptions = URL(r'https://espaceclientv3.orange.fr/js/necfe.php\?zonetype=bandeau&idPage=gt-home-page', SubscriptionsPage) subscriptions_api = URL(r'https://sso-f.orange.fr/omoi_erb/portfoliomanager/v2.0/contractSelector/users/current', SubscriptionsApiPage) manage_cgi = URL(r'https://eui.orange.fr/manage_eui/bin/manage.cgi', ManageCGI) # is billspage deprecated ? billspage = URL( r'https://m.espaceclientv3.orange.fr/\?page=factures-archives', r'https://.*.espaceclientv3.orange.fr/\?page=factures-archives', r'https://espaceclientv3.orange.fr/\?page=factures-archives', r'https://espaceclientv3.orange.fr/\?page=facture-telecharger', r'https://espaceclientv3.orange.fr/maf.php', r'https://espaceclientv3.orange.fr/\?idContrat=(?P.*)&page=factures-historique', r'https://espaceclientv3.orange.fr/\?page=factures-historique&idContrat=(?P.*)', BillsPage, ) bills_api_pro = URL( r'https://espaceclientpro.orange.fr/api/contract/(?P\d+)/bills\?count=(?P)', BillsApiProPage, ) bills_api_par = URL(r'https://sso-f.orange.fr/omoi_erb/facture/v2.0/billsAndPaymentInfos/users/current/contracts/(?P\d+)', BillsApiParPage) doc_api_par = URL(r'https://sso-f.orange.fr/omoi_erb/facture/v1.0/pdf') doc_api_pro = URL('https://espaceclientpro.orange.fr/api/contract/(?P\d+)/bill/(?P.*)/(?P.*)/\?(?P)') profile = URL('/\?page=profil-infosPerso', ProfilePage) def do_login(self): assert isinstance(self.username, basestring) assert isinstance(self.password, basestring) try: self.loginpage.stay_or_go().login(self.username, self.password) except ClientError as error: if error.response.status_code == 401: raise BrowserIncorrectPassword() if error.response.status_code == 403: # occur when user try several times with a bad password, orange block his account for a short time raise BrowserIncorrectPassword(error.response.json()) raise if self.password_page.is_here(): error_message = self.page.get_change_password_message() if error_message: raise BrowserPasswordExpired(error_message) def get_nb_remaining_free_sms(self): raise NotImplementedError() def post_message(self, message, sender): raise NotImplementedError() def _iter_subscriptions_by_type(self, name, _type): self.location('https://espaceclientv3.orange.fr/?page=gt-home-page&%s' % _type) self.subscriptions.go() for sub in self.page.iter_subscription(): sub.subscriber = name yield sub @retry(BrowserUnavailable, tries=2, delay=10) @need_login def get_subscription_list(self): try: self.profile.go() assert self.profile.is_here() or self.manage_cgi.is_here() # we land on manage_cgi page when there is cgu to validate if self.manage_cgi.is_here(): # but they are not in this page, we have to go to home_page to get message self.home_page.go() msg = self.page.get_error_message() assert "Nos Conditions Générales d'Utilisation ont évolué" in msg, msg raise ActionNeeded(msg) else: profile = self.page.get_profile() except ConnectTimeout: # sometimes server just doesn't answer raise BrowserUnavailable() # this only works when there are pro subs. nb_sub = 0 try: for sub in self.contracts.go().iter_subscriptions(): sub.subscriber = profile.name yield sub nb_sub = self.page.doc['totalContracts'] # assert pagination is not needed assert nb_sub < 15 except ServerError: pass if nb_sub > 0: return # if nb_sub is 0, we continue, because we can get them in next url for sub in self._iter_subscriptions_by_type(profile.name, 'sosh'): nb_sub += 1 yield sub for sub in self._iter_subscriptions_by_type(profile.name, 'orange'): nb_sub += 1 yield sub if nb_sub == 0: # No subscriptions found, trying with the API. headers = { 'X-Orange-Caller-Id': 'ECQ', } self.subscriptions_api.go(headers=headers) for sub in self.page.iter_subscription(): sub.subscriber = profile.name yield sub @need_login def iter_documents(self, subscription): documents = [] if subscription._is_pro: for d in self.bills_api_pro.go(subid=subscription.id, count=72).get_bills(subid=subscription.id): documents.append(d) # check pagination for this subscription assert len(documents) != 72 else: headers = {'x-orange-caller-id': 'ECQ'} self.bills_api_par.go(subid=subscription.id, headers=headers) for b in self.page.get_bills(subid=subscription.id): documents.append(b) return iter(documents) @need_login def get_profile(self): return self.profile.go().get_profile()