support deferred debit

This commit is contained in:
Romain Bignon 2013-01-15 15:39:56 +01:00
commit 07038a9989
5 changed files with 114 additions and 25 deletions

View file

@ -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 weboob.capabilities.bank import ICapBank, AccountNotFound from weboob.capabilities.bank import ICapBank
from weboob.tools.backend import BaseBackend, BackendConfig from weboob.tools.backend import BaseBackend, BackendConfig
from weboob.tools.value import ValueBackendPassword from weboob.tools.value import ValueBackendPassword
@ -43,19 +43,20 @@ class BPBackend(BaseBackend, ICapBank):
return self.create_browser(self.config['login'].get(), self.config['password'].get()) return self.create_browser(self.config['login'].get(), self.config['password'].get())
def iter_accounts(self): def iter_accounts(self):
for account in self.browser.get_accounts_list(): return self.browser.get_accounts_list()
yield account
def get_account(self, _id): def get_account(self, _id):
account = self.browser.get_account(_id) return self.browser.get_account(_id)
if account:
return account
else:
raise AccountNotFound()
def iter_history(self, account): def iter_history(self, account):
for history in self.browser.get_history(account): for tr in self.browser.get_history(account):
yield history if not tr._coming:
yield tr
def iter_coming(self, account):
for tr in self.browser.get_coming(account):
if tr._coming:
yield tr
def transfer(self, id_from, id_to, amount, reason=None): def transfer(self, id_from, id_to, amount, reason=None):
from_account = self.get_account(id_from) from_account = self.get_account(id_from)

View file

@ -24,7 +24,7 @@ from datetime import datetime
from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword, BrowserBanned from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword, BrowserBanned
from .pages import LoginPage, Initident, CheckPassword, repositionnerCheminCourant, BadLoginPage, AccountDesactivate, \ from .pages import LoginPage, Initident, CheckPassword, repositionnerCheminCourant, BadLoginPage, AccountDesactivate, \
AccountList, AccountHistory, UnavailablePage, \ AccountList, AccountHistory, CardsList, UnavailablePage, \
TransferChooseAccounts, CompleteTransfer, TransferConfirm, TransferSummary TransferChooseAccounts, CompleteTransfer, TransferConfirm, TransferSummary
from weboob.capabilities.bank import Transfer from weboob.capabilities.bank import Transfer
@ -48,6 +48,8 @@ class BPBrowser(BaseBrowser):
r'.*CCP/releves_ccp/releveCPP-releve_ccp\.ea' : AccountHistory, r'.*CCP/releves_ccp/releveCPP-releve_ccp\.ea' : AccountHistory,
r'.*CNE/releveCNE/releveCNE-releve_cne\.ea' : AccountHistory, r'.*CNE/releveCNE/releveCNE-releve_cne\.ea' : AccountHistory,
r'.*CB/releveCB/preparerRecherche-mouvementsCarteDD.ea.*' : AccountHistory,
r'.*CB/releveCB/init-mouvementsCarteDD.ea.*' : CardsList,
r'.*/virementSafran_aiguillage/init-saisieComptes\.ea' : TransferChooseAccounts, r'.*/virementSafran_aiguillage/init-saisieComptes\.ea' : TransferChooseAccounts,
r'.*/virementSafran_aiguillage/formAiguillage-saisieComptes\.ea' : CompleteTransfer, r'.*/virementSafran_aiguillage/formAiguillage-saisieComptes\.ea' : CompleteTransfer,
@ -98,9 +100,44 @@ class BPBrowser(BaseBrowser):
args['typeRecherche'] = 10 args['typeRecherche'] = 10
self.location(self.buildurl(v.path, **args)) self.location(self.buildurl(v.path, **args))
if not self.is_on_page(AccountHistory):
return iter([]) if self.is_on_page(AccountHistory):
return self.page.get_history() for tr in self.page.get_history():
yield tr
for tr in self.get_coming(account):
yield tr
def get_coming(self, account):
for card in account._card_links:
self.location(card)
if self.is_on_page(CardsList):
for link in self.page.get_cards():
self.location(link)
for tr in self._iter_card_tr():
yield tr
else:
for tr in self._iter_card_tr():
yield tr
def _iter_card_tr(self):
"""
Iter all pages until there are no transactions.
"""
ops = self.page.get_history(deferred=True)
while len(ops) > 0:
for tr in ops:
yield tr
link = self.page.get_next_link()
if link is None:
return
self.location(link)
ops = self.page.get_history(deferred=True)
def make_transfer(self, from_account, to_account, amount): def make_transfer(self, from_account, to_account, amount):
self.location('https://voscomptesenligne.labanquepostale.fr/voscomptes/canalXHTML/virement/virementSafran_aiguillage/init-saisieComptes.ea') self.location('https://voscomptesenligne.labanquepostale.fr/voscomptes/canalXHTML/virement/virementSafran_aiguillage/init-saisieComptes.ea')

