Commit 1bfb0af7 authored by Romain Bignon's avatar Romain Bignon

Update of modules

parent e37d8dbb
......@@ -55,6 +55,10 @@ class IndexPage(LoggedPage, HTMLPage):
if "prendre connaissance des nouvelles conditions" in msg:
raise ActionNeeded(msg)
msg = CleanText('//span[@id="txtErrorAccesBase"]')(self.doc)
if 'Merci de nous envoyer' in msg:
raise ActionNeeded(msg)
# website sometime crash
if self.doc.xpath(u'//div[@id="divError"]/span[contains(text(),"Une erreur est survenue")]'):
raise BrowserUnavailable()
......
......@@ -71,7 +71,7 @@ class AmazonBrowser(LoginBrowser, StatesMixin):
super(AmazonBrowser, self).__init__(*args, **kwargs)
def locate_browser(self, state):
pass
self.location(state['url'])
def push_security_otp(self, pin_code):
res_form = self.otp_form
......@@ -181,11 +181,12 @@ class AmazonBrowser(LoginBrowser, StatesMixin):
@need_login
def iter_documents(self, subscription):
documents = []
for y in range(date.today().year - 2, date.today().year + 1):
self.documents.go(year=y)
year = date.today().year
old_year = year - 2
while year >= old_year:
self.documents.go(year=year)
request_id = self.page.response.headers['x-amz-rid']
for doc in self.page.iter_documents(subid=subscription.id, currency=self.CURRENCY, request_id=request_id):
documents.append(doc)
return documents
yield doc
year -= 1
......@@ -20,11 +20,10 @@
from __future__ import unicode_literals
from collections import OrderedDict
from weboob.capabilities.bill import CapDocument, Subscription, Document, SubscriptionNotFound, DocumentNotFound
from weboob.capabilities.bill import DocumentTypes, CapDocument, Subscription, Document, SubscriptionNotFound, DocumentNotFound
from weboob.capabilities.base import find_object, NotAvailable
from weboob.tools.backend import Module, BackendConfig
from weboob.tools.value import ValueBackendPassword, Value
from weboob.tools.pdf import html_to_pdf
from .browser import AmazonBrowser
from .en.browser import AmazonEnBrowser
......@@ -64,6 +63,8 @@ class AmazonModule(Module, CapDocument):
Value('pin_code', label='OTP response', required=False, default='')
)
accepted_document_types = (DocumentTypes.BILL,)
def create_default_browser(self):
self.BROWSER = self.BROWSERS[self.config['website'].get()]
return self.create_browser(self.config)
......@@ -92,11 +93,3 @@ class AmazonModule(Module, CapDocument):
return
return self.browser.open(document.url).content
def download_document_pdf(self, document):
if not isinstance(document, Document):
document = self.get_document(document)
if document.url is NotAvailable:
return
return html_to_pdf(self.browser, url=self.browser.BASEURL + document.url)
......@@ -26,7 +26,7 @@ from weboob.browser.filters.standard import (
CleanText, CleanDecimal, Env, Regexp, Format,
Field, Currency, RegexpError, Date, Async, AsyncLoad
)
from weboob.capabilities.bill import Bill, Subscription
from weboob.capabilities.bill import DocumentTypes, Bill, Subscription
from weboob.capabilities.base import NotAvailable
from weboob.tools.date import parse_french_date
......@@ -131,7 +131,7 @@ class DocumentsPage(LoggedPage, HTMLPage):
obj_url = Async('details') & Link('//a[contains(@href, "download")]|//a[contains(@href, "generated_invoices")]')
obj_format = 'pdf'
obj_label = Format('Facture %s', Field('_simple_id'))
obj_type = 'bill'
obj_type = DocumentTypes.BILL
def obj_date(self):
date = Date(CleanText('.//div[has-class("a-span4") and not(has-class("recipient"))]/div[2]'),
......
......@@ -19,7 +19,7 @@
from __future__ import unicode_literals
from weboob.capabilities.bill import CapDocument, SubscriptionNotFound, DocumentNotFound, Subscription, Bill
from weboob.capabilities.bill import DocumentTypes, CapDocument, SubscriptionNotFound, DocumentNotFound, Subscription, Bill
from weboob.tools.backend import Module, BackendConfig
from weboob.tools.value import ValueBackendPassword
from .browser import AmeliBrowser
......@@ -38,6 +38,8 @@ class AmeliModule(Module, CapDocument):
CONFIG = BackendConfig(ValueBackendPassword('login', label='Numero de SS', regexp=r'^\d{13}$', masked=False),
ValueBackendPassword('password', label='Password', masked=True))
accepted_document_types = (DocumentTypes.BILL,)
def create_default_browser(self):
return self.create_browser(self.config['login'].get(),
self.config['password'].get())
......
......@@ -25,7 +25,7 @@ from decimal import Decimal
from weboob.browser.filters.html import Attr, XPathNotFound
from weboob.browser.pages import HTMLPage, RawPage, LoggedPage
from weboob.capabilities.bill import Subscription, Detail, Bill
from weboob.capabilities.bill import DocumentTypes, Subscription, Detail, Bill
from weboob.browser.filters.standard import CleanText, Regexp
from weboob.exceptions import BrowserUnavailable
......@@ -132,7 +132,7 @@ class LastPaymentsPage(LoggedPage, AmeliBasePage):
bil.id = sub._id + "." + date.strftime("%Y%m")
bil.date = date
bil.format = 'pdf'
bil.type = 'bill'
bil.type = DocumentTypes.BILL
bil.label = date.strftime("%Y%m%d")
bil.url = '/PortailAS/PDFServletReleveMensuel.dopdf?PDF.moisRecherche=' + date.strftime("%m%Y")
yield bil
......
......@@ -17,7 +17,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
from weboob.capabilities.bill import CapDocument, SubscriptionNotFound, DocumentNotFound, Subscription, Bill
from weboob.capabilities.bill import DocumentTypes, CapDocument, SubscriptionNotFound, DocumentNotFound, Subscription, Bill
from weboob.tools.backend import Module, BackendConfig
from weboob.tools.value import ValueBackendPassword
from .browser import AmeliProBrowser
......@@ -40,6 +40,8 @@ class AmeliProModule(Module, CapDocument):
masked=True)
)
accepted_document_types = (DocumentTypes.BILL,)
def create_default_browser(self):
self.logger.settings['save_responses'] = False # Set to True to help debugging
return self.create_browser(self.config['login'].get(),
......
......@@ -22,7 +22,7 @@ from datetime import datetime
import re
from decimal import Decimal
from weboob.browser.pages import HTMLPage
from weboob.capabilities.bill import Subscription, Detail, Bill
from weboob.capabilities.bill import DocumentTypes, Subscription, Detail, Bill
# Ugly array to avoid the use of french locale
......@@ -111,7 +111,7 @@ class BillsPage(HTMLPage):
bil.price = 0
bil.label = u''+date.strftime("%Y%m%d")
bil.format = u''+format
bil.type = u'bill'
bil.type = DocumentTypes.BILL
filedate = date.strftime("%m%Y")
bil.url = u'/PortailPS/fichier.do'
bil._data = {'FICHIER.type': format.lower()+'.releveCompteMensuel',
......
......@@ -111,6 +111,7 @@ class AccountsPage(LoggedPage, HTMLPage):
acc._idforJSON = account_data[10][-1]
else:
acc._idforJSON = account_data[-5][-1]
acc._idforJSON = re.sub('\s+', ' ', acc._idforJSON)
acc.number = '-%s' % account_data[2][2]
acc.label = '%s %s' % (account_data[6][4], account_data[10][-1])
acc._balances_token = acc.id = balances_token
......
......@@ -29,7 +29,8 @@ from weboob.capabilities.base import NotAvailable
from .pages import (
LoginPage, AccountsPage, AccountPage, MarketAccountPage,
LifeInsuranceAccountPage, CardPage, IbanPDFPage,
LifeInsuranceAccountPage, CardPage, IbanPDFPage, ActionNeededPage,
RevolvingAccountPage, LoanAccountPage,
)
......@@ -41,10 +42,13 @@ class Barclays(LoginBrowser):
login = URL('/BconnectDesk/servletcontroller', LoginPage)
accounts = URL('/BconnectDesk/servletcontroller', AccountsPage)
loan_account = URL('/BconnectDesk/servletcontroller', LoanAccountPage)
account = URL('/BconnectDesk/servletcontroller', AccountPage)
card_account = URL('/BconnectDesk/servletcontroller', CardPage)
market_account = URL('/BconnectDesk/servletcontroller', MarketAccountPage)
life_insurance_account = URL('/BconnectDesk/servletcontroller', LifeInsuranceAccountPage)
revolving_account = URL('/BconnectDesk/servletcontroller', RevolvingAccountPage)
actionNeededPage = URL('/BconnectDesk/servletcontroller', ActionNeededPage)
iban = URL('/BconnectDesk/editique', IbanPDFPage)
def __init__(self, secret, *args, **kwargs):
......@@ -127,8 +131,9 @@ class Barclays(LoginBrowser):
traccounts = []
for account in accounts:
if account.type != Account.TYPE_LOAN:
self._go_to_account(account)
self._go_to_account(account)
if account.type == Account.TYPE_LOAN:
account = self.page.get_loan_attributes(account)
if account.type == Account.TYPE_CARD:
if self.page.is_immediate_card():
......@@ -138,6 +143,8 @@ class Barclays(LoginBrowser):
continue
account._attached_account = self.page.do_account_attachment([a for a in accounts if a.type == Account.TYPE_CHECKING])
if account.type == Account.TYPE_REVOLVING_CREDIT:
account = self.page.get_revolving_attributes(account)
account.iban = self.iban.open().get_iban() if self.page.has_iban() else NotAvailable
......@@ -151,7 +158,7 @@ class Barclays(LoginBrowser):
def iter_history(self, account):
if account._multiple_type and not self._multiple_account_choice(account):
return []
elif account.type == Account.TYPE_LOAN:
elif account.type in (Account.TYPE_LOAN, Account.TYPE_REVOLVING_CREDIT):
return []
self._go_to_account(account)
......
......@@ -21,16 +21,14 @@ from __future__ import unicode_literals
import re
from six.moves.html_parser import HTMLParser
from weboob.browser.pages import HTMLPage, PDFPage, LoggedPage
from weboob.browser.elements import TableElement, ListElement, ItemElement, method
from weboob.browser.filters.standard import CleanText, CleanDecimal, Regexp, Field, Date, Eval
from weboob.browser.filters.html import Attr, TableCell
from weboob.capabilities.bank import Account, Investment, NotAvailable
from weboob.browser.filters.html import Attr, TableCell, ReplaceEntities
from weboob.capabilities.bank import Account, Investment, Loan, NotAvailable
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
from weboob.tools.capabilities.bank.iban import is_iban_valid
from weboob.exceptions import ActionNeeded
def MyDecimal(*args, **kwargs):
kwargs.update(replace_dots=True, default=NotAvailable)
......@@ -109,6 +107,8 @@ class AccountsPage(StatefulPage):
ACCOUNT_EXTRA_TYPES = {'BMOOVIE': Account.TYPE_LIFE_INSURANCE,
'B. GESTION VIE': Account.TYPE_LIFE_INSURANCE,
'E VIE MILLEIS': Account.TYPE_LIFE_INSURANCE,
'BANQUE PRIVILEGE': Account.TYPE_REVOLVING_CREDIT,
'PRET PERSONNEL': Account.TYPE_LOAN,
}
ACCOUNT_TYPE_TO_STR = {Account.TYPE_MARKET: 'TTR',
Account.TYPE_CARD: 'CRT'
......@@ -205,16 +205,6 @@ class Transaction(FrenchTransaction):
]
class Entities(CleanText):
"""
Filter to replace HTML entities like "&eacute;" or "&#x42;" with their unicode counterpart.
"""
def filter(self, data):
h = HTMLParser()
txt = super(Entities, self).filter(data)
return h.unescape(txt)
class AbstractAccountPage(StatefulPage):
def has_iban(self):
return len(self.doc.xpath('//a[contains(., "Edition RIB")]/ancestor::node()[2][not(contains(@style, "display: none;"))]')) > 1
......@@ -255,7 +245,7 @@ class AbstractAccountPage(StatefulPage):
obj_date = Date(CleanText(TableCell('date')), dayfirst=True)
obj_vdate = Date(CleanText(TableCell('vdate')), dayfirst=True)
obj_amount = MyDecimal(TableCell('credit'), default=TableCell('debit'))
obj_raw = Transaction.Raw(Entities(Regexp(CleanText('.//script[1]'), r"toggleDetails\([^,]+,[^,]+, '(.*?)', '(.*?)', '(.*?)',", r'\1 \2 \3')))
obj_raw = Transaction.Raw(ReplaceEntities(Regexp(CleanText('.//script[1]'), r"toggleDetails\([^,]+,[^,]+, '(.*?)', '(.*?)', '(.*?)',", r'\1 \2 \3')))
class AccountPage(AbstractAccountPage):
......@@ -449,6 +439,64 @@ class CardPage(AbstractAccountPage):
return (a[1], 'C4__WORKING[1].LISTCONTRATS', form['C4__WORKING[1].LISTCONTRATS'], a[2])
class RevolvingAccountPage(AbstractAccountPage):
def is_here(self):
return bool(CleanText('//span[contains(., "Crédit renouvelable")]')(self.doc))
def has_iban(self):
return False
def get_revolving_attributes(self, account):
loan = Loan()
loan.available_amount = CleanDecimal('//div/span[contains(text(), "Montant disponible")]/following-sibling::*[1]', replace_dots=True)(self.doc)
loan.used_amount = CleanDecimal('//div/span[contains(text(), "Montant Utilisé")]/following-sibling::*[1]', replace_dots=True)(self.doc)
loan.total_amount = CleanDecimal('//div/span[contains(text(), "Réserve accordée")]/following-sibling::*[1]', replace_dots=True)(self.doc)
loan.last_payment_amount = CleanDecimal('//div/span[contains(text(), "Echéance Précédente")]/following-sibling::*[1]', replace_dots=True)(self.doc)
loan.last_payment_date = Date(Regexp(CleanText('//div/span[contains(text(), "Echéance Précédente")]/following-sibling::*[2]'), r'(\d{2}\/\d{2}\/\d{4})'), dayfirst=True)(self.doc)
owner_name = CleanText('//a[@class="lien-entete login"]/span')(self.doc)
loan.name = ' '.join(owner_name.split()[1:])
loan.id = account.id
loan.currency = account.currency
loan.label = account.label
loan.balance = account.balance
loan.coming = account.coming
loan.type = account.type
loan._uncleaned_id = account._uncleaned_id
loan._multiple_type = account._multiple_type
return loan
class LoanAccountPage(AbstractAccountPage):
def is_here(self):
return bool(CleanText('//span[contains(., "Détail compte")]')(self.doc))
def has_iban(self):
return False
def get_loan_attributes(self, account):
loan = Loan()
loan.total_amount = CleanDecimal('//div/span[contains(text(), "Capital initial")]/following-sibling::*[1]', replace_dots=True)(self.doc)
owner_name = CleanText('//a[@class="lien-entete login"]/span')(self.doc)
loan.name = ' '.join(owner_name.split()[1:])
loan.subscription_date = Date(Regexp(CleanText('//h4[span[contains(text(), "Date de départ du prêt")]]'), r'(\d{2}\/\d{2}\/\d{4})'), dayfirst=True)(self.doc)
loan.maturity_date = Date(Regexp(CleanText('//h4[span[contains(text(), "Date de fin du prêt")]]'), r'(\d{2}\/\d{2}\/\d{4})'), dayfirst=True)(self.doc)
loan.rate = Eval(lambda x: x / 100, CleanDecimal('//div/span[contains(text(), "Taux fixe")]/following-sibling::*[1]', replace_dots=True))(self.doc)
loan.last_payment_amount = CleanDecimal('//div[@class="txt-detail " and not (@style)]//span[contains(text(), "Echéance du")]/following-sibling::span[1]')(self.doc)
loan.last_payment_date = Date(Regexp(CleanText('//div[@class="txt-detail " and not (@style)]//span[contains(text(), "Echéance du")]'), r'(\d{2}\/\d{2}\/\d{4})'), dayfirst=True)(self.doc)
loan.id = account.id
loan.currency = account.currency
loan.label = account.label
loan.balance = account.balance
loan.coming = account.coming
loan.type = account.type
loan._uncleaned_id = account._uncleaned_id
loan._multiple_type = account._multiple_type
return loan
class IbanPDFPage(LoggedPage, PDFPage):
def get_iban(self):
match = re.search(r'Tm \[\((FR[0-9]{2} [A-Z0-9 ]+)\)\]', self.doc.decode('ISO8859-1'))
......@@ -461,3 +509,15 @@ class IbanPDFPage(LoggedPage, PDFPage):
assert is_iban_valid(iban)
return iban
class ActionNeededPage(LoggedPage, HTMLPage):
def on_load(self):
# We only need 2 sentences because the thirds is too specific
message = CleanText("//h2[contains(@class, 'ecDIB')]")(self.doc).split('.')
raise ActionNeeded('%s.' % '.'.join(message[:-2]))
def is_here(self):
message = CleanText("//h2[contains(@class, 'ecDIB')]")(self.doc)
text = "Afin de respecter nos obligations réglementaires, nous devons disposer d’une connaissance récente des données de nos clients."
return message and text in message
......@@ -343,7 +343,8 @@ class MarketPage(LoggedPage, HTMLPage):
@method
class iter_market_accounts(TableElement):
def condition(self):
return not self.el.xpath('//table[@id="table-portefeuille"]//tr/td[contains(text(), "Aucun portefeuille à afficher")]')
return not self.el.xpath('//table[@id="table-portefeuille"]//tr/td[contains(text(), "Aucun portefeuille à afficher") \
or contains(text(), "No portfolio to display")]')
item_xpath = '//table[@id="table-portefeuille"]/tbody[@class="main-content"]/tr'
head_xpath = '//table[@id="table-portefeuille"]/thead/tr/th/label'
......
......@@ -22,7 +22,7 @@ from __future__ import unicode_literals
from datetime import timedelta, datetime
from weboob.browser import LoginBrowser, need_login, URL
from weboob.capabilities.bill import Document
from weboob.capabilities.bill import DocumentTypes, Document
from weboob.tools.capabilities.bank.investments import create_french_liquidity
from .pages import (
......@@ -97,6 +97,6 @@ class BoldenBrowser(LoginBrowser):
doc.id = inv.id
doc.url = inv._docurl
doc.label = 'Contrat %s' % inv.label
doc.type = 'other'
doc.type = DocumentTypes.OTHER
doc.format = 'pdf'
yield doc
......@@ -26,6 +26,7 @@ from weboob.capabilities.bank import CapBankWealth, Account
from weboob.capabilities.base import find_object
from weboob.capabilities.bill import (
CapDocument, Subscription, SubscriptionNotFound, DocumentNotFound, Document,
DocumentTypes,
)
from weboob.capabilities.profile import CapProfile
......@@ -50,6 +51,8 @@ class BoldenModule(Module, CapBankWealth, CapDocument, CapProfile):
ValueBackendPassword('password', label='Mot de passe'),
)
accepted_document_types = (DocumentTypes.OTHER,)
def create_default_browser(self):
return self.create_browser(self.config['login'].get(), self.config['password'].get())
......
......@@ -36,7 +36,7 @@ from weboob.capabilities.bank import (
from weboob.capabilities.contact import Advisor
from weboob.tools.captcha.virtkeyboard import VirtKeyboardError
from weboob.tools.value import Value
from weboob.tools.compat import basestring, urlsplit, urlunsplit
from weboob.tools.compat import basestring, urlsplit
from weboob.tools.capabilities.bank.transactions import sorted_transactions
from .pages import (
......@@ -45,7 +45,7 @@ from .pages import (
CardsNumberPage, CalendarPage, HomePage, PEPPage,
TransferAccounts, TransferRecipients, TransferCharac, TransferConfirm, TransferSent,
AddRecipientPage, StatusPage, CardHistoryPage, CardCalendarPage, CurrencyListPage, CurrencyConvertPage,
AccountsErrorPage, NoAccountPage,
AccountsErrorPage, NoAccountPage, TransferMainPage,
)
......@@ -85,10 +85,11 @@ class BoursoramaBrowser(RetryLoginBrowser, StatesMixin):
saving_pep = URL('/compte/epargne/pep', PEPPage)
incident = URL('/compte/cav/(?P<webid>.*)/mes-incidents.*', IncidentPage)
transfer_accounts = URL(r'/compte/(?P<type>[^/]+)/(?P<webid>\w+)/virements/nouveau/(?P<id>\w+)/1',
r'/compte/(?P<type>[^/]+)/(?P<webid>\w+)/virements/nouveau$',
TransferAccounts)
recipients_page = URL(r'/compte/(?P<type>[^/]+)/(?P<webid>\w+)/virements/$',
# transfer
transfer_main_page = URL(r'/compte/(?P<acc_type>[^/]+)/(?P<webid>\w+)/virements$', TransferMainPage)
transfer_accounts = URL(r'/compte/(?P<acc_type>[^/]+)/(?P<webid>\w+)/virements/nouveau$',
r'/compte/(?P<type>[^/]+)/(?P<webid>\w+)/virements/nouveau/(?P<id>\w+)/1', TransferAccounts)
recipients_page = URL(r'/compte/(?P<type>[^/]+)/(?P<webid>\w+)/virements$',
r'/compte/(?P<type>[^/]+)/(?P<webid>\w+)/virements/nouveau/(?P<id>\w+)/2',
TransferRecipients)
transfer_charac = URL(r'/compte/(?P<type>[^/]+)/(?P<webid>\w+)/virements/nouveau/(?P<id>\w+)/3',
......@@ -376,24 +377,25 @@ class BoursoramaBrowser(RetryLoginBrowser, StatesMixin):
def iter_transfer_recipients(self, account):
if account.type in (Account.TYPE_LOAN, Account.TYPE_LIFE_INSURANCE):
return []
assert account.url
# url transfer preparation
url = urlsplit(account.url)
parts = [part for part in url.path.split('/') if part]
if account.type == Account.TYPE_SAVINGS:
self.logger.debug('Deleting account name %s to get recipients', parts[-2])
del parts[-2]
parts.append('virements')
url = url._replace(path='/'.join(parts))
target = urlunsplit(url)
assert len(parts) > 2, 'Account url missing some important part to iter recipient'
account_type = parts[1] # cav, ord, epargne ...
account_webid = parts[-1]
try:
self.location(target)
self.transfer_main_page.go(acc_type=account_type, webid=account_webid)
except BrowserHTTPNotFound:
return []
# can check all account available transfer option
if self.transfer_main_page.is_here():
self.transfer_accounts.go(acc_type=account_type, webid=account_webid)
if self.transfer_accounts.is_here():
try:
self.page.submit_account(account.id)
......
......@@ -804,6 +804,10 @@ class NoTransferPage(LoggedPage, HTMLPage):
pass
class TransferMainPage(LoggedPage, HTMLPage):
pass
class TransferAccounts(LoggedPage, HTMLPage):
@method
class iter_accounts(ListElement):
......
......@@ -612,7 +612,7 @@ class BProBrowser(BPBrowser):
self.location('%s/voscomptes/rib/init-rib.ea' % self.base_url)
value = self.page.get_rib_value(acc.id)
if value:
self.location('%s/voscomptes/rib/preparerRIB-rib.ea?%s' % (self.base_url, value))
self.location('%s/voscomptes/rib/preparerRIB-rib.ea?idxSelection=%s' % (self.base_url, value))
if self.rib.is_here():
acc.iban = self.page.get_iban()
......@@ -626,7 +626,7 @@ class BProBrowser(BPBrowser):
self.location('%s/voscomptes/rib/init-rib.ea' % self.base_url)
value = self.page.get_rib_value(acc.id)
if value:
self.location('%s/voscomptes/rib/preparerRIB-rib.ea?%s' % (self.base_url, value))
self.location('%s/voscomptes/rib/preparerRIB-rib.ea?idxSelection=%s' % (self.base_url, value))
if self.rib.is_here():
return self.page.get_profile()
......
......@@ -21,7 +21,7 @@ from __future__ import unicode_literals
import re
from weboob.capabilities.bill import Subscription, Document
from weboob.capabilities.bill import DocumentTypes, Subscription, Document
from weboob.browser.pages import LoggedPage, HTMLPage
from weboob.browser.filters.standard import CleanText, Regexp, Env, Date, Format, Field
from weboob.browser.filters.html import Link, Attr, TableCell
......@@ -62,7 +62,7 @@ class SubscriptionPage(LoggedPage, HTMLPage):
obj_label = Format('%s - %s', CleanText('.//span[contains(@class, "lib")]'), CleanText('.//span[contains(@class, "date")]'))
obj_url = Format('/voscomptes/canalXHTML/relevePdf/relevePdf_historique/%s', Link('./a'))
obj_format = 'pdf'
obj_type = 'other'
obj_type = DocumentTypes.OTHER
def obj_date(self):
date = CleanText('.//span[contains(@class, "date")]')(self)
......@@ -141,7 +141,7 @@ class ProSubscriptionPage(LoggedPage, HTMLPage):
# on the page of the year XXX for the subscription YYYY
obj_url = Link('.//a')
obj_format = 'pdf'
obj_type = 'other'
obj_type = DocumentTypes.OTHER
def submit_form(self, sub_number, year):
form = self.get_form(name='formRechHisto')
......
......@@ -411,6 +411,10 @@ class CaisseEpargne(LoginBrowser, StatesMixin):
self.page.submit()
if 'offrebourse.com' in self.url:
# Some users may not have access to this.
if self.page.is_error():
continue
self.update_linebourse_token()
page = self.linebourse.go_portfolio(account.id)
assert self.linebourse.portfolio.is_here()
......
......@@ -29,7 +29,7 @@ from weboob.capabilities import NotAvailable
from weboob.capabilities.bank import Account, Transaction
from weboob.capabilities.contact import Advisor
from weboob.capabilities.profile import Profile
from weboob.capabilities.bill import Subscription, Document
from weboob.capabilities.bill import DocumentTypes, Subscription, Document
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
from weboob.exceptions import BrowserUnavailable
......@@ -278,7 +278,7 @@ class SubscriptionPage(LoggedPage, CenetJsonPage):
obj_id = Format('%s_%s_%s', Env('sub_id'), Dict('Numero'), CleanText(Env('french_date'), symbols='/'))
obj_format = 'pdf'
obj_type = 'other'
obj_type = DocumentTypes.OTHER
obj__numero = CleanText(Dict('Numero'))
obj__sub_id = Env('sub_id')
obj__sub_label = Env('sub_label')
......
......@@ -24,7 +24,7 @@ from decimal import Decimal
from weboob.capabilities.bank import CapBankWealth, CapBankTransferAddRecipient, AccountNotFound, Account, RecipientNotFound
from weboob.capabilities.bill import (
CapDocument, Subscription, SubscriptionNotFound,
Document, DocumentNotFound,
Document, DocumentNotFound, DocumentTypes,
)
from weboob.capabilities.base import NotAvailable
from weboob.capabilities.contact import CapContact
......@@ -56,6 +56,8 @@ class CaisseEpargneModule(Module, CapBankWealth, CapBankTransferAddRecipient, Ca
Value('nuser', label='User ID (optional)', default='', regexp='\d{0,8}'),
Value('pincode', label='pincode', required=False))
accepted_document_types = (DocumentTypes.OTHER,)
def create_default_browser(self):
return self.create_browser(nuser=self.config['nuser'].get(),
username=self.config['login'].get(),
......
......@@ -37,7 +37,7 @@ from weboob.capabilities.bank import (
Account, Investment, Recipient, TransferError, TransferBankError, Transfer,
AddRecipientBankError, Loan,
)
from weboob.capabilities.bill import Subscription, Document
from weboob.capabilities.bill import DocumentTypes, Subscription, Document
from weboob.tools.capabilities.bank.investments import is_isin_valid
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
from weboob.tools.capabilities.bank.iban import is_rib_valid, rib2iban, is_iban_valid
......@@ -762,11 +762,8 @@ class NatixisRedirectPage(LoggedPage, HTMLPage):
class MarketPage(LoggedPage, HTMLPage):
def on_load(self):
error = CleanText('//caption[contains(text(),"Erreur")]')(self.doc)
if error:
message = CleanText('//td[contains(@class,"donneeLongIdent")]')(self.doc)
raise BrowserUnavailable(message)
def is_error(self):
return CleanText('//caption[contains(text(),"Erreur")]')(self.doc)
def parse_decimal(self, td, percentage=False):
value = CleanText('.')(td)
......@@ -1388,7 +1385,7 @@ class SubscriptionPage(LoggedPage, HTMLPage):
obj_label = Format('%s %s', CleanText('./preceding::h3[1]'), CleanText('./span'))
obj_date = Date(CleanText('./span'), dayfirst=True)
obj_type = 'other'
obj_type = DocumentTypes.OTHER
obj_format = 'pdf'
obj_url = Regexp(Link('.'), r'WebForm_PostBackOptions\("(\S*)"')
obj_id = Format('%s_%s_%s', Env('sub_id'), CleanText('./span', symbols='/'), Regexp(Field('url'), r'ctl(.*)'))
......
......@@ -20,7 +20,7 @@
from __future__ import unicode_literals
from weboob.capabilities.bill import CapDocument, Subscription, Document, SubscriptionNotFound, DocumentNotFound
from weboob.capabilities.bill import DocumentTypes, CapDocument, Subscription, Document, SubscriptionNotFound, DocumentNotFound
from weboob.capabilities.base import find_object, NotAvailable
from weboob.tools.backend import Module, BackendConfig
from weboob.tools.value import ValueBackendPassword
......@@ -43,6 +43,8 @@ class CityscootModule(Module, CapDocument):
BROWSER = CityscootBrowser
accepted_document_types = (DocumentTypes.BILL,)
def create_default_browser(self):
return self.create_browser(self.config['login'].get(), self.config['password'].get())
......
......@@ -24,7 +24,7 @@ from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.browser.elements import ItemElement, TableElement, method
from weboob.browser.filters.standard import CleanText, CleanDecimal, Env, Regexp, Format, Date, Async, AsyncLoad
from weboob.browser.filters.html import Link
from weboob.capabilities.bill import Bill, Subscription
from weboob.capabilities.bill import DocumentTypes, Bill, Subscription
from weboob.capabilities.base import NotAvailable
class LoginPage(HTMLPage):
......@@ -68,7 +68,7 @@ class DocumentsPage(LoggedPage, HTMLPage):
obj_date = Async('details') & Date(Regexp(CleanText('.//h3'), r'(\d{2}\/\d{2}\/\d{4})'), dayfirst=True)
obj_format = 'html'
obj_label = Async('details') & CleanText('.//h3')
obj_type = 'bill'
obj_type = DocumentTypes.BILL
obj_price = Async('details') & CleanDecimal('.//td[.="Total"]/following-sibling::td')
obj_vat = Async('details') & CleanDecimal('.//td[contains(text(), "TVA")]/following-sibling::td')
obj_currency = u'EUR'
......@@ -23,24 +23,25 @@ from weboob.browser import LoginBrowser, URL, need_login
from .pages import (
LoginPage, AccountsPage, FCPEInvestmentPage,
CCBInvestmentPage, HistoryPage, AlertPage,
CCBInvestmentPage, HistoryPage, CustomPage,
)
class CmesBrowser(LoginBrowser):
BASEURL = 'https://www.cic-epargnesalariale.fr'
login = URL('(?P<subsite>.*)fr/identification/default.cgi', LoginPage)
login = URL('/espace-client/fr/identification/authentification.html', LoginPage)
accounts = URL('(?P<subsite>.*)fr/espace/devbavoirs.aspx\?mode=net&menu=cpte$', AccountsPage)
fcpe_investment = URL(r'/fr/.*GoPositionsParFond.*',
r'/fr/espace/devbavoirs.aspx\?.*SituationParFonds.*GoOpenDetailFond.*',
r'(?P<subsite>.*)fr/espace/devbavoirs.aspx\?_tabi=C&a_mode=net&a_menu=cpte&_pid=SituationGlobale&_fid=GoPositionsParFond',
r'(?P<subsite>.*)fr/espace/devbavoirs.aspx\?_tabi=C&a_mode=net&a_menu=cpte&_pid=SituationParFonds.*', FCPEInvestmentPage)
ccb_investment = URL('(?P<subsite>.*)fr/.*LstSuppCCB.*', CCBInvestmentPage)
ccb_investment = URL('(?P<subsite>.*)fr/espace/devbavoirs.aspx\?_tabi=C&a_mode=net&a_menu=cpte&_pid=SituationGlobale&_fid=GoCCB', CCBInvestmentPage)
history = URL('(?P<subsite>.*)fr/espace/devbavoirs.aspx\?mode=net&menu=cpte&page=operations',
'(?P<subsite>.*)fr/.*GoOperationsTraitees',
'(?P<subsite>.*)fr/.*GoOperationDetails', HistoryPage)
supp_alert = URL(r'(?P<subsite>.*)fr/espace/LstSuppAlerte.asp', AlertPage)
custom_page = URL('/fr/espace/personnel/index.html', CustomPage)
def __init__(self, website, username, password, subsite="", *args, **kwargs):
super(LoginBrowser, self).__init__(*args, **kwargs)
......@@ -50,19 +51,26 @@ class CmesBrowser(LoginBrowser):
self.subsite = subsite
def do_login(self):
self.login.go(subsite=self.subsite).login(self.username, self.password)
self.login.go()
self.page.login(self.username, self.password)