diff --git a/modules/societegenerale/module.py b/modules/societegenerale/module.py index af39b56fedd16c9f7afdbe99b467dbb154dbb7d8..8712116979a0de51e95367069a44db3c9dee0af7 100644 --- a/modules/societegenerale/module.py +++ b/modules/societegenerale/module.py @@ -111,7 +111,7 @@ def new_recipient(self, recipient, **params): return self.browser.new_recipient(recipient, **params) def init_transfer(self, transfer, **params): - if self.config['website'].get() != 'par': + if self.config['website'].get() not in ('par', 'pro'): raise NotImplementedError() transfer.label = ' '.join(w for w in re.sub('[^0-9a-zA-Z ]+', '', transfer.label).split()) self.logger.info('Going to do a new transfer') @@ -130,7 +130,7 @@ def init_transfer(self, transfer, **params): return self.browser.init_transfer(account, recipient, transfer) def execute_transfer(self, transfer, **params): - if self.config['website'].get() != 'par': + if self.config['website'].get() not in ('par', 'pro'): raise NotImplementedError() return self.browser.execute_transfer(transfer) diff --git a/modules/societegenerale/sgpe/browser.py b/modules/societegenerale/sgpe/browser.py index 641d5f72e7ef0ff35662bf5f3c654b78f44d3af5..414c862b2fdcbd46af9a53015b8b315699bab74e 100644 --- a/modules/societegenerale/sgpe/browser.py +++ b/modules/societegenerale/sgpe/browser.py @@ -26,7 +26,9 @@ from weboob.browser.exceptions import ClientError from weboob.exceptions import BrowserIncorrectPassword from weboob.capabilities.base import find_object -from weboob.capabilities.bank import AccountNotFound +from weboob.capabilities.bank import ( + AccountNotFound, RecipientNotFound, +) from .pages import ( LoginPage, CardsPage, CardHistoryPage, IncorrectLoginPage, @@ -34,7 +36,7 @@ ) from .json_pages import AccountsJsonPage, BalancesJsonPage, HistoryJsonPage, BankStatementPage from .transfer_pages import ( - EasyTransferPage, RecipientsJsonPage, + EasyTransferPage, RecipientsJsonPage, TransferPage, SignTransferPage, ) @@ -178,6 +180,10 @@ class SGProfessionalBrowser(SGEnterpriseBrowser): internal_recipients = URL('/ord-web/ord//ord-virement-simplifie-beneficiaire.html', EasyTransferPage) external_recipients = URL('/ord-web/ord//ord-liste-compte-beneficiaire-externes.json', RecipientsJsonPage) + init_transfer_page = URL('/ord-web/ord//ord-enregistrer-ordre-simplifie.json', TransferPage) + sign_transfer_page = URL('/ord-web/ord//ord-verifier-habilitation-signature-ordre.json', SignTransferPage) + confirm_transfer = URL('/ord-web/ord//ord-valider-signature-ordre.json', TransferPage) + bank_statement_menu = URL('/icd/syd-front/data/syd-rce-accederDepuisMenu.json', BankStatementPage) bank_statement_search = URL('/icd/syd-front/data/syd-rce-lancerRecherche.json', BankStatementPage) @@ -249,6 +255,59 @@ def iter_recipients(self, origin_account): for external_rcpt in self.page.iter_external_recipients(): yield external_rcpt + @need_login + def init_transfer(self, account, recipient, transfer): + # update account and recipient info + recipient = find_object(self.iter_recipients(account), iban=recipient.iban, error=RecipientNotFound) + + data = [ + ('an_codeAction', 'C'), + ('an_referenceSiOrdre', ''), + ('cl_compteEmetteur_intitule', account._account_title), + ('cl_compteEmetteur_libelle', account.label), + ('an_compteEmetteur_iban', account.iban), + ('cl_compteEmetteur_ibanFormate', account._formatted_iban), + ('an_compteEmetteur_bic', account._bic), + ('b64_compteEmetteur_idPrestation', account._id_service), + ('an_guichetGestionnaire', account._manage_counter), + ('an_codeProduit', account._product_code), + ('an_codeSousProduit', account._underproduct_code), + ('n_ordreMontantValeur', int(transfer.amount * (10 ** account._decimal_code))), + ('n_ordreMontantCodeDecimalisation', account._decimal_code), + ('an_ordreMontantCodeDevise', account._currency_code), + ('cl_dateExecution', transfer.exec_date.strftime('%d/%m/%Y')), + ('cl_ordreLibelle', transfer.label), + ('an_beneficiaireCodeAction', 'C'), + ('cl_beneficiaireRefSiCoordonnee', recipient._ref), + ('cl_beneficiaireCompteLibelle', recipient.label), + ('cl_beneficiaireCompteIntitule', recipient._account_title), + ('cl_beneficiaireCompteIbanFormate', recipient._formatted_iban), + ('an_beneficiaireCompteIban', recipient.iban), + ('cl_beneficiaireCompteBic', recipient._bic), + ('cl_beneficiaireAdressePays', recipient.iban[:2]), + ('an_indicateurIntraAbonnement', 'false'), + ('cl_reference', ' '), + ('cl_motif', transfer.label), + ] + # WARNING: this save transfer information on user account + self.init_transfer_page.go(data=data) + return self.page.handle_response(account, recipient, transfer.amount, transfer.label, transfer.exec_date) + + @need_login + def execute_transfer(self, transfer, **params): + assert transfer._b64_id_transfer, 'Transfer token is missing' + # get virtual keyboard + data = { + 'b64_idOrdre': transfer._b64_id_transfer + } + self.sign_transfer_page.go(data=data) + + data.update(self.page.get_confirm_transfer_data(self.password)) + self.confirm_transfer.go(data=data) + + self.page.is_transfer_validated() + return transfer + @need_login def iter_documents(self, subscribtion): # This quality website can only fetch documents through a form, looking for dates diff --git a/modules/societegenerale/sgpe/pages.py b/modules/societegenerale/sgpe/pages.py index 91073a071916baec3ad8fbfdecb7f366cf2afda7..5d45e79d42cf4125009541151bac5c143d80f8a5 100644 --- a/modules/societegenerale/sgpe/pages.py +++ b/modules/societegenerale/sgpe/pages.py @@ -95,7 +95,7 @@ def on_load(self): class LoginPage(SGPEPage): - def login(self, login, password): + def get_authentication_data(self): infos_data = self.browser.open('/sec/vk/gen_crypto?estSession=0').text infos_data = re.match('^_vkCallback\((.*)\);$', infos_data).group(1) infos = json.loads(infos_data.replace("'", '"')) @@ -110,10 +110,18 @@ def login(self, login, password): if err.tile: err.tile.display() + return { + 'infos': infos, + 'img': img, + } + + def login(self, login, password): + authentication_data = self.get_authentication_data() + form = self.get_form(name=self.browser.LOGIN_FORM) form['user_id'] = login - form['codsec'] = img.get_codes(password[:6]) - form['cryptocvcs'] = infos['crypto'] + form['codsec'] = authentication_data['img'].get_codes(password[:6]) + form['cryptocvcs'] = authentication_data['infos']['crypto'] form['vk_op'] = 'auth' form.url = '/authent.html' try: diff --git a/modules/societegenerale/sgpe/transfer_pages.py b/modules/societegenerale/sgpe/transfer_pages.py index bafe80de29a6300cad45eb7f4422dfb431b81970..078a0015d93535e8680f6593724d896ba91eb6b1 100644 --- a/modules/societegenerale/sgpe/transfer_pages.py +++ b/modules/societegenerale/sgpe/transfer_pages.py @@ -26,8 +26,11 @@ from weboob.browser.pages import LoggedPage, HTMLPage, JsonPage from weboob.browser.elements import method, DictElement, ItemElement from weboob.browser.filters.html import Attr -from weboob.capabilities.bank import Recipient from weboob.browser.filters.json import Dict +from weboob.browser.filters.standard import Date, Eval +from weboob.capabilities.bank import Recipient, Transfer + +from .pages import LoginPage class RecipientsJsonPage(LoggedPage, JsonPage): @@ -53,6 +56,10 @@ def condition(self): obj_label = obj__account_title = Dict('nomRaisonSociale') obj_enabled_at = date.today() + obj__formatted_iban = Dict('coordonnee/0/numeroCompteFormate') + obj__bic = Dict('coordonnee/0/BIC') + obj__ref = Dict('coordonnee/0/refSICoordonnee') + class EasyTransferPage(LoggedPage, HTMLPage): def update_origin_account(self, origin_account): @@ -65,6 +72,15 @@ def update_origin_account(self, origin_account): origin_account.label == json_data['libelleCompte'] and origin_account.iban == json_data['ibanCompte'] ): + origin_account._currency_code = json_data['codeDevise'] + origin_account._formatted_iban = json_data['ibanFormateCompte'] + origin_account._min_amount = json_data['montantMin'] + origin_account._max_amount = json_data['montantMax'] + origin_account._decimal_code = json_data['codeDecimal'] + origin_account._manage_counter = json_data['guichetGestionnaire'] + origin_account._account_title = json_data['intituleCompte'] + origin_account._bic = json_data['bicCompte'] + origin_account._id_service = json_data['idPrestation'] origin_account._product_code = json_data['codeProduit'] origin_account._underproduct_code = json_data['codeSousProduit'] break @@ -83,4 +99,63 @@ def iter_internal_recipients(self): rcpt.label = json_data['libelleCompte'] rcpt.enabled_at = date.today() + rcpt._formatted_iban = json_data['ibanFormateCompte'] + rcpt._account_title = json_data['intituleCompte'] + rcpt._bic = json_data['bicCompte'] + rcpt._ref = '' + yield rcpt + + +class TransferPage(LoggedPage, JsonPage): + def on_load(self): + assert Dict('commun/statut')(self.doc) == 'ok', 'Something went wrong: %s' % Dict('commun/raison')(self.doc) + + def handle_response(self, origin, recipient, amount, reason, exec_date): + account_data = Dict('donnees/detailOrdre/compteEmetteur')(self.doc) + recipient_data = Dict('donnees/listOperations/0/compteBeneficiaire')(self.doc) + transfer_data = Dict('donnees/detailOrdre')(self.doc) + + transfer = Transfer() + transfer._b64_id_transfer = Dict('idOrdre')(transfer_data) + + transfer.account_id = origin.id + transfer.account_label = Dict('libelleCompte')(account_data) + transfer.account_iban = Dict('ibanCompte')(account_data) + transfer.account_balance = origin.balance + + transfer.recipient_id = recipient.id + transfer.recipient_label = Dict('libelleCompte')(recipient_data) + transfer.recipient_iban = Dict('ibanCompte')(recipient_data) + + transfer.currency = Dict('montantTotalOrdre/codeDevise')(transfer_data) + transfer.amount = Eval( + lambda x, y: x * (10 ** -y), + Dict('montantTotalOrdre/valeurMontant'), + Dict('montantTotalOrdre/codeDecimalisation') + )(transfer_data) + transfer.exec_date = Date(Dict('dateExecution'), dayfirst=True)(transfer_data) + transfer.label = Dict('libelleClientOrdre')(transfer_data) + + return transfer + + def is_transfer_validated(self): + return Dict('donnees/statutOrdre')(self.doc) not in ('rejete', 'a_signer', ) + + +class SignTransferPage(LoggedPage, LoginPage): + def get_token(self): + result_page = json.loads(self.content) + assert result_page['commun']['statut'] == 'ok', 'Something went wrong: %s' % result_page['commun']['raison'] + return result_page['donnees']['jeton'] + + def get_confirm_transfer_data(self, password): + token = self.get_token() + + authentication_data = self.get_authentication_data() + return { + 'codsec': authentication_data['img'].get_codes(password[:6]), + 'cryptocvcs': authentication_data['infos']['crypto'], + 'vk_op': 'sign', + 'context': token, + }