Commit 5b367292 authored by Dorian Roly's avatar Dorian Roly Committed by ntome

[BNP] Add documents to personnal pages

Now bnp personnal, bnp pro and bnp privee can get documents
parent e417e2f8
......@@ -79,6 +79,14 @@ class BNPCompany(LoginBrowser):
(date.today() - timedelta(days=90)).strftime('%Y%m%d'),
date.today().strftime('%Y%m%d'))
@need_login
def iter_documents(self, subscription):
raise NotImplementedError()
@need_login
def iter_subscription(self):
raise NotImplementedError()
@need_login
def iter_coming_operations(self, account):
return self.get_transactions(account.id,
......
......@@ -33,7 +33,7 @@ from weboob.tools.capabilities.bank.transactions import sorted_transactions
from .pages import (
LoginPage, AuthPage, AccountsPage, AccountHistoryViewPage, AccountHistoryPage,
ActionNeededPage, TransactionPage, MarketPage, InvestPage
ActionNeededPage, TransactionPage, MarketPage, InvestPage,
)
......@@ -124,6 +124,14 @@ class BNPEnterprise(LoginBrowser):
return []
return self._iter_history_base(account)
@need_login
def iter_documents(self, subscription):
raise NotImplementedError()
@need_login
def iter_subscription(self):
raise NotImplementedError()
def _iter_history_base(self, account):
dformat = "%Y%m%d"
......
......@@ -33,6 +33,10 @@ from weboob.capabilities.profile import CapProfile
from weboob.capabilities.base import find_object, strict_find_object
from weboob.tools.backend import Module, BackendConfig
from weboob.tools.value import ValueBackendPassword, Value, ValueBool
from weboob.capabilities.bill import (
Subscription, CapDocument, SubscriptionNotFound, DocumentNotFound, Document,
DocumentTypes,
)
from .enterprise.browser import BNPEnterprise
from .company.browser import BNPCompany
......@@ -42,7 +46,7 @@ from .pp.browser import BNPPartPro, HelloBank
__all__ = ['BNPorcModule']
class BNPorcModule(Module, CapBankWealth, CapBankTransferAddRecipient, CapMessages, CapContact, CapProfile):
class BNPorcModule(Module, CapBankWealth, CapBankTransferAddRecipient, CapMessages, CapContact, CapProfile, CapDocument):
NAME = 'bnporc'
MAINTAINER = u'Romain Bignon'
EMAIL = 'romain@weboob.org'
......@@ -61,6 +65,13 @@ class BNPorcModule(Module, CapBankWealth, CapBankTransferAddRecipient, CapMessag
'ent2': 'Entreprises et PME (nouveau site)'}))
STORAGE = {'seen': []}
accepted_document_types = (
DocumentTypes.STATEMENT,
DocumentTypes.REPORT,
DocumentTypes.BILL,
DocumentTypes.OTHER,
)
# Store the messages *list* for this duration
CACHE_THREADS = timedelta(seconds=3 * 60 * 60)
......@@ -74,6 +85,14 @@ class BNPorcModule(Module, CapBankWealth, CapBankTransferAddRecipient, CapMessag
self.BROWSER = b[self.config['website'].get()]
return self.create_browser(self.config)
def iter_resources(self, objs, split_path):
if Account in objs:
self._restrict_level(split_path)
return self.iter_accounts()
if Subscription in objs:
self._restrict_level(split_path)
return self.iter_subscription()
def iter_accounts(self):
return self.browser.iter_accounts()
......@@ -205,4 +224,27 @@ class BNPorcModule(Module, CapBankWealth, CapBankTransferAddRecipient, CapMessag
self.storage.get('seen', default=[]).append(message.thread.id)
self.storage.save()
def get_subscription(self, _id):
return find_object(self.iter_subscription(), id=_id, error=SubscriptionNotFound)
def iter_documents(self, subscription):
if not isinstance(subscription, Subscription):
subscription = self.get_subscription(subscription)
return self.browser.iter_documents(subscription)
def iter_subscription(self):
return self.browser.iter_subscription()
def get_document(self, _id):
subscription_id = _id.split('_')[0]
subscription = self.get_subscription(subscription_id)
return find_object(self.iter_documents(subscription), id=_id, error=DocumentNotFound)
def download_document(self, document):
if not isinstance(document, Document):
document = self.get_document(document)
return self.browser.open(document.url).content
OBJECTS = {Thread: fill_thread}
......@@ -30,6 +30,7 @@ from weboob.capabilities.bank import (
AccountNotFound, Account, AddRecipientStep, AddRecipientTimeout,
TransferInvalidRecipient, Loan,
)
from weboob.capabilities.bill import Subscription
from weboob.capabilities.profile import ProfileMissing
from weboob.tools.decorators import retry
from weboob.tools.capabilities.bank.transactions import sorted_transactions
......@@ -50,6 +51,7 @@ from .pages import (
UselessPage, TransferAssertionError, LoanDetailsPage,
)
from .document_pages import DocumentsPage, TitulairePage
__all__ = ['BNPPartPro', 'HelloBank']
......@@ -121,6 +123,9 @@ class BNPParibasBrowser(JsonBrowserMixin, LoginBrowser):
advisor = URL(r'/conseiller-wspl/rest/monConseiller', AdvisorPage)
titulaire = URL(r'/demat-wspl/rest/listerTitulairesDemat', TitulairePage)
document = URL(r'/demat-wspl/rest/rechercheCriteresDemat', DocumentsPage)
profile = URL(r'/kyc-wspl/rest/informationsClient', ProfilePage)
list_detail_card = URL(r'/udcarte-wspl/rest/listeDetailCartes', ListDetailCardPage)
......@@ -510,6 +515,40 @@ class BNPParibasBrowser(JsonBrowserMixin, LoginBrowser):
def get_thread(self, thread):
raise NotImplementedError()
@need_login
def iter_documents(self, subscription):
titulaires = self.titulaire.go().get_titulaires()
# Calling '/demat-wspl/rest/listerDocuments' before the request on 'document'
# is necessary when you specify an ikpi, otherwise no documents are returned
self.location('/demat-wspl/rest/listerDocuments')
# When we only have one titulaire, no need to use the ikpi parameter in the request,
# all document are provided with this simple request
data = {
'dateDebut': (datetime.now() - relativedelta(years=3)).strftime('%d/%m/%Y'),
'dateFin': datetime.now().strftime('%d/%m/%Y'),
}
# Ikpi is necessary for multi titulaires accounts to get each document of each titulaires
if len(titulaires) > 1:
data['ikpiPersonne'] = subscription._iduser
self.document.go(json=data)
return self.page.iter_documents(sub_id=subscription.id, sub_number=subscription._number, baseurl=self.BASEURL)
@need_login
def iter_subscription(self):
acc_list = self.iter_accounts()
for acc in acc_list:
sub = Subscription()
sub.label = acc.label
sub.subscriber = acc._subscriber
sub.id = acc.id
# number is the hidden number of an account like "****1234"
# and it's used in the parsing of the docs in iter_documents
sub._number = acc.number
# iduser is the ikpi affiliate to the account,
# usefull for multi titulaires connexions
sub._iduser = acc._iduser
yield sub
class BNPPartPro(BNPParibasBrowser):
BASEURL_TEMPLATE = r'https://%s.bnpparibas/'
......
# -*- coding: utf-8 -*-
# Copyright(C) 2009-2019 Romain Bignon
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this weboob module. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
import re
from weboob.browser.elements import DictElement, ItemElement, method
from weboob.browser.filters.json import Dict
from weboob.browser.filters.standard import Format, Date, Env
from weboob.browser.pages import JsonPage, LoggedPage
from weboob.capabilities.bill import Document, DocumentTypes
patterns = {
r'Relevé': DocumentTypes.STATEMENT,
r'Livret(s) A': DocumentTypes.STATEMENT,
r'développement durable': DocumentTypes.STATEMENT,
r'Synthèse': DocumentTypes.STATEMENT,
r'Echelles/Décomptes': DocumentTypes.STATEMENT,
r'épargne logement': DocumentTypes.STATEMENT,
r'Livret(s) jeune': DocumentTypes.STATEMENT,
r'Compte(s) sur Livret': DocumentTypes.STATEMENT,
r'Récapitulatifs annuels': DocumentTypes.REPORT,
r"Avis d'exécution": DocumentTypes.REPORT,
r'Factures': DocumentTypes.BILL,
}
def get_document_type(family):
for patt, type in patterns.items():
if re.search(re.escape(patt), family):
return type
return DocumentTypes.OTHER
class TitulairePage(LoggedPage, JsonPage):
def get_titulaires(self):
return set([t['idKpiTitulaire'] for t in self.doc['data']['listeTitulairesDemat']['listeTitulaires']])
class DocumentsPage(LoggedPage, JsonPage):
@method
class iter_documents(DictElement):
item_xpath = 'data/rechercheCriteresDemat/*/*/listeDocument'
ignore_duplicate = True
class item(ItemElement):
klass = Document
def condition(self):
if 'ibanCrypte' in self.el:
return Env('sub_id')(self) in Dict('ibanCrypte')(self)
else:
return Env('sub_number')(self) in Dict('idContrat')(self)
obj_date = Date(Dict('dateDoc'), dayfirst=True)
obj_format = 'pdf'
obj_id = Format('%s_%s', Env('sub_id'), Dict('idDoc'))
def obj_label(self):
if 'ibanCrypte' in self.el:
return '%s %s N° %s' % (Dict('dateDoc')(self), Dict('libelleSousFamille')(self), Dict('numeroCompteAnonymise')(self))
else:
return '%s %s N° %s' % (Dict('dateDoc')(self), Dict('libelleSousFamille')(self), Dict('idContrat')(self))
def obj_url(self):
# For most of the cases on the json
if 'ibanCrypte' in self.el:
ibanCrypte = Dict('ibanCrypte')(self)
idDoc = Dict('idDoc')(self)
typeCompte = Dict('typeCompte')(self)
typeDoc = Dict('typeDoc')(self)
typeFamille = 'R001' # add typeFamille correctly for professional and private pages
idLocalisation = Dict('idLocalisation')(self)
viDocDocument = Dict('viDocDocument')(self)
famDoc = Dict('famDoc')(self)
consulted = Dict('consulted')(self)
dateDoc = Dict('dateDoc')(self)
return '%sdemat-wspl/rest/consultationDocumentDemat?'\
'ibanCrypte=%s&idDocument=%s&typeCpt=%s&typeDoc=%s&typeFamille=%s&idLocalisation=%s'\
'&viDocDocument=%s&familleDoc=%s&consulted=%s&dateDocument=%s&ikpiPersonne=' % (Env('baseurl')(self), ibanCrypte, idDoc, typeCompte,
typeDoc, typeFamille, idLocalisation, viDocDocument, famDoc, consulted, dateDoc)
# For the cases present on privee.mabanque where sometimes the doc url is the different
else:
idDoc = Dict('idDoc')(self)
numClient = Dict('numClient')(self)
heureDoc = Dict('heureDoc')(self)
idLocalisation = Dict('idLocalisation')(self)
viDocDocument = Dict('viDocDocument')(self)
typeReport = Dict('typeReport')(self)
dateDoc = Dict('dateDoc')(self)
return '%sdemat-wspl/rest/consultationDocumentSpecialBpfDemat?'\
'ibanCrypte=&idDocument=%s&numClient=%s&heureDocument=%s'\
'&idLocalisation=%s&typeReport=%s&viDocDocument=%s&dateDocument=%s' % (Env('baseurl')(self), idDoc, numClient,
heureDoc, idLocalisation, typeReport, viDocDocument, dateDoc)
def obj_type(self):
return get_document_type(Dict('libelleSousFamille')(self))
......@@ -30,7 +30,8 @@ import lxml.html as html
from weboob.browser.elements import DictElement, ListElement, TableElement, ItemElement, method
from weboob.browser.filters.json import Dict
from weboob.browser.filters.standard import (
Format, Eval, Regexp, CleanText, Date, CleanDecimal, Field, Coalesce, Map, Env, Currency,
Format, Eval, Regexp, CleanText, Date, CleanDecimal, Field, Coalesce, Map, Env,
Currency,
)
from weboob.browser.filters.html import TableCell
from weboob.browser.pages import JsonPage, LoggedPage, HTMLPage
......@@ -306,7 +307,6 @@ class ProfilePage(LoggedPage, JsonPage):
class AccountsPage(BNPPage):
@method
class iter_accounts(DictElement):
item_xpath = 'data/infoUdc/familleCompte'
......@@ -354,6 +354,8 @@ class AccountsPage(BNPPage):
obj_balance = Dict('soldeDispo')
obj_coming = Dict('soldeAVenir')
obj_number = Dict('value')
obj__subscriber = Format('%s %s', Dict('titulaire/nom'), Dict('titulaire/prenom'))
obj__iduser = Dict('titulaire/ikpi')
def obj_iban(self):
iban = Map(Dict('key'), Env('ibans')(self), default=NotAvailable)(self)
......@@ -381,6 +383,8 @@ class LoanDetailsPage(BNPPage):
obj_rate = Dict('data/tauxRemboursement')
obj_nb_payments_left = Dict('data/nbRemboursementRestant')
obj_next_payment_date = Date(Dict('data/dateProchainAmortissement'), dayfirst=True)
obj__subscriber = Format('%s %s', Dict('data/titulaire/nom'), Dict('data/titulaire/prenom'))
obj__iduser = None
@method
class fill_revolving_details(ItemElement):
......@@ -745,6 +749,8 @@ class CapitalisationPage(LoggedPage, HTMLPage):
obj_balance = CleanDecimal(TableCell('balance'), replace_dots=True)
obj_coming = None
obj_iban = None
obj__subscriber = None
obj__iduser = None
def obj_type(self):
for k, v in self.page.ACCOUNT_TYPES.items():
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment