pax_global_header 0000666 0000000 0000000 00000000064 14042356110 0014506 g ustar 00root root 0000000 0000000 52 comment=18d41565f955028f9fcd2f6cc437f5f1cb717401
woob-18d41565f955028f9fcd2f6cc437f5f1cb717401-modules-lendosphere/ 0000775 0000000 0000000 00000000000 14042356110 0023307 5 ustar 00root root 0000000 0000000 woob-18d41565f955028f9fcd2f6cc437f5f1cb717401-modules-lendosphere/modules/ 0000775 0000000 0000000 00000000000 14042356110 0024757 5 ustar 00root root 0000000 0000000 woob-18d41565f955028f9fcd2f6cc437f5f1cb717401-modules-lendosphere/modules/lendosphere/ 0000775 0000000 0000000 00000000000 14042356110 0027267 5 ustar 00root root 0000000 0000000 woob-18d41565f955028f9fcd2f6cc437f5f1cb717401-modules-lendosphere/modules/lendosphere/__init__.py 0000664 0000000 0000000 00000001562 14042356110 0031404 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2019 Vincent A
#
# This file is part of a woob module.
#
# This woob 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 woob 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 woob module. If not, see .
from __future__ import unicode_literals
from .module import LendosphereModule
__all__ = ['LendosphereModule']
woob-18d41565f955028f9fcd2f6cc437f5f1cb717401-modules-lendosphere/modules/lendosphere/browser.py 0000664 0000000 0000000 00000006746 14042356110 0031341 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2019 Vincent A
#
# This file is part of a woob module.
#
# This woob 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 woob 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 woob module. If not, see .
from __future__ import unicode_literals
import datetime
from woob.browser import LoginBrowser, URL, need_login
from woob.tools.capabilities.bank.investments import create_french_liquidity
from woob.capabilities.wealth import Investment
from .pages import (
LoginPage, SummaryPage, GSummaryPage, ProfilePage, ComingPage,
)
class AttrURL(URL):
def build(self, *args, **kwargs):
import re
for pattern in self.urls:
regex = re.compile(pattern)
for k in regex.groupindex:
if hasattr(self.browser, k) and k not in kwargs:
kwargs[k] = getattr(self.browser, k)
return super(AttrURL, self).build(*args, **kwargs)
class LendosphereBrowser(LoginBrowser):
BASEURL = 'https://www.lendosphere.com'
login = URL(r'/membres/se-connecter', LoginPage)
dashboard = AttrURL(r'/membres/(?P[a-z0-9-]+)/tableau-de-bord', SummaryPage)
global_summary = AttrURL(r'/membres/(?P[a-z0-9-]+)/dashboard_global_info', GSummaryPage)
coming = AttrURL(r'/membres/(?P[a-z0-9-]+)/mes-echeanciers.csv', ComingPage)
profile = AttrURL(r'/membres/(?P[a-z0-9-]+)', ProfilePage)
user_id = None
def do_login(self):
self.login.go()
self.page.do_login(self.username, self.password)
if self.login.is_here():
self.page.raise_error()
self.user_id = self.page.params['user_id']
@need_login
def iter_accounts(self):
self.dashboard.go()
liquidities = self.page.get_liquidities()
self.global_summary.go()
account = self.page.get_account()
# Account balance is the sum of liquidities and invested money
account._liquidities = liquidities
account.balance = account._liquidities + account._invested
yield account
@need_login
def iter_investment(self, account):
today = datetime.date.today()
self.coming.go()
# unfortunately there doesn't seem to be a page indicating what's
# left to be repaid on each project, so let's sum...
valuations = {}
commissions = {}
for tr in self.page.iter_transactions():
if tr.date <= today:
continue
if tr.raw not in valuations:
valuations[tr.raw] = tr.amount
commissions[tr.raw] = tr.commission
else:
valuations[tr.raw] += tr.amount
commissions[tr.raw] += tr.commission
for label, value in valuations.items():
inv = Investment()
inv.label = label
inv.valuation = value
inv.diff = commissions[label]
yield inv
yield create_french_liquidity(account._liquidities)
woob-18d41565f955028f9fcd2f6cc437f5f1cb717401-modules-lendosphere/modules/lendosphere/module.py 0000664 0000000 0000000 00000003367 14042356110 0031137 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2019 Vincent A
#
# This file is part of a woob module.
#
# This woob 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 woob 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 woob module. If not, see .
from __future__ import unicode_literals
from woob.tools.backend import Module, BackendConfig
from woob.tools.value import ValueBackendPassword
from woob.capabilities.wealth import CapBankWealth
from .browser import LendosphereBrowser
__all__ = ['LendosphereModule']
class LendosphereModule(Module, CapBankWealth):
NAME = 'lendosphere'
DESCRIPTION = 'Lendosphere'
MAINTAINER = 'Vincent A'
EMAIL = 'dev@indigo.re'
LICENSE = 'LGPLv3+'
VERSION = '3.1'
BROWSER = LendosphereBrowser
CONFIG = BackendConfig(
ValueBackendPassword('login', label='Email', 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.iter_accounts()
def iter_investment(self, account):
return self.browser.iter_investment(account)
woob-18d41565f955028f9fcd2f6cc437f5f1cb717401-modules-lendosphere/modules/lendosphere/pages.py 0000664 0000000 0000000 00000006125 14042356110 0030744 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2019 Vincent A
#
# This file is part of a woob module.
#
# This woob 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 woob 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 woob module. If not, see .
from __future__ import unicode_literals
from woob.browser.elements import ItemElement, method, DictElement
from woob.browser.filters.json import Dict
from woob.browser.filters.standard import (
CleanText, CleanDecimal, Date,
)
from woob.browser.pages import HTMLPage, CsvPage, LoggedPage
from woob.capabilities.base import NotAvailable
from woob.capabilities.bank import Account, Transaction
from woob.exceptions import BrowserIncorrectPassword
MAIN_ID = '_lendosphere_'
class LoginPage(HTMLPage):
def do_login(self, username, password):
form = self.get_form(id='new_user')
form['user[email]'] = username
form['user[password]'] = password
form.submit()
def raise_error(self):
msg = CleanText('//div[has-class("alert-danger")]')(self.doc)
if 'Votre email ou mot de passe est incorrect' in msg:
raise BrowserIncorrectPassword(msg)
assert False, 'unhandled error %r' % msg
class SummaryPage(LoggedPage, HTMLPage):
def get_liquidities(self):
# 'Mon compte' tag appears 3 times on the page
return CleanDecimal.French('(//span[@id="current-wallet-amount"])[1]')(self.doc)
class ProfilePage(LoggedPage, HTMLPage):
pass
class ComingProjectPage(LoggedPage, HTMLPage):
def iter_projects(self):
return [value for value in self.doc.xpath('//select[@id="offer"]/option/@value') if value != '*']
class ComingPage(LoggedPage, CsvPage):
HEADER = 1
@method
class iter_transactions(DictElement):
class item(ItemElement):
klass = Transaction
obj_type = Transaction.TYPE_BANK
obj_raw = Dict('Projet')
obj_date = Date(Dict('Date'), dayfirst=True)
obj_gross_amount = CleanDecimal.SI(Dict('Capital rembourse'))
obj_amount = CleanDecimal.SI(Dict('Montant brut'))
obj_commission = CleanDecimal.SI(Dict('Interets'))
obj__amount_left = CleanDecimal.SI(Dict('Capital restant du'))
class GSummaryPage(LoggedPage, HTMLPage):
@method
class get_account(ItemElement):
klass = Account
obj_id = MAIN_ID
obj_currency = 'EUR'
obj_number = NotAvailable
obj_type = Account.TYPE_MARKET
obj_label = 'Lendosphere'
obj__invested = CleanDecimal.French('//tr[td[contains(text(),"Echéances restantes")]]/td[last()]')