parse categories

This commit is contained in:
Romain Bignon 2012-02-26 15:05:37 +01:00
commit defcacb9db
6 changed files with 147 additions and 151 deletions

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright(C) 2010-2011 Romain Bignon # Copyright(C) 2010-2012 Romain Bignon
# #
# This file is part of weboob. # This file is part of weboob.
# #
@ -40,7 +40,7 @@ class BNPorcBackend(BaseBackend, ICapBank):
DESCRIPTION = 'BNP Paribas French bank website' DESCRIPTION = 'BNP Paribas French bank website'
CONFIG = BackendConfig(ValueBackendPassword('login', label='Account ID', masked=False), CONFIG = BackendConfig(ValueBackendPassword('login', label='Account ID', masked=False),
ValueBackendPassword('password', label='Password', regexp='^(\d{6}|)$'), ValueBackendPassword('password', label='Password', regexp='^(\d{6}|)$'),
ValueBackendPassword('rotating_password', ValueBackendPassword('rotating_password', default='',
label='Password to set when the allowed uses are exhausted (6 digits)', label='Password to set when the allowed uses are exhausted (6 digits)',
regexp='^(\d{6}|)$')) regexp='^(\d{6}|)$'))
BROWSER = BNPorc BROWSER = BNPorc
@ -76,13 +76,11 @@ class BNPorcBackend(BaseBackend, ICapBank):
def iter_history(self, account): def iter_history(self, account):
with self.browser: with self.browser:
for history in self.browser.get_history(account.id): return self.browser.iter_history(account.id)
yield history
def iter_operations(self, account): def iter_operations(self, account):
with self.browser: with self.browser:
for coming in self.browser.get_coming_operations(account.id): return self.browser.iter_coming_operations(account.id)
yield coming
def iter_transfer_recipients(self, ignored): def iter_transfer_recipients(self, ignored):
for account in self.browser.get_transfer_accounts().itervalues(): for account in self.browser.get_transfer_accounts().itervalues():

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright(C) 2009-2011 Romain Bignon # Copyright(C) 2009-2012 Romain Bignon
# #
# This file is part of weboob. # This file is part of weboob.
# #
@ -129,16 +129,41 @@ class BNPorc(BaseBrowser):
return None return None
def get_history(self, id): #def get_history(self, id):
self.location('/banque/portail/particulier/FicheA?contractId=%d&pageId=releveoperations&_eventId=changeOperationsPerPage&operationsPerPage=200' % int(id)) # data = {'contactId': int(id),
return self.page.get_operations() # 'pageId': 'releveoperations',
# '_eventId': 'pastOperations',
# 'operationsPerPage': 200,
# 'groupId': -2
# }
# self.location('/banque/portail/particulier/FicheA#pageId=releveoperations', urllib.urlencode(data))
# return self.page.get_operations()
def get_coming_operations(self, id): #def get_coming_operations(self, id):
# if not self.is_on_page(AccountsList):
# self.location('/NSFR?Action=DSP_VGLOBALE')
# execution = self.page.get_execution_id()
# data = {'externalIAId': 'IAStatements',
# 'contactId': int(id),
# 'pastOrPendingOperations': 2,
# 'pageId': 'mouvementsavenir',
# 'execution': execution,
# }
# self.location('/banque/portail/particulier/FicheA#pageId=mouvementsavenir', urllib.urlencode(data))
# return self.page.get_operations()
def iter_history(self, id):
self.location('/banque/portail/particulier/FicheA?contractId=%d&pageId=releveoperations&_eventId=changeOperationsPerPage&operationsPerPage=200' % int(id))
return self.page.iter_operations()
def iter_coming_operations(self, id):
if not self.is_on_page(AccountsList): if not self.is_on_page(AccountsList):
self.location('/NSFR?Action=DSP_VGLOBALE') self.location('/NSFR?Action=DSP_VGLOBALE')
execution = self.page.get_execution_id() execution = self.page.get_execution_id()
self.location('/banque/portail/particulier/FicheA?externalIAId=IAStatements&contractId=%d&pastOrPendingOperations=2&pageId=mouvementsavenir&execution=%s' % (int(id), execution)) self.location('/banque/portail/particulier/FicheA?externalIAId=IAStatements&contractId=%d&pastOrPendingOperations=2&pageId=mouvementsavenir&execution=%s' % (int(id), execution))
return self.page.get_operations() return self.page.iter_operations()
@check_expired_password @check_expired_password
def get_transfer_accounts(self): def get_transfer_accounts(self):

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright(C) 2009-2011 Romain Bignon # Copyright(C) 2009-2012 Romain Bignon
# #
# This file is part of weboob. # This file is part of weboob.
# #
@ -19,8 +19,7 @@
from .accounts_list import AccountsList from .accounts_list import AccountsList
from .account_coming import AccountComing from .transactions import AccountHistory, AccountComing
from .account_history import AccountHistory
from .transfer import TransferPage, TransferConfirmPage, TransferCompletePage from .transfer import TransferPage, TransferConfirmPage, TransferCompletePage
from .login import LoginPage, ConfirmPage, ChangePasswordPage, MessagePage from .login import LoginPage, ConfirmPage, ChangePasswordPage, MessagePage

