Commit 32208c6f authored by Lucas Ficheux's avatar Lucas Ficheux Committed by Vincent A

[bnpcards] Added new site and siteswitch from old site to new site

Added new PhenixBrowser to the module to handle the new site.
All connections with type 1 (cardholder) will be redirected towards the new website.
parent 39d0a931
......@@ -73,6 +73,8 @@ class BnpcartesentrepriseBrowser(LoginBrowser):
def do_login(self):
assert isinstance(self.username, basestring)
assert isinstance(self.password, basestring)
if self.type == '1':
raise SiteSwitch('phenix')
self.login.stay_or_go()
assert self.login.is_here()
self.page.login(self.type, self.username, self.password)
......
# -*- coding: utf-8 -*-
# Copyright(C) 2019 Budget Insight
#
# 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 weboob.exceptions import BrowserIncorrectPassword, BrowserPasswordExpired
from weboob.browser import LoginBrowser, URL, need_login
from .pages import (
LoginPage, DashboardPage, TransactionPage, TransactionCSV,
PasswordExpiredPage,
)
__all__ = ['BnpcartesentreprisePhenixBrowser']
class BnpcartesentreprisePhenixBrowser(LoginBrowser):
BASEURL = 'https://corporatecards.bnpparibas.com'
login_cas = URL(r'https://cartesentreprise-oidc.phenix.bnpparibas/login', LoginPage)
login = URL(r'/login', LoginPage)
dashboard = URL(r'/group/bddf/dashboard', DashboardPage)
transaction_csv = URL(
r'/group/bddf/transactions\?p_p_id=Phenix_Transactions_Portlet_INSTANCE_(?P<instance_id1>.*)'
r'&p_p_lifecycle=2&p_p_state=normal&p_p_mode=view&p_p_resource_id=/transaction/export&p_p_cacheability=cacheLevelPage&'
r'_Phenix_Transactions_Portlet_INSTANCE_(?P<instance_id2>.*)_MVCResourceCommand=/transaction/export',
TransactionCSV
)
transactions_page = URL(r'/group/bddf/transactions', TransactionPage)
password_expired = URL(r'https://corporatecards.bnpparibas.com/group/bddf/mot-de-passe-expire', PasswordExpiredPage)
def __init__(self, website, *args, **kwargs):
super(BnpcartesentreprisePhenixBrowser, self).__init__(*args, **kwargs)
self.website = website
def do_login(self):
self.login_cas.go()
self.page.login(self.username, self.password)
if not(self.page.is_logged()):
raise BrowserIncorrectPassword(self.page.get_error_message())
self.dashboard.go()
if self.password_expired.is_here():
raise BrowserPasswordExpired(self.page.get_error_message())
@need_login
def iter_accounts(self):
self.dashboard.go()
for account in self.page.iter_accounts():
self.location(account.url)
yield self.page.fill_account(obj=account)
@need_login
def get_transactions(self, account):
self.dashboard.stay_or_go()
self.location(account.url)
self.transactions_page.go()
instance_id = self.page.get_instance_id()
page_csv = self.transaction_csv.open(method="POST", instance_id1=instance_id, instance_id2=instance_id)
for tr in page_csv.iter_history():
yield tr
# -*- coding: utf-8 -*-
# Copyright(C) 2019 Budget Insight
#
# 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 sys
from datetime import date
from weboob.browser.filters.standard import (
CleanText, CleanDecimal, Date, MapIn, Field,
Currency, Regexp, Format, Eval,
)
from weboob.browser.filters.json import Dict
from weboob.browser.filters.html import Attr, Link
from weboob.capabilities.bank import Account, Transaction
from weboob.browser.elements import (
DictElement, ListElement, ItemElement, method,
)
from weboob.capabilities.base import NotAvailable
from weboob.tools.compat import unicode
from weboob.browser.pages import HTMLPage, LoggedPage, CsvPage
class LoginPage(HTMLPage):
def login(self, username, password):
form = self.get_form(id='fm1')
form['username'] = username
form['password'] = password
form.submit()
def get_error_message(self):
return CleanText('//div[@class="alert alert-danger"]')(self.doc)
def is_logged(self):
return CleanText('//div[@id="successTextBloc"]/h2')(self.doc) == 'Log In Successful'
class DashboardPage(LoggedPage, HTMLPage):
@method
class iter_accounts(ListElement):
item_xpath = '//div[@class="container header_desktop"]//a[@class="carte"]'
class item(ItemElement):
klass = Account
def condition(self):
return CleanText('./span[@class="lanNavSel_succes_carte"]')(self)
obj_url = Link('.')
@method
class fill_account(ItemElement):
obj_type = Account.TYPE_CARD
# most xpaths in the module are long and strict because the html contains multiple versions of
# the site that are displayed or not via js depending on the size of the screen
# they are not displayed but still present, so the xpaths can catch them
# and we want to avoid that
obj_number = CleanText('//div[@class="row bnp_carte_dashboard_one"]//span[@id="carte_dashboard_numero_compte"]')
obj_id = Field('number')
obj_label = Format(
'%s %s',
CleanText('//div[@class="row bnp_carte_dashboard_one"]//span[@id="carte_dashboard_title"]'),
CleanText('//div[contains(@class,"hidden-xs")]//div[contains(@class,"bnp_info_general_one")]//ul[@class="list-group bnp_information"]/li[2]')
)
# TODO Handle 'Fin du mois'
obj_paydate = Date(
Regexp(
CleanText('//div[@class="row prelevement"]/div[@class="prelevement-box"][1]/span[@class="prelevement_le"]'),
r'(\d{2}/\d{2}/\d{4})',
default=NotAvailable
),
dayfirst=True,
default=NotAvailable
)
obj_currency = Currency(
CleanText('//div[@class="plafondStyle"]//p[@class="paiement_content_color"]')
)
obj_coming = Eval(
lambda x, y: x + y,
CleanDecimal.French('//div[contains(@class, "hidden-xs")]//div[contains(@class, "cumul_content_dashboard")]//span[@class = "content_paiement"]', default=NotAvailable),
CleanDecimal.French('//div[contains(@class, "hidden-xs")]//div[contains(@class, "cumul_content_dashboard")]//span[@class = "content_retrait"]', default=NotAvailable)
)
class TransactionPage(LoggedPage, HTMLPage):
def get_instance_id(self):
return Regexp(
Attr('//span[contains(@id,"p_Phenix_Transactions_Portlet_INSTANCE_")]', 'id'),
r'INSTANCE_([^_]*)'
)(self.doc)
class TransactionCSV(LoggedPage, CsvPage):
HEADER = 9
FMTPARAMS = {'delimiter': ';'}
def build_doc(self, content):
# Dict splits keys on '/' it is intended behaviour because it's primary
# use is with json files, but it means I have to replace '/' here
delimiter = self.FMTPARAMS.get('delimiter')
if sys.version_info.major == 2 and delimiter and isinstance(delimiter, unicode):
self.FMTPARAMS['delimiter'] = delimiter.encode('utf-8')
content = content.replace(b'/', b'-')
return super(TransactionCSV, self).build_doc(content)
@method
class iter_history(DictElement):
class item(ItemElement):
klass = Transaction
TRANSACTION_TYPES = {
'FACTURE CB': Transaction.TYPE_CARD,
'RETRAIT CB': Transaction.TYPE_WITHDRAWAL,
}
obj_label = CleanText(Dict('Raison sociale commerçant'))
obj_amount = CleanDecimal.French(Dict('Montant EUR'))
obj_original_currency = CleanText(Dict("Devise d'origine"))
obj_rdate = Date(CleanText(Dict("Date d'opération")), dayfirst=True)
obj_date = Date(CleanText(Dict('Date débit-crédit')), dayfirst=True)
obj_type = MapIn(
CleanText(Dict('Libellé opération')),
TRANSACTION_TYPES
)
def obj_commission(self):
commission = CleanDecimal.French(Dict('Commission'))(self)
if commission != 0: # We don't want to return null commissions
return commission
return NotAvailable
def obj_original_amount(self):
original_amount = CleanDecimal.French(Dict("Montant d'origine"))(self)
if original_amount != 0: # We don't want to return null original_amounts
return original_amount
return NotAvailable
def obj__coming(self):
return Field('date')(self) >= date.today()
class PasswordExpiredPage(LoggedPage, HTMLPage):
def get_error_message(self):
return CleanText('//span[@class="messageWarning"]')(self.doc)
......@@ -22,10 +22,12 @@ from weboob.browser.switch import SwitchingBrowser
from .browser import BnpcartesentrepriseBrowser
from .corporate.browser import BnpcartesentrepriseCorporateBrowser
from .phenix.browser import BnpcartesentreprisePhenixBrowser
class ProxyBrowser(SwitchingBrowser):
BROWSERS = {
'main': BnpcartesentrepriseBrowser,
'corporate': BnpcartesentrepriseCorporateBrowser,
'phenix': BnpcartesentreprisePhenixBrowser,
}
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