View file

@ -20,9 +20,10 @@
from .login import LoginPage, Initident, CheckPassword,repositionnerCheminCourant, BadLoginPage, AccountDesactivate, UnavailablePage from .login import LoginPage, Initident, CheckPassword,repositionnerCheminCourant, BadLoginPage, AccountDesactivate, UnavailablePage
from .accountlist import AccountList from .accountlist import AccountList
from .accounthistory import AccountHistory from .accounthistory import AccountHistory, CardsList
from .transfer import TransferChooseAccounts, CompleteTransfer, TransferConfirm, TransferSummary from .transfer import TransferChooseAccounts, CompleteTransfer, TransferConfirm, TransferSummary
__all__ = ['LoginPage','Initident', 'CheckPassword', 'repositionnerCheminCourant', "AccountList", 'AccountHistory', 'BadLoginPage', __all__ = ['LoginPage','Initident', 'CheckPassword', 'repositionnerCheminCourant', "AccountList", 'AccountHistory', 'BadLoginPage',
'AccountDesactivate', 'TransferChooseAccounts', 'CompleteTransfer', 'TransferConfirm', 'TransferSummary', 'UnavailablePage'] 'AccountDesactivate', 'TransferChooseAccounts', 'CompleteTransfer', 'TransferConfirm', 'TransferSummary', 'UnavailablePage',
'CardsList']

View file

