From 6fdd8b3718f209bd95c96bb56f695fe54999466c Mon Sep 17 00:00:00 2001 From: Romain Bignon Date: Sun, 24 Feb 2019 21:33:06 +0100 Subject: [PATCH] Update of modules --- modules/sogecartenet/__init__.py | 23 ++++++ modules/sogecartenet/browser.py | 59 ++++++++++++++ modules/sogecartenet/module.py | 55 +++++++++++++ modules/sogecartenet/pages.py | 135 +++++++++++++++++++++++++++++++ 4 files changed, 272 insertions(+) create mode 100644 modules/sogecartenet/__init__.py create mode 100644 modules/sogecartenet/browser.py create mode 100644 modules/sogecartenet/module.py create mode 100644 modules/sogecartenet/pages.py diff --git a/modules/sogecartenet/__init__.py b/modules/sogecartenet/__init__.py new file mode 100644 index 000000000..3560aad60 --- /dev/null +++ b/modules/sogecartenet/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2015 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 . + + +from .module import SogecartenetModule + +__all__ = ['SogecartenetModule'] diff --git a/modules/sogecartenet/browser.py b/modules/sogecartenet/browser.py new file mode 100644 index 000000000..064058090 --- /dev/null +++ b/modules/sogecartenet/browser.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2015 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 . + + +from weboob.browser import LoginBrowser, URL, need_login + +from .pages import LoginPage, AccountsPage, TransactionsPage, PassModificationPage + + +class SogecartesBrowser(LoginBrowser): + BASEURL = 'https://www.sogecartenet.fr/' + + login = URL('/internationalisation/identification', LoginPage) + pass_modification = URL('/internationalisation/./modificationMotPasse.*', PassModificationPage) + accounts = URL('/internationalisation/gestionParcCartes', AccountsPage) + transactions = URL('/internationalisation/csv/operationsParCarte.*', TransactionsPage) + + def load_state(self, state): + pass + + def do_login(self): + assert isinstance(self.username, basestring) + assert isinstance(self.password, basestring) + data = {"USER": self.username, + "PWD": self.password[:10], + "ACCES": "PE", + "LANGUE": "en", + "QUEFAIRE": "LOGIN", + } + self.login.go(data=data) + + @need_login + def iter_accounts(self): + self.accounts.go() + return self.page.iter_accounts() + + @need_login + def get_history(self, account): + if not account._url: + return ([]) + self.location(account._url) + assert self.transactions.is_here() + return self.page.get_history() diff --git a/modules/sogecartenet/module.py b/modules/sogecartenet/module.py new file mode 100644 index 000000000..bb9d9f7a3 --- /dev/null +++ b/modules/sogecartenet/module.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2015 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 . + + +from weboob.tools.backend import Module, BackendConfig +from weboob.capabilities.bank import CapBank, AccountNotFound +from weboob.capabilities.base import find_object +from weboob.tools.value import ValueBackendPassword + +from .browser import SogecartesBrowser + + +__all__ = ['SogecartenetModule'] + + +class SogecartenetModule(Module, CapBank): + NAME = 'sogecartenet' + DESCRIPTION = u'Sogecarte Net' + MAINTAINER = u'Vincent Paredes' + EMAIL = 'vparedes@budget-insight.fr' + LICENSE = 'LGPLv3+' + VERSION = '1.5' + CONFIG = BackendConfig(ValueBackendPassword('login', label='Identifiant', masked=False), + ValueBackendPassword('password', label='Mot de passe')) + + BROWSER = SogecartesBrowser + + 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_history(self, account): + return self.browser.get_history(account) diff --git a/modules/sogecartenet/pages.py b/modules/sogecartenet/pages.py new file mode 100644 index 000000000..04f1bcd6d --- /dev/null +++ b/modules/sogecartenet/pages.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2015 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 . + +import requests + +from weboob.browser.pages import HTMLPage, CsvPage, pagination +from weboob.exceptions import BrowserIncorrectPassword, BrowserPasswordExpired, NoAccountsException +from weboob.browser.elements import DictElement, ItemElement, method, TableElement +from weboob.browser.filters.standard import CleanText, CleanDecimal, Date, Env +from weboob.browser.filters.html import TableCell +from weboob.browser.filters.json import Dict +from weboob.capabilities.bank import Account +from weboob.tools.capabilities.bank.transactions import FrenchTransaction + +__all__ = ['LoginPage', 'AccountsPage', 'TransactionsPage'] + + +class PassModificationPage(HTMLPage): + def on_load(self): + raise BrowserPasswordExpired('New pass needed') + +class LoginPage(HTMLPage): + pass + +class SogeLoggedPage(object): + @property + def logged(self): + if hasattr(self.doc, 'xpath'): + return not self.doc.xpath('//input[@value="LOGIN"][@name="QUEFAIRE"]') + return True + + def on_load(self): + if hasattr(self.doc, 'xpath') and self.doc.xpath('//input[@value="LOGIN"][@name="QUEFAIRE"]'): + raise BrowserIncorrectPassword() + +class AccountsPage(SogeLoggedPage, HTMLPage): + @pagination + @method + class iter_accounts(TableElement): + item_xpath = '//table[@bgcolor="#92ADC2"]//tr' + head_xpath = '//table[@bgcolor="#92ADC2"]/tr[1]/td[text()]' + + col_id = 'card iconetriwbeb(2);' + col_label = 'name iconetriwbeb(1);' + + def parse(self, el): + msg = CleanText('//font[@color="#FF0000"]')(self) + if msg and 'NO INFORMATION AVAILABLE.' in msg: + raise NoAccountsException() + + def next_page(self): + array_page = self.page.doc.xpath('//table[3]')[0] + if array_page.xpath('.//a[@href="javascript:fctSuivant();"]'): + curr_page = CleanDecimal().filter(array_page.xpath('.//td')[3].text) + data = {'PAGE': curr_page, 'QUEFAIRE':'NEXT', 'TRI':'ACC', 'TYPEDETAIL':'C'} + return requests.Request("POST", self.page.url, data=data) + return + + class item(ItemElement): + klass = Account + + obj_id = CleanText(TableCell('id'), replace=[(' ', ''), ('X','')]) + obj_label = CleanText(TableCell('label')) + obj_type = Account.TYPE_CARD + obj_currency = u'EUR' + + @property + def obj__url(self): + a = self.el.xpath('.//a') + if a and len(a) > 1: + #handling relative path + return '%s/%s' % ('/'.join(self.page.url.split('/')[:-1]), a[-1].attrib['href'][2:]) + return None + + def condition(self): + return self.el.xpath('./td[@bgcolor="#FFFFFF"]') + +class TransactionsPage(SogeLoggedPage, CsvPage): + ENCODING = 'iso_8859_1' + HEADER = 1 + FMTPARAMS = {'delimiter':';'} + @method + class get_history(DictElement): + class item(ItemElement): + klass = FrenchTransaction + + obj_rdate = Date(CleanText(Dict('Processing date'))) + obj_date = Date(CleanText(Dict('Transaction date'))) + obj_raw = FrenchTransaction.Raw(CleanText(Dict('corporate name'))) + obj_amount = FrenchTransaction.Amount(CleanText(Dict('charged amt')), replace_dots=False) + obj_original_amount = FrenchTransaction.Amount(CleanText(Dict('orig. currency gross amt')), replace_dots=False) + obj_original_currency = CleanText(Dict('orig. currency code')) + obj_country = CleanText(Dict('country cde')) + obj_type = FrenchTransaction.TYPE_CARD + + def condition(self): + return False + + def has_data(self): + return not Dict().filter(self.el)['processing date'] == u'No data found' + + def check_debit(self): + return Dict().filter(self.el)['debit / credit'] == 'D' + + class credit(item): + def condition(self): + return self.has_data() and not self.check_debit() + + class debit(item): + + obj_amount = FrenchTransaction.Amount(CleanText(Env('amount')), replace_dots=False) + obj_original_amount = FrenchTransaction.Amount(CleanText(Env('original_amount')), replace_dots=False) + + def condition(self): + if self.has_data() and self.check_debit(): + self.env['amount'] = "-" + self.el['charged amt'] + self.env['original_amount'] = "-" + self.el['orig. currency gross amt'] + return True + return False -- GitLab