diff --git a/modules/apivie/__init__.py b/modules/apivie/__init__.py new file mode 100644 index 00000000..46566a7d --- /dev/null +++ b/modules/apivie/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Romain Bignon +# +# This file is part of weboob. +# +# weboob 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. +# +# weboob 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 weboob. If not, see . + + +from .backend import ApivieBackend + + +__all__ = ['ApivieBackend'] diff --git a/modules/apivie/backend.py b/modules/apivie/backend.py new file mode 100644 index 00000000..96e4e58c --- /dev/null +++ b/modules/apivie/backend.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Romain Bignon +# +# This file is part of weboob. +# +# weboob 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. +# +# weboob 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 weboob. If not, see . + +from weboob.capabilities.bank import ICapBank +from weboob.tools.backend import BaseBackend, BackendConfig +from weboob.tools.value import ValueBackendPassword + +from .browser import ApivieBrowser + + +__all__ = ['ApivieBackend'] + + +class ApivieBackend(BaseBackend, ICapBank): + NAME = 'apivie' + DESCRIPTION = u'apivie' + MAINTAINER = u'Romain Bignon' + EMAIL = 'romain@weboob.org' + VERSION = '0.h' + + BROWSER = ApivieBrowser + + CONFIG = BackendConfig(ValueBackendPassword('login', label='Account ID', masked=False), + ValueBackendPassword('password', label='Password of account')) + + def create_default_browser(self): + return self.create_browser(self.config['login'].get(), + self.config['password'].get()) + + def iter_accounts(self): + with self.browser: + return self.browser.iter_accounts() + + def get_account(self, _id): + with self.browser: + return self.browser.get_account(_id) + + def iter_history(self, account): + with self.browser: + return self.browser.iter_history(account) diff --git a/modules/apivie/browser.py b/modules/apivie/browser.py new file mode 100644 index 00000000..96b6e013 --- /dev/null +++ b/modules/apivie/browser.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Romain Bignon +# +# This file is part of weboob. +# +# weboob 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. +# +# weboob 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 weboob. If not, see . + + +from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword + +from .pages import LoginPage, AccountsPage, OperationsPage + + +__all__ = ['ApivieBrowser'] + + +class ApivieBrowser(BaseBrowser): + PROTOCOL = 'https' + DOMAIN = 'www.apivie.fr' + ENCODING = None + + PAGES = { + 'https?://www.apivie.fr/': LoginPage, + 'https?://www.apivie.fr/accueil': LoginPage, + 'https?://www.apivie.fr/perte.*': LoginPage, + 'https?://www.apivie.fr/accueil-connect': AccountsPage, + 'https?://www.apivie.fr/historique-contrat.*': OperationsPage, + } + + def home(self): + self.location('https://www.apivie.fr/accueil-connect') + + def login(self): + assert isinstance(self.username, basestring) + assert isinstance(self.password, basestring) + + if not self.is_on_page(LoginPage): + self.location('/accueil', no_login=True) + + self.page.login(self.username, self.password) + + if not self.is_logged(): + raise BrowserIncorrectPassword() + + def is_logged(self): + return not self.is_on_page(LoginPage) + + def iter_accounts(self): + self.location('/accueil-connect') + return self.page.iter_accounts() + + def get_account(self, _id): + try: + return next(a for a in self.get_accounts_list() if a.id == id) + except StopIteration: + return None + + def iter_history(self, account): + self.location(self.buildurl('/historique-contrat', contratId=account.id)) + + assert self.is_on_page(OperationsPage) + return self.page.iter_history() diff --git a/modules/apivie/favicon.png b/modules/apivie/favicon.png new file mode 100644 index 00000000..ae4fa367 Binary files /dev/null and b/modules/apivie/favicon.png differ diff --git a/modules/apivie/pages.py b/modules/apivie/pages.py new file mode 100644 index 00000000..41b7e26f --- /dev/null +++ b/modules/apivie/pages.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Romain Bignon +# +# This file is part of weboob. +# +# weboob 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. +# +# weboob 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 weboob. If not, see . + + +from decimal import Decimal + +from weboob.capabilities.bank import Account +from weboob.tools.browser import BasePage +from weboob.tools.capabilities.bank.transactions import FrenchTransaction + + +__all__ = ['LoginPage', 'AccountsPage', 'OperationsPage'] + + +class LoginPage(BasePage): + def login(self, username, password): + self.browser.select_form(nr=0) + self.browser['_58_login'] = username.encode('utf-8') + self.browser['_58_password'] = password.encode('utf-8') + self.browser.submit(nologin=True) + + +class AccountsPage(BasePage): + COL_LABEL = 0 + COL_OWNER = 1 + COL_ID = 2 + COL_AMOUNT = 3 + + def iter_accounts(self): + for line in self.document.xpath('//table[@summary="informations contrat"]/tbody/tr'): + yield self._get_account(line) + + def _get_account(self, line): + tds = line.findall('td') + account = Account() + account.id = self.parser.tocleanstring(tds[self.COL_ID]) + account.label = self.parser.tocleanstring(tds[self.COL_LABEL]) + + balance_str = self.parser.tocleanstring(tds[self.COL_AMOUNT]) + account.balance = Decimal(FrenchTransaction.clean_amount(balance_str)) + account.currency = account.get_currency(balance_str) + return account + + +class Transaction(FrenchTransaction): + pass + + +class OperationsPage(BasePage): + COL_DATE = 0 + COL_LABEL = 1 + COL_AMOUNT = 2 + + def iter_history(self): + for line in self.document.xpath('//table[@role="treegrid"]/tbody/tr'): + tds = line.findall('td') + + operation = Transaction(int(line.attrib['data-rk'])) + + date = self.parser.tocleanstring(tds[self.COL_DATE]) + label = self.parser.tocleanstring(tds[self.COL_LABEL]) + amount = self.parser.tocleanstring(tds[self.COL_AMOUNT]) + + + if len(amount) == 0: + continue + + color = tds[self.COL_AMOUNT].find('span').attrib['class'] + if color == 'black': + continue + if color == 'red': + amount = '-' + amount + + operation.parse(date, label) + operation.set_amount(amount) + + yield operation diff --git a/modules/apivie/test.py b/modules/apivie/test.py new file mode 100644 index 00000000..249801e5 --- /dev/null +++ b/modules/apivie/test.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Romain Bignon +# +# This file is part of weboob. +# +# weboob 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. +# +# weboob 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 weboob. If not, see . + + +from weboob.tools.test import BackendTest + + +class ApivieTest(BackendTest): + BACKEND = 'apivie' + + def test_apivie(self): + l = list(self.backend.iter_accounts()) + if len(l) > 0: + a = l[0] + list(self.backend.iter_history(a))