@ -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 datetime
import re import re
from weboob.tools.capabilities.bank.transactions import FrenchTransaction from weboob.tools.capabilities.bank.transactions import FrenchTransaction
from weboob.tools.browser import BasePage from weboob.tools.browser import BasePage
__all__ = ['AccountHistory'] __all__ = ['AccountHistory', 'CardsList']
class Transaction(FrenchTransaction): class Transaction(FrenchTransaction):
@ -47,17 +48,39 @@ class Transaction(FrenchTransaction):
] ]
class AccountHistory(BasePage): class AccountHistory(BasePage):
def get_history(self): def get_next_link(self):
for a in self.document.xpath('//a[@class="btn_crt"]'):
txt = u''.join([txt.strip() for txt in a.itertext()])
if u'mois précédent' in txt:
return a.attrib['href']
def get_history(self, deferred=False):
"""
deffered is True when we are on a card page.
"""
mvt_table = self.document.xpath("//table[@id='mouvements']", smart_strings=False)[0] mvt_table = self.document.xpath("//table[@id='mouvements']", smart_strings=False)[0]
mvt_ligne = mvt_table.xpath("./tbody/tr") mvt_ligne = mvt_table.xpath("./tbody/tr")
operations = [] operations = []
if deferred:
# look for the debit date, and if it is already debited
txt = u''.join([txt.strip() for txt in self.document.xpath('//div[@class="infosynthese"]')[0].itertext()])
m = re.search('(\d+)/(\d+)/(\d+)', txt)
if m:
debit_date = datetime.date(*map(int, reversed(m.groups())))
coming = 'En cours' in txt
else:
coming = False
for mvt in mvt_ligne: for mvt in mvt_ligne:
op = Transaction(len(operations)) op = Transaction(len(operations))
op.parse(date=mvt.xpath("./td/span")[0].text.strip(), op.parse(date=mvt.xpath("./td/span")[0].text.strip(),
raw=unicode(self.parser.tocleanstring(mvt.xpath('./td/span')[1]).strip())) raw=unicode(self.parser.tocleanstring(mvt.xpath('./td/span')[1]).strip()))
if op.label.startswith('DEBIT CARTE BANCAIRE DIFFERE'):
continue
r = re.compile(r'\d+') r = re.compile(r'\d+')
tmp = mvt.xpath("./td/span/strong") tmp = mvt.xpath("./td/span/strong")
@ -70,5 +93,22 @@ class AccountHistory(BasePage):
op.set_amount(amount) op.set_amount(amount)
if deferred:
op.rdate = op.date
op.date = debit_date
# on card page, amounts are without sign
if op.amount > 0:
op.amount = - op.amount
op._coming = coming
operations.append(op) operations.append(op)
return operations return operations
class CardsList(BasePage):
def get_cards(self):
cards = []
for tr in self.document.xpath('//table[@class="dataNum"]/tbody/tr'):
cards.append(tr.xpath('.//a')[0].attrib['href'])
return cards

View file

@ -24,6 +24,7 @@ from weboob.capabilities.bank import Account, AccountNotFound
from weboob.tools.browser import BasePage from weboob.tools.browser import BasePage
from weboob.tools.misc import to_unicode from weboob.tools.misc import to_unicode
from weboob.tools.capabilities.bank.transactions import FrenchTransaction from weboob.tools.capabilities.bank.transactions import FrenchTransaction
from weboob.tools.ordereddict import OrderedDict
__all__ = ['AccountList'] __all__ = ['AccountList']
@ -31,7 +32,7 @@ __all__ = ['AccountList']
class AccountList(BasePage): class AccountList(BasePage):
def on_loaded(self): def on_loaded(self):
self.account_list = [] self.accounts = OrderedDict()
self.parse_table('comptes') self.parse_table('comptes')
self.parse_table('comptesEpargne') self.parse_table('comptesEpargne')
self.parse_table('comptesTitres') self.parse_table('comptesTitres')
@ -39,7 +40,7 @@ class AccountList(BasePage):
self.parse_table('comptesRetraireEuros') self.parse_table('comptesRetraireEuros')
def get_accounts_list(self): def get_accounts_list(self):
return self.account_list return self.accounts.itervalues()
def parse_table(self, what): def parse_table(self, what):
tables = self.document.xpath("//table[@id='%s']" % what, smart_strings=False) tables = self.document.xpath("//table[@id='%s']" % what, smart_strings=False)
@ -66,10 +67,19 @@ class AccountList(BasePage):
account.id = tmp_id account.id = tmp_id
account.currency = account.get_currency(tmp_balance) account.currency = account.get_currency(tmp_balance)
account.balance = Decimal(FrenchTransaction.clean_amount(tmp_balance)) account.balance = Decimal(FrenchTransaction.clean_amount(tmp_balance))
self.account_list.append(account)
if account.id in self.accounts:
a = self.accounts[account.id]
a._card_links.append(account._link_id)
if not a.coming:
a.coming = Decimal('0.0')
a.coming += account.balance
else:
account._card_links = []
self.accounts[account.id] = account
def get_account(self, id): def get_account(self, id):
for account in self.account_list: try:
if account.id == id: return self.accounts[id]
return account except KeyError:
raise AccountNotFound('Unable to find account: %s' % id) raise AccountNotFound('Unable to find account: %s' % id)