diff --git a/modules/societegenerale/browser.py b/modules/societegenerale/browser.py index d6003b9d52c420b546dfe3468f6d06897574d147..7d225ba56049d598e2b3a11c3da1d770c413b620 100644 --- a/modules/societegenerale/browser.py +++ b/modules/societegenerale/browser.py @@ -24,6 +24,7 @@ from dateutil.relativedelta import relativedelta from weboob.browser import LoginBrowser, URL, need_login, StatesMixin +from weboob.capabilities.bill import Document, DocumentTypes from weboob.exceptions import BrowserIncorrectPassword, ActionNeeded, BrowserUnavailable from weboob.capabilities.bank import Account, TransferBankError, AddRecipientStep, TransactionType, AccountOwnerType from weboob.capabilities.base import find_object, NotAvailable @@ -40,7 +41,7 @@ ) from .pages.transfer import AddRecipientPage, SignRecipientPage, TransferJson, SignTransferPage from .pages.login import MainPage, LoginPage, BadLoginPage, ReinitPasswordPage, ActionNeededPage, ErrorPage -from .pages.subscription import BankStatementPage +from .pages.subscription import BankStatementPage, RibPdfPage __all__ = ['SocieteGenerale'] @@ -100,6 +101,7 @@ class SocieteGenerale(LoginBrowser, StatesMixin): bank_statement = URL(r'/restitution/rce_derniers_releves.html', BankStatementPage) bank_statement_search = URL(r'/restitution/rce_recherche.html\?noRedirect=1', r'/restitution/rce_recherche_resultat.html', BankStatementPage) + rib_pdf_page = URL(r'/com/icd-web/cbo/pdf/rib-authsec.pdf', RibPdfPage) bad_login = URL(r'/acces/authlgn.html', r'/error403.html', BadLoginPage) reinit = URL(r'/acces/changecodeobligatoire.html', @@ -475,24 +477,39 @@ def iter_subscription(self): except (ProfileMissing, BrowserUnavailable): subscriber = NotAvailable - # subscriptions which have statements are present on the last statement page - self.bank_statement.go() - subscriptions_list = list(self.page.iter_subscription()) + self.accounts.go() + subscriptions_list = list(self.page.iter_subscription(subscriber=subscriber)) - # this way the no statement accounts are excluded - # and the one keeped have all the data and parameters needed self.bank_statement_search.go() - for sub in self.page.iter_searchable_subscription(subscriber=subscriber): - found_sub = find_object(subscriptions_list, id=sub.id) + searchable_subscription_list = list(self.page.iter_searchable_subscription()) + for sub in subscriptions_list: + found_sub = find_object(searchable_subscription_list, id=sub.id) if found_sub: - yield sub - - @need_login - def iter_documents(self, subscription): - end_date = datetime.today() + # we need it to get bank statement, but not all subscription have it + sub._rad_button_id = found_sub._rad_button_id + else: + # even without bank statement we still can get RIB document, so we yield subscription anyway + sub._rad_button_id = NotAvailable + yield sub + + def _fetch_rib_document(self, subscription): + d = Document() + d.id = subscription.id + '_RIB' + d.url = self.rib_pdf_page.build(params={'b64e200_prestationIdTechnique': subscription._internal_id}) + d.type = DocumentTypes.RIB + d.format = 'pdf' + d.label = 'RIB' + return d + + def _iter_statements(self, subscription): + # we need _rad_button_id for post_form function + # if not present it means this subscription doesn't have any bank statement + if subscription._rad_button_id is NotAvailable: + return # 5 years since it goes with a 2 months step security_limit = 30 + end_date = datetime.today() i = 0 while i < security_limit: self.bank_statement_search.go() @@ -509,3 +526,20 @@ def iter_documents(self, subscription): # from the 08 to the 06, the 06 statement is included end_date = end_date - relativedelta(months=+3) i += 1 + + @need_login + def iter_documents(self, subscription): + yield self._fetch_rib_document(subscription) + for doc in self._iter_statements(subscription): + yield doc + + @need_login + def iter_documents_by_types(self, subscription, accepted_types): + if DocumentTypes.RIB in accepted_types: + yield self._fetch_rib_document(subscription) + + if DocumentTypes.STATEMENT not in accepted_types: + return + + for doc in self._iter_statements(subscription): + yield doc diff --git a/modules/societegenerale/module.py b/modules/societegenerale/module.py index e5b26165b04845c510b290f38065a190f7be4b6e..7e5c46380f5ccd284cf0ebb4b061034170b85f73 100644 --- a/modules/societegenerale/module.py +++ b/modules/societegenerale/module.py @@ -57,7 +57,7 @@ class SocieteGeneraleModule(Module, CapBankWealth, CapBankTransferAddRecipient, Value('website', label='Type de compte', default='par', choices={'par': 'Particuliers', 'pro': 'Professionnels', 'ent': 'Entreprises'})) - accepted_document_types = (DocumentTypes.STATEMENT,) + accepted_document_types = (DocumentTypes.STATEMENT, DocumentTypes.RIB) def create_default_browser(self): b = {'par': SocieteGenerale, 'pro': SGProfessionalBrowser, 'ent': SGEnterpriseBrowser} @@ -157,6 +157,9 @@ def iter_documents(self, subscription): return self.browser.iter_documents(subscription) + def iter_documents_by_types(self, subscription, accepted_types): + return self.browser.iter_documents_by_types(subscription, accepted_types) + def download_document(self, document): if not isinstance(document, Document): document = self.get_document(document) diff --git a/modules/societegenerale/pages/accounts_list.py b/modules/societegenerale/pages/accounts_list.py index 7b7639af346d7824cf691212bb70a0e3b638c279..bdb83d8d2b14a44bf36d9912b3eec0ad033d6d14 100644 --- a/modules/societegenerale/pages/accounts_list.py +++ b/modules/societegenerale/pages/accounts_list.py @@ -26,6 +26,7 @@ from dateutil.relativedelta import relativedelta from weboob.capabilities.base import NotAvailable from weboob.capabilities.bank import Account, Investment, Loan, AccountOwnership +from weboob.capabilities.bill import Subscription from weboob.capabilities.contact import Advisor from weboob.capabilities.profile import Person, ProfileMissing from weboob.tools.capabilities.bank.transactions import FrenchTransaction @@ -215,6 +216,19 @@ def obj__is_json_histo(self): not Dict('produit')(self) in ('PLAN_EPARGNE_POPULAIRE', ): return True + @method + class iter_subscription(DictElement): + item_xpath = 'donnees' + + class item(ItemElement): + klass = Subscription + + obj_id = CleanText(Dict('numeroCompteFormate'), replace=[(' ', '')]) + obj_subscriber = Env('subscriber') + obj_label = Format('%s %s', Dict('labelToDisplay'), Field('id')) + obj__internal_id = Dict('idTechnique') + + class AccountsSynthesesPage(JsonBasePage): def is_new_website_available(self): if not Dict('commun/raison')(self.doc): diff --git a/modules/societegenerale/pages/subscription.py b/modules/societegenerale/pages/subscription.py index 292eb75d6a424c5af149729bb56701dbdf336b01..69dbd5f3c884a3f3ee5a7210aec2f0de142204b2 100644 --- a/modules/societegenerale/pages/subscription.py +++ b/modules/societegenerale/pages/subscription.py @@ -24,31 +24,14 @@ from weboob.capabilities.bill import Document, Subscription, DocumentTypes from weboob.browser.elements import TableElement, ItemElement, method -from weboob.browser.filters.standard import CleanText, Regexp, Env, Date, Format, Field +from weboob.browser.filters.standard import CleanText, Regexp, Date, Format, Field from weboob.browser.filters.html import Link, TableCell, Attr -from weboob.browser.pages import LoggedPage +from weboob.browser.pages import LoggedPage, RawPage from .base import BasePage -class BankStatementPage(LoggedPage, BasePage): - @method - class iter_subscription(TableElement): - item_xpath = '//table[.//th]//tr[td and @class="LGNTableRow"]' - head_xpath = '//table//th' - - col_id = 'Numéro de Compte' - col_label = 'Type de Compte' - col__last_document_label = 'Derniers relevés' - - class item(ItemElement): - def condition(self): - return 'Récapitulatif annuel' not in CleanText(TableCell('_last_document_label'))(self) - - klass = Subscription - - obj_id = CleanText(TableCell('id'), replace=[(' ', '')]) - obj_label = CleanText(TableCell('label')) +class BankStatementPage(LoggedPage, BasePage): @method class iter_searchable_subscription(TableElement): item_xpath = '//table//tr[@class="fond_ligne"]' @@ -63,7 +46,6 @@ class item(ItemElement): klass = Subscription obj_id = CleanText(TableCell('id'), replace=[(' ', '')]) - obj_subscriber = Env('subscriber') def obj_label(self): label = CleanText(TableCell('label'))(self) @@ -119,3 +101,7 @@ def has_error_msg(self): return any((CleanText('//div[@class="MessageErreur"]')(self.doc), CleanText('//span[@class="error_msg"]')(self.doc), self.doc.xpath('//div[contains(@class, "error_page")]'), )) + + +class RibPdfPage(LoggedPage, RawPage): + pass