From 1a1773ea5f7e5ea771ba021e1c7321253f3538ce Mon Sep 17 00:00:00 2001 From: Vincent A Date: Fri, 28 May 2021 15:56:19 +0200 Subject: [PATCH] [primonialreim] new CapBank and CapDocument module No real details on accounts --- modules/primonialreim/__init__.py | 26 +++++++++ modules/primonialreim/browser.py | 53 ++++++++++++++++++ modules/primonialreim/favicon.png | Bin 0 -> 1943 bytes modules/primonialreim/module.py | 82 ++++++++++++++++++++++++++++ modules/primonialreim/pages.py | 88 ++++++++++++++++++++++++++++++ modules/primonialreim/test.py | 47 ++++++++++++++++ 6 files changed, 296 insertions(+) create mode 100644 modules/primonialreim/__init__.py create mode 100644 modules/primonialreim/browser.py create mode 100644 modules/primonialreim/favicon.png create mode 100644 modules/primonialreim/module.py create mode 100644 modules/primonialreim/pages.py create mode 100644 modules/primonialreim/test.py diff --git a/modules/primonialreim/__init__.py b/modules/primonialreim/__init__.py new file mode 100644 index 0000000000..93b805c453 --- /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 0000000000..503bbae264 --- /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 GIT binary patch literal 1943 zcmZ`)dotYnfoQN=rRfyiyt+(QJCo{Ih#@@ArJ~_j^9)d++(&`#qm~v%S5@ zD7Zcx000!l&ED$NqzoIE=q!_=fZvag|-BVmFe9q?(c8!kMG<9Ow>c+rrLI!PpLSK z!SySeMj@*gPKvkRR+!e#dP28cKAf-nZqGV&eWQ*a|IPyaxS$qOu{%$nMf^Y(ifuY# zZ5*xE`Wo^ngS#`cUtWNT4g1{x>VA@9;784sWjqkW=dA}K_^$%wvxks#Pm1WmksRYR zS1T+;>qvxU4H#h?@Ru_lwG8~qdn1GPk$Ko69WNNnVkbvuou=bp`x1uDNpWU) z&nj==-QYr596@P4^la|)=tR%rE?$+ez`nB!d-%s%>6N@|a@Ob1tGE4c;0Gh(`W`<` zJ)vp~^ulSf3!waFm2HAT6`~R2c0L{eY)rp7D1nc^ssdpwil-~=Bg6n@Z>A9PVpNbG z%k>48AZbl!LhLo#uG#x^U4dSP0w&l#`zAGqMt)&Ebl5E9;HzU7CM5opSqJH691ITyN{NbjtPS%wx6=$+@)wD+V*zv!@u^B6)2 zX#CS{(7xm_09p>-_r2-EdoN?i-g;{=$CiCXs^a5nho|pAFmO!&i_Er=M_4vUwdj&A zyDelG%TBwDT3dK4ILzm9B*61SSO%0feH&z1^-sujf*ARqEPZCN0={iKhJR#DyFA?+ z9Fw0-BK(G#c2UlkD&VS^LhdEg*~*EAom&a)cQVW$;Sff}{( z%G0C!L(?lQk?mAHc84a93Yfy2p)1t;$fI^Ze#1PuS^d)50U&))MNR-9n;b}N56z1a zr43_Zq;XlFCXVpnMr?BJ9XzrMK%RuqFds7zL>;y_a0;XjG5)XQMSewvrmN43_P#JX z>D3bkXxQ5*`ya^U#wSl89aBnLh1QB>ax!IA?(Eg|EE2b z_i>TOzH?6AVoyv=RQ5<$R^WC>BpQ7oDe1&QJD+dn46ooHa9jlvS$>jcqj~Zh3O^m73z0J9)mISRO3A8f&anM(oz=FrWlc#nc3Q$ zn~O?TehnJ)KYP}q7_hLgAiiN93-l1|JbHA*%)(-6A}lP7^`@q#rgga`daC-~J-6>c zs=ZScTUx9TFE1|-1g-Jh(8x&5PusGOh=GBDD1?8@n}=_v#>cZnB8PQ|sJ;Ew>Qu-2 z=F-`moE$Z&k-k1h6455#uH*A38Rl!k`go-~oz9O+Vlq);u^3?Y_EIL>=LajgqguFu zYG3UgVpU50JrXoC+y8>%>6wd>+_-+-F(4p-#hhwSNgtf=Rux}aHZ(K@k$z~(dc6uR zEi3c!^-bq+z?R^hP438|OLX+=a`V`dYeYmuXIq9$7WbtttqXU0vXoq|!*$1z@pQ&|tX}DKIe5O~W}=kyT%R zFjURW-5s8&e800TKYZImrXI76-M{-^OH27hMY;`xOPe25XF5esqqzo$hGK7Vxu|PG ztr1&Qe`$`a^qv{5xxXC-PNw{El=fcm@F6NYJ6opu1Ah%}gO@_;1cJtf24m`;@aX6< z-5PXeH*a3g2UJj4xV|_dfc1i}1!+)q%x9g{wKEvB#KgoQ-1)y-5kMT;u`>QI5KDqO u4u>m&AUV|x#V5nC|Ea$}6=`C21JFI%U-*ah{wUS^3{YIXT!g1+oPPs6>19v= literal 0 HcmV?d00001 diff --git a/modules/primonialreim/module.py b/modules/primonialreim/module.py new file mode 100644 index 0000000000..c47546f4d7 --- /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 0000000000..bd030583a7 --- /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 0000000000..2d556aa360 --- /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]) -- GitLab