Commit 2d6248de authored by Romain Bignon's avatar Romain Bignon

backport modules fixes

parent 630e57ba
Pipeline #2308 canceled with stages
......@@ -368,7 +368,8 @@ class BanquePopulaire(LoginBrowser):
self.location('/cyber/internet/Page.do', params=next_params)
if coming and account._coming_count:
for i in range(account._coming_count):
for i in range(account._coming_start,
account._coming_start + account._coming_count):
for tr in get_history_by_receipt(account, coming, sel_tbl1=i):
yield tr
else:
......
......@@ -310,26 +310,27 @@ class LoginPage(MyHTMLPage):
class MyVirtKeyboard(SplitKeyboard):
char_to_hash = {
'0': '6a2cb38bcfc27781faaec727ad304ce2',
'1': '296140f37a22b5e2b4871272aed22444',
'2': 'c1318fd381665a97e1052f85213867a7',
'3': 'fe19d2cc8f8d09b818b05c2a10218233',
'4': 'd5a03e69857bf01fc373cedbe2530ca9',
'5': '289ae90e4adfa58ef4767d9151c96348',
'6': '88938bbbb6b81ee2a32568f7081be488',
'7': '96499777fb95974ee651f19181de6c01',
'8': '6e2e052c9301d1f381155912ad4d3874',
'9': '5958d54d88bfaa172305575164b39a8d',
'0': 'cce0f72c47c74a3dde57c4fdbcda1db4',
'1': 'f5d22afb3ece4dec73bd8a2a4c2844da',
'2': '6d3e5db2ccac3f2c13c1f0ba22571857',
'3': ('c8e4f6addac4d322f0f9668d472a146c', '34d0566ea3f2330c675365da3178f6ab'),
'4': '8a8c769418ec829c208ed442fbf5fe77',
'5': '2c3ae480bc91f73b431b048b584026c7',
'6': 'a80d639443818e838b434c36dd518df5',
'7': '8e59048702e4c5f89bbbc1a598d06d1e',
'8': '46bc59a5b288c63477ff52811a3961c5',
'9': 'a7bf34568154ef91e990aa5bade3e946',
}
codesep = ' '
def convert(self, buffer):
im = Image.open(BytesIO(buffer))
im = im.resize((5, 8), Image.BILINEAR)
im = im.resize((5, 8), Image.BICUBIC)
im = im.filter(ImageFilter.UnsharpMask(radius=2,
percent=110,
threshold=3))
im = im.convert("P", dither=Image.NONE)
im = im.convert("L", dither=Image.NONE)
im = Image.eval(im, lambda x: 0 if x < 160 else 255)
s = BytesIO()
im.save(s, 'png')
......@@ -682,6 +683,11 @@ class CardsPage(LoggedPage, MyHTMLPage):
self.logger.debug('there are no cards on this page')
continue
# We are processing another card, so reset account
if CleanText('.')(cols[0]) and account is not None:
yield account
account = None
id = CleanText(None).filter(cols[self.COL_ID])
if len(id) > 0:
if account is not None:
......@@ -700,7 +706,15 @@ class CardsPage(LoggedPage, MyHTMLPage):
account._coming_params = params.copy()
account._coming_params['dialogActionPerformed'] = 'SELECTION_ENCOURS_CARTE'
account._coming_params['attribute($SEL_$%s)' % tr.attrib['id'].split('_')[0]] = tr.attrib['id'].split('_', 1)[1]
account._coming_count = len(self.doc.xpath('//table[@id="tbl1"]/tbody/tr/td[5]/span[not(contains(text(), "(1)"))]'))
# select current row and next rows till parent name is empty
account._coming_start = int(tr.attrib['id'].split('_', 1)[1])
account._coming_count = 1
for row in tr.xpath('./following-sibling::tr[./td[5]/span[not(contains(text(), "(1)"))]]'):
if CleanText('./td[2]')(row):
break
account._coming_count += 1
elif account is None:
raise BrokenPageError('Unable to find accounts on cards page')
else:
......
......@@ -30,6 +30,7 @@ from weboob.tools.capabilities.bank.investments import create_french_liquidity
from .pages import (
LoginPage, HomePage, AccountsPage, OldAccountsPage, HistoryPage, InvestmentPage, InvestDetailPage,
InvestmentListPage, QuestionPage, ChangePassPage, LogonFlowPage, ViewPage, SwitchPage,
HandlePasswordsPage, PostponePasswords,
)
......@@ -61,6 +62,8 @@ class BinckBrowser(LoginBrowser):
r'FsmaMandatoryQuestionnairesOverview', QuestionPage)
change_pass = URL(r'/ChangePassword/Index',
r'/EditSetting/GetSetting\?code=MutationPassword', ChangePassPage)
handle_passwords = URL(r'/PersonalCredentials/Index', HandlePasswordsPage)
postpone_passwords = URL(r'/PersonalCredentials/PostPone', PostponePasswords)
def deinit(self):
if self.page and self.page.logged:
......@@ -94,6 +97,13 @@ class BinckBrowser(LoginBrowser):
@need_login
def iter_accounts(self):
# If we already know that it is an old website connection,
# we can call old_website_connection() right away.
if self.old_website_connection:
for account in self.iter_old_accounts():
yield account
return
if self.unique_account:
self.account.stay_or_go()
else:
......@@ -121,41 +131,46 @@ class BinckBrowser(LoginBrowser):
# so we need to fetch them on the OldAccountsPage for now:
else:
self.old_website_connection = True
self.old_accounts.go()
for a in self.page.iter_accounts():
try:
self.old_accounts.stay_or_go().go_to_account(a.id)
except ServerError as exception:
# get html error to parse
parser = etree.HTMLParser()
html_error = etree.parse(StringIO(exception.response.text), parser)
account_error = html_error.xpath('//p[contains(text(), "Votre compte est")]/text()')
if account_error:
raise ActionNeeded(account_error[0])
else:
raise
a.iban = self.page.get_iban()
# Get token
token = self.page.get_token()
# Get investment page
data = {'grouping': "SecurityCategory"}
try:
a._invpage = self.investment.go(data=data, headers=token) \
if self.page.is_investment() else None
except HTTPNotFound:
# if it's not an invest account, the portfolio link may be present but hidden and return a 404
a._invpage = None
for account in self.iter_old_accounts():
yield account
@need_login
def iter_old_accounts(self):
self.old_accounts.go()
for a in self.page.iter_accounts():
try:
self.old_accounts.stay_or_go().go_to_account(a.id)
except ServerError as exception:
# get html error to parse
parser = etree.HTMLParser()
html_error = etree.parse(StringIO(exception.response.text), parser)
account_error = html_error.xpath('//p[contains(text(), "Votre compte est")]/text()')
if account_error:
raise ActionNeeded(account_error[0])
else:
raise
a.iban = self.page.get_iban()
# Get token
token = self.page.get_token()
# Get investment page
data = {'grouping': "SecurityCategory"}
try:
a._invpage = self.investment.go(data=data, headers=token) \
if self.page.is_investment() else None
except HTTPNotFound:
# if it's not an invest account, the portfolio link may be present but hidden and return a 404
a._invpage = None
if a._invpage:
a.valuation_diff = a._invpage.get_valuation_diff()
# Get history page
data = [('currencyCode', a.currency), ('startDate', ""), ('endDate', "")]
a._histpages = [self.history.go(data=data, headers=token)]
while self.page.doc['EndOfData'] is False:
a._histpages.append(self.history.go(data=self.page.get_nextpage_data(data[:]), headers=token))
if a._invpage:
a.valuation_diff = a._invpage.get_valuation_diff()
# Get history page
data = [('currencyCode', a.currency), ('startDate', ""), ('endDate', "")]
a._histpages = [self.history.go(data=data, headers=token)]
while self.page.doc['EndOfData'] is False:
a._histpages.append(self.history.go(data=self.page.get_nextpage_data(data[:]), headers=token))
yield a
yield a
@need_login
def iter_investment(self, account):
......
......@@ -47,6 +47,13 @@ class QuestionPage(HTMLPage):
form.submit()
class BinckPage(LoggedPage, HTMLPage):
# Used to factorize the get_token() method
def get_token(self):
return [{Attr('.', 'name')(input): Attr('.', 'value')(input)}
for input in self.doc.xpath('//input[contains(@name, "Token")]')][0]
class ViewPage(LoggedPage, HTMLPage):
# We automatically skip the new website tutorial
def on_load(self):
......@@ -75,6 +82,16 @@ class ChangePassPage(LoggedPage, HTMLPage):
raise BrowserPasswordExpired(message)
class HandlePasswordsPage(BinckPage):
def on_load(self):
token = self.get_token()
self.browser.postpone_passwords.go(headers=token, method='POST')
self.browser.home_page.go()
class PostponePasswords(LoggedPage, HTMLPage):
pass
class LogonFlowPage(HTMLPage):
def on_load(self):
raise ActionNeeded(CleanText('//article//h1 | //article//h3')(self.doc))
......@@ -91,7 +108,7 @@ class LoginPage(HTMLPage):
return CleanText('//div[contains(@class, "errors")]')(self.doc)
class AccountsPage(LoggedPage, HTMLPage):
class AccountsPage(BinckPage):
TYPES = {'L': Account.TYPE_SAVINGS,
'CT': Account.TYPE_MARKET,
'PEA': Account.TYPE_PEA,
......@@ -103,10 +120,6 @@ class AccountsPage(LoggedPage, HTMLPage):
def has_accounts_table(self):
return self.doc.xpath('//table[contains(@class, "accountoverview-table")]')
def get_token(self):
return [{Attr('.', 'name')(input): Attr('.', 'value')(input)} \
for input in self.doc.xpath('//input[contains(@name, "Token")]')][0]
@method
class iter_accounts(ListElement):
# Tables have no headers so we must use ListElement.
......@@ -135,7 +148,7 @@ class AccountsPage(LoggedPage, HTMLPage):
return Account.get_currency(CleanText('.//div[contains(text(), "Total des avoirs")]/following::strong[1]')(self))
class OldAccountsPage(LoggedPage, HTMLPage):
class OldAccountsPage(BinckPage):
'''
Old website accounts page. We can get rid of this
class when all users have access to the new website.
......@@ -154,10 +167,6 @@ class OldAccountsPage(LoggedPage, HTMLPage):
def get_iban(self):
return CleanText('//div[@class="iban"]/text()', replace=[(' ', '')], default=NotAvailable)(self.doc)
def get_token(self):
return [{Attr('.', 'name')(input): Attr('.', 'value')(input)} \
for input in self.doc.xpath('//input[contains(@name, "Token")]')][0]
def is_investment(self):
# warning: the link can be present even in case of non-investement account
return CleanText('//a[contains(@href, "Portfolio")]', default=False)(self.doc)
......
......@@ -146,8 +146,8 @@ class BNPEnterprise(LoginBrowser):
self.logger.debug('skipping coming %r', transaction.to_dict())
continue
history.append(transaction)
for transaction in sorted_transactions(history):
yield transaction
for transaction in sorted_transactions(history):
yield transaction
@need_login
def iter_coming_operations(self, account):
......
......@@ -116,11 +116,6 @@ class HistoryPage(LoggedPage, HTMLPage):
class item(ItemElement):
klass = Transaction
def obj_id(self):
label = CleanText(Attr('./a[contains(@class, "accordion_collapse")]', "id"))(self)
label = ''.join(i for i in label if i.isdigit())
return label
obj_date = Date(CleanText('./div[contains(@class, "accordion_header")]/div[1]/p'))
obj_category = CleanText('./div[contains(@class, "accordion_header")]/div[2]/p[1]')
obj_label = CleanText('./div[contains(@class, "accordion_header")]/div[3]/p[1]')
......
......@@ -65,7 +65,7 @@ class IbanPage(LoggedPage, HTMLPage):
if self.doc.xpath('//div[has-class("alert")]/p[contains(text(), "Une erreur est survenue")]') or \
self.doc.xpath('//div[has-class("alert")]/p[contains(text(), "Le compte est introuvable")]'):
return NotAvailable
return CleanText('//table[thead[tr[th[contains(text(), "Code I.B.A.N")]]]]/tbody/tr/td[2]', replace=[(' ', '')])(self.doc)
return CleanText('//div[strong[contains(text(),"IBAN")]]/div[contains(@class, "definition")]', replace=[(' ', '')])(self.doc)
class AuthenticationPage(HTMLPage):
......
......@@ -331,9 +331,13 @@ class ErrorCodePage(HTMLPage):
def on_load(self):
code = re.search(r'\/\?errorCode=(\d+)', self.url).group(1)
page = self.browser.open('/particuliers/compte-bancaire/comptes-en-ligne/bredconnect-compte-ligne?errorCode=%s' % code).page
# invalid login/password
if code == '20100':
msg = CleanText('//label[contains(@class, "error")]')(page.doc)
msg = CleanText('//label[contains(@class, "error")]', default=None)(page.doc)
# 20100: invalid login/password
# 139: dispobank user trying to connect to Bred
if code in ('20100', '139'):
raise BrowserIncorrectPassword(msg)
# 20104 & 1000: unknown error during login
elif code in ('20104', '1000'):
raise BrowserUnavailable(msg)
assert False, 'The % error is not handled.' % code
assert False, 'Error %s is not handled yet.' % code
This diff is collapsed.
This diff is collapsed.
......@@ -57,7 +57,7 @@ class ActionNeededPage(HTMLPage, LoggedPage):
# Need to update mail. Try to skip
msg = "Merci de renseigner votre adresse e-mail"
if CleanText('//p[@role="heading" and contains(text(), "%s")]' % msg)(self.doc):
url = Link('//a[contains(., "PASSER CETTE ETAPE")]')(self.doc)
url = Link('//a[contains(., "PASSER CETTE ETAPE")]', default=None)(self.doc)
if url:
self.browser.location(url)
else:
......
......@@ -33,7 +33,7 @@ from weboob.capabilities.base import find_object
from weboob.tools.capabilities.bank.transactions import sorted_transactions
from .pages import (
LogoutPage, InfosPage, AccountsPage, HistoryPage, LifeinsurancePage, MarketPage,
LogoutPage, AccountsPage, HistoryPage, LifeinsurancePage, MarketPage,
AdvisorPage, LoginPage, ProfilePage,
)
from .transfer_pages import TransferInfoPage, RecipientsListPage, TransferPage
......@@ -84,7 +84,6 @@ class CmsoParBrowser(LoginBrowser, StatesMixin):
logout = URL('/securityapi/revoke',
'/auth/errorauthn',
'/\/auth/errorauthn', LogoutPage)
infos = URL('/comptes/', InfosPage)
accounts = URL('/domiapi/oauth/json/accounts/synthese(?P<type>.*)', AccountsPage)
history = URL('/domiapi/oauth/json/accounts/(?P<page>.*)', HistoryPage)
loans = URL('/creditapi/rest/oauth/v1/synthese', AccountsPage)
......@@ -171,8 +170,7 @@ class CmsoParBrowser(LoginBrowser, StatesMixin):
accounts_eligibilite_debit = self.page.get_eligibilite_debit()
# First get all checking accounts...
data = dict(self.infos.stay_or_go().get_typelist())
self.accounts.go(data=json.dumps(data), type='comptes', headers=self.json_headers)
self.accounts.go(json={'typeListeCompte': 'COMPTE_SOLDE_COMPTES_CHEQUES'}, type='comptes')
self.page.check_response()
for key in self.page.get_keys():
for a in self.page.iter_accounts(key=key):
......
......@@ -55,15 +55,6 @@ class LogoutPage(RawPage):
pass
class InfosPage(LoggedPage, HTMLPage):
def get_typelist(self):
url = Attr(None, 'src').filter(self.doc.xpath('//script[contains(@src, "comptes/scripts")]'))
m = re.findall(r'synthesecomptes[^\w]+([^:]+)[^\w]+([^"]+)', self.browser.open(url).text)
for data in m:
if data[0] != 'method':
return {data[0]: data[1]}
class AccountsPage(LoggedPage, JsonPage):
TYPES = OrderedDict([('courant', Account.TYPE_CHECKING),
('pee', Account.TYPE_PEE),
......
......@@ -29,7 +29,7 @@ from weboob.browser.filters.html import Link, Attr, TableCell
from .compat.weboob_capabilities_bank import Account, Investment
from weboob.capabilities.base import NotAvailable
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
from weboob.tools.compat import urljoin
from weboob.tools.compat import urljoin, parse_qsl
from weboob.tools.capabilities.bank.investments import is_isin_valid
......@@ -284,9 +284,13 @@ class SSODomiPage(JsonPage, UpdateTokenMixin):
class TokenPage(CMSOPage, UpdateTokenMixin):
def on_load(self):
d = re.search(r'id_token=(?P<id_token>[^&]+)&access_token=(?P<access_token>[^&]+)', self.text).groupdict()
self.browser.token = d['id_token']
self.browser.csrf = d['access_token']
auth_query_params = re.search(r'parent\.location = ".*#(.*)";', self.text)
assert auth_query_params, 'Url query parameter with token for authentication was not found'
auth_query_params = auth_query_params.group(1)
params = dict(parse_qsl(auth_query_params))
self.browser.token = params['id_token']
self.browser.csrf = params['access_token']
class AuthCheckUser(HTMLPage):
......
......@@ -139,6 +139,7 @@ class item_account_generic(ItemElement):
('C/C', Account.TYPE_CHECKING),
('Start', Account.TYPE_CHECKING),
('Comptes courants', Account.TYPE_CHECKING),
('Service Accueil', Account.TYPE_CHECKING),
('Catip', Account.TYPE_DEPOSIT),
('Cic Immo', Account.TYPE_LOAN),
('Credit', Account.TYPE_LOAN),
......
......@@ -38,84 +38,84 @@ class GoogleTranslateModule(Module, CapTranslate):
NAME = 'googletranslate'
DESCRIPTION = u'Google translation web service'
BROWSER = GoogleTranslateBrowser
GOOGLELANGUAGE = {
'Arabic': 'ar',
'Afrikaans': 'af',
'Albanian': 'sq',
'Armenian': 'hy',
'Azerbaijani': 'az',
'Basque': 'eu',
'Belarusian': 'be',
'Bengali': 'bn',
'Bulgarian': 'bg',
'Catalan': 'ca',
'Chinese': 'zh-CN',
'Croatian': 'hr',
'Czech': 'cs',
'Danish': 'da',
'Dutch': 'nl',
'English': 'en',
'Esperanto': 'eo',
'Estonian': 'et',
'Filipino': 'tl',
'Finnish': 'fi',
'French': 'fr',
'Galician': 'gl',
'Georgian': 'ka',
'German': 'de',
'Greek': 'el',
'Gujarati': 'gu',
'Haitian': 'ht',
'Hebrew': 'iw',
'Hindi': 'hi',
'Hungaric': 'hu',
'Icelandic': 'is',
'Indonesian': 'id',
'Irish': 'ga',
'Italian': 'it',
'Japanese': 'ja',
'Kannada': 'kn',
'Korean': 'ko',
'Latin': 'la',
'Latvian': 'lv',
'Lithuanian': 'lt',
'Macedonian': 'mk',
'Malay': 'ms',
'Maltese': 'mt',
'Norwegian': 'no',
'Persian': 'fa',
'Polish': 'pl',
'Portuguese': 'pt',
'Romanian': 'ro',
'Russian': 'ru',
'Serbian': 'sr',
'Slovak': 'sk',
'Slovenian': 'sl',
'Spanish': 'es',
'Swahili': 'sw',
'Swedish': 'sv',
'Tamil': 'ta',
'Telugu': 'te',
'Thai': 'th',
'Turkish': 'tr',
'Ukrainian': 'uk',
'Urdu': 'ur',
'Vietnamese': 'vi',
'Welsh': 'cy',
'Yiddish': 'yi',
}
GOOGLELANGUAGE = [
'ar',
'af',
'sq',
'hy',
'az',
'eu',
'be',
'bn',
'bg',
'ca',
'zh-CN',
'hr',
'cs',
'da',
'nl',
'en',
'eo',
'et',
'tl',
'fi',
'fr',
'gl',
'ka',
'de',
'el',
'gu',
'ht',
'iw',
'hi',
'hu',
'is',
'id',
'ga',
'it',
'ja',
'kn',
'ko',
'la',
'lv',
'lt',
'mk',
'ms',
'mt',
'no',
'fa',
'pl',
'pt',
'ro',
'ru',
'sr',
'sk',
'sl',
'es',
'sw',
'sv',
'ta',
'te',
'th',
'tr',
'uk',
'ur',
'vi',
'cy',
'yi',
]
def translate(self, lan_from, lan_to, text):
if lan_from not in self.GOOGLELANGUAGE.keys():
if lan_from not in self.GOOGLELANGUAGE:
raise LanguageNotSupported()
if lan_to not in self.GOOGLELANGUAGE.keys():
if lan_to not in self.GOOGLELANGUAGE:
raise LanguageNotSupported()
translation = Translation(0)
translation.lang_src = self.GOOGLELANGUAGE[lan_from]
translation.lang_dst = self.GOOGLELANGUAGE[lan_to]
translation.text = self.browser.translate(self.GOOGLELANGUAGE[lan_from], self.GOOGLELANGUAGE[lan_to], text)
translation.lang_src = lan_from
translation.lang_dst = lan_to
translation.text = self.browser.translate(lan_from, lan_to, text)
if empty(translation.text):
raise TranslationFail()
......
......@@ -25,13 +25,10 @@ from .pages import LangList, WordPage
class LarousseBrowser(PagesBrowser):
BASEURL = 'http://www.larousse.fr'
BASEURL = 'https://www.larousse.fr'
langlist = URL('/dictionnaires/bilingues$', LangList)
# warning: the order of params is important...
word = URL(r'/dictionnaires/rechercher\?q=(?P<word>.*)&l=(?P<src>\w+)-(?P<dst>\w+)&culture=',
r'/dictionnaires/(?P<src>\w+)-(?P<dst>\w+)/(?P<word>[^/]+)(?:/(?P<id>\d+))?',
WordPage)
word = URL(r'/dictionnaires/(?P<src>\w+)-(?P<dst>\w+)/(?P<word>.*)', WordPage)
LANGS = None
......
......@@ -27,13 +27,13 @@ from .compat.weboob_browser_filters_standard import Env, CleanText
from weboob.browser.pages import HTMLPage
CODES = {
'allemand': 'German',
'anglais': 'English',
'arabe': 'Arabic',
'chinois': 'Chinese',
'espagnol': 'Spanish',
'francais': 'French',
'italien': 'Italian',
'allemand': 'de',
'anglais': 'en',
'arabe': 'ar',
'chinois': 'zh',
'espagnol': 'es',
'francais': 'fr',
'italien': 'it',
}
RCODES = {v: k for k, v in CODES.items()}
......@@ -41,14 +41,12 @@ RCODES = {v: k for k, v in CODES.items()}
class LangList(HTMLPage):
def get_langs(self):
res = {}
for a in self.doc.xpath('//ul[@class="menu-items"]/li//a'):
for a in self.doc.xpath('//a[@class="item-dico-bil"]'):
url = a.attrib['href']
mtc = re.search(r'/dictionnaires/(\w+)-(\w+)', url)
if not mtc:
continue
src, dst = mtc.groups()
if dst == 'monolingue':
continue
res[CODES[src], CODES[dst]] = (src, dst)
return res
......
......@@ -145,7 +145,7 @@ class LCLModule(Module, CapBankWealth, CapBankTransferAddRecipient, CapContact,
return self.browser.execute_transfer(transfer)
def transfer_check_label(self, old, new):
old = re.sub(r"[/<\?='!\+:]", '', old).strip()
old = re.sub(r"[/<\?='!\+:#]", '', old).strip()
old = old.encode('latin-1', errors='replace').decode('latin-1')
# if no reason given, the site changes the label
if not old and ("INTERNET-FAVEUR" in new):
......
......@@ -191,7 +191,8 @@ class AMFAmundiPage(HTMLPage):
CODE_TYPE = Investment.CODE_TYPE_AMF
def get_code(self):
return Regexp(CleanText('//td[@class="bannerColumn"]//li[contains(., "(C)")]', default=NotAvailable), r'(\d+)')(self.doc)
return Regexp(CleanText('//td[@class="bannerColumn"]//li[contains(., "(C)")]', default=NotAvailable),
r'(\d+)', default=NotAvailable)(self.doc)
class AMFSGPage(HTMLPage):
......@@ -384,6 +385,8 @@ class AccountsPage(LoggedPage, MultiPage):
obj_label = Env('label')
def obj_type(self):
if Field('label')(self).startswith('ETOILE'):
return self.page.TYPES.get(Field('label')(self).split()[1].upper(), Account.TYPE_UNKNOWN)
return self.page.TYPES.get(Field('label')(self).split()[0].upper(), Account.TYPE_UNKNOWN)
def obj_balance(self):
......
......@@ -26,7 +26,7 @@ from weboob.browser.browsers import LoginBrowser, need_login, StatesMixin
from weboob.browser.url import URL
from weboob.browser.exceptions import ClientError
from weboob.exceptions import BrowserIncorrectPassword, ActionNeeded, NoAccountsException
from weboob.capabilities.base import find_object
from weboob.capabilities.base import find_object, NotAvailable
from .compat.weboob_capabilities_bank import (
AccountNotFound, RecipientNotFound, AddRecipientStep, AddRecipientBankError,
Recipient, TransferBankError, AccountOwnerType,
......@@ -36,7 +36,7 @@ from weboob.tools.value import Value
from .pages import (
LoginPage, CardsPage, CardHistoryPage, IncorrectLoginPage,
ProfileProPage, ProfileEntPage, ChangePassPage, SubscriptionPage, InscriptionPage,
ErrorPage, UselessPage,
ErrorPage, UselessPage, MainPage, MarketAccountPage, MarketInvestmentPage,
)
from .json_pages import (
AccountsJsonPage, BalancesJsonPage, HistoryJsonPage, BankStatementPage,
......@@ -107,6 +107,10 @@ class SGPEBrowser(LoginBrowser):
@need_login
def get_cb_operations(self, account):
if account.type in (account.TYPE_MARKET, ):
# market account transactions are in checking account
return
self.location('/Pgn/NavigationServlet?PageID=Cartes&MenuID=%sOPF&Classeur=1&NumeroPage=1&Rib=%s&Devise=%s' % (self.MENUID, account.id, account.currency))
if self.inscription_page.is_here():
......@@ -132,6 +136,8 @@ class SGEnterpriseBrowser(SGPEBrowser):
MENUID = 'BANREL'
CERTHASH = '2231d5ddb97d2950d5e6fc4d986c23be4cd231c31ad530942343a8fdcc44bb99'
main_page = URL('/icd-web/syd-front/index-comptes.html', MainPage)
accounts = URL('/icd/syd-front/data/syd-comptes-accederDepuisMenu.json', AccountsJsonPage)
intraday_accounts = URL('/icd/syd-front/data/syd-intraday-accederDepuisMenu.json', AccountsJsonPage)
......@@ -142,6 +148,13 @@ class SGEnterpriseBrowser(SGPEBrowser):
'/icd/syd-front/data/syd-intraday-chargerDetail.json', HistoryJsonPage)
history_next = URL('/icd/syd-front/data/syd-comptes-chargerProchainLotEcriture.json', HistoryJsonPage)
market_investment = URL(r'/Pgn/NavigationServlet\?.*PageID=CompteTitreDetailFrame',
r'/Pgn/NavigationServlet\?.*PageID=CompteTitreDetail',
MarketInvestmentPage)
market_accounts = URL(r'/Pgn/NavigationServlet\?.*PageID=CompteTitreFrame',
r'/Pgn/NavigationServlet\?.*PageID=CompteTitre',
MarketAccountPage)
profile = URL('/gae/afficherModificationMesDonnees.html', ProfileEntPage)
subscription = URL(r'/Pgn/NavigationServlet\?MenuID=BANRELRIE&PageID=ReleveRIE&NumeroPage=1&Origine=Menu', SubscriptionPage)
......@@ -177,14 +190,37 @@ class SGEnterpriseBrowser(SGPEBrowser):
acc.owner_type = AccountOwnerType.ORGANIZATION
yield acc
# retrieve market accounts if exist
for market_account in self.iter_market_accounts():