View file

@ -1,69 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2009-2011 Romain Bignon
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
import re
from datetime import date
from weboob.tools.browser import BasePage
from weboob.capabilities.bank import Operation
__all__ = ['AccountComing']
class AccountComing(BasePage):
LABEL_PATTERNS = [('^FACTURE CARTE DU (?P<dd>\d{2})(?P<mm>\d{2})(?P<yy>\d{2}) (?P<text>.*)',
u'CB %(yy)s-%(mm)s-%(dd)s: %(text)s'),
('^PRELEVEMENT(?P<text>.*)', 'Order: %(text)s'),
('^ECHEANCEPRET(?P<text>.*)', u'Loan payment n°%(text)s'),
]
def on_loaded(self):
self.operations = []
for tr in self.document.xpath('//table[@id="tableauOperations"]//tr'):
if 'typeop' in tr.attrib:
tds = tr.findall('td')
if len(tds) != 3:
continue
d = tr.attrib['dateop']
d = date(int(d[4:8]), int(d[2:4]), int(d[0:2]))
label = tds[1].text or u''
label = label.replace(u'\xa0', u'')
for child in tds[1].getchildren():
if child.text: label += child.text
if child.tail: label += child.tail
label = label.strip()
for pattern, text in self.LABEL_PATTERNS:
m = re.match(pattern, label)
if m:
label = text % m.groupdict()
amount = tds[2].text.replace('.','').replace(',','.').strip(u' \t\u20ac\xa0\n\r')
operation = Operation(len(self.operations))
operation.date = d
operation.label = label
operation.amount = float(amount)
self.operations.append(operation)
def get_operations(self):
return self.operations

View file

@ -1,68 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2009-2011 Romain Bignon
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
import re
from datetime import date
from weboob.tools.browser import BasePage
from weboob.capabilities.bank import Operation
from weboob.capabilities.base import NotAvailable
__all__ = ['AccountHistory']
class AccountHistory(BasePage):
LABEL_PATTERNS = [(u'^CHEQUEN°(?P<no>.*)', u'CHEQUE', u'%(no)s')]
def on_loaded(self):
self.operations = []
for tr in self.document.xpath('//table[@id="tableCompte"]//tr'):
if len(tr.xpath('td[@class="debit"]')) == 0:
continue
id = tr.find('td').find('input').attrib['value']
op = Operation(id)
op.label = tr.findall('td')[2].text.replace(u'\xa0', u'').strip()
op.date = date(*reversed([int(x) for x in tr.findall('td')[1].text.split('/')]))
op.category = NotAvailable
for pattern, _cat, _lab in self.LABEL_PATTERNS:
m = re.match(pattern, op.label)
if m:
op.category = _cat % m.groupdict()
op.label = _lab % m.groupdict()
break
else:
if ' ' in op.label:
op.category, useless, op.label = [part.strip() for part in op.label.partition(' ')]
debit = tr.xpath('.//td[@class="debit"]')[0].text.replace('.','').replace(',','.').strip(u' \t\u20ac\xa0\n\r')
credit = tr.xpath('.//td[@class="credit"]')[0].text.replace('.','').replace(',','.').strip(u' \t\u20ac\xa0\n\r')
if len(debit) > 0:
op.amount = - float(debit)
else:
op.amount = float(credit)
self.operations.append(op)
def get_operations(self):
return self.operations

