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])