From c93255ef99b595d69a7649c62ef17ef63cdb688d Mon Sep 17 00:00:00 2001 From: Vincent Ardisson Date: Wed, 7 Dec 2016 18:16:38 +0100 Subject: [PATCH] [bforbank] use spirica for life insurance TODO: use PARENT --- modules/bforbank/browser.py | 38 ++++++++++++++++++++++++++-- modules/bforbank/module.py | 2 +- modules/bforbank/pages.py | 14 ++++++++++ modules/bforbank/spirica/__init__.py | 0 modules/bforbank/spirica/browser.py | 1 + modules/bforbank/spirica/pages.py | 1 + modules/spirica/pages.py | 30 ++++++++++++++++++++-- 7 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 modules/bforbank/spirica/__init__.py create mode 120000 modules/bforbank/spirica/browser.py create mode 120000 modules/bforbank/spirica/pages.py diff --git a/modules/bforbank/browser.py b/modules/bforbank/browser.py index b04e284dfd..4f59259506 100644 --- a/modules/bforbank/browser.py +++ b/modules/bforbank/browser.py @@ -22,7 +22,11 @@ from weboob.browser import LoginBrowser, URL, need_login from weboob.capabilities.bank import Account -from .pages import LoginPage, ErrorPage, AccountsPage, HistoryPage, LoanHistoryPage, RibPage +from .pages import ( + LoginPage, ErrorPage, AccountsPage, HistoryPage, LoanHistoryPage, RibPage, + LifeInsuranceIframe, LifeInsuranceRedir +) +from .spirica.browser import SpiricaBrowser class BforbankBrowser(LoginBrowser): @@ -35,12 +39,16 @@ class BforbankBrowser(LoginBrowser): '/espace-client/rib/(?P\d+)', RibPage) loan_history = URL('/espace-client/livret/consultation.*', LoanHistoryPage) history = URL('/espace-client/consultation/operations/.*', HistoryPage) + lifeinsurance_iframe = URL(r'/client/accounts/lifeInsurance/consultationDetailSpirica.action', LifeInsuranceIframe) + lifeinsurance_redir = URL(r'https://assurance-vie.bforbank.com:443/sylvea/welcomeSSO.xhtml', LifeInsuranceRedir) def __init__(self, birthdate, *args, **kwargs): super(BforbankBrowser, self).__init__(*args, **kwargs) self.birthdate = birthdate self.accounts = None + self.spirica = SpiricaBrowser('https://assurance-vie.bforbank.com:443/', None, None) + def do_login(self): assert isinstance(self.username, basestring) assert isinstance(self.password, basestring) @@ -62,7 +70,33 @@ def iter_accounts(self): @need_login def get_history(self, account): - if account.type == Account.TYPE_MARKET or account.type == Account.TYPE_LIFE_INSURANCE: + if account.type == Account.TYPE_MARKET: raise NotImplementedError() + elif account.type == Account.TYPE_LIFE_INSURANCE: + self.goto_spirica(account) + return self.spirica.iter_history(account) + self.location(account._link.replace('tableauDeBord', 'operations')) return self.page.get_operations() + + def goto_spirica(self, account): + assert account.type == Account.TYPE_LIFE_INSURANCE + self.home.stay_or_go() # make sure we are on the right domain + self.location('/client/accounts/lifeInsurance/lifeInsuranceSummary.action') + assert self.lifeinsurance_iframe.is_here() + + self.location(self.page.get_iframe()) + assert self.lifeinsurance_redir.is_here() + + redir = self.page.get_redir() + assert redir + account._link = self.absurl(redir) + self.spirica.session.cookies.update(self.session.cookies) + self.spirica.logged = True + + @need_login + def iter_investment(self, account): + if account.type == Account.TYPE_LIFE_INSURANCE: + self.goto_spirica(account) + return self.spirica.iter_investment(account) + raise NotImplementedError() diff --git a/modules/bforbank/module.py b/modules/bforbank/module.py index 3ec50caa09..bf24d5f639 100644 --- a/modules/bforbank/module.py +++ b/modules/bforbank/module.py @@ -60,4 +60,4 @@ def iter_history(self, account): return self.browser.get_history(account) def iter_investment(self, account): - raise NotImplementedError() + return self.browser.iter_investment(account) diff --git a/modules/bforbank/pages.py b/modules/bforbank/pages.py index 296ec6369b..c6b5bfa54f 100644 --- a/modules/bforbank/pages.py +++ b/modules/bforbank/pages.py @@ -192,3 +192,17 @@ def obj_date(self): obj_raw = Transaction.Raw('./td[1]') obj_amount = MyDecimal('./td[2]', replace_dots=True) + + +class LifeInsuranceIframe(LoggedPage, HTMLPage): + def get_iframe(self): + return Attr(None, 'src').filter(self.doc.xpath('//iframe[@id="iframePartenaire"]')) + + +class LifeInsuranceRedir(LoggedPage, HTMLPage): + def get_redir(self): + # meta http-equiv redirection... + for meta in self.doc.xpath('//meta[@http-equiv="Refresh"]/@content'): + match = re.search(r'URL=([^\s"\']+)', meta) + if match: + return match.group(1) diff --git a/modules/bforbank/spirica/__init__.py b/modules/bforbank/spirica/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/bforbank/spirica/browser.py b/modules/bforbank/spirica/browser.py new file mode 120000 index 0000000000..c6e5247cba --- /dev/null +++ b/modules/bforbank/spirica/browser.py @@ -0,0 +1 @@ +../../spirica/browser.py \ No newline at end of file diff --git a/modules/bforbank/spirica/pages.py b/modules/bforbank/spirica/pages.py new file mode 120000 index 0000000000..09325e4584 --- /dev/null +++ b/modules/bforbank/spirica/pages.py @@ -0,0 +1 @@ +../../spirica/pages.py \ No newline at end of file diff --git a/modules/spirica/pages.py b/modules/spirica/pages.py index f64dd434eb..eaea43b232 100644 --- a/modules/spirica/pages.py +++ b/modules/spirica/pages.py @@ -118,6 +118,11 @@ class item(ItemInvestment): obj_code = Regexp(CleanText(TableCell('code')), pattern='([A-Z]{2}\d{10})', default=NotAvailable) +class ProfileTableInvestment(TableInvestment): + # used only when portfolio is divided in multiple "profiles" + head_xpath = '//thead[ends-with(@id, ":contratProfilTable_head")]/tr/th' + + class DetailsPage(LoggedPage, HTMLPage): DEBIT_WORDS = [u'arrêté', 'rachat', 'frais', u'désinvestir'] @@ -131,8 +136,8 @@ def get_investment_form(self): @method class iter_investment(TableInvestment): - item_xpath = '//div[contains(@id, "INVESTISSEMENT")]//table/tbody/tr[@data-ri]' - head_xpath = '//div[contains(@id, "INVESTISSEMENT")]//table/thead/tr/th' + item_xpath = '//div[contains(@id,"INVESTISSEMENT")]//div[ends-with(@id, ":tableDetailSituationCompte")]//table/tbody/tr[@data-ri]' + head_xpath = '//div[contains(@id,"INVESTISSEMENT")]//div[ends-with(@id, ":tableDetailSituationCompte")]//table/thead/tr/th' col_valuation = re.compile('Contre') @@ -147,6 +152,27 @@ def obj_diff(self): return MyDecimal('//div[contains(@id, "PRIX_REVIENT")]//a[contains(text(), \ "%s")]/ancestor::tr/td[6]' % Field('label')(self))(self) + def obj_portfolio_share(self): + inv_share = ItemInvestment.obj_portfolio_share(self) + if self.xpath('ancestor::tbody[ends-with(@id, "contratProfilTable_data")]'): + # investments are nested in profiles, row share is relative to profile share + profile_table_el = self.xpath('ancestor::tr/ancestor::table[position() = 1]')[0] + profile_table = ProfileTableInvestment(self.page, self, profile_table_el) + share_idx = profile_table.get_colnum('portfolio_share') + assert share_idx + + curr_profile_el = self.xpath('ancestor::tr/preceding-sibling::tr[@data-ri][position() = 1]')[0] + share_el = curr_profile_el.xpath('./td[%d]' % (share_idx + 1)) + path = 'ancestor::tr/preceding-sibling::tr[@data-ri][position() = 1][1]/td[%d]' % (share_idx + 1) + + profile_share = MyDecimal(path)(self) + assert profile_share + #raise Exception('dtc') + profile_share = Eval(lambda x: x / 100, profile_share)(self) + return inv_share * profile_share + else: + return inv_share + def get_historytab_form(self): form = self.get_form('//form[contains(@id, "j_idt")]') idt = Attr(None, 'name').filter(self.doc.xpath('//input[contains(@name, "j_idt") \ -- GitLab