diff --git a/modules/cragr/api/transfer_pages.py b/modules/cragr/api/transfer_pages.py new file mode 100644 index 0000000000000000000000000000000000000000..8b2f9f9f6bbcd634b40d18c74327d7bab57f5e9f --- /dev/null +++ b/modules/cragr/api/transfer_pages.py @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2019 Sylvie Ye +# +# 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 Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this weboob module. If not, see . + +from __future__ import unicode_literals + +from datetime import date + +from weboob.browser.pages import LoggedPage, JsonPage, RawPage +from weboob.browser.elements import method, ItemElement, DictElement +from weboob.capabilities.bank import ( + Account, Recipient, Transfer, TransferBankError, +) +from weboob.browser.filters.standard import ( + CleanDecimal, Env, Date, CleanText, +) +from weboob.browser.filters.json import Dict + + +class RecipientsPage(LoggedPage, JsonPage): + def is_sender_account(self, account_id): + for acc in self.doc: + if acc.get('senderOfTransfert') and account_id == acc.get('accountNumber'): + return True + + @method + class iter_debit_accounts(DictElement): + class item(ItemElement): + def condition(self): + return Dict('accountNumber', default=None)(self) + + klass = Account + + obj_id = obj_number = Dict('accountNumber') + obj_label = Dict('accountNatureLongLabel') + obj_iban = Dict('ibanCode') + obj_currency = Dict('currencyCode') + + def obj_balance(self): + balance_value = CleanDecimal(Dict('balanceValue'))(self) + if CleanText(Dict('balanceSign'))(self) == '-': + return -balance_value + return balance_value + + @method + class iter_internal_recipient(DictElement): + class item(ItemElement): + def condition(self): + return Dict('recipientOfTransfert', default=None)(self) and \ + Env('account_id')(self) != Dict('accountNumber', default=None)(self) + + klass = Recipient + + obj_id = Dict('accountNumber') + obj_label = Dict('accountNatureLongLabel') + obj_iban = Dict('ibanCode') + obj_category = 'Interne' + obj_enabled_at = date.today() + + @method + class iter_external_recipient(DictElement): + def store(self, obj): + return obj + + class item(ItemElement): + def condition(self): + return Dict('recipientId', default=None)(self) + + klass = Recipient + + obj_id = obj_iban = Dict('ibanCode') + obj_label = Dict('recipientName') + obj_category = 'Externe' + obj_enabled_at = date.today() + + +class TransferTokenPage(LoggedPage, RawPage): + def get_token(self): + return self.doc + + +class TransferPage(LoggedPage, JsonPage): + def check_transfer(self): + error_msg = Dict('messageErreur')(self.doc) + if error_msg: + raise TransferBankError(message=error_msg) + return Dict('page')(self.doc) == '/recap' + + def handle_response(self, transfer): + t = Transfer() + t._space = transfer._space + t._operation = transfer._operation + t._token = transfer._token + t._connection_id = transfer._connection_id + + t.label = Dict('transferComplementaryInformations1')(self.doc) + t.exec_date = Date(Dict('dateVirement'), dayfirst=True)(self.doc) + t.amount = CleanDecimal(Dict('amount'))(self.doc) + t.currency = Dict('currencyCode')(self.doc) + + t.account_id = Dict('currentDebitAccountNumber')(self.doc) + t.account_iban = Dict('currentDebitIbanCode')(self.doc) + t.account_label = Dict('typeCompte')(self.doc) + + t.recipient_id = t.recipient_iban = Dict('currentCreditIbanCode')(self.doc) + t.recipient_label = Dict('currentCreditAccountName')(self.doc) + + return t + + def check_transfer_exec(self): + error_msg = Dict('messageErreur')(self.doc) + if error_msg: + raise TransferBankError(message=error_msg) + return Dict('page')(self.doc) diff --git a/modules/humanis/__init__.py b/modules/humanis/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..daddbd449f06b1b4fbd9435f2029002c089fb55c --- /dev/null +++ b/modules/humanis/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2017 Jean Walrave +# +# 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 . + +from __future__ import unicode_literals + + +from .module import HumanisModule + + +__all__ = ['HumanisModule'] diff --git a/modules/humanis/browser.py b/modules/humanis/browser.py new file mode 100644 index 0000000000000000000000000000000000000000..4f52f0f4753a80f379ae110c1fa7abf8efd11680 --- /dev/null +++ b/modules/humanis/browser.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2016 Jean Walrave +# +# 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 . + + +from weboob.browser import AbstractBrowser, URL + +from .pages import LoginPage + +class HumanisBrowser(AbstractBrowser): + PARENT = 'cmes' + + login = URL('humanis/fr/identification/login.cgi', LoginPage) + + def __init__(self, login, password, baseurl, subsite, *args, **kwargs): + self.weboob = kwargs['weboob'] + super(HumanisBrowser, self).__init__(login, password, baseurl, subsite, *args, **kwargs) diff --git a/modules/humanis/module.py b/modules/humanis/module.py new file mode 100644 index 0000000000000000000000000000000000000000..85e1e694729ac52a6286cff9c50ae44441f7b076 --- /dev/null +++ b/modules/humanis/module.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2016 Jean Walrave +# +# 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 . + + +from weboob.tools.backend import Module, BackendConfig +from weboob.tools.value import ValueBackendPassword +from weboob.capabilities.bank import CapBankPockets, AccountNotFound +from weboob.capabilities.base import find_object + +from .browser import HumanisBrowser + + +__all__ = ['HumanisModule'] + + +class HumanisModule(Module, CapBankPockets): + NAME = 'humanis' + DESCRIPTION = u'Humanis Épargne Salariale' + MAINTAINER = u'Jean Walrave' + EMAIL = 'jwalrave@budget-insight.com' + LICENSE = 'LGPLv3+' + VERSION = '1.5' + CONFIG = BackendConfig(ValueBackendPassword('login', label=u'Code d\'accès', masked=False), + ValueBackendPassword('password', label='Mot de passe')) + + BROWSER = HumanisBrowser + + def create_default_browser(self): + return self.create_browser( + self.config['login'].get(), + self.config['password'].get(), + 'https://www.gestion-epargne-salariale.fr', + 'humanis/', + weboob=self.weboob + ) + + def get_account(self, _id): + return find_object(self.browser.iter_accounts(), id=_id, error=AccountNotFound) + + def iter_accounts(self): + return self.browser.iter_accounts() + + def iter_history(self, account): + return self.browser.iter_history(account) + + def iter_investment(self, account): + return self.browser.iter_investment(account) + + def iter_pocket(self, account): + return self.browser.iter_pocket(account) diff --git a/modules/humanis/pages.py b/modules/humanis/pages.py new file mode 100644 index 0000000000000000000000000000000000000000..a7d153e27c1eac98dbcc63bc0ae7fd61743f0e13 --- /dev/null +++ b/modules/humanis/pages.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2016 Jean Walrave +# +# 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 . + + +from weboob.browser.pages import AbstractPage + + +class LoginPage(AbstractPage): + PARENT = 'cmes' + PARENT_URL = 'login' + BROWSER_ATTR = 'package.browser.CmesBrowser' diff --git a/modules/humanis/test.py b/modules/humanis/test.py new file mode 100644 index 0000000000000000000000000000000000000000..67094555bd7308d6633762c31467f26810318add --- /dev/null +++ b/modules/humanis/test.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2017 Jean Walrave +# +# 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 . + +from __future__ import unicode_literals + + +from weboob.tools.test import BackendTest + + +class HumanisTest(BackendTest): + MODULE = 'humanis' diff --git a/modules/themisbanque/__init__.py b/modules/themisbanque/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..a07a1c71f6528d3fd12a8ca15a021a731359be44 --- /dev/null +++ b/modules/themisbanque/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2015 Romain Bignon +# +# 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 . + + +from .module import ThemisModule + + +__all__ = ['ThemisModule'] diff --git a/modules/themisbanque/browser.py b/modules/themisbanque/browser.py new file mode 100644 index 0000000000000000000000000000000000000000..2821536689815d4fa3f3a8ac0e979075827d48f7 --- /dev/null +++ b/modules/themisbanque/browser.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2015 Romain Bignon +# +# 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 . + + +from weboob.browser import LoginBrowser, URL, need_login +from weboob.tools.compat import urljoin + +from .pages import LoginPage, LoginConfirmPage, AccountsPage, RibPage, RibPDFPage, HistoryPage + + +class ThemisBrowser(LoginBrowser): + BASEURL = 'https://esab.themisbanque.eu/' + + home = URL('/es@b/fr/esab.jsp') + login = URL('/es@b/fr/codeident.jsp', LoginPage) + login_confirm = URL('/es@b/servlet/internet0.ressourceWeb.servlet.Login', LoginConfirmPage) + accounts = URL(r'/es@b/servlet/internet0.ressourceWeb.servlet.PremierePageServlet\?pageToTreatError=fr/Infos.jsp&dummyDate=', + r'/es@b/servlet/internet0.ressourceWeb.servlet.PremierePageServlet\?cryptpara=.*', + r'/es@b/servlet/internet0.ressourceWeb.servlet.EsabServlet.*', + AccountsPage) + history = URL('/es@b/servlet/internet0.ressourceWeb.servlet.ListeDesMouvementsServlet.*', HistoryPage) + rib = URL(r'/es@b/fr/rib.jsp\?cryptpara=.*', RibPage) + rib_pdf = URL(r'/es@b/servlet/internet0.ressourceWeb.servlet.RibPdfDownloadServlet', RibPDFPage) + + def do_login(self): + self.home.go() + self.login.go() + self.page.login(self.username, self.password) + + @need_login + def iter_accounts(self): + self.accounts.stay_or_go() + # sometimes when the user has messages, accounts's page will redirect + # to the message page and the user will have to click "ok" to access his accounts + # this will happen as long as the messages aren't deleted. + # In this case, accounts may be reached through a different link (in the "ok" button) + acc_link = self.page.get_acc_link() + if acc_link: + self.location(urljoin(self.BASEURL, acc_link)) + return self.page.iter_accounts() + + @need_login + def get_history(self, account): + self.location(account._link) + return self.page.get_operations() + + @need_login + def get_profile(self): + accounts = list(self.iter_accounts()) + self.location(accounts[0]._url) + return self.page.get_profile() diff --git a/modules/themisbanque/module.py b/modules/themisbanque/module.py new file mode 100644 index 0000000000000000000000000000000000000000..389070fd22ed1106a8ec950477c0149aacfdfd02 --- /dev/null +++ b/modules/themisbanque/module.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2015 Romain Bignon +# +# 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 . + + +from weboob.tools.backend import Module, BackendConfig +from weboob.capabilities.bank import CapBank, AccountNotFound +from weboob.capabilities.base import find_object +from weboob.capabilities.profile import CapProfile +from weboob.tools.value import ValueBackendPassword +from .browser import ThemisBrowser + + +__all__ = ['ThemisModule'] + + +class ThemisModule(Module, CapBank, CapProfile): + NAME = 'themisbanque' + DESCRIPTION = u'Themis' + MAINTAINER = u'Romain Bignon' + EMAIL = 'romain@weboob.org' + LICENSE = 'LGPLv3+' + VERSION = '1.5' + CONFIG = BackendConfig(ValueBackendPassword('login', label=u"Numéro d'abonné", masked=False), + ValueBackendPassword('password', label='Code secret'), + ) + + BROWSER = ThemisBrowser + + def create_default_browser(self): + return self.create_browser(self.config['login'].get(), + self.config['password'].get()) + + def get_account(self, _id): + return find_object(self.browser.iter_accounts(), id=_id, error=AccountNotFound) + + def iter_accounts(self): + return self.browser.iter_accounts() + + def iter_coming(self, account): + raise NotImplementedError() + + def iter_history(self, account): + return self.browser.get_history(account) + + def iter_investment(self, account): + raise NotImplementedError() + + def get_profile(self): + return self.browser.get_profile() diff --git a/modules/themisbanque/pages.py b/modules/themisbanque/pages.py new file mode 100644 index 0000000000000000000000000000000000000000..e2b11278c929137b91de8cbf6eb7221264c8cb41 --- /dev/null +++ b/modules/themisbanque/pages.py @@ -0,0 +1,245 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2015 Romain Bignon +# +# 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 . + +from __future__ import unicode_literals + +import re + +from weboob.exceptions import BrowserIncorrectPassword +from weboob.browser.pages import LoggedPage, HTMLPage, pagination, PDFPage +from weboob.browser.elements import method, ItemElement, TableElement +from weboob.capabilities.bank import Account +from weboob.capabilities.base import NotAvailable +from weboob.capabilities.profile import Profile +from weboob.browser.filters.standard import CleanText, CleanDecimal, Async, Regexp, Join, Field +from weboob.browser.filters.html import Attr, Link, TableCell, ColumnNotFound +from weboob.tools.capabilities.bank.transactions import FrenchTransaction +from weboob.tools.capabilities.bank.iban import is_iban_valid +from weboob.tools.compat import basestring +from weboob.tools.pdf import extract_text + + +class MyCleanText(CleanText): + @classmethod + def clean(cls, txt, children=True, newlines=True, normalize='NFC'): + if not isinstance(txt, basestring): + txt = u'\n'.join([t.strip() for t in txt.itertext()]) + + return txt + + +class LoginPage(HTMLPage): + def login(self, username, password): + form = self.get_form() + form['identifiant'] = username + form['motpasse'] = password + form.submit() + + +class LoginConfirmPage(HTMLPage): + def on_load(self): + error = CleanText('//td[has-class("ColonneLibelle")]')(self.doc) + if len(error) > 0: + raise BrowserIncorrectPassword(error) + + +class AccountsPage(LoggedPage, HTMLPage): + def get_acc_link(self): + msg = CleanText('//body[@class="message"]')(self.doc) + if msg: + acc_link = Link('//div[@class="Boutons"]/a', 'href')(self.doc) + return acc_link + + @method + class iter_accounts(TableElement): + item_xpath = '//table[has-class("TableBicolore")]//tr[@id and count(td) > 4]' + head_xpath = '//table[has-class("TableBicolore")]//tr/td[@id]/@id' + + col_id = 'idCompteLibelle' + col_label = 'idCompteIntitule' + col_balance = 'idCompteSolde' + col_currency = 'idCompteSoldeUM' + col_rib = 'idCompteRIB' + col_type = 'idCompteNature' + + class item(ItemElement): + klass = Account + + def condition(self): + return CleanDecimal(TableCell('balance'), replace_dots=True, default=NotAvailable)(self) is not NotAvailable + + TYPE = { + 'COMPTE COURANT': Account.TYPE_CHECKING, + 'COMPTE TRANSACTION': Account.TYPE_CHECKING, + 'COMPTE ORDINAIRE': Account.TYPE_CHECKING, + } + TYPE_BY_LABELS = { + 'CAV': Account.TYPE_CHECKING, + } + + obj_id = CleanText(TableCell('id')) + obj_label = CleanText(TableCell('label')) + obj_currency = FrenchTransaction.Currency(TableCell('currency')) + obj_balance = CleanDecimal(TableCell('balance'), replace_dots=True) + + def obj__link(self): + return Attr(TableCell('id')(self)[0].xpath('./a'), 'href')(self) + + def obj__url(self): + return Link(TableCell('rib')(self)[0].xpath('./a[img[starts-with(@alt, "RIB")]]'), default=None)(self) + + def load_iban(self): + link = Link(TableCell('rib')(self)[0].xpath('./a[img[starts-with(@alt, "RIB")]]'), default=None)(self) + return self.page.browser.async_open(link) + + def obj_type(self): + try: + el_to_check = CleanText(TableCell('type'))(self) + type_dict = self.TYPE + except ColumnNotFound: + el_to_check = Field('label')(self) + type_dict = self.TYPE_BY_LABELS + + for k, v in type_dict.items(): + if el_to_check.startswith(k): + return v + return Account.TYPE_UNKNOWN + + def obj_iban(self): + rib_page = Async('iban').loaded_page(self) + if 'RibPdf' in rib_page.url: + return rib_page.get_iban() + return Join('', Regexp(CleanText('//td[has-class("ColonneCode")][contains(text(), "IBAN")]'), r'\b((?!IBAN)[A-Z0-9]+)\b', nth='*'))(rib_page.doc) or NotAvailable + + +class RibPage(LoggedPage, HTMLPage): + def get_profile(self): + profile = Profile() + + # profile is inside a separated with a simple
without or
+ profile_txt = MyCleanText('//div[@class="TableauAffichage"]/table/tr[3]/td[1]')(self.doc).split('\n') + i_name = 0 + profile.name = u'' + # name can be on one, two, (more ?) lines, so we stop when line start by a number, we suppose it's the address number + while not re.search('^\d', profile_txt[i_name]): + profile.name += ' ' + profile_txt[i_name] + i_name += 1 + + profile.name = profile.name.strip() + profile.address = u'' + # address is not always on two lines, so we consider every lines from here to before last are address, (last one is country) + for i in range(i_name, len(profile_txt)-1): + profile.address += ' ' + profile_txt[i] + + profile.address = profile.address.strip() + profile.country = profile_txt[-1] + + profile.name = profile.name.replace('MONSIEUR ', '').replace('MADAME ', '') + + return profile + + +class RibPDFPage(LoggedPage, PDFPage): + def get_iban(self): + text = extract_text(self.doc) + iban = re.search(r'IBAN([A-Z]{2}\d+)', text).group(1) + assert is_iban_valid(iban), 'did not parse IBAN properly' + return iban + + +class Transaction(FrenchTransaction): + PATTERNS = [(re.compile(r'^VIR(EMENT)?( SEPA)? (?P.*)'), FrenchTransaction.TYPE_TRANSFER), + (re.compile(r'^PRLV (?P.*)'), FrenchTransaction.TYPE_ORDER), + (re.compile(r'^(?P.*) CARTE \d+ PAIEMENT CB\s+(?P
\d{2})(?P\d{2}) ?(.*)$'), + FrenchTransaction.TYPE_CARD), + (re.compile(r'^RETRAIT DAB (?P
\d{2})(?P\d{2}) (?P.*) CARTE [\*\d]+'), + FrenchTransaction.TYPE_WITHDRAWAL), + (re.compile(r'^CHEQUE( (?P.*))?$'), FrenchTransaction.TYPE_CHECK), + (re.compile(r'^(F )?COTIS\.? (?P.*)'), FrenchTransaction.TYPE_BANK), + (re.compile(r'^(REMISE|REM.CHQ) (?P.*)'), FrenchTransaction.TYPE_DEPOSIT), + (re.compile(r'^(?P.*) CARTE BLEUE'), FrenchTransaction.TYPE_CARD), + (re.compile(r'^PRVL SEPA (?P.*)'), FrenchTransaction.TYPE_ORDER), + (re.compile(r'^(?P(INT. DEBITEURS).*)'), FrenchTransaction.TYPE_BANK), + (re.compile(r'^(?P.*(VIR EMIS).*)'), FrenchTransaction.TYPE_TRANSFER), + (re.compile(r'^(?P.*(\bMOUVEMENT\b).*)'), FrenchTransaction.TYPE_TRANSFER), + (re.compile(r'^(?P.*(ARRETE TRIM.).*)'), FrenchTransaction.TYPE_BANK), + (re.compile(r'^(?P.*(TENUE DE DOSSIE).*)'), FrenchTransaction.TYPE_BANK), + (re.compile(r'^(?P.*(RELEVE LCR ECH).*)'), FrenchTransaction.TYPE_ORDER), + (re.compile(r'^(?P.*(\+ FORT DECOUVERT).*)'), FrenchTransaction.TYPE_BANK), + (re.compile(r'^(?P.*(EXTRANET @THEMI).*)'), FrenchTransaction.TYPE_BANK), + (re.compile(r'^(?P.*(REL CPT DEBITEU).*)'), FrenchTransaction.TYPE_ORDER), + (re.compile(r"^(?P.*(\bAFFRANCHISSEMENT\b).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(REMISE VIREMENTS MAGNE).*)"), FrenchTransaction.TYPE_TRANSFER), + (re.compile(r"^(?P.*(\bEFFET\b).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(\bMANIP\.\b).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(INTERETS SUR REMISE PTF).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(REMISE ESCOMPTE PTF).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(RETENUE DE GARANTIE).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(RESTITUTION RETENUE GARANTIE).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(\bAMENDES\b).*)"), FrenchTransaction.TYPE_TRANSFER), + (re.compile(r"^(?P.*(\bOA\b).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^.* COTIS ANN (?P.*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(FORFAIT CENT\.RE).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(ENVOI CB).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(RET\.SDD).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(RETOUR PVL ACD EXPERTISE).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(Annulation PAR REJ\/CHQ).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(REJET CHEQUE).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(CHQ PAYE INFRAC).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P^(CHQ IRREGULIER).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(ERREUR REMISE C).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P^(\bREMCHQ\b).*)"), FrenchTransaction.TYPE_DEPOSIT), + (re.compile(r"^(?P^(RETOUR PVL).*)"), FrenchTransaction.TYPE_TRANSFER), + (re.compile(r"^(?P.*(\bTRANSFERT\b).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(\bCONFIRMATION\b).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(CAUTION AVEC GAGE).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(\bRAPATRIEMENT\b).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r"^(?P.*(CHANGE REF).*)"), FrenchTransaction.TYPE_BANK), + (re.compile(r'^CARTE DU'), FrenchTransaction.TYPE_CARD), + (re.compile(r'^(VIR (SEPA)?|Vir|VIR.)(?P.*)'), FrenchTransaction.TYPE_TRANSFER), + (re.compile(r'^VIREMENT DE (?P.*)'), FrenchTransaction.TYPE_TRANSFER), + (re.compile(r'^(CHQ|CHEQUE) (?P.*)'), FrenchTransaction.TYPE_CHECK), + (re.compile(r'^(PRLV SEPA|PRELEVEMENT) (?P.*)'), FrenchTransaction.TYPE_ORDER), + ] + + +class HistoryPage(LoggedPage, HTMLPage): + @pagination + @method + class get_operations(Transaction.TransactionsElement): + def next_page(self): + for script in self.page.doc.xpath('//script'): + m = re.search(r"getCodePagination\('(\d+)','(\d+)','([^']+)'.*", script.text or '', re.MULTILINE) + if m: + cur_page = int(m.group(1)) + nb_pages = int(m.group(2)) + baseurl = m.group(3) + + if cur_page < nb_pages: + return baseurl + '&numeroPage=%s&nbrPage=%s' % (cur_page + 1, nb_pages) + + head_xpath = '//div[has-class("TableauBicolore")]/table/tr[not(@id)]/td' + item_xpath = '//div[has-class("TableauBicolore")]/table/tr[@id and count(td) > 3]' + + col_date = ['Date comptable', "Date d'opération"] + col_vdate = ['Date de valeur'] + col_raw = ["Libellé de l'opération"] + + class item(Transaction.TransactionElement): + pass diff --git a/modules/themisbanque/test.py b/modules/themisbanque/test.py new file mode 100644 index 0000000000000000000000000000000000000000..035181218a5e9497c36021c6ffd7b2c6b5797348 --- /dev/null +++ b/modules/themisbanque/test.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2015 Romain Bignon +# +# 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 . + + +from weboob.tools.test import BackendTest + + +class ThemisBanqueTest(BackendTest): + MODULE = 'themisbanque' + + def test_themisbanque(self): + raise NotImplementedError()