View file

@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2009-2012 Romain Bignon
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
import re
from datetime import date
from weboob.tools.browser import BasePage
from weboob.capabilities.bank import Transaction
from weboob.capabilities.base import NotAvailable
__all__ = ['AccountHistory', 'AccountComing']
class TransactionsBasePage(BasePage):
LABEL_PATTERNS = [(re.compile(u'^CHEQUEN°(?P<no>.*)'),
Transaction.TYPE_CHECK, u'%(no)s'),
(re.compile('^FACTURE CARTE DU (?P<dd>\d{2})(?P<mm>\d{2})(?P<yy>\d{2}) (?P<text>.*)'),
Transaction.TYPE_CARD, u'20%(yy)s-%(mm)s-%(dd)s: %(text)s'),
(re.compile('^(PRELEVEMENT|TELEREGLEMENT) (?P<text>.*)'),
Transaction.TYPE_ORDER, '%(text)s'),
(re.compile('^ECHEANCEPRET(?P<text>.*)'),
Transaction.TYPE_LOAN_PAYMENT, u'%(text)s'),
(re.compile('^RETRAIT DAB (?P<dd>\d{2})/(?P<mm>\d{2})/(?P<yy>\d{2}) (?P<HH>\d+)H(?P<MM>\d+) (?P<text>.*)'),
Transaction.TYPE_WITHDRAWAL, u'20%(yy)s-%(mm)s-%(dd)s %(HH)s:%(MM)s: %(text)s'),
(re.compile('^VIREMENT (?P<text>.*)'),
Transaction.TYPE_TRANSFER, u'%(text)s'),
(re.compile('^REMBOURST (?P<text>.*)'),
Transaction.TYPE_PAYBACK, '%(text)s'),
(re.compile('^COMMISSIONS (?P<text>.*)'),
Transaction.TYPE_BANK, '%(text)s'),
]
def parse_text(self, op):
op.category = NotAvailable
if ' ' in op.text:
op.category, useless, op.label = [part.strip() for part in op.label.partition(' ')]
else:
op.label = op.text
for pattern, _type, _label in self.LABEL_PATTERNS:
m = pattern.match(op.text)
if m:
op.type = _type
op.label = (_label % m.groupdict()).strip()
return
class AccountHistory(TransactionsBasePage):
def iter_operations(self):
for tr in self.document.xpath('//table[@id="tableCompte"]//tr'):
if len(tr.xpath('td[@class="debit"]')) == 0:
continue
id = tr.find('td').find('input').attrib['value']
op = Transaction(id)
op.text = tr.findall('td')[2].text.replace(u'\xa0', u'').strip()
op.date = date(*reversed([int(x) for x in tr.findall('td')[1].text.split('/')]))
self.parse_text(op)
debit = tr.xpath('.//td[@class="debit"]')[0].text.replace('.','').replace(',','.').strip(u' \t\u20ac\xa0\n\r')
credit = tr.xpath('.//td[@class="credit"]')[0].text.replace('.','').replace(',','.').strip(u' \t\u20ac\xa0\n\r')
if len(debit) > 0:
op.amount = - float(debit)
else:
op.amount = float(credit)
yield op
class AccountComing(TransactionsBasePage):
def iter_operations(self):
i = 0
for tr in self.document.xpath('//table[@id="tableauOperations"]//tr'):
if 'typeop' in tr.attrib:
tds = tr.findall('td')
if len(tds) != 3:
continue
d = tr.attrib['dateop']
d = date(int(d[4:8]), int(d[2:4]), int(d[0:2]))
text = tds[1].text or u''
text = text.replace(u'\xa0', u'')
for child in tds[1].getchildren():
if child.text: text += child.text
if child.tail: text += child.tail
amount = tds[2].text.replace('.','').replace(',','.').strip(u' \t\u20ac\xa0\n\r')
i += 1
operation = Transaction(i)
operation.date = d
operation.text = text.strip()
self.parse_text(operation)
operation.amount = float(amount)
yield operation