diff --git a/modules/groupamaes/__init__.py b/modules/groupamaes/__init__.py
new file mode 100644
index 00000000..46414fd5
--- /dev/null
+++ b/modules/groupamaes/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014 Bezleputh
+#
+# 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 GroupamaesBackend
+
+
+__all__ = ['GroupamaesBackend']
diff --git a/modules/groupamaes/backend.py b/modules/groupamaes/backend.py
new file mode 100644
index 00000000..675cc5d8
--- /dev/null
+++ b/modules/groupamaes/backend.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014 Bezleputh
+#
+# 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, AccountNotFound
+from weboob.tools.backend import BaseBackend, BackendConfig
+from weboob.tools.value import ValueBackendPassword
+
+
+from .browser import GroupamaesBrowser
+
+
+__all__ = ['GroupamaesBackend']
+
+
+class GroupamaesBackend(BaseBackend, ICapBank):
+ NAME = 'groupamaes'
+ DESCRIPTION = u'groupama-es website'
+ MAINTAINER = u'Bezleputh'
+ EMAIL = 'carton_ben@yahoo.fr'
+ LICENSE = 'AGPLv3+'
+ VERSION = '0.i'
+
+ BROWSER = GroupamaesBrowser
+
+ CONFIG = BackendConfig(ValueBackendPassword('login', label='Identifiant', regexp='\d{8}', masked=False),
+ ValueBackendPassword('password', label='Mot de passe'))
+
+ def create_default_browser(self):
+ return self.create_browser(self.config['login'].get(), self.config['password'].get())
+
+ def iter_accounts(self):
+ return self.browser.get_accounts_list()
+
+ def iter_coming(self, account):
+ return self.browser.get_coming()
+
+ def iter_history(self, account):
+ return self.browser.get_history()
+
+ def get_account(self, _id):
+ account = self.browser.get_account(_id)
+ if account:
+ return account
+ else:
+ raise AccountNotFound()
diff --git a/modules/groupamaes/browser.py b/modules/groupamaes/browser.py
new file mode 100644
index 00000000..4ec1dd50
--- /dev/null
+++ b/modules/groupamaes/browser.py
@@ -0,0 +1,67 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014 Bezleputh
+#
+# 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.browser2 import LoginBrowser, URL, need_login
+from weboob.tools.browser import BrowserIncorrectPassword
+
+from .pages import LoginPage, LoginErrorPage, AvoirPage, OperationsTraiteesPage, OperationsFuturesPage
+
+
+__all__ = ['GroupamaesBrowser']
+
+
+class GroupamaesBrowser(LoginBrowser):
+ BASEURL = 'https://www.gestion-epargne-salariale.fr'
+
+ login = URL('/groupama-es/fr/index.html', LoginPage)
+ login_error = URL('/groupama-es/fr/identification/default.cgi', LoginErrorPage)
+ avoir = URL('/groupama-es/fr/espace/devbavoirs.aspx.*', AvoirPage)
+ operations_traitees = URL('/groupama-es/fr/espace/ListeOperations.asp\?TypeOperation=T', OperationsTraiteesPage)
+ operations_futures = URL('/groupama-es/fr/espace/ListeOperations.asp\?TypeOperation=E', OperationsFuturesPage)
+
+ def do_login(self):
+ self.login.stay_or_go()
+
+ self.page.login(self.username, self.password)
+
+ if not self.page.logged or self.login_error.is_here():
+ raise BrowserIncorrectPassword()
+
+ @need_login
+ def get_accounts_list(self):
+ return self.avoir.stay_or_go().iter_accounts()
+
+ @need_login
+ def get_history(self):
+ transactions = list(self.operations_traitees.go().get_history())
+ transactions.sort(key=lambda tr: tr.rdate, reverse=True)
+ return transactions
+
+ @need_login
+ def get_coming(self):
+ transactions = list(self.operations_futures.go().get_list())
+ transactions.sort(key=lambda tr: tr.rdate, reverse=True)
+ return transactions
+
+ def get_account(self, id):
+ assert isinstance(id, basestring)
+ for a in self.get_accounts_list():
+ if a.id == id:
+ return a
diff --git a/modules/groupamaes/pages.py b/modules/groupamaes/pages.py
new file mode 100644
index 00000000..c7285c98
--- /dev/null
+++ b/modules/groupamaes/pages.py
@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014 Bezleputh
+#
+# 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.browser2.page import HTMLPage, method, TableElement, ItemElement, LoggedPage
+from weboob.tools.browser2.filters import CleanText, CleanDecimal, TableCell, Date
+from weboob.capabilities.bank import Account, Transaction
+from weboob.tools.capabilities.bank.transactions import FrenchTransaction
+from weboob.tools.date import LinearDateGuesser
+
+__all__ = ['LoginPage', 'LoginErrorPage', 'AvoirPage', 'OperationsFuturesPage', 'OperationsTraiteesPage']
+
+
+class LoginPage(HTMLPage):
+ def login(self, login, passwd):
+ form = self.get_form(nr=0)
+ form['_cm_user'] = login
+ form['_cm_pwd'] = passwd
+ form.submit()
+
+
+class LoginErrorPage(HTMLPage):
+ pass
+
+
+class AvoirPage(LoggedPage, HTMLPage):
+ @method
+ class iter_accounts(TableElement):
+ item_xpath = u'//table[@summary="Liste des échéances"]/tbody/tr'
+ head_xpath = u'//table[@summary="Liste des échéances"]/thead/tr/th/text()'
+
+ col_name = u'Plan'
+ col_value = u'Evaluation en'
+
+ class item(ItemElement):
+ klass = Account
+
+ obj_id = CleanText(TableCell('name'))
+ obj_label = CleanText(TableCell('name'))
+ #obj_coming = CleanDecimal(TableCell('value'))
+ obj_balance = CleanDecimal(TableCell('value'))
+ obj_currency = CleanText(u'//table[@summary="Liste des échéances"]/thead/tr/th/small/text()')
+ obj_type = Account.TYPE_UNKNOWN
+
+
+class OperationsFuturesPage(LoggedPage, HTMLPage):
+ @method
+ class get_list(TableElement):
+ head_xpath = u'//table[@summary="Liste des opérations en attente"]/thead/tr/th/text()'
+ item_xpath = u'//table[@summary="Liste des opérations en attente"]/tbody/tr'
+
+ col_date = u'Date'
+ col_operation = u'Opération'
+ col_etat = u'Etat'
+ col_montant = u'Montant net en'
+ col_action = u'Action'
+
+ class item(ItemElement):
+ klass = Transaction
+
+ def condition(self):
+ return not u'Aucune opération en attente' in CleanText(TableCell('date'))(self)
+
+ obj_date = Date(CleanText(TableCell('date')), LinearDateGuesser())
+ obj_type = Transaction.TYPE_UNKNOWN
+ obj_label = CleanText(TableCell('operation'))
+ obj_amount = CleanDecimal(TableCell('montant'))
+
+
+class OperationsTraiteesPage(LoggedPage, HTMLPage):
+ @method
+ class get_history(TableElement):
+ head_xpath = u'//table[@summary="Liste des opérations en attente"]/thead/tr/th/text()'
+ item_xpath = u'//table[@summary="Liste des opérations en attente"]/tbody/tr'
+
+ col_date = u'Date'
+ col_operation = u'Opération'
+ col_montant = u'Montant net en'
+
+ class item(ItemElement):
+ klass = Transaction
+
+ def condition(self):
+ return not u'Aucune opération' in CleanText(TableCell('date'))(self)
+
+ obj_date = Date(CleanText(TableCell('date')), LinearDateGuesser())
+ obj_type = Transaction.TYPE_UNKNOWN
+ obj_label = CleanText(TableCell('operation'))
+ obj_amount = CleanDecimal(TableCell('montant'))
diff --git a/modules/groupamaes/test.py b/modules/groupamaes/test.py
new file mode 100644
index 00000000..a7bfd352
--- /dev/null
+++ b/modules/groupamaes/test.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014 Bezleputh
+#
+# 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 GroupamaesTest(BackendTest):
+ BACKEND = 'groupamaes'
+
+ def test_groupamaes(self):
+ l = list(self.backend.iter_accounts())
+ if len(l) > 0:
+ a = l[0]
+ list(self.backend.iter_history(a))