Commit 7ca85b03 authored by Sylvie Ye's avatar Sylvie Ye Committed by Romain Bignon

[lcl] retrieve all life insurance accounts on external website

Go on lcl external life insurance to get accounts for account with "routage" option
For life insurance accounts with "popup" option, stay on main website
parent c105b3cc
......@@ -34,7 +34,7 @@ from import Value
from .pages import LoginPage, AccountsPage, AccountHistoryPage, \
CBListPage, CBHistoryPage, ContractsPage, ContractsChoicePage, BoursePage, \
AVPage, AVDetailPage, DiscPage, NoPermissionPage, RibPage, \
AVListPage, AVPage, AVDetailPage, DiscPage, NoPermissionPage, RibPage, \
HomePage, LoansPage, TransferPage, AddRecipientPage, \
RecipientPage, RecipConfirmPage, SmsPage, RecipRecapPage, \
LoansProPage, Form2Page, DocumentsPage, ClientPage, SendTokenPage, \
......@@ -84,7 +84,7 @@ class LCLBrowser(LoginBrowser, StatesMixin):
'/outil/UAUT/RetourPartenaire/retourCar', DiscPage)
form2 = URL(r'/outil/UWVI/Routage/', Form2Page)
form2 = URL(r'/outil/UWVI/Routage', Form2Page)
send_token = URL('/outil/UWVI/AssuranceVie/envoyerJeton', SendTokenPage)
calie = URL('*',
......@@ -94,9 +94,10 @@ class LCLBrowser(LoginBrowser, StatesMixin):
av_list = URL('', AVListPage)
avdetail = URL('', AVDetailPage)
av_history = URL('', AVHistoryPage)
av_investments = URL('', AVInvestmentsPage)
av_investments = URL('<life_insurance_id>\w+)', AVInvestmentsPage)
loans = URL('/outil/UWCR/SynthesePar/', LoansPage)
loans_pro = URL('/outil/UWCR/SynthesePro/', LoansProPage)
......@@ -179,6 +180,24 @@ class LCLBrowser(LoginBrowser, StatesMixin):
def deconnexion_bourse(self):
def go_life_insurance_website(self):
life_insurance_routage_url =
if life_insurance_routage_url:
def update_life_insurance_account(self, life_insurance):
def go_back_from_life_insurance_website(self):
def select_contract(self, id_contract):
if self.current_contract and id_contract != self.current_contract:
# when we go on bourse page, we can't change contract anymore... we have to logout.
......@@ -215,20 +234,27 @@ class LCLBrowser(LoginBrowser, StatesMixin):
def get_accounts(self):
# This is required in case the browser is left in the middle of add_recipient and the session expires.
if self.login.is_here():
return self.get_accounts_list()
if self.accounts_list is None:
self.accounts_list = []
# retrieve life insurance accounts
if self.no_perm.is_here():
self.logger.warning('Life insurances are unavailable.')
for a in
for a in
# retrieve life insurance on special lcl life insurance website
for life_insurance in
life_insurance = self.update_life_insurance_account(life_insurance)
# retrieve accounts on main page
for a in
if not self.check_accounts(a):
......@@ -246,6 +272,7 @@ class LCLBrowser(LoginBrowser, StatesMixin):
a.iban = iban if iban is not None else NotAvailable
# retrieve loans accounts
if self.no_perm.is_here():
self.logger.warning('Loans are unavailable.')
......@@ -253,6 +280,7 @@ class LCLBrowser(LoginBrowser, StatesMixin):
for a in
# retrieve pro loans accounts
if self.no_perm.is_here():
self.logger.warning('Loans are unavailable.')
......@@ -267,6 +295,7 @@ class LCLBrowser(LoginBrowser, StatesMixin):
# Disconnecting from bourse portal before returning account list
# to be sure that we are on the banque portal
# retrieve deposit accounts
if self.no_perm.is_here():
self.logger.warning('Deposits are unavailable.')
......@@ -280,6 +309,8 @@ class LCLBrowser(LoginBrowser, StatesMixin):
def get_accounts_list(self):
if self.accounts_list is None:
self.accounts_list = []
if self.contracts and self.current_contract:
for id_contract in self.contracts:
......@@ -41,7 +41,8 @@ from weboob.browser.exceptions import ServerError
from weboob.browser.pages import LoggedPage, HTMLPage, JsonPage, FormNotFound, pagination
from weboob.browser.filters.html import Attr, Link, TableCell, AttributeNotFound
from weboob.browser.filters.standard import (
CleanText, Field, Regexp, Format, Date, CleanDecimal, Map, AsyncLoad, Async, Env, Slugify, BrowserURL, Eval,
CleanText, Field, Regexp, Format, Date, CleanDecimal, Map, AsyncLoad, Async, Env,
Slugify, BrowserURL, Eval, Lower,
from weboob.browser.filters.json import Dict
from weboob.exceptions import BrowserUnavailable, BrowserIncorrectPassword
......@@ -687,8 +688,18 @@ class NoPermissionPage(LoggedPage, HTMLPage):
class AVPage(LoggedPage, HTMLPage):
def get_routage_url(self):
for account in self.doc.xpath('//table[@class]/tbody/tr'):
if account.xpath('.//td[has-class("nomContrat")]//a[has-class("routageCAR")]'):
return Link('.//td[has-class("nomContrat")]//a[has-class("routageCAR")]')(account)
def is_website_life_insurance(self):
# no need specific account to go on life insurance external website
# because we just need to go on life insurance external website
return bool(self.get_routage_url())
class get_list(ListElement):
class get_popup_life_insurance(ListElement):
item_xpath = '//table[@class]/tbody/tr'
class item(ItemElement):
......@@ -698,7 +709,8 @@ class AVPage(LoggedPage, HTMLPage):
if self.obj_balance(self) == 0 and not self.el.xpath('.//td[has-class("nomContrat")]//a'):
self.logger.warning("ignoring an AV account because there's no link for it")
return False
return True
# there is life insurance detail page link but check if it's a popup
return self.el.xpath('.//td[has-class("nomContrat")]//a[has-class("clickPopupDetail")]')
obj__owner = CleanText('.//td[2]')
obj_label = Format(u'%s %s', CleanText('.//td/text()[following-sibling::br]'), obj__owner)
......@@ -710,19 +722,17 @@ class AVPage(LoggedPage, HTMLPage):
obj__coming_links = []
obj__transfer_id = None
obj_number = Field('id')
obj__external_website = False
def obj_id(self):
_id = CleanText('.//td/@id')(self)
# in old code, we use _id, it seems that is not used anymore
# but check if it's the case for all users
assert not _id, '_id is still used to retrieve life insurance'
_id = CleanText('.//td/@id')(self)
if not _id:
ac_details_page ='.//td[has-class("nomContrat")]//a')(self)).page
if '-' in _id:
split = _id.split('-')
ac_details_page ='/outil/UWVI/AssuranceVie/accesDetail?ID_CONTRAT=%s&PRODUCTEUR=%s' % (split[0], split[1])).page
ac_details_page ='/outil/UWVI/AssuranceVie/accesDetail?ID_CONTRAT=%s' % (_id)).page
ac_details_page ='.//td[has-class("nomContrat")]//a')(self)).page
return CleanText('(//tr[3])/td[2]')(ac_details_page.doc)
except ServerError:
self.logger.debug("link didn't work, trying with the form instead")
......@@ -737,6 +747,7 @@ class AVPage(LoggedPage, HTMLPage):
return account_id
def obj__form(self):
# maybe deprecated
form_id = Attr('.//td[has-class("nomContrat")]//a', 'id', default=None)(self)
if form_id:
if '-' in form_id:
......@@ -851,6 +862,34 @@ class AVDetailPage(LoggedPage, LCLBasePage):
return self.browser.location('', params=params)
class AVListPage(LoggedPage, JsonPage):
class iter_life_insurance(DictElement):
item_xpath = 'syntheseContrats'
class item(ItemElement):
def condition(self):
return (
Lower(Dict('lcstacntgen'))(self) == 'actif'
and Lower(Dict('lcgampdt'))(self) == 'epargne'
klass = Account
obj_id = obj_number = Dict('idcntcar')
obj_balance = CleanDecimal(Dict('mtvalcnt'))
obj_label = Dict('lnpdt')
obj_type = Account.TYPE_LIFE_INSURANCE
obj_currency = 'EUR'
obj__external_website = True
obj__form = None
obj__link_id = None
obj__market_link = None
obj__coming_links = []
obj__transfer_id = None
class AVHistoryPage(LoggedPage, JsonPage):
class iter_history(DictElement):
......@@ -885,6 +924,14 @@ class AVHistoryPage(LoggedPage, JsonPage):
class AVInvestmentsPage(LoggedPage, JsonPage):
def update_life_insurance_account(self, life_insurance):
life_insurance._owner = Format('%s %s',
life_insurance.label = '%s %s' % (Dict('situationAdministrativeEpargne/lcofc')(self.doc), life_insurance._owner)
life_insurance.valuation_diff = CleanDecimal(Dict('situationFinanciereEpargne/mtpmvcnt'), default=NotAvailable)(self.doc)
return life_insurance
class iter_investment(DictElement):
item_xpath = 'listeSupports/support'
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