diff --git a/modules/bp/browser.py b/modules/bp/browser.py index ed139cc62f6a284bc20fd131f36a85b88f7ddc75..6184dbf3f7bfd15e1c368744d7bec1ddbbb2afac 100644 --- a/modules/bp/browser.py +++ b/modules/bp/browser.py @@ -40,7 +40,7 @@ from weboob.tools.decorators import retry from weboob.capabilities.bank import ( Account, Recipient, AddRecipientStep, TransferStep, - TransferInvalidEmitter, + TransferInvalidEmitter, RecipientInvalidOTP, ) from weboob.tools.value import Value, ValueBool @@ -51,7 +51,7 @@ ValidateCountry, ConfirmPage, RcptSummary, SubscriptionPage, DownloadPage, ProSubscriptionPage, RevolvingAttributesPage, - TwoFAPage, Validated2FAPage, SmsPage, DecoupledPage, HonorTransferPage, RecipientSubmitDevicePage, + TwoFAPage, Validated2FAPage, SmsPage, DecoupledPage, HonorTransferPage, RecipientSubmitDevicePage, RcptErrorPage, ) from .pages.accounthistory import ( LifeInsuranceInvest, LifeInsuranceHistory, LifeInsuranceHistoryInv, RetirementHistory, @@ -303,6 +303,10 @@ class BPBrowser(LoginBrowser, StatesMixin): r'/voscomptes/canalXHTML/virement/mpiGestionBeneficiairesVirementsCreationBeneficiaire/validerRecapBeneficiaire-creationBeneficiaire.ea', ConfirmPage ) + rcpt_error = URL( + r'/voscomptes/canalXHTML/securisation/otp/validation-securisationOTP.ea', + RcptErrorPage, + ) rcpt_summary = URL( r'/voscomptes/canalXHTML/virement/mpiGestionBeneficiairesVirementsCreationBeneficiaire/finalisation-creationBeneficiaire.ea', RcptSummary @@ -374,7 +378,7 @@ class BPBrowser(LoginBrowser, StatesMixin): accounts = None - __states__ = ('need_reload_state', 'sms_form') + __states__ = ('need_reload_state', 'sms_form', 'recipient_form') def __init__(self, config, *args, **kwargs): self.weboob = kwargs.pop('weboob') @@ -407,9 +411,6 @@ def load_state(self, state): super(BPBrowser, self).load_state(state) self.need_reload_state = None - if 'recipient_form' in state and state['recipient_form'] is not None: - self.logged = True - def deinit(self): super(BPBrowser, self).deinit() self.linebourse.deinit() @@ -893,7 +894,7 @@ def init_new_recipient(self, recipient, is_bp_account=False, **params): # Case of SMS OTP self.page.set_browser_form() - raise AddRecipientStep(self.build_recipient(recipient), Value('code', label='Veuillez saisir votre code de validation')) + raise AddRecipientStep(self.build_recipient(recipient), Value('code', label='Veuillez saisir le code reçu par SMS')) def new_recipient(self, recipient, is_bp_account=False, **params): if params.get('resume') or self.resume: @@ -902,11 +903,17 @@ def new_recipient(self, recipient, is_bp_account=False, **params): if 'code' in params: # Case of SMS OTP - assert self.rcpt_code.is_here() - self.post_code(params['code']) self.recipient_form = None - assert self.rcpt_summary.is_here() + + if self.rcpt_error.is_here(): + error = self.page.get_error() + if error: + if 'Votre code sécurité est incorrect' in error: + raise RecipientInvalidOTP(message=error) + raise AssertionError('Unhandled error message : "%s"' % error) + + assert self.rcpt_summary.is_here(), 'Should be on recipient addition summary page' return self.build_recipient(recipient) self.init_new_recipient(recipient, is_bp_account, **params) diff --git a/modules/bp/pages/__init__.py b/modules/bp/pages/__init__.py index 72a56a9c90b45b76fc2ec469e0a198e9b4e5ec66..5a2b7230ad4522276f4a50bdafb2cd1758ff80fd 100644 --- a/modules/bp/pages/__init__.py +++ b/modules/bp/pages/__init__.py @@ -30,6 +30,7 @@ TransferSummary, CreateRecipient, ValidateRecipient, ValidateCountry, ConfirmPage, RcptSummary, HonorTransferPage, RecipientSubmitDevicePage, + RcptErrorPage, ) from .subscription import SubscriptionPage, DownloadPage, ProSubscriptionPage @@ -39,5 +40,5 @@ 'AccountDesactivate', 'TransferChooseAccounts', 'CompleteTransfer', 'TransferConfirm', 'TransferSummary', 'UnavailablePage', 'CardsList', 'AccountRIB', 'Advisor', 'CreateRecipient', 'ValidateRecipient', 'ValidateCountry', 'ConfirmPage', 'RcptSummary', 'SubscriptionPage', 'DownloadPage', 'ProSubscriptionPage', 'RevolvingAttributesPage', 'Validated2FAPage', 'TwoFAPage', - 'SmsPage', 'DecoupledPage', 'HonorTransferPage', 'RecipientSubmitDevicePage', + 'SmsPage', 'DecoupledPage', 'HonorTransferPage', 'RecipientSubmitDevicePage', 'RcptErrorPage', ] diff --git a/modules/bp/pages/transfer.py b/modules/bp/pages/transfer.py index cf24d267079a7efcb6b6a1aba622e0a518533e4f..393212ce39e2a9235fdfe2b7434db9031869749a 100644 --- a/modules/bp/pages/transfer.py +++ b/modules/bp/pages/transfer.py @@ -36,6 +36,7 @@ from weboob.tools.capabilities.bank.transactions import FrenchTransaction from weboob.tools.capabilities.bank.iban import is_iban_valid from weboob.tools.value import Value +from weboob.tools.compat import urljoin from weboob.exceptions import BrowserUnavailable, AuthMethodNotImplemented from .base import MyHTMLPage @@ -391,12 +392,14 @@ def get_confirm_link(self): return Link('//a[@title="confirmer la creation"]')(self.doc) -class ConfirmPage(LoggedPage, MyHTMLPage): +class CheckErrorsPage(LoggedPage, MyHTMLPage): def check_errors(self): error_msg = CleanText('//h2[contains(text(), "Compte rendu")]/following-sibling::p')(self.doc) if error_msg: raise AddRecipientBankError(message=error_msg) + +class ConfirmPage(CheckErrorsPage): def get_device_choice_url(self): device_choice_popup_js = CleanText('//script[contains(text(), "popupChoixDevice")]')(self.doc) if device_choice_popup_js: @@ -407,7 +410,15 @@ def get_device_choice_url(self): def set_browser_form(self): form = self.get_form(name='SaisieOTP') self.browser.recipient_form = dict((k, v) for k, v in form.items() if v) - self.browser.recipient_form['url'] = form.url + # Confirmation url is relative to the current page. We need to + # build it now or the relative path will fail when reloading state + # because we do not reload the url in it. + self.browser.recipient_form['url'] = urljoin(self.url, form.url) + + +class RcptErrorPage(LoggedPage, MyHTMLPage): + def get_error(self): + return CleanText('//form//span[@class="warning"]')(self.doc) class RecipientSubmitDevicePage(LoggedPage, MyHTMLPage): @@ -431,5 +442,5 @@ def get_app_validation_message(self): return app_validation_message -class RcptSummary(LoggedPage, MyHTMLPage): +class RcptSummary(CheckErrorsPage): pass