diff --git a/modules/orange/browser.py b/modules/orange/browser.py index 061a08d5a310b638d5ae20e7c25008ad53deab4c..b2d06d9e98aa11f89e6654e064502ebe2554ae26 100644 --- a/modules/orange/browser.py +++ b/modules/orange/browser.py @@ -53,7 +53,7 @@ class OrangeBillBrowser(LoginBrowser, StatesMixin): password_page = URL(r'https://login.orange.fr/front/password', PasswordPage) captcha_page = URL(r'https://login.orange.fr/captcha', CaptchaPage) - contracts = URL(r'https://espaceclientpro.orange.fr/api/contracts\?page=1&nbcontractsbypage=15', ContractsPage) + contracts = URL(r'https://espaceclientpro.orange.fr/api/contracts', ContractsPage) contracts_api = URL(r'https://sso-f.orange.fr/omoi_erb/portfoliomanager/contracts/users/current\?filter=telco,security', ContractsApiPage) subscriptions = URL(r'https://espaceclientv3.orange.fr/js/necfe.php\?zonetype=bandeau&idPage=gt-home-page', SubscriptionsPage) @@ -158,13 +158,18 @@ def get_subscription_list(self): # this only works when there are pro subs. nb_sub = 0 + subscription_id_list = [] try: - for sub in self.contracts.go().iter_subscriptions(): + params = { + 'page': 1, + 'nbcontractsbypage': 15 + } + self.contracts.go(params=params) + for sub in self.page.iter_subscriptions(): sub.subscriber = profile.name + subscription_id_list.append(sub.id) yield sub nb_sub = self.page.doc['totalContracts'] - # assert pagination is not needed - assert nb_sub < 15 except ServerError: pass @@ -175,8 +180,10 @@ def get_subscription_list(self): "X-Orange-Origin-ID": "ECQ", } for sub in self.contracts_api.go(headers=headers).iter_subscriptions(): - nb_sub += 1 - yield sub + # subscription returned here may be duplicated with the one returned by contracts page + if sub.id not in subscription_id_list: + nb_sub += 1 + yield sub except (ServerError, ClientError) as e: # The orange website will return odd status codes when there are no subscriptions to return # I've seen the 404, 500 and 503 response codes diff --git a/modules/orange/pages/bills.py b/modules/orange/pages/bills.py index 571af8c5eb94278d727bb13d066fce4d870e6572..6ac055fa571a92ce693bb40ce9a7fbc000ce6650 100644 --- a/modules/orange/pages/bills.py +++ b/modules/orange/pages/bills.py @@ -25,7 +25,7 @@ except ImportError: import HTMLParser -from weboob.browser.pages import HTMLPage, LoggedPage, JsonPage +from weboob.browser.pages import HTMLPage, LoggedPage, JsonPage, pagination from weboob.capabilities.bill import Subscription from weboob.browser.elements import DictElement, ListElement, ItemElement, method, TableElement from weboob.browser.filters.standard import ( @@ -39,7 +39,7 @@ from weboob.capabilities.base import NotAvailable from weboob.capabilities.bill import DocumentTypes, Bill from weboob.tools.date import parse_french_date -from weboob.tools.compat import urlencode +from weboob.tools.compat import urlencode, urlparse, parse_qsl class BillsApiProPage(LoggedPage, JsonPage): @@ -215,10 +215,26 @@ def condition(self): class ContractsPage(LoggedPage, JsonPage): + @pagination @method class iter_subscriptions(DictElement): item_xpath = 'contracts' + def next_page(self): + params = dict(parse_qsl(urlparse(self.page.url).query)) + page_number = int(params['page']) + nbcontractsbypage = int(params['nbcontractsbypage']) + nb_subs = page_number * nbcontractsbypage + + # sometimes totalContracts can be different from real quantity + # already seen totalContracts=39 with 38 contracts in json + # so we compare nb contracts received in this response with number per page to make sure we stop + # even if there is oneday totalContracts=7677657689 but just 8 contracts + doc = self.page.doc + if nb_subs < doc['totalContracts'] and len(doc['contracts']) == nbcontractsbypage: + params['page'] = page_number + 1 + return self.page.browser.contracts.build(params=params) + class item(ItemElement): klass = Subscription @@ -249,7 +265,8 @@ def obj_subscriber(self): CleanText(Dict('holder/firstName', default=""))(self), CleanText(Dict('holder/lastName', default=""))(self), ) - assert any(names), "At least one name field should be populated. Has the page changed?" + if not any(names): + return NotAvailable return ' '.join([n for n in names if n]) def obj__is_pro(self):