Commit dd07fce0 authored by Quentin Defenouillere's avatar Quentin Defenouillere Committed by Romain Bignon

[hsbc] Fetch Comptes de Tiers

Some HSBC connections have a link called "comptes de tiers" in which
users can check their family members accounts.
This patch enables the scraping of all third party accounts.

Closes: 7605@Zendesk
parent df3fa35a
This diff is collapsed.
...@@ -47,11 +47,11 @@ class HSBCModule(Module, CapBankWealth, CapProfile): ...@@ -47,11 +47,11 @@ class HSBCModule(Module, CapBankWealth, CapProfile):
self.config['secret'].get()) self.config['secret'].get())
def iter_accounts(self): def iter_accounts(self):
for account in self.browser.get_accounts_list(): for account in self.browser.iter_account_owners():
yield account yield account
def get_account(self, _id): def get_account(self, _id):
return find_object(self.browser.get_accounts_list(), id=_id, error=AccountNotFound) return find_object(self.browser.iter_account_owners(), id=_id, error=AccountNotFound)
def iter_history(self, account): def iter_history(self, account):
for tr in self.browser.get_history(account): for tr in self.browser.get_history(account):
...@@ -160,13 +160,20 @@ class AccountsPage(GenericLandingPage): ...@@ -160,13 +160,20 @@ class AccountsPage(GenericLandingPage):
def condition(self): def condition(self):
return len(self.el.xpath('./td')) > 2 return len(self.el.xpath('./td')) > 2
# Some accounts have no <a> in the first <td>
def obj_label(self): def obj_label(self):
return Label(CleanText('./td[1]/a'))(self) or 'Compte sans libellé' if self.el.xpath('./td[1]/a'):
return Label(CleanText('./td[1]/a'))(self) or 'Compte sans libellé'
return Label(CleanText('./td[1]'))(self) or 'Compte sans libellé'
obj_coming = Env('coming') obj_coming = Env('coming')
obj_currency = FrenchTransaction.Currency('./td[2]') obj_currency = FrenchTransaction.Currency('./td[2]')
obj_url = CleanText(AbsoluteLink('./td[1]/a'), replace=[('\n', '')]) def obj_url(self):
# Accounts without an <a> in the <td> have no link
if self.el.xpath('./td[1]/a'):
return CleanText(AbsoluteLink('./td[1]/a'), default=None, replace=[('\n', '')])(self)
return None
obj_type = AccountsType(Field('label')) obj_type = AccountsType(Field('label'))
obj_coming = NotAvailable obj_coming = NotAvailable
...@@ -226,6 +233,13 @@ class AccountsPage(GenericLandingPage): ...@@ -226,6 +233,13 @@ class AccountsPage(GenericLandingPage):
return account_id return account_id
class OwnersListPage(AccountsPage):
is_here = '//h1[text()="Comptes de tiers"]'
def get_owners_urls(self):
return self.doc.xpath('//div[@class="GoBack"]/a/@href')
class RibPage(GenericLandingPage): class RibPage(GenericLandingPage):
def is_here(self): def is_here(self):
return bool(self.doc.xpath('//h1[contains(text(), "RIB/IBAN")]')) return bool(self.doc.xpath('//h1[contains(text(), "RIB/IBAN")]'))
...@@ -244,7 +258,8 @@ class RibPage(GenericLandingPage): ...@@ -244,7 +258,8 @@ class RibPage(GenericLandingPage):
form = self.get_form(name="FORM_RIB") form = self.get_form(name="FORM_RIB")
form['index_rib'] = str(nb+1) form['index_rib'] = str(nb+1)
form.submit() form.submit() if self.browser.rib.is_here():
class Pagination(object): class Pagination(object):
...@@ -9,6 +9,7 @@ import time ...@@ -9,6 +9,7 @@ import time
from weboob.capabilities import NotAvailable from weboob.capabilities import NotAvailable
from import Account, Investment from import Account, Investment
from import is_isin_valid
from weboob.browser.elements import ItemElement, TableElement, DictElement, method from weboob.browser.elements import ItemElement, TableElement, DictElement, method
from weboob.browser.pages import HTMLPage, JsonPage, LoggedPage from weboob.browser.pages import HTMLPage, JsonPage, LoggedPage
...@@ -359,9 +360,13 @@ class RetrieveInvestmentsPage(LoggedPage, JsonPage): ...@@ -359,9 +360,13 @@ class RetrieveInvestmentsPage(LoggedPage, JsonPage):
klass = Investment klass = Investment
obj_label = CleanText(Dict('productName')) obj_label = CleanText(Dict('productName'))
obj_code = CleanText(Dict('productIdInformation/0/productAlternativeNumber'))
obj_code_type = Investment.CODE_TYPE_ISIN
obj_quantity = CleanDecimal(Dict('holdingDetailInformation/0/productHoldingQuantityCount')) obj_quantity = CleanDecimal(Dict('holdingDetailInformation/0/productHoldingQuantityCount'))
obj_code = CleanText(Dict('productIdInformation/0/productAlternativeNumber'), replace=[('-FR', '')])
def obj_code_type(self):
if is_isin_valid(Field('code')(self)):
return Investment.CODE_TYPE_ISIN
return NotAvailable
def obj_vdate(self): def obj_vdate(self):
vdate = Dict('holdingDetailInformation/0/productPriceUpdateDate')(self) vdate = Dict('holdingDetailInformation/0/productPriceUpdateDate')(self)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment