diff --git a/modules/barclays/browser.py b/modules/barclays/browser.py
index 70f58f96148bab86c4cc5c7fdbc7ee2f58ffa4d0..c9ed8486e4c30b99f6b7f2165c2d4da46554559d 100644
--- a/modules/barclays/browser.py
+++ b/modules/barclays/browser.py
@@ -17,6 +17,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this weboob module. If not, see .
+# flake8: compatible
from __future__ import unicode_literals
@@ -41,16 +42,16 @@ class Barclays(LoginBrowser):
logout = URL('https://www.milleis.fr/deconnexion')
milleis_ajax = URL('/BconnectDesk/ajaxservletcontroller')
- login = URL('/BconnectDesk/servletcontroller', LoginPage)
- accounts = URL('/BconnectDesk/servletcontroller', AccountsPage)
- loan_account = URL('/BconnectDesk/servletcontroller', LoanAccountPage)
- account = URL('/BconnectDesk/servletcontroller', AccountPage)
- card_account = URL('/BconnectDesk/servletcontroller', CardPage)
- market_account = URL('/BconnectDesk/servletcontroller', MarketAccountPage)
+ login = URL('/BconnectDesk/servletcontroller', LoginPage)
+ accounts = URL('/BconnectDesk/servletcontroller', AccountsPage)
+ loan_account = URL('/BconnectDesk/servletcontroller', LoanAccountPage)
+ account = URL('/BconnectDesk/servletcontroller', AccountPage)
+ card_account = URL('/BconnectDesk/servletcontroller', CardPage)
+ market_account = URL('/BconnectDesk/servletcontroller', MarketAccountPage)
life_insurance_account = URL('/BconnectDesk/servletcontroller', LifeInsuranceAccountPage)
- revolving_account = URL('/BconnectDesk/servletcontroller', RevolvingAccountPage)
- actionNeededPage = URL('/BconnectDesk/servletcontroller', ActionNeededPage)
- iban = URL('/BconnectDesk/editique', IbanPDFPage)
+ revolving_account = URL('/BconnectDesk/servletcontroller', RevolvingAccountPage)
+ actionNeededPage = URL('/BconnectDesk/servletcontroller', ActionNeededPage)
+ iban = URL('/BconnectDesk/editique', IbanPDFPage)
def __init__(self, secret, *args, **kwargs):
super(Barclays, self).__init__(*args, **kwargs)
@@ -72,7 +73,8 @@ def _go_to_account(self, account, refresh=False):
else:
if not self.accounts.is_here():
self.page.go_to_menu('Comptes et contrats')
- if not self.accounts.is_here(): # Sometime we can't go out from account page, so re-login
+ if not self.accounts.is_here():
+ # Sometime we can't go out from account page, so re-login
self._relogin()
self.page.go_to_account(account)
@@ -93,8 +95,8 @@ def _go_to_account_space(self, space, account):
'controllername': 'servletcontroller',
'disable': 'false',
'title': 'Milleis',
- token[0]: token[1]
- }
+ token[0]: token[1],
+ }
self.milleis_ajax.open(data=data)
self._go_to_account(account, refresh=True)
@@ -132,7 +134,7 @@ def iter_accounts(self):
if not self.accounts.is_here():
self.page.go_to_menu('Comptes et contrats')
- if not 'accounts' in self.cache:
+ if 'accounts' not in self.cache:
accounts = list(self.page.iter_accounts())
traccounts = []
@@ -145,7 +147,10 @@ def iter_accounts(self):
if account.type == Account.TYPE_CHECKING:
# Only checking accounts have an IBAN
self._go_to_account(account)
- account.iban = self.iban.open().get_iban() if self.page.has_iban() else NotAvailable
+ if self.page.has_iban():
+ account.iban = self.iban.open().get_iban()
+ else:
+ account.iban = NotAvailable
if account.type == Account.TYPE_LOAN:
self._go_to_account(account)
@@ -159,7 +164,9 @@ def iter_accounts(self):
if not self.page.has_history():
continue
- account._attached_account = self.page.do_account_attachment([a for a in accounts if a.type == Account.TYPE_CHECKING])
+ account._attached_account = self.page.do_account_attachment([
+ a for a in accounts if a.type == Account.TYPE_CHECKING
+ ])
if account.type == Account.TYPE_REVOLVING_CREDIT:
self._go_to_account(account)
@@ -174,8 +181,10 @@ def iter_accounts(self):
# is not specified, therefore to avoid transaction duplicates,
# we only return transactions from the 'EUR' twin account.
for account in self.cache['accounts']:
- if (account.id.replace(account.currency, '') in
- [acc.id.replace(acc.currency, '') for acc in self.cache['accounts'] if acc.id != account.id]):
+ accounts_id_without_currency = [
+ acc.id.replace(acc.currency, '') for acc in self.cache['accounts'] if acc.id != account.id
+ ]
+ if account.id.replace(account.currency, '') in accounts_id_without_currency:
account._twin = True
else:
account._twin = False
@@ -208,7 +217,9 @@ def iter_history(self, account):
history_page = self.page
if account.type != Account.TYPE_LIFE_INSURANCE:
- for _ in range(100): # on new history page they take previous results too, so go to the last page before starts recover history
+ for _ in range(100):
+ # on new history page they take previous results too,
+ # so go to the last page before starts recover history
form = history_page.form_to_history_page()
if not form:
@@ -216,13 +227,14 @@ def iter_history(self, account):
try:
history_page = self.account.open(data=form)
- except ConnectionError: # Sometime accounts have too much history and website crash
+ except ConnectionError:
+ # Sometime accounts have too much history and website crash
# Need to relogin
self._relogin()
break
else:
- assert False, "Too many iterations"
+ raise AssertionError('Too many iterations')
if history_page.has_history():
return list(history_page.iter_history())
diff --git a/modules/barclays/module.py b/modules/barclays/module.py
index ea366137f440f2f8e71f1c114fc9767fea5aa0b9..d9c9585013bc8e959ff1ae40e2ba7fd55dde40b4 100644
--- a/modules/barclays/module.py
+++ b/modules/barclays/module.py
@@ -17,14 +17,13 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this weboob module. If not, see .
+# flake8: compatible
from __future__ import unicode_literals
-from weboob.capabilities.bank import AccountNotFound
from weboob.capabilities.wealth import CapBankWealth
from weboob.tools.backend import Module, BackendConfig
from weboob.tools.value import ValueBackendPassword
-from weboob.capabilities.base import find_object
from .browser import Barclays
@@ -34,27 +33,28 @@
class BarclaysModule(Module, CapBankWealth):
NAME = 'barclays'
- MAINTAINER = u'Jean Walrave'
+ MAINTAINER = 'Jean Walrave'
EMAIL = 'jwalrave@budget-insight.com'
VERSION = '2.1'
- DESCRIPTION = u'Barclays'
+ DESCRIPTION = 'Barclays'
LICENSE = 'LGPLv3+'
- CONFIG = BackendConfig(ValueBackendPassword('login', label=u"N° d'abonné", masked=False),
- ValueBackendPassword('password', label='Code confidentiel'),
- ValueBackendPassword('secret', label='Mot secret'))
+ CONFIG = BackendConfig(
+ ValueBackendPassword('login', label="N° d'abonné", masked=False),
+ ValueBackendPassword('password', label='Code confidentiel'),
+ ValueBackendPassword('secret', label='Mot secret'),
+ )
BROWSER = Barclays
def create_default_browser(self):
- return self.create_browser(self.config['secret'].get(),
- self.config['login'].get(),
- self.config['password'].get())
+ return self.create_browser(
+ self.config['secret'].get(),
+ self.config['login'].get(),
+ self.config['password'].get(),
+ )
def iter_accounts(self):
return self.browser.iter_accounts()
- def get_account(self, _id):
- return find_object(self.browser.iter_accounts(), id=_id, error=AccountNotFound)
-
def iter_history(self, account):
return self.browser.iter_history(account)
diff --git a/modules/barclays/pages.py b/modules/barclays/pages.py
index 4d68e3902c10ac94f0fd5265f3907ea00725ab39..743d1eb72856e05553bac31adbae252bdb20fb9e 100644
--- a/modules/barclays/pages.py
+++ b/modules/barclays/pages.py
@@ -17,13 +17,18 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this weboob module. If not, see .
+# flake8: compatible
+
from __future__ import unicode_literals
import re
from weboob.browser.pages import HTMLPage, PDFPage, LoggedPage
from weboob.browser.elements import TableElement, ListElement, ItemElement, method
-from weboob.browser.filters.standard import CleanText, CleanDecimal, Regexp, Field, Date, Eval
+from weboob.browser.filters.standard import (
+ CleanText, CleanDecimal, Regexp, Field, Date, Coalesce,
+ Map, Currency,
+)
from weboob.browser.filters.html import Attr, TableCell, ReplaceEntities
from weboob.capabilities.base import NotAvailable
from weboob.capabilities.bank import Account, Loan
@@ -34,11 +39,6 @@
from weboob.exceptions import ActionNeeded, BrowserUnavailable
-def MyDecimal(*args, **kwargs):
- kwargs.update(replace_dots=True, default=NotAvailable)
- return CleanDecimal(*args, **kwargs)
-
-
class SecretTooShort(Exception):
# secret is a word which contains at least 8 char and website ask us to enter 2 chars of it
# char 3 and 4 or 6 and 7
@@ -49,9 +49,12 @@ class SecretTooShort(Exception):
class StatefulPage(LoggedPage, HTMLPage):
def get_form_for_menu(self, menu):
- btn = Regexp(Attr('//div[@class="menuvert"]//a[contains(., "%s")]' % (menu), 'onclick'), r"\('', '(.*?)',")(self.doc)
+ btn = Regexp(
+ Attr('//div[@class="menuvert"]//a[contains(., "%s")]' % menu, 'onclick'),
+ r"\('', '(.*?)',"
+ )(self.doc)
form = self.get_form(id='form1')
- form['MODE'] = 'NAVMENU_' + btn
+ form['MODE'] = 'NAVMENU_%s' % btn
return form
def go_to_menu(self, menu):
@@ -64,7 +67,12 @@ def go_to_account(self, account):
form = self.get_form(id='form1')
for attr in list(form):
- if attr not in ['MENUSTATE', 'DEVICE_SIZE_INFO', 'C11__GETMODULENOTEPAD[1].IOGETMODULENOTEPAD[1].OUTPUTPARAMETER[1].TEXT', token[0]]:
+ if attr not in (
+ 'MENUSTATE',
+ 'DEVICE_SIZE_INFO',
+ 'C11__GETMODULENOTEPAD[1].IOGETMODULENOTEPAD[1].OUTPUTPARAMETER[1].TEXT',
+ token[0],
+ ):
del form[attr]
form['MODE'] = account._btn
@@ -74,7 +82,10 @@ def go_to_account(self, account):
form.submit()
def isolate_token(self):
- return (Attr('(//input[@type="hidden"])[2]', 'name')(self.doc), Attr('(//input[@type="hidden"])[2]', 'value')(self.doc))
+ return (
+ Attr('(//input[@type="hidden"])[2]', 'name')(self.doc),
+ Attr('(//input[@type="hidden"])[2]', 'value')(self.doc),
+ )
class LoginPage(HTMLPage):
@@ -101,7 +112,7 @@ def login_secret(self, secret):
label = CleanText('//label[@for="C1__IdTwoLetters"]')(self.doc).strip()
letters = ''
- for n in re.findall('(\d+)', label):
+ for n in re.findall(r'(\d+)', label):
if int(n) > len(secret):
raise SecretTooShort()
letters += secret[int(n) - 1]
@@ -119,23 +130,29 @@ def get_error_message(self):
return CleanText('//div[@class="bloc-message error" and not(@style)]')(self.doc)
-class AccountsPage(StatefulPage):
- ACCOUNT_TYPES = {'Liquidités': Account.TYPE_CHECKING,
- 'Epargne': Account.TYPE_SAVINGS,
- 'Titres': Account.TYPE_MARKET,
- 'Engagement/Crédits': Account.TYPE_LOAN,
- }
- ACCOUNT_EXTRA_TYPES = {'BMOOVIE': Account.TYPE_LIFE_INSURANCE,
- 'B. GESTION VIE': Account.TYPE_LIFE_INSURANCE,
- 'E VIE MILLEIS': Account.TYPE_LIFE_INSURANCE,
- 'BANQUE PRIVILEGE': Account.TYPE_REVOLVING_CREDIT,
- 'PRET PERSONNEL': Account.TYPE_LOAN,
- 'CREDIT IMMOBILIE': Account.TYPE_LOAN,
- }
- ACCOUNT_TYPE_TO_STR = {Account.TYPE_MARKET: 'TTR',
- Account.TYPE_CARD: 'CRT'
- }
+ACCOUNT_TYPES = {
+ 'Liquidités': Account.TYPE_CHECKING,
+ 'Epargne': Account.TYPE_SAVINGS,
+ 'Titres': Account.TYPE_MARKET,
+ 'Engagement/Crédits': Account.TYPE_LOAN,
+}
+
+ACCOUNT_EXTRA_TYPES = {
+ 'BMOOVIE': Account.TYPE_LIFE_INSURANCE,
+ 'B. GESTION VIE': Account.TYPE_LIFE_INSURANCE,
+ 'E VIE MILLEIS': Account.TYPE_LIFE_INSURANCE,
+ 'BANQUE PRIVILEGE': Account.TYPE_REVOLVING_CREDIT,
+ 'PRET PERSONNEL': Account.TYPE_LOAN,
+ 'CREDIT IMMOBILIE': Account.TYPE_LOAN,
+}
+ACCOUNT_TYPE_TO_STR = {
+ Account.TYPE_MARKET: 'TTR',
+ Account.TYPE_CARD: 'CRT',
+}
+
+
+class AccountsPage(StatefulPage):
def is_here(self):
return bool(self.doc.xpath('//h1[contains(., "Mes comptes")]'))
@@ -149,90 +166,112 @@ class item(ItemElement):
obj_label = CleanText('.//td[1]//span')
obj__uncleaned_id = CleanText('.//td[2]//a')
obj__btn = Attr('.//button', 'name', default=None)
- obj__attached_account = NotAvailable # for card account only
+ obj__attached_account = NotAvailable # for card account only
def obj_id(self):
- return re.sub(r'\s', '', str(Field('_uncleaned_id')(self))) + self.page.ACCOUNT_TYPE_TO_STR.get(Field('type')(self), '')
+ return '%s%s' % (
+ re.sub(r'\s', '', str(Field('_uncleaned_id')(self))),
+ ACCOUNT_TYPE_TO_STR.get(Field('type')(self), ''),
+ )
def is_card(self):
- return bool(self.xpath('.//div[contains(@id, "9385968FC88E7527131931") and not(contains(@style, "display: none;"))]'))
+ return bool(self.xpath(
+ './/div[contains(@id, "9385968FC88E7527131931") and not(contains(@style, "display: none;"))]'
+ ))
def obj_balance(self):
if self.is_card():
return 0
- return MyDecimal('.//td[4]//div[1]/a')(self)
+ return CleanDecimal.French('.//td[4]//div[1]/a', default=NotAvailable)(self)
def obj_coming(self):
if self.is_card():
- return MyDecimal('.//td[4]//div[1]/a')(self)
+ return CleanDecimal.French('.//td[4]//div[1]/a', default=NotAvailable)(self)
return NotAvailable
- def obj_currency(self):
- return Account.get_currency(CleanText('.//td[5]//div[1]/a')(self))
+ obj_currency = Currency(CleanText('.//td[5]//div[1]/a'))
def obj_type(self):
if self.is_card():
return Account.TYPE_CARD
- type = CleanText('./ancestor::node()[7]//button[contains(@id, "C4__BUT_787E7BC48BF75E723710")]')(self)
- return self.page.ACCOUNT_EXTRA_TYPES.get(Field('label')(self)) or self.page.ACCOUNT_TYPES.get(type, Account.TYPE_UNKNOWN)
+ return Coalesce(
+ Map(Field('label'), ACCOUNT_EXTRA_TYPES, ''),
+ Map(
+ CleanText('./ancestor::node()[7]//button[contains(@id, "C4__BUT_787E7BC48BF75E723710")]'),
+ ACCOUNT_TYPES,
+ ''
+ ),
+ default=Account.TYPE_UNKNOWN
+ )(self)
def obj__multiple_type(self):
- # Sometime account can be twice declared with different types but same id, we flag them to avoid some errors
+ # Sometimes an account can be declared twice with different types but the same id.
+ # We flag them to avoid some errors
for account in self.parent.objects.values():
if account._uncleaned_id == Field('_uncleaned_id')(self):
if not account._multiple_type:
account._multiple_type = True
-
return True
-
return False
class Transaction(FrenchTransaction):
PATTERNS = [
- (re.compile(r'\w+ FRAIS RET DAB '), FrenchTransaction.TYPE_BANK),
- (re.compile('^RET DAB (?P.*?) RETRAIT DU (?P\d{2})(?P\d{2})(?P\d{2}).*'),
- FrenchTransaction.TYPE_WITHDRAWAL),
- (re.compile('^RET DAB (?P.*?) CARTE ?:.*'),
- FrenchTransaction.TYPE_WITHDRAWAL),
- (re.compile('^RET DAB (?P\d{2})/(?P\d{2})/(?P\d{2}) (?P.*?) CARTE .*'),
- FrenchTransaction.TYPE_WITHDRAWAL),
- (re.compile(r'(?P.*) RET DAB DU (?P\d{2})/(?P\d{2})/(?P\d{2}) (?P.*?) CARTE .*'),
- FrenchTransaction.TYPE_WITHDRAWAL),
- (re.compile('^(?P.*) RETRAIT DU (?P\d{2})(?P\d{2})(?P\d{2}) .*'),
- FrenchTransaction.TYPE_WITHDRAWAL),
- (re.compile('(\w+) (?P\d{2})(?P\d{2})(?P\d{2}) CB[:\*][^ ]+ (?P.*)'),
- FrenchTransaction.TYPE_CARD),
- (re.compile('^(?PVIR(EMEN)?T? (SEPA)?(RECU|FAVEUR)?)( /FRM)?(?P.*)'),
- FrenchTransaction.TYPE_TRANSFER),
- (re.compile(r'^PRLV (?P.*) (?:REF: \w+ DE (?P.*))?$'),FrenchTransaction.TYPE_ORDER),
- (re.compile(r'PRELEVEMENT (?P.*)'), FrenchTransaction.TYPE_ORDER),
- (re.compile('^CHEQUE.*? (REF \w+)?$'), FrenchTransaction.TYPE_CHECK),
- (re.compile('^(AGIOS /|FRAIS) (?P.*)'), FrenchTransaction.TYPE_BANK),
- (re.compile('^(CONVENTION \d+ )?COTIS(ATION)? (?P.*)'),
- FrenchTransaction.TYPE_BANK),
- (re.compile('^REMISE (?P.*)'), FrenchTransaction.TYPE_DEPOSIT),
- (re.compile('^(?P.*)( \d+)? QUITTANCE .*'),
- FrenchTransaction.TYPE_ORDER),
- (re.compile('^.* LE (?P\d{2})/(?P\d{2})/(?P\d{2})$'),
- FrenchTransaction.TYPE_UNKNOWN),
- (re.compile('^CARTE .*'), FrenchTransaction.TYPE_CARD_SUMMARY),
- (re.compile(r'CONTRIBUTIONS SOCIALES'), FrenchTransaction.TYPE_BANK),
- (re.compile(r'COMMISSION INTERVENTION'), FrenchTransaction.TYPE_BANK),
- (re.compile(r'INTERETS CREDITEURS'), FrenchTransaction.TYPE_BANK),
- (re.compile(r'(ANNUL |ANNULATION |)FRAIS '), FrenchTransaction.TYPE_BANK),
- (re.compile(r'(ANNUL |ANNULATION |)INT DEB'), FrenchTransaction.TYPE_BANK),
- (re.compile(r'TAEG APPLIQUE '), FrenchTransaction.TYPE_BANK),
- ]
+ (re.compile(r'\w+ FRAIS RET DAB '), FrenchTransaction.TYPE_BANK),
+ (
+ re.compile(r'^RET DAB (?P.*?) RETRAIT DU (?P\d{2})(?P\d{2})(?P\d{2}).*'),
+ FrenchTransaction.TYPE_WITHDRAWAL,
+ ),
+ (re.compile(r'^RET DAB (?P.*?) CARTE ?:.*'), FrenchTransaction.TYPE_WITHDRAWAL),
+ (
+ re.compile(r'^RET DAB (?P\d{2})/(?P\d{2})/(?P\d{2}) (?P.*?) CARTE .*'),
+ FrenchTransaction.TYPE_WITHDRAWAL,
+ ),
+ (
+ re.compile(r'(?P.*) RET DAB DU (?P\d{2})/(?P\d{2})/(?P\d{2}) (?P.*?) CARTE .*'),
+ FrenchTransaction.TYPE_WITHDRAWAL,
+ ),
+ (
+ re.compile(r'^(?P.*) RETRAIT DU (?P\d{2})(?P\d{2})(?P\d{2}) .*'),
+ FrenchTransaction.TYPE_WITHDRAWAL,
+ ),
+ (
+ re.compile(r'(\w+) (?P\d{2})(?P\d{2})(?P\d{2}) CB[:\*][^ ]+ (?P.*)'),
+ FrenchTransaction.TYPE_CARD,
+ ),
+ (
+ re.compile(r'^(?PVIR(EMEN)?T? (SEPA)?(RECU|FAVEUR)?)( /FRM)?(?P.*)'),
+ FrenchTransaction.TYPE_TRANSFER,
+ ),
+ (re.compile(r'^PRLV (?P.*) (?:REF: \w+ DE (?P.*))?$'), FrenchTransaction.TYPE_ORDER),
+ (re.compile(r'PRELEVEMENT (?P.*)'), FrenchTransaction.TYPE_ORDER),
+ (re.compile(r'^CHEQUE.*? (REF \w+)?$'), FrenchTransaction.TYPE_CHECK),
+ (re.compile(r'^(AGIOS /|FRAIS) (?P.*)'), FrenchTransaction.TYPE_BANK),
+ (re.compile(r'^(CONVENTION \d+ )?COTIS(ATION)? (?P.*)'), FrenchTransaction.TYPE_BANK),
+ (re.compile(r'^REMISE (?P.*)'), FrenchTransaction.TYPE_DEPOSIT),
+ (re.compile(r'^(?P.*)( \d+)? QUITTANCE .*'), FrenchTransaction.TYPE_ORDER),
+ (re.compile(r'^.* LE (?P\d{2})/(?P\d{2})/(?P\d{2})$'), FrenchTransaction.TYPE_UNKNOWN),
+ (re.compile(r'^CARTE .*'), FrenchTransaction.TYPE_CARD_SUMMARY),
+ (re.compile(r'CONTRIBUTIONS SOCIALES'), FrenchTransaction.TYPE_BANK),
+ (re.compile(r'COMMISSION INTERVENTION'), FrenchTransaction.TYPE_BANK),
+ (re.compile(r'INTERETS CREDITEURS'), FrenchTransaction.TYPE_BANK),
+ (re.compile(r'(ANNUL |ANNULATION |)FRAIS '), FrenchTransaction.TYPE_BANK),
+ (re.compile(r'(ANNUL |ANNULATION |)INT DEB'), FrenchTransaction.TYPE_BANK),
+ (re.compile(r'TAEG APPLIQUE '), FrenchTransaction.TYPE_BANK),
+ ]
class AbstractAccountPage(StatefulPage):
def has_iban(self):
- return len(self.doc.xpath('//a[contains(., "Edition RIB")]/ancestor::node()[2][not(contains(@style, "display: none;"))]')) > 1
+ return len(self.doc.xpath(
+ '//a[contains(., "Edition RIB")]/ancestor::node()[2][not(contains(@style, "display: none;"))]'
+ )) > 1
def has_history(self):
- return bool(self.doc.xpath(u'//div[contains(@id, "83B48AC016951684534547") and contains(@style, "display: none;")]'))
+ return bool(self.doc.xpath(
+ '//div[contains(@id, "83B48AC016951684534547") and contains(@style, "display: none;")]'
+ ))
def form_to_history_page(self):
btn = Attr('//button[contains(@id, "moreOperations")]', 'name', default=NotAvailable)(self.doc)
@@ -244,7 +283,13 @@ def form_to_history_page(self):
form = self.get_form(id='form1')
for attr in list(form):
- if attr not in ['MENUSTATE', 'DEVICE_SIZE_INFO', 'C4__WORKING[1].IDENTINTCONTRAT', 'C9__GETMODULENOTEPAD[1].IOGETMODULENOTEPAD[1].OUTPUTPARAMETER[1].TEXT', token[0]]:
+ if attr not in (
+ 'MENUSTATE',
+ 'DEVICE_SIZE_INFO',
+ 'C4__WORKING[1].IDENTINTCONTRAT',
+ 'C9__GETMODULENOTEPAD[1].IOGETMODULENOTEPAD[1].OUTPUTPARAMETER[1].TEXT',
+ token[0],
+ ):
del form[attr]
form['MODE'] = btn
@@ -256,18 +301,25 @@ class iter_history(TableElement):
head_xpath = '//table[@class="table_operations"]/thead/tr/th//a/text()'
item_xpath = '//table[@class="table_operations"]/tbody/tr'
- col_date = u'Date Opération'
+ col_date = 'Date Opération'
col_vdate = 'Date valeur'
- col_debit = u'Débit'
- col_credit = u'Crédit'
+ col_debit = 'Débit'
+ col_credit = 'Crédit'
class item(ItemElement):
klass = Transaction
obj_date = Date(CleanText(TableCell('date')), dayfirst=True)
obj_vdate = Date(CleanText(TableCell('vdate')), dayfirst=True)
- obj_amount = MyDecimal(TableCell('credit'), default=TableCell('debit'))
- obj_raw = Transaction.Raw(ReplaceEntities(Regexp(CleanText('.//script[1]'), r"toggleDetails\([^,]+,[^,]+, '(.*?)', '(.*?)', '(.*?)',", r'\1 \2 \3')))
+ obj_amount = Coalesce(
+ CleanDecimal.French(TableCell('credit'), default=None),
+ CleanDecimal.French(TableCell('debit')),
+ )
+ obj_raw = Transaction.Raw(ReplaceEntities(Regexp(
+ CleanText('.//script[1]'),
+ r"toggleDetails\([^,]+,[^,]+, '(.*?)', '(.*?)', '(.*?)',",
+ r'\1 \2 \3'
+ )))
class AccountPage(AbstractAccountPage):
@@ -288,7 +340,12 @@ def get_space_attrs(self, space):
a = Regexp(Attr('.', 'onclick'), r'\((.*?)\)')(a[0]).replace('\'', '').split(', ')
form = self.get_form(id='form1')
- return (a[1], 'C4__WORKING[1].SELECTEDSECURITYACCOUNTID', form['C4__WORKING[1].SELECTEDSECURITYACCOUNTID'], a[2])
+ return (
+ a[1],
+ 'C4__WORKING[1].SELECTEDSECURITYACCOUNTID',
+ form['C4__WORKING[1].SELECTEDSECURITYACCOUNTID'],
+ a[2],
+ )
@method
class iter_investments(TableElement):
@@ -348,7 +405,12 @@ def get_space_attrs(self, space):
a = Regexp(Attr('.', 'onclick'), r'\((.*?)\)')(a[0]).replace('\'', '').split(', ')
form = self.get_form(id='form1')
- return (a[1], 'C4__WORKING[1].IDENTCONTRACTLIST', form['C4__WORKING[1].IDENTCONTRACTLIST'], a[2])
+ return (
+ a[1],
+ 'C4__WORKING[1].IDENTCONTRACTLIST',
+ form['C4__WORKING[1].IDENTCONTRACTLIST'],
+ a[2],
+ )
@method
class iter_history(TableElement):
@@ -366,14 +428,13 @@ class item(ItemElement):
obj_vdate = Date(CleanText(TableCell('vdate')), dayfirst=True)
def obj_amount(self):
- return MyDecimal('.//div/span')(TableCell('amount')(self)[0])
+ return CleanDecimal.French('.//div/span', default=NotAvailable)(TableCell('amount')(self)[0])
def obj_date(self):
return Date(CleanText('.//span[contains(@id, "C4__QUE_50FADFF19F566198286748")]'), dayfirst=True)(self)
@method
class iter_investments(TableElement):
-
def condition(self):
return not self.xpath('//h1[text()="Aucune position"]')
@@ -390,10 +451,16 @@ class item(ItemElement):
klass = Investment
obj_label = CleanText(TableCell('label'))
- obj_quantity = MyDecimal(TableCell('quantity'))
- obj_unitvalue = MyDecimal(TableCell('unitvalue'))
- obj_valuation = MyDecimal(TableCell('valuation'))
- obj_portfolio_share = Eval(lambda x: x / 100, MyDecimal(TableCell('portfolio_share')))
+ obj_quantity = CleanDecimal.French(TableCell('quantity'), default=NotAvailable)
+ obj_unitvalue = CleanDecimal.French(TableCell('unitvalue'), default=NotAvailable)
+ obj_valuation = CleanDecimal.French(TableCell('valuation'))
+
+ def obj_portfolio_share(self):
+ portfolio_share_percent = CleanDecimal.French(TableCell('portfolio_share'), default=None)(self)
+ if portfolio_share_percent is not None:
+ return portfolio_share_percent / 100
+ return NotAvailable
+
obj_code = NotAvailable
obj_code_type = NotAvailable
@@ -420,7 +487,9 @@ def do_account_attachment(self, accounts):
return NotAvailable
def has_history(self):
- return bool(self.doc.xpath('//h1[contains(@id, "C0B43C670D16A2667437")]/ancestor::node()[2][contains(@style, "display: none;")]'))
+ return bool(self.doc.xpath(
+ '//h1[contains(@id, "C0B43C670D16A2667437")]/ancestor::node()[2][contains(@style, "display: none;")]'
+ ))
@method
class iter_history(TableElement):
@@ -448,10 +517,13 @@ def obj_date(self):
return self.page.get_debit_date()
def obj_amount(self):
- return MyDecimal('./td[5]//div/span')(self)
+ return CleanDecimal.French('./td[5]//div/span', default=NotAvailable)(self)
def get_debit_date(self):
- return Date(Regexp(CleanText('//label[starts-with(text(),"Echéance au ")]'), r'(\d{2}/\d{2}/\d{4})'), dayfirst=True)(self.doc)
+ return Date(
+ Regexp(CleanText('//label[starts-with(text(),"Echéance au ")]'), r'(\d{2}/\d{2}/\d{4})'),
+ dayfirst=True,
+ )(self.doc)
def get_space_attrs(self, space):
a = self.doc.xpath('//a[contains(span, $space)]', space=space)
@@ -462,7 +534,12 @@ def get_space_attrs(self, space):
a = Regexp(Attr('.', 'onclick'), r'\((.*?)\)')(a[0]).replace('\'', '').split(', ')
form = self.get_form(id='form1')
- return (a[1], 'C4__WORKING[1].LISTCONTRATS', form['C4__WORKING[1].LISTCONTRATS'], a[2])
+ return (
+ a[1],
+ 'C4__WORKING[1].LISTCONTRATS',
+ form['C4__WORKING[1].LISTCONTRATS'],
+ a[2],
+ )
class RevolvingAccountPage(AbstractAccountPage):
@@ -475,11 +552,25 @@ def has_iban(self):
def get_revolving_attributes(self, account):
loan = Loan()
- loan.available_amount = CleanDecimal('//div/span[contains(text(), "Montant disponible")]/following-sibling::*[1]', replace_dots=True)(self.doc)
- loan.used_amount = CleanDecimal('//div/span[contains(text(), "Montant Utilisé")]/following-sibling::*[1]', replace_dots=True)(self.doc)
- loan.total_amount = CleanDecimal('//div/span[contains(text(), "Réserve accordée")]/following-sibling::*[1]', replace_dots=True)(self.doc)
- loan.last_payment_amount = CleanDecimal('//div/span[contains(text(), "Echéance Précédente")]/following-sibling::*[1]', replace_dots=True)(self.doc)
- loan.last_payment_date = Date(Regexp(CleanText('//div/span[contains(text(), "Echéance Précédente")]/following-sibling::*[2]'), r'(\d{2}\/\d{2}\/\d{4})'), dayfirst=True)(self.doc)
+ loan.available_amount = CleanDecimal.French(
+ '//div/span[contains(text(), "Montant disponible")]/following-sibling::*[1]'
+ )(self.doc)
+ loan.used_amount = CleanDecimal.French(
+ '//div/span[contains(text(), "Montant Utilisé")]/following-sibling::*[1]'
+ )(self.doc)
+ loan.total_amount = CleanDecimal.French(
+ '//div/span[contains(text(), "Réserve accordée")]/following-sibling::*[1]'
+ )(self.doc)
+ loan.last_payment_amount = CleanDecimal.French(
+ '//div/span[contains(text(), "Echéance Précédente")]/following-sibling::*[1]'
+ )(self.doc)
+ loan.last_payment_date = Date(
+ Regexp(
+ CleanText('//div/span[contains(text(), "Echéance Précédente")]/following-sibling::*[2]'),
+ r'(\d{2}\/\d{2}\/\d{4})'
+ ),
+ dayfirst=True
+ )(self.doc)
owner_name = CleanText('//a[@class="lien-entete login"]/span')(self.doc)
loan.name = ' '.join(owner_name.split()[1:])
@@ -503,14 +594,31 @@ def has_iban(self):
def get_loan_attributes(self, account):
loan = Loan()
- loan.total_amount = CleanDecimal('//div/span[contains(text(), "Capital initial")]/following-sibling::*[1]', replace_dots=True)(self.doc)
+ loan.total_amount = CleanDecimal.French(
+ '//div/span[contains(text(), "Capital initial")]/following-sibling::*[1]'
+ )(self.doc)
owner_name = CleanText('//a[@class="lien-entete login"]/span')(self.doc)
loan.name = ' '.join(owner_name.split()[1:])
- loan.subscription_date = Date(Regexp(CleanText('//h4[span[contains(text(), "Date de départ du prêt")]]'), r'(\d{2}\/\d{2}\/\d{4})'), dayfirst=True)(self.doc)
- loan.maturity_date = Date(Regexp(CleanText('//h4[span[contains(text(), "Date de fin du prêt")]]'), r'(\d{2}\/\d{2}\/\d{4})'), dayfirst=True)(self.doc)
- loan.rate = Eval(lambda x: x / 100, CleanDecimal('//div/span[contains(text(), "Taux fixe")]/following-sibling::*[1]', replace_dots=True))(self.doc)
- loan.last_payment_amount = CleanDecimal('//div[@class="txt-detail " and not (@style)]//span[contains(text(), "Echéance du")]/following-sibling::span[1]')(self.doc)
- loan.last_payment_date = Date(Regexp(CleanText('//div[@class="txt-detail " and not (@style)]//span[contains(text(), "Echéance du")]'), r'(\d{2}\/\d{2}\/\d{4})'), dayfirst=True)(self.doc)
+ loan.subscription_date = Date(
+ Regexp(CleanText('//h4[span[contains(text(), "Date de départ du prêt")]]'), r'(\d{2}\/\d{2}\/\d{4})'),
+ dayfirst=True,
+ )(self.doc)
+ loan.maturity_date = Date(
+ Regexp(CleanText('//h4[span[contains(text(), "Date de fin du prêt")]]'), r'(\d{2}\/\d{2}\/\d{4})'),
+ dayfirst=True,
+ )(self.doc)
+
+ loan.rate = CleanDecimal.French('//div/span[contains(text(), "Taux fixe")]/following-sibling::*[1]')(self.doc)
+ loan.last_payment_amount = CleanDecimal.SI(
+ '//div[@class="txt-detail " and not (@style)]//span[contains(text(), "Echéance du")]/following-sibling::span[1]'
+ )(self.doc)
+ loan.last_payment_date = Date(
+ Regexp(
+ CleanText('//div[@class="txt-detail " and not (@style)]//span[contains(text(), "Echéance du")]'),
+ r'(\d{2}\/\d{2}\/\d{4})'
+ ),
+ dayfirst=True,
+ )(self.doc)
loan.id = account.id
loan.currency = account.currency