Commit 93035c30 authored by Jerome Berthier's avatar Jerome Berthier Committed by Romain Bignon

[cmes] Handle new website, currently only for cmes and cices

Note that there is less information than before for investment (no code, no unit
quantity/price).

The behavior is also modified, unstead of one account grouping everything,
there are now several accounts (PEE, PERCO, ...).

As a result, accounts id are modified. It is now 'client_number' + 'account.label',
instead of 'client_name' + 'client_number'.
parent e188452b
......@@ -22,7 +22,7 @@ from weboob.exceptions import BrowserIncorrectPassword
from weboob.browser import LoginBrowser, URL, need_login
from .pages import (
LoginPage, AccountsPage, FCPEInvestmentPage,
LoginPage, NewWebsitePage, AccountsPage, FCPEInvestmentPage,
CCBInvestmentPage, HistoryPage, CustomPage,
)
......@@ -32,6 +32,7 @@ class CmesBrowser(LoginBrowser):
login = URL('/espace-client/fr/identification/authentification.html', LoginPage)
accounts = URL('(?P<subsite>.*)fr/espace/devbavoirs.aspx\?mode=net&menu=cpte$', AccountsPage)
new_website = URL('(?P<subsite>.*)espace-client/fr/epargnants/tableau-de-bord/index.html', NewWebsitePage)
fcpe_investment = URL(r'/fr/.*GoPositionsParFond.*',
r'/fr/espace/devbavoirs.aspx\?.*SituationParFonds.*GoOpenDetailFond.*',
r'(?P<subsite>.*)fr/espace/devbavoirs.aspx\?_tabi=(C|I1)&a_mode=net&a_menu=cpte&_pid=Situation(Globale|ParPlan)&_fid=GoPositionsParFond',
......@@ -49,6 +50,10 @@ class CmesBrowser(LoginBrowser):
self.password = password
self.subsite = subsite
@property
def logged(self):
return 'IdSes' in self.session.cookies
def do_login(self):
self.login.go()
self.page.login(self.username, self.password)
......
......@@ -23,7 +23,7 @@ from weboob.tools.value import ValueBackendPassword
from weboob.capabilities.bank import CapBankPockets, AccountNotFound
from weboob.capabilities.base import find_object
from .browser import CmesBrowser
from .proxy_browser import ProxyBrowser
__all__ = ['CmesModule']
......@@ -40,7 +40,7 @@ class CmesModule(Module, CapBankPockets):
ValueBackendPassword('login', label='Identifiant', masked=False),
ValueBackendPassword('password', label='Mot de passe'))
BROWSER = CmesBrowser
BROWSER = ProxyBrowser
def create_default_browser(self):
return self.create_browser(
......
# -*- coding: utf-8 -*-
# Copyright(C) 2019 Budget Insight
#
# 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 <http://www.gnu.org/licenses/>.
from weboob.browser import URL, need_login
from ..browser import CmesBrowser
from .pages import (
NewAccountsPage, OperationsListPage, OperationPage
)
class CmesBrowserNew(CmesBrowser):
accounts = URL(r'(?P<subsite>.*)espace-client/fr/epargnants/mon-epargne/situation-financiere-detaillee/index.html',
r'(?P<subsite>.*)espace-client/fr/epargnants/tableau-de-bord/index.html',
NewAccountsPage)
operations_list = URL(r'(?P<subsite>.*)espace-client/fr/epargnants/operations/index.html',
OperationsListPage)
operation = URL(r'(?P<subsite>.*)espace-client/fr/epargnants/operations/consulter-une-operation/index.html\?param_=(?P<idx>\d+)',
OperationPage)
@need_login
def iter_investment(self, account):
return self.accounts.stay_or_go(subsite=self.subsite).iter_investment(account=account)
@need_login
def iter_history(self, account):
self.operations_list.stay_or_go(subsite=self.subsite)
for idx in self.page.get_operations_idx():
tr = self.operation.go(subsite=self.subsite, idx=idx).get_transaction()
if account.label == tr._account_label:
yield tr
@need_login
def iter_pocket(self, account):
for inv in self.iter_investment(account=account):
for pocket in self.page.iter_pocket(inv=inv):
yield pocket
# -*- coding: utf-8 -*-
# Copyright(C) 2019 Budget Insight
#
# 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 <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
import re
from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.browser.elements import ListElement, ItemElement, method
from weboob.browser.filters.standard import (
CleanText, Date, Regexp, Field, Currency, Upper, MapIn, Eval
)
from weboob.capabilities.bank import Account, Investment, Pocket
from ..pages import MyDecimal, Transaction
ACCOUNTS_TYPES = {
"pargne entreprise": Account.TYPE_PEE,
"pargne retraite": Account.TYPE_PERCO
}
class NewAccountsPage(LoggedPage, HTMLPage):
@method
class iter_accounts(ListElement):
item_xpath = '//th[text()= "Nom du support" or text()="Nom du profil"]/ancestor::table/ancestor::table'
class item(ItemElement):
klass = Account
balance_xpath = './/span[contains(text(), "Montant total")]/following-sibling::span'
obj_label = CleanText('./tbody/tr/th//div')
obj_balance = MyDecimal(balance_xpath)
obj_currency = Currency(balance_xpath)
obj_type = MapIn(Field('label'), ACCOUNTS_TYPES, default=Account.TYPE_UNKNOWN)
def obj_id(self):
# Use customer number + label to build account id
number = Regexp(CleanText('//div[@id="ei_tpl_fullSite"]//div[contains(@class, "ei_tpl_profil_content")]/p'),
r'(\d+)$', '\\1')(self)
return Field('label')(self) + number
def iter_invest_rows(self, account):
for row in self.doc.xpath('//th/div[contains(., "%s")]/ancestor::table//table/tbody/tr' % account.label):
idx = re.search(r'_(\d+)\.', row.xpath('.//a[contains(@href, "GoFund")]/@id')[0]).group(1)
yield idx, row
def iter_investment(self, account):
for idx, row in self.iter_invest_rows(account=account):
inv = Investment()
inv._account = account
inv._idx = idx
inv.label = CleanText('.//a[contains(@href, "GoFund")]/text()')(row)
inv.valuation = MyDecimal('.//td[2]')(row)
inv.diff_ratio = Eval(lambda x: x / 100, MyDecimal('.//td[3]'))(row)
# Get data from a popup not reachable from the current row
inv.diff = MyDecimal('//div[@id="I0:F1_%s.R20:D"]//span' % idx)(self.doc)
if account.balance != 0:
inv.portfolio_share = inv.valuation / account.balance
yield inv
def iter_pocket(self, inv):
for idx, _ in self.iter_invest_rows(account=inv._account):
if idx != inv._idx:
continue
for row in self.doc.xpath('//div[@id="I0:F1_%s.R16:D"]//tr[position()>1]' % idx):
pocket = Pocket()
pocket.label = inv.label
pocket.investment = inv
pocket.amount = MyDecimal('./td[2]')(row)
if 'DISPONIBLE' in Upper(CleanText('./td[1]'))(row):
pocket.condition = Pocket.CONDITION_AVAILABLE
else:
pocket.condition = Pocket.CONDITION_DATE
pocket.availability_date = Date(Regexp(Upper(CleanText('./td[1]')), 'AU[\s]+(.*)'), dayfirst=True)(row)
yield pocket
class OperationPage(LoggedPage, HTMLPage):
@method
class get_transaction(ItemElement):
klass = Transaction
obj_amount = MyDecimal('//td[contains(text(), "Montant total")]/following-sibling::td')
obj_label = CleanText('(//p[contains(@id, "smltitle")])[2]')
obj_raw = Transaction.Raw(Field('label'))
obj_date = Date(Regexp(CleanText('(//p[contains(@id, "smltitle")])[1]'), r'(\d{1,2}/\d{1,2}/\d+)'), dayfirst=True)
obj__account_label = CleanText('//td[contains(text(), "Montant total")]/../following-sibling::tr/th[1]')
class OperationsListPage(LoggedPage, HTMLPage):
def __init__(self, *a, **kw):
self._cache = []
super(OperationsListPage, self).__init__(*a, **kw)
def get_operations_idx(self):
return [i.split(':')[-1] for i in self.doc.xpath('.//input[contains(@name, "_FID_GoOperationDetails")]/@name')]
......@@ -28,6 +28,7 @@ from weboob.browser.filters.standard import (
CleanDecimal, Env, Async, AsyncLoad, Currency,
)
from weboob.browser.filters.html import Link, TableCell, Attr
from weboob.browser.switch import SiteSwitch
from weboob.capabilities.bank import Account, Investment, Pocket
from weboob.capabilities.base import NotAvailable
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
......@@ -47,6 +48,11 @@ class LoginPage(HTMLPage):
form.submit()
class NewWebsitePage(HTMLPage, LoggedPage):
def on_load(self):
raise SiteSwitch('cmes_new')
class AccountsPage(LoggedPage, HTMLPage):
def on_load(self):
if self.doc.xpath('//label[contains(@for, "AcceptCGU")]'):
......@@ -181,9 +187,9 @@ class CCBInvestmentPage(LoggedPage, HTMLPage):
class Transaction(FrenchTransaction):
PATTERNS = [(re.compile(u'^(?P<text>Versement.*)'), FrenchTransaction.TYPE_DEPOSIT),
PATTERNS = [(re.compile(u'^(?P<text>.*Versement.*)'), FrenchTransaction.TYPE_DEPOSIT),
(re.compile(u'^(?P<text>(Arbitrage|Prélèvements.*))'), FrenchTransaction.TYPE_ORDER),
(re.compile(u'^(?P<text>Retrait.*)'), FrenchTransaction.TYPE_WITHDRAWAL),
(re.compile(u'^(?P<text>(Retrait|Paiement.*))'), FrenchTransaction.TYPE_WITHDRAWAL),
(re.compile(u'^(?P<text>.*)'), FrenchTransaction.TYPE_BANK),
]
......
# -*- coding: utf-8 -*-
# Copyright(C) 2019 Budget Insight
#
# 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 <http://www.gnu.org/licenses/>.
from weboob.browser.switch import SwitchingBrowser
from .browser import CmesBrowser
from .new_website.browser import CmesBrowserNew
class ProxyBrowser(SwitchingBrowser):
BROWSERS = {
'main': CmesBrowser,
'cmes_new': CmesBrowserNew,
}
KEEP_SESSION = True
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