support of ASV accounts

This commit is contained in:
Romain Bignon 2015-01-21 13:14:37 +01:00
commit d26bbc50a8
3 changed files with 77 additions and 14 deletions

View file

@ -18,13 +18,14 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
import re
import hashlib
import time
from weboob.browser import LoginBrowser, URL, need_login
from weboob.exceptions import BrowserIncorrectPassword, ParseError
from weboob.capabilities.bank import Account, TransferError
from .pages import AccountsList, LoginPage, TitrePage, TitreHistory,\
TransferPage, TransferConfirmPage, BillsPage, StopPage
TransferPage, TransferConfirmPage, BillsPage, StopPage, TitreDetails
__all__ = ['IngBrowser']
@ -52,6 +53,7 @@ class IngBrowser(LoginBrowser):
transferpage = URL('/protected/pages/cc/transfer/transferManagement.jsf', TransferPage)
dotransferpage = URL('/general\?command=DisplayDoTransferCommand', TransferPage)
valtransferpage = URL('/protected/pages/cc/transfer/create/transferCreateValidation.jsf', TransferConfirmPage)
titredetails = URL('/general\?command=display.*', TitreDetails)
# CapBank-Market
starttitre = URL('/general\?command=goToAccount&zone=COMPTE', TitrePage)
titrepage = URL('https://bourse.ingdirect.fr/priv/portefeuille-TR.php', TitrePage)
@ -226,7 +228,17 @@ class IngBrowser(LoginBrowser):
"javax.faces.ViewState": account._jid,
"cptnbr": account._id
}
self.accountspage.go(data=data)
# On ASV pages, data maybe not available.
for i in range(4):
time.sleep(2**i)
self.accountspage.go(data=data)
if not self.page.has_error():
break
if self.page.is_asv:
return
self.starttitre.go()
self.where = u"titre"
@ -237,12 +249,15 @@ class IngBrowser(LoginBrowser):
raise NotImplementedError()
self.go_investments(account)
self.titrerealtime.go()
if self.where == u'titre':
self.titrerealtime.go()
return self.page.iter_investments()
def get_history_titre(self, account):
self.go_investments(account)
self.titrehistory.go()
if self.where == u'titre':
self.titrehistory.go()
return self.page.iter_history()
############# CapBill #############

View file

@ -18,7 +18,7 @@
# 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 .transfer import TransferPage, TransferConfirmPage
from .bills import BillsPage
@ -28,6 +28,6 @@ from .titre import TitrePage, TitreHistory
class AccountPrelevement(AccountsList):
pass
__all__ = ['AccountsList', 'LoginPage',
__all__ = ['AccountsList', 'LoginPage', 'TitreDetails',
'AccountPrelevement', 'TransferPage', 'TransferConfirmPage',
'BillsPage', 'StopPage', 'TitrePage', 'TitreHistory']

View file

@ -20,13 +20,15 @@
from datetime import date, timedelta
import datetime
from decimal import Decimal
import re
from weboob.capabilities.bank import Account
from weboob.capabilities.bank import Account, Investment
from weboob.capabilities.base import NotAvailable
from weboob.browser.pages import HTMLPage, LoggedPage
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.tools.capabilities.bank.transactions import FrenchTransaction
@ -57,7 +59,8 @@ class AddPref(MultiFilter):
class AddType(Filter):
types = {u'Courant': Account.TYPE_CHECKING, u'Livret A': 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):
for key, acc_type in self.types.items():
@ -112,9 +115,10 @@ class INGCategory(Filter):
class AccountsList(LoggedPage, HTMLPage):
def __init__(self, browser, response, *args, **kwargs):
super(AccountsList, self).__init__(browser, response, *args, **kwargs)
self.i = 0
i = 0
def has_error(self):
return self.doc.xpath('//div[has-class("alert-warning")]') > 0
@method
class get_list(ListElement):
@ -166,8 +170,7 @@ class AccountsList(LoggedPage, HTMLPage):
item_xpath = '//table'
def get_history_jid(self):
span = self.doc.xpath('//span[@id="index:panelASV"]')
if len(span) > 1:
if self.is_asv:
# Assurance Vie, we do not support this kind of account.
return None
@ -182,3 +185,48 @@ class AccountsList(LoggedPage, HTMLPage):
nomore = self.doc.getroot().cssselect('.no-more-transactions')
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