diff --git a/modules/primonialreim/__init__.py b/modules/primonialreim/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..93b805c4530c6c843352c667d50cde53575ed2bb
--- /dev/null
+++ b/modules/primonialreim/__init__.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2019 Vincent A
+#
+# 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 PrimonialreimModule
+
+
+__all__ = ['PrimonialreimModule']
diff --git a/modules/primonialreim/browser.py b/modules/primonialreim/browser.py
new file mode 100644
index 0000000000000000000000000000000000000000..503bbae264f1396b1da9c2e5efa5fc9bca32ad12
--- /dev/null
+++ b/modules/primonialreim/browser.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2019 Vincent A
+#
+# 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 .
+
+# flake8: compatible
+
+from __future__ import unicode_literals
+
+from woob.browser import LoginBrowser, need_login, URL
+
+from .pages import (
+ LoginPage, AfterLoginPage, AccountsPage, TaxDocsPage,
+)
+
+
+class PrimonialreimBrowser(LoginBrowser):
+ BASEURL = 'https://www.primonialreim.com'
+
+ login = URL("/login", LoginPage)
+ accounts = URL("/group/extranet-associes/mon-patrimoine", AccountsPage)
+ tax_documents = URL("/group/extranet-associes/ma-fiscalit%C3%A9", TaxDocsPage)
+ home = URL("/group/extranet-associes", AfterLoginPage)
+
+ def do_login(self):
+ self.login.go()
+ self.page.do_login(self.username, self.password)
+ # twice because site submits username first then password
+ self.page.do_login(self.username, self.password)
+
+ @need_login
+ def iter_accounts(self):
+ self.accounts.go()
+ return self.page.iter_accounts()
+
+ @need_login
+ def iter_documents(self):
+ self.tax_documents.go()
+ return self.page.iter_documents()
diff --git a/modules/primonialreim/favicon.png b/modules/primonialreim/favicon.png
new file mode 100644
index 0000000000000000000000000000000000000000..8883e5bc0a98d262862ef85e299d0f209982c8d5
Binary files /dev/null and b/modules/primonialreim/favicon.png differ
diff --git a/modules/primonialreim/module.py b/modules/primonialreim/module.py
new file mode 100644
index 0000000000000000000000000000000000000000..c47546f4d74a0d185da66c4c104aefcb8deb46ba
--- /dev/null
+++ b/modules/primonialreim/module.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2019 Vincent A
+#
+# 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 .
+
+# flake8: compatible
+
+from __future__ import unicode_literals
+
+from weboob.tools.backend import Module, BackendConfig
+from weboob.tools.value import Value, ValueBackendPassword
+from weboob.capabilities.base import find_object
+from weboob.capabilities.bank import CapBank, Account
+from weboob.capabilities.bill import (
+ CapDocument, Subscription, SubscriptionNotFound, DocumentNotFound,
+)
+
+from .browser import PrimonialreimBrowser
+
+
+__all__ = ['PrimonialreimModule']
+
+
+class PrimonialreimModule(Module, CapBank, CapDocument):
+ NAME = 'primonialreim'
+ DESCRIPTION = 'Primonial REIM'
+ MAINTAINER = 'Vincent A'
+ EMAIL = 'dev@indigo.re'
+ LICENSE = 'LGPLv3+'
+ VERSION = '3.1'
+
+ BROWSER = PrimonialreimBrowser
+
+ CONFIG = BackendConfig(
+ Value('username', label='Identifiant'),
+ ValueBackendPassword('password', label='Mot de passe'),
+ )
+
+ def create_default_browser(self):
+ return self.create_browser(self.config['username'].get(), self.config['password'].get())
+
+ # CapBank
+ def iter_accounts(self):
+ return self.browser.iter_accounts()
+
+ # CapDocument
+ def iter_subscription(self):
+ return [Subscription.from_dict(dict(id="primonial", label="Primonial"))]
+
+ def get_subscription(self, id):
+ return find_object(self.iter_subscription(), id=id, error=SubscriptionNotFound)
+
+ def iter_documents(self, subscription):
+ return self.browser.iter_documents()
+
+ def download_document(self, document):
+ if isinstance(document, str):
+ document = find_object(self.iter_documents(None), id=document, error=DocumentNotFound)
+ return self.browser.open(document.url).content
+
+ # CapCollection
+ def iter_resources(self, objs, split_path):
+ if Account in objs:
+ self._restrict_level(split_path)
+ return self.iter_accounts()
+ if Subscription in objs:
+ self._restrict_level(split_path)
+ return self.iter_subscription()
diff --git a/modules/primonialreim/pages.py b/modules/primonialreim/pages.py
new file mode 100644
index 0000000000000000000000000000000000000000..bd030583a7abe471e0ab85d0a701846c532051c4
--- /dev/null
+++ b/modules/primonialreim/pages.py
@@ -0,0 +1,88 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2019 Vincent A
+#
+# 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 .
+
+# flake8: compatible
+
+from __future__ import unicode_literals
+
+import datetime
+from decimal import Decimal
+import re
+import json
+
+from woob.capabilities.bank.base import Account
+from woob.capabilities.bill import Document, DocumentTypes
+from woob.browser.pages import HTMLPage, LoggedPage
+from woob.browser.filters.standard import (
+ CleanText, Format, Regexp,
+)
+from woob.browser.filters.html import AbsoluteLink
+from woob.browser.elements import ListElement, ItemElement, method
+
+
+class LoginPage(HTMLPage):
+ def do_login(self, username, password):
+ form = self.get_form(xpath="//form[contains(@action, 'login')]")
+
+ url = form.el.attrib["action"]
+ token = re.search(r"INSTANCE_([a-zA-Z0-9]+)_", url)[1]
+
+ form[f"_com_preim_portlet_login_PreimLoginPortlet_INSTANCE_{token}_username"] = username
+ form[f"_com_preim_portlet_login_PreimLoginPortlet_INSTANCE_{token}_password"] = password
+ form.submit()
+
+
+class AfterLoginPage(LoggedPage, HTMLPage):
+ pass
+
+
+class AccountsPage(LoggedPage, HTMLPage):
+ def iter_accounts(self):
+ jdata = json.loads(self.doc.xpath("//div/@js-new-graph[contains(., 'bar')]")[0])
+ jdata = {item["legendText"]: item["dataPoints"] for item in jdata["data"]}
+ for jpoint in jdata["Valeur totale d achat"]:
+ yield Account.from_dict(dict(
+ id=jpoint["label"].lower().replace(" ", ""),
+ label=jpoint["label"],
+ balance=Decimal(str(jpoint["y"])),
+ type=Account.TYPE_REAL_ESTATE,
+ ))
+
+
+class TaxDocsPage(LoggedPage, HTMLPage):
+ @method
+ class iter_documents(ListElement):
+ item_xpath = "//a[contains(@href, '.pdf')]"
+
+ class item(ItemElement):
+ klass = Document
+
+ obj_type = DocumentTypes.NOTICE
+ obj_url = AbsoluteLink(".")
+ obj_id = Regexp(obj_url, r"/([^/]+)\.pdf")
+
+ obj__year = Regexp(obj_url, r"(\d+)\.pdf")
+ obj_label = Format(
+ "%s %s",
+ CleanText("."),
+ obj__year
+ )
+
+ def obj_date(self):
+ return datetime.date(int(self.obj._year) + 1, 1, 1)
diff --git a/modules/primonialreim/test.py b/modules/primonialreim/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..2d556aa3609f7c68e8b86f2d6997e631b7b9dddf
--- /dev/null
+++ b/modules/primonialreim/test.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2019 Vincent A
+#
+# 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 PrimonialreimTest(BackendTest):
+ MODULE = 'primonialreim'
+
+ def test_accounts(self):
+ accounts = list(self.backend.iter_accounts())
+ assert accounts
+ for account in accounts:
+ assert account.id
+ assert account.label
+ assert account.balance
+ assert account.type
+
+ def test_documents(self):
+ sub, = self.backend.iter_subscription()
+ docs = list(self.backend.iter_documents())
+ assert docs
+ for doc in docs:
+ assert doc.id
+ assert doc.label
+ assert doc.date
+ assert doc.type
+ assert self.backend.download_document(docs[0])