From defcacb9dbaba90f4206cd535f31be3f31cc74ff Mon Sep 17 00:00:00 2001 From: Romain Bignon Date: Sun, 26 Feb 2012 15:05:37 +0100 Subject: [PATCH] parse categories --- modules/bnporc/backend.py | 10 +-- modules/bnporc/browser.py | 37 ++++++-- modules/bnporc/pages/__init__.py | 5 +- modules/bnporc/pages/account_coming.py | 69 --------------- modules/bnporc/pages/account_history.py | 68 --------------- modules/bnporc/pages/transactions.py | 111 ++++++++++++++++++++++++ 6 files changed, 148 insertions(+), 152 deletions(-) delete mode 100644 modules/bnporc/pages/account_coming.py delete mode 100644 modules/bnporc/pages/account_history.py create mode 100644 modules/bnporc/pages/transactions.py diff --git a/modules/bnporc/backend.py b/modules/bnporc/backend.py index ef0c177c..22be42ca 100644 --- a/modules/bnporc/backend.py +++ b/modules/bnporc/backend.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2010-2011 Romain Bignon +# Copyright(C) 2010-2012 Romain Bignon # # This file is part of weboob. # @@ -40,7 +40,7 @@ class BNPorcBackend(BaseBackend, ICapBank): DESCRIPTION = 'BNP Paribas French bank website' CONFIG = BackendConfig(ValueBackendPassword('login', label='Account ID', masked=False), 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)', regexp='^(\d{6}|)$')) BROWSER = BNPorc @@ -76,13 +76,11 @@ class BNPorcBackend(BaseBackend, ICapBank): def iter_history(self, account): with self.browser: - for history in self.browser.get_history(account.id): - yield history + return self.browser.iter_history(account.id) def iter_operations(self, account): with self.browser: - for coming in self.browser.get_coming_operations(account.id): - yield coming + return self.browser.iter_coming_operations(account.id) def iter_transfer_recipients(self, ignored): for account in self.browser.get_transfer_accounts().itervalues(): diff --git a/modules/bnporc/browser.py b/modules/bnporc/browser.py index 94edc507..04c599d0 100644 --- a/modules/bnporc/browser.py +++ b/modules/bnporc/browser.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2009-2011 Romain Bignon +# Copyright(C) 2009-2012 Romain Bignon # # This file is part of weboob. # @@ -129,16 +129,41 @@ class BNPorc(BaseBrowser): return None - def get_history(self, id): - self.location('/banque/portail/particulier/FicheA?contractId=%d&pageId=releveoperations&_eventId=changeOperationsPerPage&operationsPerPage=200' % int(id)) - return self.page.get_operations() + #def get_history(self, id): + # data = {'contactId': int(id), + # '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): self.location('/NSFR?Action=DSP_VGLOBALE') 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)) - return self.page.get_operations() + return self.page.iter_operations() @check_expired_password def get_transfer_accounts(self): diff --git a/modules/bnporc/pages/__init__.py b/modules/bnporc/pages/__init__.py index 1e5cecaf..d30ae986 100644 --- a/modules/bnporc/pages/__init__.py +++ b/modules/bnporc/pages/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2009-2011 Romain Bignon +# Copyright(C) 2009-2012 Romain Bignon # # This file is part of weboob. # @@ -19,8 +19,7 @@ from .accounts_list import AccountsList -from .account_coming import AccountComing -from .account_history import AccountHistory +from .transactions import AccountHistory, AccountComing from .transfer import TransferPage, TransferConfirmPage, TransferCompletePage from .login import LoginPage, ConfirmPage, ChangePasswordPage, MessagePage diff --git a/modules/bnporc/pages/account_coming.py b/modules/bnporc/pages/account_coming.py deleted file mode 100644 index 17fcd6d8..00000000 --- a/modules/bnporc/pages/account_coming.py +++ /dev/null @@ -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 . - - -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
\d{2})(?P\d{2})(?P\d{2}) (?P.*)', - u'CB %(yy)s-%(mm)s-%(dd)s: %(text)s'), - ('^PRELEVEMENT(?P.*)', 'Order: %(text)s'), - ('^ECHEANCEPRET(?P.*)', 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 diff --git a/modules/bnporc/pages/account_history.py b/modules/bnporc/pages/account_history.py deleted file mode 100644 index affc9e43..00000000 --- a/modules/bnporc/pages/account_history.py +++ /dev/null @@ -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 . - - -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.*)', u'CHEQUE', u'N°%(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 diff --git a/modules/bnporc/pages/transactions.py b/modules/bnporc/pages/transactions.py new file mode 100644 index 00000000..3da96564 --- /dev/null +++ b/modules/bnporc/pages/transactions.py @@ -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 . + + +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.*)'), + Transaction.TYPE_CHECK, u'N°%(no)s'), + (re.compile('^FACTURE CARTE DU (?P
\d{2})(?P\d{2})(?P\d{2}) (?P.*)'), + Transaction.TYPE_CARD, u'20%(yy)s-%(mm)s-%(dd)s: %(text)s'), + (re.compile('^(PRELEVEMENT|TELEREGLEMENT) (?P.*)'), + Transaction.TYPE_ORDER, '%(text)s'), + (re.compile('^ECHEANCEPRET(?P.*)'), + Transaction.TYPE_LOAN_PAYMENT, u'n°%(text)s'), + (re.compile('^RETRAIT DAB (?P
\d{2})/(?P\d{2})/(?P\d{2}) (?P\d+)H(?P\d+) (?P.*)'), + Transaction.TYPE_WITHDRAWAL, u'20%(yy)s-%(mm)s-%(dd)s %(HH)s:%(MM)s: %(text)s'), + (re.compile('^VIREMENT (?P.*)'), + Transaction.TYPE_TRANSFER, u'%(text)s'), + (re.compile('^REMBOURST (?P.*)'), + Transaction.TYPE_PAYBACK, '%(text)s'), + (re.compile('^COMMISSIONS (?P.*)'), + 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