Commit b60e3587 authored by Vincent Ardisson's avatar Vincent Ardisson Committed by Vincent A

[cmso] improve code style

parent 73ae8754
......@@ -17,6 +17,8 @@
# 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/>.
# flake8: compatible
from __future__ import unicode_literals
from weboob.capabilities.bank import CapBankTransfer, Account, AccountNotFound, RecipientNotFound
......@@ -41,23 +43,40 @@ class CmsoModule(Module, CapBankTransfer, CapBankWealth, CapContact, CapProfile)
VERSION = '2.1'
DESCRIPTION = 'Crédit Mutuel Sud-Ouest'
LICENSE = 'LGPLv3+'
CONFIG = BackendConfig(ValueBackendPassword('login', label='Identifiant', masked=False),
ValueBackendPassword('password', label='Mot de passe'),
ValueTransient('code'),
ValueTransient('request_information'),
Value('website', label='Type de compte', default='par',
choices={'par': 'Particuliers', 'pro': 'Professionnels'}))
CONFIG = BackendConfig(
ValueBackendPassword('login', label='Identifiant', masked=False),
ValueBackendPassword('password', label='Mot de passe'),
ValueTransient('code'),
ValueTransient('request_information'),
Value(
'website',
label='Type de compte',
default='par',
choices={
'par': 'Particuliers',
'pro': 'Professionnels',
}
)
)
BROWSER = CmsoParBrowser
AVAILABLE_BROWSERS = {'par': CmsoParBrowser, 'pro': CmsoProBrowser}
def create_default_browser(self):
self.BROWSER = self.AVAILABLE_BROWSERS[self.config['website'].get()]
return self.create_browser("%s.%s" % (self.NAME, 'com' if self.NAME == 'cmso' else 'fr'),
self.config,
self.config['login'].get(),
self.config['password'].get(),
weboob=self.weboob)
if self.NAME == 'cmso':
tld = 'com'
else:
tld = 'fr'
return self.create_browser(
"%s.%s" % (self.NAME, tld),
self.config,
self.config['login'].get(),
self.config['password'].get(),
weboob=self.weboob
)
def get_account(self, _id):
return find_object(self.browser.iter_accounts(), id=_id, error=AccountNotFound)
......
......@@ -17,6 +17,8 @@
# 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/>.
# flake8: compatible
from __future__ import unicode_literals
import time
......@@ -54,7 +56,8 @@ def retry(exc_check, tries=4):
def decorator(func):
@wraps(func)
def wrapper(browser, *args, **kwargs):
cb = lambda: func(browser, *args, **kwargs)
def cb():
return func(browser, *args, **kwargs)
for i in range(tries, 0, -1):
try:
......@@ -102,9 +105,12 @@ class CmsoParBrowser(TwoFactorBrowser):
RedirectInsurancePage
)
lifeinsurance = URL(r'https://domiweb.suravenir.fr', LifeinsurancePage)
market = URL(r'/domiapi/oauth/json/ssoDomifronttitre',
r'https://www.(?P<website>.*)/domifronttitre/front/sso/domiweb/01/(?P<action>.*)Portefeuille\?csrf=',
r'https://www.*/domiweb/prive/particulier', MarketPage)
market = URL(
r'/domiapi/oauth/json/ssoDomifronttitre',
r'https://www.(?P<website>.*)/domifronttitre/front/sso/domiweb/01/(?P<action>.*)Portefeuille\?csrf=',
r'https://www.*/domiweb/prive/particulier',
MarketPage
)
advisor = URL(r'/edrapi/v(?P<version>\w+)/oauth/(?P<page>\w+)', AdvisorPage)
transfer_info = URL(r'/domiapi/oauth/json/transfer/transferinfos', TransferInfoPage)
......@@ -112,7 +118,10 @@ class CmsoParBrowser(TwoFactorBrowser):
# recipients
ext_recipients_list = URL(r'/transfersfedesapi/api/beneficiaries', RecipientsListPage)
int_recipients_list = URL(r'/transfersfedesapi/api/accounts', RecipientsListPage)
available_int_recipients = URL(r'/transfersfedesapi/api/credited-accounts/(?P<ciphered_contract_number>.*)', AllowedRecipientsPage)
available_int_recipients = URL(
r'/transfersfedesapi/api/credited-accounts/(?P<ciphered_contract_number>.*)',
AllowedRecipientsPage
)
# transfers
init_transfer_page = URL(r'/transfersfedesapi/api/transfers/control', TransferPage)
......@@ -149,7 +158,7 @@ class CmsoParBrowser(TwoFactorBrowser):
if self.headers:
self.session.headers = self.headers
else:
self.set_profile(self.PROFILE) # reset headers but don't clear them
self.set_profile(self.PROFILE) # reset headers but don't clear them
self.session.cookies.clear()
self.accounts_list = []
......@@ -166,7 +175,7 @@ class CmsoParBrowser(TwoFactorBrowser):
data = {
'template': '',
'typeMedia': 'SMS', # can be SVI for interactive voice server
'valueMedia': contact_information['portable']['numeroCrypte']
'valueMedia': contact_information['portable']['numeroCrypte'],
}
self.location('/securityapi/otp/generate', json=data)
......@@ -192,7 +201,7 @@ class CmsoParBrowser(TwoFactorBrowser):
'accessInfos': {
'efs': self.arkea,
'si': self.arkea_si,
}
},
}
def get_login_data(self):
......@@ -355,7 +364,7 @@ class CmsoParBrowser(TwoFactorBrowser):
self.history.go(
json={
'index': account._index,
'filtreOperationsComptabilisees': "MOIS_MOINS_UN"
'filtreOperationsComptabilisees': "MOIS_MOINS_UN",
},
page="detailcompte"
)
......@@ -394,9 +403,9 @@ class CmsoParBrowser(TwoFactorBrowser):
if hasattr(c, '_deferred_date'):
c.bdate = c.rdate
c.date = c._deferred_date
c.type = Transaction.TYPE_DEFERRED_CARD # force deferred card type for comings inside cards
c.type = Transaction.TYPE_DEFERRED_CARD # force deferred card type for comings inside cards
c.vdate = None # vdate don't work for comings
c.vdate = None # vdate don't work for comings
comings.append(c)
return iter(comings)
......@@ -612,8 +621,7 @@ class iter_retry(object):
# recreated iterator, consume previous items
try:
nb = -1
for nb, sent in enumerate(self.items):
for sent in self.items:
new = next(self.it)
if hasattr(new, 'iter_fields'):
equal = dict(sent.iter_fields()) == dict(new.iter_fields())
......@@ -623,7 +631,7 @@ class iter_retry(object):
# safety is not guaranteed
raise BrowserUnavailable('Site replied inconsistently between retries, %r vs %r', sent, new)
except StopIteration:
raise BrowserUnavailable('Site replied fewer elements (%d) than last iteration (%d)', nb + 1, len(self.items))
raise BrowserUnavailable('Site replied fewer elements than last iteration')
except self.exc_check as exc:
self.delogged = True
if self.logger:
......
......@@ -17,6 +17,8 @@
# 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/>.
# flake8: compatible
from __future__ import unicode_literals
import re
......@@ -88,10 +90,11 @@ class AccountsPage(LoggedPage, JsonPage):
def check_response(self):
if "exception" in self.doc:
self.logger.warning("There are no checking accounts: exception '{}' with code {}".format(
self.doc['exception']['message'],
self.doc['exception']['code'])
)
self.logger.warning(
"There are no checking accounts: exception %r with code %s",
self.doc['exception']['message'],
self.doc['exception']['code']
)
def get_numbers(self):
keys = self.get_keys()
......@@ -114,7 +117,7 @@ class AccountsPage(LoggedPage, JsonPage):
selector = self.item_xpath.split('/')
for sub_element in selector:
if isinstance(self.el, dict) and self.el and sub_element == '*':
self.el = next(iter(self.el.values())) # replace self.el with its first value
self.el = next(iter(self.el.values())) # replace self.el with its first value
if sub_element == '*':
continue
self.el = self.el[sub_element]
......@@ -124,11 +127,12 @@ class AccountsPage(LoggedPage, JsonPage):
class item(ItemElement):
klass = Account
condition = lambda self: "LIVRET" not in Dict('accountType')(self.el)
def condition(self):
return "LIVRET" not in Dict('accountType')(self.el)
obj_id = Dict('numeroContratSouscrit')
obj_label = Upper(Dict('lib'))
obj_currency = Dict('deviseCompteCode')
obj_currency = Dict('deviseCompteCode')
obj_coming = CleanDecimal(Dict('AVenir', default=None), default=NotAvailable)
# Iban is available without last 5 numbers, or by sms
obj_iban = NotAvailable
......@@ -170,7 +174,9 @@ class AccountsPage(LoggedPage, JsonPage):
def obj_balance(self):
balance = CleanDecimal(Dict('soldeEuro', default="0"))(self)
return -abs(balance) if Field('type')(self) == Account.TYPE_LOAN else balance
if Field('type')(self) == Account.TYPE_LOAN:
balance = -abs(balance)
return balance
# It can have revolving credit on this page
def obj__total_amount(self):
......@@ -305,7 +311,7 @@ class AccountsPage(LoggedPage, JsonPage):
# between the request in iter_accounts and the requests
# listing recipients. Sorting the owner name is a way to
# have the same md5 hash in both of those cases.
to_hash = '%s %s' % (
to_hash = '%s %s' % (
Upper(Field('label'))(self),
''.join(sorted(Field('_owner_name')(self))),
)
......@@ -343,14 +349,14 @@ class AccountsPage(LoggedPage, JsonPage):
# Key not always available, when revolving credit not yet consummed
timestamp = Dict('dateFin', default=None)(self)
if timestamp:
return dt.date.fromtimestamp(timestamp/1000)
return dt.date.fromtimestamp(timestamp / 1000)
return NotAvailable
def obj_next_payment_date(self):
# Key not always available, when revolving credit not yet consummed
timestamp = Dict('dateProchaineEcheance', default=None)(self)
if timestamp:
return dt.date.fromtimestamp(timestamp/1000)
return dt.date.fromtimestamp(timestamp / 1000)
return NotAvailable
def obj_balance(self):
......@@ -366,16 +372,17 @@ class AccountsPage(LoggedPage, JsonPage):
class Transaction(FrenchTransaction):
PATTERNS = [(re.compile(r'^CARTE (?P<dd>\d{2})/(?P<mm>\d{2}) (?P<text>.*)'), FrenchTransaction.TYPE_CARD),
(re.compile(r'^(?P<text>(PRLV|PRELEVEMENTS).*)'), FrenchTransaction.TYPE_ORDER),
(re.compile(r'^(?P<text>RET DAB.*)'), FrenchTransaction.TYPE_WITHDRAWAL),
(re.compile(r'^(?P<text>ECH.*)'), FrenchTransaction.TYPE_LOAN_PAYMENT),
(re.compile(r'^(?P<text>VIR.*)'), FrenchTransaction.TYPE_TRANSFER),
(re.compile(r'^(?P<text>ANN.*)'), FrenchTransaction.TYPE_PAYBACK),
(re.compile(r'^(?P<text>(VRST|VERSEMENT).*)'), FrenchTransaction.TYPE_DEPOSIT),
(re.compile(r'^(?P<text>CHQ.*)'), FrenchTransaction.TYPE_CHECK),
(re.compile(r'^(?P<text>.*)'), FrenchTransaction.TYPE_BANK)
]
PATTERNS = [
(re.compile(r'^CARTE (?P<dd>\d{2})/(?P<mm>\d{2}) (?P<text>.*)'), FrenchTransaction.TYPE_CARD),
(re.compile(r'^(?P<text>(PRLV|PRELEVEMENTS).*)'), FrenchTransaction.TYPE_ORDER),
(re.compile(r'^(?P<text>RET DAB.*)'), FrenchTransaction.TYPE_WITHDRAWAL),
(re.compile(r'^(?P<text>ECH.*)'), FrenchTransaction.TYPE_LOAN_PAYMENT),
(re.compile(r'^(?P<text>VIR.*)'), FrenchTransaction.TYPE_TRANSFER),
(re.compile(r'^(?P<text>ANN.*)'), FrenchTransaction.TYPE_PAYBACK),
(re.compile(r'^(?P<text>(VRST|VERSEMENT).*)'), FrenchTransaction.TYPE_DEPOSIT),
(re.compile(r'^(?P<text>CHQ.*)'), FrenchTransaction.TYPE_CHECK),
(re.compile(r'^(?P<text>.*)'), FrenchTransaction.TYPE_BANK),
]
class HistoryPage(LoggedPage, JsonPage):
......@@ -444,7 +451,7 @@ class HistoryPage(LoggedPage, JsonPage):
deferred_date = Dict('dateDiffere', default=None)(x)
if deferred_date:
break
setattr(self.obj, '_deferred_date', self.FromTimestamp().filter(deferred_date))
self.obj._deferred_date = self.FromTimestamp().filter(deferred_date)
class RedirectInsurancePage(LoggedPage, JsonPage):
......@@ -485,7 +492,11 @@ class LifeinsurancePage(LoggedPage, HTMLPage):
@method
class fill_account(ItemElement):
def obj_valuation_diff_ratio(self):
valuation_diff_percent = CleanDecimal.French('//div[@class="perfContrat"]/span[@class="value"]', default=None)(self)
valuation_diff_percent = CleanDecimal.French(
'//div[@class="perfContrat"]/span[@class="value"]',
default=None
)(self)
if valuation_diff_percent:
return valuation_diff_percent / 100
return NotAvailable
......@@ -543,7 +554,8 @@ class LifeinsurancePage(LoggedPage, HTMLPage):
class MarketPage(LoggedPage, HTMLPage):
def find_account(self, acclabel, accowner):
accowner = sorted(accowner.lower().split()) # first name and last name may not be ordered the same way on market site...
# first name and last name may not be ordered the same way on market site...
accowner = sorted(accowner.lower().split())
def get_ids(ref, acclabel, accowner):
ids = None
......@@ -564,8 +576,10 @@ class MarketPage(LoggedPage, HTMLPage):
return False
ref = CleanText(self.doc.xpath('//a[contains(@href, "indiceCompte")]'))(self)
return get_ids('onclick', acclabel, accowner) if not ref else get_ids('href', acclabel, accowner)
if not ref:
return get_ids('onclick', acclabel, accowner)
else:
return get_ids('href', acclabel, accowner)
def get_account_id(self, acclabel, owner):
account = self.find_account(acclabel, owner)
......@@ -638,7 +652,8 @@ class MarketPage(LoggedPage, HTMLPage):
class item(ItemElement):
klass = Investment
condition = lambda self: not CleanText('//div[has-class("errorConteneur")]', default=None)(self.el)
def condition(self):
return not CleanText('//div[has-class("errorConteneur")]', default=None)(self.el)
obj_label = Upper(TableCell('label'))
obj_quantity = CleanDecimal.French(TableCell('quantity'), default=NotAvailable)
......@@ -681,11 +696,13 @@ class ProfilePage(LoggedPage, JsonPage):
klass = Profile
def obj_id(self):
return (Dict('identifiantExterne',default=None)(self)
or Dict('login')(self))
return (
Dict('identifiantExterne', default=None)(self)
or Dict('login')(self)
)
obj_name = Format('%s %s', Dict('firstName'), Dict('lastName'))
obj_email = Dict('email', default=NotAvailable) # can be unavailable on pro website for example
obj_email = Dict('email', default=NotAvailable) # can be unavailable on pro website for example
def get_token(self):
return Dict('loginEncrypted')(self.doc)
......@@ -17,6 +17,8 @@
# 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/>.
# flake8: compatible
from __future__ import unicode_literals
from hashlib import md5
......@@ -156,7 +158,8 @@ class TransferInfoPage(LoggedPage, JsonPage):
class item(ItemElement):
klass = Emitter
condition = lambda self: Dict('eligibiliteDebit', default=None)(self.el)
def condition(self):
return Dict('eligibiliteDebit', default=None)(self.el)
obj_id = Dict('numeroContratSouscrit')
obj_label = Upper(Dict('lib'))
......@@ -173,8 +176,10 @@ class TransferPage(LoggedPage, JsonPage):
if self.doc.get('exception') and not self.doc.get('debitAccountOwner'):
if Dict('exception/type')(self.doc) == 1:
# technical error
assert False, 'Error with code %s occured during init_transfer: %s' % \
(Dict('exception/code')(self.doc), Dict('exception/message')(self.doc))
raise AssertionError(
'Error with code %s occured during init_transfer: %s'
% (Dict('exception/code')(self.doc), Dict('exception/message')(self.doc))
)
elif Dict('exception/type')(self.doc) == 2:
# user error
raise TransferBankError(message=Dict('exception/message')(self.doc))
......
......@@ -17,6 +17,8 @@
# 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/>.
# flake8: compatible
from __future__ import unicode_literals
import datetime
......@@ -43,12 +45,24 @@ from ..par.pages import ProfilePage
class CmsoProBrowser(LoginBrowser):
login = URL(r'https://api.(?P<website>[\w.]+)/oauth-implicit/token', LoginPage)
subscription = URL(r'https://api.(?P<website>[\w.]+)/domiapi/oauth/json/accesAbonnement', SubscriptionPage)
accounts = URL(r'/domiweb/prive/professionnel/situationGlobaleProfessionnel/0-situationGlobaleProfessionnel.act', AccountsPage)
history = URL(r'/domiweb/prive/professionnel/situationGlobaleProfessionnel/1-situationGlobaleProfessionnel.act', HistoryPage)
password_creation = URL(r'/domiweb/prive/particulier/modificationMotDePasse/0-creationMotDePasse.act', PasswordCreationPage)
accounts = URL(
r'/domiweb/prive/professionnel/situationGlobaleProfessionnel/0-situationGlobaleProfessionnel.act',
AccountsPage
)
history = URL(
r'/domiweb/prive/professionnel/situationGlobaleProfessionnel/1-situationGlobaleProfessionnel.act',
HistoryPage
)
password_creation = URL(
r'/domiweb/prive/particulier/modificationMotDePasse/0-creationMotDePasse.act',
PasswordCreationPage
)
useless = URL(r'/domiweb/prive/particulier/modificationMotDePasse/0-expirationMotDePasse.act', UselessPage)
investment = URL(r'/domiweb/prive/particulier/portefeuilleSituation/0-situationPortefeuille.act', InvestmentPage)
invest_account = URL(r'/domiweb/prive/particulier/portefeuilleSituation/2-situationPortefeuille.act\?(?:csrf=[^&]*&)?indiceCompte=(?P<idx>\d+)&idRacine=(?P<idroot>\d+)', InvestmentAccountPage)
invest_account = URL(
r'/domiweb/prive/particulier/portefeuilleSituation/2-situationPortefeuille.act\?(?:csrf=[^&]*&)?indiceCompte=(?P<idx>\d+)&idRacine=(?P<idroot>\d+)',
InvestmentAccountPage
)
error = URL(r'https://pro.(?P<website>[\w.]+)/auth/errorauthn', ErrorPage)
profile = URL(r'https://api.(?P<website>[\w.]+)/domiapi/oauth/json/edr/infosPerson', ProfilePage)
ssoDomiweb = URL(r'https://api.(?P<website>[\w.]+)/domiapi/oauth/json/ssoDomiwebEmbedded', SSODomiPage)
......@@ -201,10 +215,14 @@ class CmsoProBrowser(LoginBrowser):
def _build_next_date_range(self, date_range):
date_format = '%d/%m/%Y'
last_day = datetime.datetime.strptime(date_range[10:], date_format)
first_day = last_day + datetime.timedelta(days=1)
last_day = first_day + relativedelta(months=1, days=-1)
return ''.join((datetime.datetime.strftime(first_day, date_format), datetime.datetime.strftime(last_day, date_format)))
first_str = datetime.datetime.strftime(first_day, date_format)
last_str = datetime.datetime.strftime(last_day, date_format)
return first_str + last_str
@need_login
def iter_history(self, account):
......
......@@ -17,6 +17,8 @@
# 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/>.
# flake8: compatible
from __future__ import unicode_literals
import re
......@@ -24,7 +26,9 @@ import re
from weboob.exceptions import BrowserIncorrectPassword
from weboob.browser.pages import HTMLPage, JsonPage, pagination, LoggedPage
from weboob.browser.elements import ListElement, ItemElement, TableElement, method
from weboob.browser.filters.standard import CleanText, CleanDecimal, DateGuesser, Env, Field, Filter, Regexp, Currency, Date
from weboob.browser.filters.standard import (
CleanText, CleanDecimal, DateGuesser, Env, Field, Filter, Regexp, Currency, Date,
)
from weboob.browser.filters.html import Link, Attr, TableCell
from weboob.capabilities.bank import Account
from weboob.capabilities.wealth import Investment
......@@ -68,11 +72,12 @@ class CMSOPage(HTMLPage):
class AccountsPage(CMSOPage):
TYPES = {'COMPTE CHEQUES': Account.TYPE_CHECKING,
'COMPTE TITRES': Account.TYPE_MARKET,
"ACTIV'EPARGNE": Account.TYPE_SAVINGS,
"TRESO'VIV": Account.TYPE_SAVINGS,
}
TYPES = {
'COMPTE CHEQUES': Account.TYPE_CHECKING,
'COMPTE TITRES': Account.TYPE_MARKET,
"ACTIV'EPARGNE": Account.TYPE_SAVINGS,
"TRESO'VIV": Account.TYPE_SAVINGS,
}
@method
class iter_accounts(ListElement):
......@@ -107,8 +112,7 @@ class AccountsPage(CMSOPage):
def on_load(self):
if self.doc.xpath('//p[contains(text(), "incident technique")]'):
raise BrowserIncorrectPassword("Vous n'avez aucun compte sur cet espace. " \
"Veuillez choisir un autre type de compte.")
raise BrowserIncorrectPassword("Vous n'avez aucun compte sur cet espace. Veuillez choisir un autre type de compte.")
class InvestmentPage(CMSOPage):
......@@ -123,8 +127,12 @@ class InvestmentPage(CMSOPage):
klass = Account
def obj_id(self):
area_id = Regexp(CleanText('(./preceding-sibling::tr[@class="LnMnTiers"][1])//span[@class="CelMnTiersT1"]'),
r'\((\d+)\)', default='')(self)
area_id = Regexp(
CleanText('(./preceding-sibling::tr[@class="LnMnTiers"][1])//span[@class="CelMnTiersT1"]'),
r'\((\d+)\)',
default=''
)(self)
acc_id = Regexp(CleanText('./td[1]'), r'(\d+)\s*(\d+)', r'\1\2')(self)
if area_id:
return '%s.%s' % (area_id, acc_id)
......@@ -177,33 +185,38 @@ class InvestmentAccountPage(CMSOPage):
def obj_code(self):
if Field('label')(self) == "LIQUIDITES":
return 'XX-liquidity'
code = CleanText(TableCell('code'))(self)
return code if is_isin_valid(code) else NotAvailable
if is_isin_valid(code):
return code
return NotAvailable
def obj_code_type(self):
return Investment.CODE_TYPE_ISIN if is_isin_valid(Field('code')(self)) else NotAvailable
if is_isin_valid(Field('code')(self)):
return Investment.CODE_TYPE_ISIN
return NotAvailable
class Transaction(FrenchTransaction):
PATTERNS = [(re.compile(r'^RET DAB (?P<dd>\d{2})/?(?P<mm>\d{2})(/?(?P<yy>\d{2}))? (?P<text>.*)'),
FrenchTransaction.TYPE_WITHDRAWAL),
(re.compile(r'CARTE (?P<dd>\d{2})/(?P<mm>\d{2}) (?P<text>.*)'),
FrenchTransaction.TYPE_CARD),
(re.compile(r'^(?P<category>VIR(EMEN)?T? (SEPA)?(RECU|FAVEUR)?)( /FRM)?(?P<text>.*)'),
FrenchTransaction.TYPE_TRANSFER),
(re.compile(r'^PRLV (?P<text>.*)( \d+)?$'), FrenchTransaction.TYPE_ORDER),
(re.compile(r'^(CHQ|CHEQUE) .*$'), FrenchTransaction.TYPE_CHECK),
(re.compile(r'^(AGIOS /|FRAIS) (?P<text>.*)'), FrenchTransaction.TYPE_BANK),
(re.compile(r'^(CONVENTION \d+ |F )?COTIS(ATION)? (?P<text>.*)'),
FrenchTransaction.TYPE_BANK),
(re.compile(r'^REMISE (?P<text>.*)'), FrenchTransaction.TYPE_DEPOSIT),
(re.compile(r'^(?P<text>.*)( \d+)? QUITTANCE .*'),
FrenchTransaction.TYPE_ORDER),
(re.compile(r'^.* LE (?P<dd>\d{2})/(?P<mm>\d{2})/(?P<yy>\d{2})$'),
FrenchTransaction.TYPE_UNKNOWN),
(re.compile(r'^.* PAIEMENT (?P<dd>\d{2})/(?P<mm>\d{2}) (?P<text>.*)'),
FrenchTransaction.TYPE_UNKNOWN),
]
PATTERNS = [
(
re.compile(r'^RET DAB (?P<dd>\d{2})/?(?P<mm>\d{2})(/?(?P<yy>\d{2}))? (?P<text>.*)'),
FrenchTransaction.TYPE_WITHDRAWAL,
),
(re.compile(r'CARTE (?P<dd>\d{2})/(?P<mm>\d{2}) (?P<text>.*)'), FrenchTransaction.TYPE_CARD),
(
re.compile(r'^(?P<category>VIR(EMEN)?T? (SEPA)?(RECU|FAVEUR)?)( /FRM)?(?P<text>.*)'),
FrenchTransaction.TYPE_TRANSFER,
),
(re.compile(r'^PRLV (?P<text>.*)( \d+)?$'), FrenchTransaction.TYPE_ORDER),
(re.compile(r'^(CHQ|CHEQUE) .*$'), FrenchTransaction.TYPE_CHECK),
(re.compile(r'^(AGIOS /|FRAIS) (?P<text>.*)'), FrenchTransaction.TYPE_BANK),
(re.compile(r'^(CONVENTION \d+ |F )?COTIS(ATION)? (?P<text>.*)'), FrenchTransaction.TYPE_BANK),
(re.compile(r'^REMISE (?P<text>.*)'), FrenchTransaction.TYPE_DEPOSIT),
(re.compile(r'^(?P<text>.*)( \d+)? QUITTANCE .*'), FrenchTransaction.TYPE_ORDER),
(re.compile(r'^.* LE (?P<dd>\d{2})/(?P<mm>\d{2})/(?P<yy>\d{2})$'), FrenchTransaction.TYPE_UNKNOWN),
(re.compile(r'^.* PAIEMENT (?P<dd>\d{2})/(?P<mm>\d{2}) (?P<text>.*)'), FrenchTransaction.TYPE_UNKNOWN),
]
class CmsoTransactionElement(ItemElement):
......@@ -234,9 +247,11 @@ class HistoryPage(CMSOPage):
return self.page.browser.build_request(url_next_page)
class item(CmsoTransactionElement):
def date(selector):
return DateGuesser(Regexp(CleanText(selector), r'\w+ (\d{2}/\d{2})'), Env('date_guesser')) | Transaction.Date(selector)
return (
DateGuesser(Regexp(CleanText(selector), r'\w+ (\d{2}/\d{2})'), Env('date_guesser'))
| Transaction.Date(selector)
)
# CAUTION: this website write a 'Date valeur' inside a div with a class == 'c-ope'
# and a 'Date opération' inside a div with a class == 'c-val'
......@@ -260,4 +275,3 @@ class SSODomiPage(JsonPage, UpdateTokenMixin):
class AuthCheckUser(HTMLPage):
pass
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