support of ASV accounts
This commit is contained in:
parent
130cec8c5a
commit
d26bbc50a8
3 changed files with 77 additions and 14 deletions
|
|
@ -18,13 +18,14 @@
|
||||||
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
|
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
|
||||||
import re
|
import re
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import time
|
||||||
|
|
||||||
from weboob.browser import LoginBrowser, URL, need_login
|
from weboob.browser import LoginBrowser, URL, need_login
|
||||||
from weboob.exceptions import BrowserIncorrectPassword, ParseError
|
from weboob.exceptions import BrowserIncorrectPassword, ParseError
|
||||||
from weboob.capabilities.bank import Account, TransferError
|
from weboob.capabilities.bank import Account, TransferError
|
||||||
|
|
||||||
from .pages import AccountsList, LoginPage, TitrePage, TitreHistory,\
|
from .pages import AccountsList, LoginPage, TitrePage, TitreHistory,\
|
||||||
TransferPage, TransferConfirmPage, BillsPage, StopPage
|
TransferPage, TransferConfirmPage, BillsPage, StopPage, TitreDetails
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['IngBrowser']
|
__all__ = ['IngBrowser']
|
||||||
|
|
@ -52,6 +53,7 @@ class IngBrowser(LoginBrowser):
|
||||||
transferpage = URL('/protected/pages/cc/transfer/transferManagement.jsf', TransferPage)
|
transferpage = URL('/protected/pages/cc/transfer/transferManagement.jsf', TransferPage)
|
||||||
dotransferpage = URL('/general\?command=DisplayDoTransferCommand', TransferPage)
|
dotransferpage = URL('/general\?command=DisplayDoTransferCommand', TransferPage)
|
||||||
valtransferpage = URL('/protected/pages/cc/transfer/create/transferCreateValidation.jsf', TransferConfirmPage)
|
valtransferpage = URL('/protected/pages/cc/transfer/create/transferCreateValidation.jsf', TransferConfirmPage)
|
||||||
|
titredetails = URL('/general\?command=display.*', TitreDetails)
|
||||||
# CapBank-Market
|
# CapBank-Market
|
||||||
starttitre = URL('/general\?command=goToAccount&zone=COMPTE', TitrePage)
|
starttitre = URL('/general\?command=goToAccount&zone=COMPTE', TitrePage)
|
||||||
titrepage = URL('https://bourse.ingdirect.fr/priv/portefeuille-TR.php', TitrePage)
|
titrepage = URL('https://bourse.ingdirect.fr/priv/portefeuille-TR.php', TitrePage)
|
||||||
|
|
@ -226,8 +228,18 @@ class IngBrowser(LoginBrowser):
|
||||||
"javax.faces.ViewState": account._jid,
|
"javax.faces.ViewState": account._jid,
|
||||||
"cptnbr": account._id
|
"cptnbr": account._id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# On ASV pages, data maybe not available.
|
||||||
|
for i in range(4):
|
||||||
|
time.sleep(2**i)
|
||||||
self.accountspage.go(data=data)
|
self.accountspage.go(data=data)
|
||||||
|
|
||||||
|
if not self.page.has_error():
|
||||||
|
break
|
||||||
|
|
||||||
|
if self.page.is_asv:
|
||||||
|
return
|
||||||
|
|
||||||
self.starttitre.go()
|
self.starttitre.go()
|
||||||
self.where = u"titre"
|
self.where = u"titre"
|
||||||
self.titrepage.go()
|
self.titrepage.go()
|
||||||
|
|
@ -237,11 +249,14 @@ class IngBrowser(LoginBrowser):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
self.go_investments(account)
|
self.go_investments(account)
|
||||||
|
|
||||||
|
if self.where == u'titre':
|
||||||
self.titrerealtime.go()
|
self.titrerealtime.go()
|
||||||
return self.page.iter_investments()
|
return self.page.iter_investments()
|
||||||
|
|
||||||
def get_history_titre(self, account):
|
def get_history_titre(self, account):
|
||||||
self.go_investments(account)
|
self.go_investments(account)
|
||||||
|
|
||||||
|
if self.where == u'titre':
|
||||||
self.titrehistory.go()
|
self.titrehistory.go()
|
||||||
return self.page.iter_history()
|
return self.page.iter_history()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
|
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
from .accounts_list import AccountsList
|
from .accounts_list import AccountsList, TitreDetails
|
||||||
from .login import LoginPage, StopPage
|
from .login import LoginPage, StopPage
|
||||||
from .transfer import TransferPage, TransferConfirmPage
|
from .transfer import TransferPage, TransferConfirmPage
|
||||||
from .bills import BillsPage
|
from .bills import BillsPage
|
||||||
|
|
@ -28,6 +28,6 @@ from .titre import TitrePage, TitreHistory
|
||||||
class AccountPrelevement(AccountsList):
|
class AccountPrelevement(AccountsList):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
__all__ = ['AccountsList', 'LoginPage',
|
__all__ = ['AccountsList', 'LoginPage', 'TitreDetails',
|
||||||
'AccountPrelevement', 'TransferPage', 'TransferConfirmPage',
|
'AccountPrelevement', 'TransferPage', 'TransferConfirmPage',
|
||||||
'BillsPage', 'StopPage', 'TitrePage', 'TitreHistory']
|
'BillsPage', 'StopPage', 'TitrePage', 'TitreHistory']
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,15 @@
|
||||||
|
|
||||||
from datetime import date, timedelta
|
from datetime import date, timedelta
|
||||||
import datetime
|
import datetime
|
||||||
|
from decimal import Decimal
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from weboob.capabilities.bank import Account
|
from weboob.capabilities.bank import Account, Investment
|
||||||
from weboob.capabilities.base import NotAvailable
|
from weboob.capabilities.base import NotAvailable
|
||||||
from weboob.browser.pages import HTMLPage, LoggedPage
|
from weboob.browser.pages import HTMLPage, LoggedPage
|
||||||
from weboob.browser.elements import ListElement, ItemElement, method
|
from weboob.browser.elements import ListElement, ItemElement, method
|
||||||
from weboob.browser.filters.standard import CleanText, CleanDecimal, Filter, Field, MultiFilter, Date, Lower
|
from weboob.browser.filters.standard import CleanText, CleanDecimal, Filter, Field, MultiFilter, \
|
||||||
|
Date, Lower, Regexp, Async, AsyncLoad, Slugify
|
||||||
from weboob.browser.filters.html import Attr
|
from weboob.browser.filters.html import Attr
|
||||||
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
|
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
|
||||||
|
|
||||||
|
|
@ -57,7 +59,8 @@ class AddPref(MultiFilter):
|
||||||
class AddType(Filter):
|
class AddType(Filter):
|
||||||
types = {u'Courant': Account.TYPE_CHECKING, u'Livret A': Account.TYPE_SAVINGS,
|
types = {u'Courant': Account.TYPE_CHECKING, u'Livret A': Account.TYPE_SAVINGS,
|
||||||
u'Orange': Account.TYPE_SAVINGS, u'Durable': Account.TYPE_SAVINGS,
|
u'Orange': Account.TYPE_SAVINGS, u'Durable': Account.TYPE_SAVINGS,
|
||||||
u'Titres': Account.TYPE_MARKET, u'PEA': Account.TYPE_MARKET}
|
u'Titres': Account.TYPE_MARKET, u'PEA': Account.TYPE_MARKET,
|
||||||
|
u'Direct Vie': Account.TYPE_MARKET}
|
||||||
|
|
||||||
def filter(self, label):
|
def filter(self, label):
|
||||||
for key, acc_type in self.types.items():
|
for key, acc_type in self.types.items():
|
||||||
|
|
@ -112,9 +115,10 @@ class INGCategory(Filter):
|
||||||
|
|
||||||
|
|
||||||
class AccountsList(LoggedPage, HTMLPage):
|
class AccountsList(LoggedPage, HTMLPage):
|
||||||
def __init__(self, browser, response, *args, **kwargs):
|
i = 0
|
||||||
super(AccountsList, self).__init__(browser, response, *args, **kwargs)
|
|
||||||
self.i = 0
|
def has_error(self):
|
||||||
|
return self.doc.xpath('//div[has-class("alert-warning")]') > 0
|
||||||
|
|
||||||
@method
|
@method
|
||||||
class get_list(ListElement):
|
class get_list(ListElement):
|
||||||
|
|
@ -166,8 +170,7 @@ class AccountsList(LoggedPage, HTMLPage):
|
||||||
item_xpath = '//table'
|
item_xpath = '//table'
|
||||||
|
|
||||||
def get_history_jid(self):
|
def get_history_jid(self):
|
||||||
span = self.doc.xpath('//span[@id="index:panelASV"]')
|
if self.is_asv:
|
||||||
if len(span) > 1:
|
|
||||||
# Assurance Vie, we do not support this kind of account.
|
# Assurance Vie, we do not support this kind of account.
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -182,3 +185,48 @@ class AccountsList(LoggedPage, HTMLPage):
|
||||||
|
|
||||||
nomore = self.doc.getroot().cssselect('.no-more-transactions')
|
nomore = self.doc.getroot().cssselect('.no-more-transactions')
|
||||||
return (len(nomore) > 0)
|
return (len(nomore) > 0)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_asv(self):
|
||||||
|
span = self.doc.xpath('//span[@id="index:panelASV"]')
|
||||||
|
return len(span) > 0
|
||||||
|
|
||||||
|
@method
|
||||||
|
class iter_investments(ListElement):
|
||||||
|
item_xpath = '//div[has-class("asv_fond")]'
|
||||||
|
|
||||||
|
class item(ItemElement):
|
||||||
|
klass = Investment
|
||||||
|
|
||||||
|
# ASV.popup('/general?command=displayAVEuroEpargne')
|
||||||
|
load_details = Attr('.//div[has-class("asv_fond_view")]//a', 'onclick') & Regexp(pattern="'(.*)'") & AsyncLoad
|
||||||
|
|
||||||
|
obj_label = CleanText('.//span[has-class("asv_cat_lbl")]')
|
||||||
|
# XXX I would like to do that... but 1. CleanText doesn't deal with default 2. default values can't be filters yet
|
||||||
|
#obj_code = Async('details') & CleanText('//li[contains(text(), "Code ISIN")]/span') | (Field('label') & Format('XX%s', Slugify))
|
||||||
|
obj_code = Async('details') & CleanText('//li[contains(text(), "Code ISIN")]/span')
|
||||||
|
obj_id = obj_code
|
||||||
|
obj_description = Async('details') & CleanText('//h5')
|
||||||
|
obj_quantity = CleanDecimal('.//dl[contains(dt/text(), "Nombre de parts")]/dd', replace_dots=True)
|
||||||
|
obj_unitvalue = CleanDecimal('.//dl[contains(dt/text(), "Valeur de part")]/dd', replace_dots=True)
|
||||||
|
obj_valuation = CleanDecimal('.//dl[has-class("ligne-montant")]/dd', replace_dots=True)
|
||||||
|
|
||||||
|
def obj_unitprice(self):
|
||||||
|
if 'eurossima' in self.el.get('class'):
|
||||||
|
return self.obj.unitvalue
|
||||||
|
|
||||||
|
percent = CleanDecimal('.//dl[has-class("ligne-pmvalue")]/dd', replace_dots=True)(self)
|
||||||
|
return (self.obj.unitvalue / (1 + percent/Decimal('100.0'))).quantize(Decimal('1.00'))
|
||||||
|
|
||||||
|
def obj_diff(self):
|
||||||
|
return (self.obj.valuation - (self.obj.quantity * self.obj.unitprice)).quantize(Decimal('1.00'))
|
||||||
|
|
||||||
|
def validate(self, obj):
|
||||||
|
if not obj.id:
|
||||||
|
obj.id = obj.code = 'XX' + Slugify(self.obj_label)(self)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class TitreDetails(LoggedPage, HTMLPage):
|
||||||
|
pass
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue