The new woob repository is here: https://gitlab.com/woob/woob. This gitlab will be removed soon.

The new woob repository is here: https://gitlab.com/woob/woob. This gitlab will be removed soon.

Commit 8f6ccb18 authored by Florian Duguet's avatar Florian Duguet Committed by Vincent A

[banquepopulaire] Add CapDocument to get bank statements

parent a5617121
......@@ -21,9 +21,11 @@
import re
from datetime import datetime
from collections import OrderedDict
from functools import wraps
from dateutil.relativedelta import relativedelta
from weboob.exceptions import BrowserIncorrectPassword, BrowserUnavailable
from weboob.browser.exceptions import HTTPNotFound, ServerError
from weboob.browser import LoginBrowser, URL, need_login
......@@ -41,6 +43,8 @@
LineboursePage, AlreadyLoginPage,
)
from .document_pages import BasicTokenPage, SubscriberPage, SubscriptionsPage, DocumentsPage
from .linebourse_browser import LinebourseBrowser
......@@ -169,6 +173,11 @@ class BanquePopulaire(LoginBrowser):
advisor = URL(r'https://[^/]+/cyber/internet/StartTask.do\?taskInfoOID=accueil.*',
r'https://[^/]+/cyber/internet/StartTask.do\?taskInfoOID=contacter.*', AdvisorPage)
basic_token_page = URL(r'/SRVATE/context/mde/1.1.5', BasicTokenPage)
subscriber_page = URL(r'https://[^/]+/api-bp/wapi/2.0/abonnes/current/mes-documents-electroniques', SubscriberPage)
subscription_page = URL(r'https://[^/]+/api-bp/wapi/2.0/abonnes/current/contrats', SubscriptionsPage)
documents_page = URL(r'/api-bp/wapi/2.0/abonnes/current/documents/recherche-avancee', DocumentsPage)
def __init__(self, website, *args, **kwargs):
self.BASEURL = 'https://%s' % website
# this url is required because the creditmaritime abstract uses an other url
......@@ -186,6 +195,7 @@ def __init__(self, website, *args, **kwargs):
self.linebourse = LinebourseBrowser('https://www.linebourse.fr', logger=self.logger, responses_dirname=dirname, weboob=self.weboob, proxy=self.PROXIES)
self.investments = {}
self.documents_headers = None
def deinit(self):
super(BanquePopulaire, self).deinit()
......@@ -563,6 +573,45 @@ def get_advisor(self):
self.page.update_agency(advisor)
return iter([advisor])
@need_login
def iter_subscriptions(self):
self.location('/SRVATE/context/mde/1.1.5')
headers = {'Authorization': 'Basic %s' % self.page.get_basic_token()}
response = self.location('/as-bp/as/2.0/tokens', method='POST', headers=headers)
self.documents_headers = {'Authorization': 'Bearer %s' % response.json()['access_token']}
self.location('/api-bp/wapi/2.0/abonnes/current/mes-documents-electroniques', headers=self.documents_headers)
subscriber = self.page.get_subscriber()
params = {'type': 'dematerialisationEffective'}
self.location('/api-bp/wapi/2.0/abonnes/current/contrats', params=params, headers=self.documents_headers)
return self.page.get_subscriptions(subscriber=subscriber)
@need_login
def iter_documents(self, subscription):
now = datetime.now()
# website says we can't get documents more than one year range at once but it seems it's just a javascript check
# no problem here so far
first_date = now - relativedelta(years=5)
start_date = first_date.strftime('%Y-%m-%dT00:00:00.000+00:00')
end_date = now.strftime('%Y-%m-%dT%H:%M:%S.000+00:00')
body = {
'inTypeRecherche': {'type': 'typeRechercheDocument', 'code': 'DEMAT'},
'inDateDebut': start_date,
'inDateFin': end_date,
'inListeIdentifiantsContrats': [
{'identifiantContrat': {'identifiant': subscription.id, 'codeBanque': subscription._bank_code}}
],
'inListeTypesDocuments': [
{'typeDocument': {'code': 'EXTRAIT', 'label': 'Extrait de compte', 'type': 'referenceLogiqueDocument'}}
]
}
self.location('/api-bp/wapi/2.0/abonnes/current/documents/recherche-avancee', json=body, headers=self.documents_headers)
return self.page.iter_documents(subid=subscription.id)
def download_document(self, document):
return self.open(document.url, headers=self.documents_headers).content
class iter_retry(object):
# when the callback is retried, it will create a new iterator, but we may already yielded
......
# -*- coding: utf-8 -*-
# Copyright(C) 2012 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 base64
from weboob.browser.elements import method, DictElement, ItemElement
from weboob.browser.filters.standard import Date, Env, Format
from weboob.browser.filters.json import Dict
from weboob.capabilities.bill import Subscription, Document, DocumentTypes
from weboob.browser.pages import LoggedPage, JsonPage
class BasicTokenPage(LoggedPage, JsonPage):
def get_basic_token(self):
token = ('BP_MDE.RIA_PROD_1.0:%s' % self.doc['appContext']['clientSecret']).encode('utf-8')
return base64.b64encode(token).decode('utf-8')
class SubscriberPage(LoggedPage, JsonPage):
def get_subscriber(self):
return self.doc['nomRaisonSociale']
class SubscriptionsPage(LoggedPage, JsonPage):
@method
class get_subscriptions(DictElement):
item_xpath = '_embedded/content'
class item(ItemElement):
klass = Subscription
obj_id = Dict('idContrat/identifiant')
obj_subscriber = Env('subscriber')
obj_label = Dict('intituleContrat')
obj__bank_code = Dict('idContrat/codeBanque')
class DocumentsPage(LoggedPage, JsonPage):
@method
class iter_documents(DictElement):
item_xpath = '_embedded/content'
def condition(self):
return '_embedded' in self.page.doc
class item(ItemElement):
klass = Document
obj_id = Format('%s_%s', Env('subid'), Dict('identifiantDocument/identifiant'))
obj_date = Date(Dict('dateCreation'))
obj_label = Dict('libelle')
obj_format = 'pdf'
obj_type = DocumentTypes.STATEMENT
obj_url = Dict('_links/document/href')
......@@ -23,6 +23,10 @@
from functools import reduce
from weboob.capabilities.bank import CapBankWealth, AccountNotFound
from weboob.capabilities.base import find_object
from weboob.capabilities.bill import (
CapDocument, SubscriptionNotFound, DocumentNotFound, Document, Subscription, DocumentTypes,
)
from weboob.capabilities.contact import CapContact
from weboob.capabilities.profile import CapProfile
from weboob.tools.backend import Module, BackendConfig
......@@ -34,7 +38,7 @@
__all__ = ['BanquePopulaireModule']
class BanquePopulaireModule(Module, CapBankWealth, CapContact, CapProfile):
class BanquePopulaireModule(Module, CapBankWealth, CapContact, CapProfile, CapDocument):
NAME = 'banquepopulaire'
MAINTAINER = 'Romain Bignon'
EMAIL = 'romain@weboob.org'
......@@ -70,6 +74,8 @@ class BanquePopulaireModule(Module, CapBankWealth, CapContact, CapProfile):
ValueBackendPassword('password', label='Mot de passe'))
BROWSER = BanquePopulaire
accepted_document_types = (DocumentTypes.STATEMENT,)
def create_default_browser(self):
repls = [
('alsace', 'bpalc'),
......@@ -112,3 +118,26 @@ def iter_contacts(self):
def get_profile(self):
return self.browser.get_profile()
def iter_subscription(self):
return self.browser.iter_subscriptions()
def iter_documents(self, subscription):
if not isinstance(subscription, Subscription):
subscription = self.get_subscription(subscription)
return self.browser.iter_documents(subscription)
def get_subscription(self, _id):
return find_object(self.iter_subscription(), id=_id, error=SubscriptionNotFound)
def get_document(self, _id):
subid = _id.rsplit('_', 1)[0]
subscription = self.get_subscription(subid)
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.download_document(document)
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