From 4ae9d7cc0361da94091fef28c274a08c854edca2 Mon Sep 17 00:00:00 2001 From: Sylvie Ye Date: Tue, 15 Jan 2019 18:16:24 +0100 Subject: [PATCH] [cmb] add new feature iter recipient --- modules/cmso/module.py | 12 +++- modules/cmso/par/browser.py | 35 +++++++++- modules/cmso/par/pages.py | 33 ++------- modules/cmso/par/transfer_pages.py | 108 +++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 34 deletions(-) create mode 100644 modules/cmso/par/transfer_pages.py diff --git a/modules/cmso/module.py b/modules/cmso/module.py index 87b404797a..7a0b899018 100644 --- a/modules/cmso/module.py +++ b/modules/cmso/module.py @@ -19,7 +19,7 @@ from __future__ import unicode_literals -from weboob.capabilities.bank import CapBankWealth, AccountNotFound +from weboob.capabilities.bank import CapBankTransfer, CapBankWealth, Account, AccountNotFound from weboob.capabilities.contact import CapContact from weboob.capabilities.base import find_object from weboob.capabilities.profile import CapProfile @@ -33,7 +33,7 @@ __all__ = ['CmsoModule'] -class CmsoModule(Module, CapBankWealth, CapContact, CapProfile): +class CmsoModule(Module, CapBankTransfer, CapBankWealth, CapContact, CapProfile): NAME = 'cmso' MAINTAINER = 'Romain Bignon' EMAIL = 'romain@weboob.org' @@ -69,6 +69,14 @@ def iter_coming(self, account): def iter_investment(self, account): return self.browser.iter_investment(account) + def iter_transfer_recipients(self, origin_account): + if self.config['website'].get() != "par": + raise NotImplementedError() + + if not isinstance(origin_account, Account): + origin_account = self.get_account(origin_account) + return self.browser.iter_recipients(origin_account) + def iter_contacts(self): if self.config['website'].get() != "par": raise NotImplementedError() diff --git a/modules/cmso/par/browser.py b/modules/cmso/par/browser.py index 846374cdd3..afaead6f8e 100644 --- a/modules/cmso/par/browser.py +++ b/modules/cmso/par/browser.py @@ -33,8 +33,9 @@ from .pages import ( LogoutPage, InfosPage, AccountsPage, HistoryPage, LifeinsurancePage, MarketPage, - AdvisorPage, LoginPage, RecipientsPage, ProfilePage, + AdvisorPage, LoginPage, ProfilePage, ) +from .transfer_pages import TransferInfoPage def retry(exc_check, tries=4): @@ -92,7 +93,8 @@ class CmsoParBrowser(LoginBrowser, StatesMixin): 'https://www.*/domiweb/prive/particulier', MarketPage) advisor = URL('/edrapi/v(?P\w+)/oauth/(?P\w+)', AdvisorPage) - recipients = URL(r'/domiapi/oauth/json/transfer/transferinfos', RecipientsPage) + # transfer + transfer_info = URL(r'/domiapi/oauth/json/transfer/transferinfos', TransferInfoPage) profile = URL(r'/domiapi/oauth/json/edr/infosPerson', ProfilePage) @@ -158,7 +160,7 @@ def iter_accounts(self): seen = {} - self.recipients.go(data='{"beneficiaryType":"INTERNATIONAL"}', headers=self.json_headers) + self.transfer_info.go(data='{"beneficiaryType":"INTERNATIONAL"}', headers=self.json_headers) numbers = self.page.get_numbers() # First get all checking accounts... @@ -305,6 +307,33 @@ def iter_investment(self, account): return [] raise NotImplementedError() + @retry((ClientError, ServerError)) + @need_login + def iter_recipients(self, account): + self.transfer_info.go( + data='{"beneficiaryType":"INTERNATIONAL"}', + headers=self.json_headers + ) + + if account.type in (Account.TYPE_LOAN, ): + return + if not account._eligible_debit: + return + + # internal recipient + for rcpt in self.page.iter_titu_accounts(): + if rcpt.id != account.id: + yield rcpt + for rcpt in self.page.iter_manda_accounts(): + if rcpt.id != account.id: + yield rcpt + for rcpt in self.page.iter_legal_rep_accounts(): + if rcpt.id != account.id: + yield rcpt + # external recipient + for rcpt in self.page.iter_external_recipients(): + yield rcpt + @retry((ClientError, ServerError)) @need_login def get_advisor(self): diff --git a/modules/cmso/par/pages.py b/modules/cmso/par/pages.py index c6c99b1a45..6e8e1fe759 100644 --- a/modules/cmso/par/pages.py +++ b/modules/cmso/par/pages.py @@ -135,6 +135,8 @@ class item(ItemElement): # Iban is available without last 5 numbers, or by sms obj_iban = NotAvailable obj__index = Dict('index') + # to know if we can do transfer on account + obj__eligible_debit = Dict('eligibiliteDebit', default=False) def obj_balance(self): balance = CleanDecimal(Dict('soldeEuro', default="0"))(self) @@ -194,6 +196,8 @@ class item(ItemElement): obj_coming = CleanDecimal(Dict('AVenir', default=None), default=NotAvailable) obj__index = Dict('index') obj__owner = Dict('nomTitulaire') + # to know if we can do transfer on account + obj__eligible_debit = Dict('eligibiliteDebit', default=False) def obj_id(self): type = Field('type')(self) @@ -549,35 +553,6 @@ class update_agency(ItemElement): obj_address = Format('%s %s', Dict('adresse1'), Dict('adresse3')) -class RecipientsPage(LoggedPage, JsonPage): - def get_numbers(self): - # If account information is not available when asking for the - # recipients (server error for ex.), return an empty dictionary - # that will be filled later after being returned the json of the - # account page (containing the accounts IDs too). - if 'listCompteTitulaireCotitulaire' not in self.doc and 'exception' in self.doc: - return {} - - ret = {} - - ret.update({ - d['index']: d['numeroContratSouscrit'] - for d in self.doc['listCompteTitulaireCotitulaire'] - }) - ret.update({ - d['index']: d['numeroContratSouscrit'] - for p in self.doc['listCompteMandataire'].values() - for d in p - }) - ret.update({ - d['index']: d['numeroContratSouscrit'] - for p in self.doc['listCompteLegalRep'].values() - for d in p - }) - - return ret - - class ProfilePage(LoggedPage, JsonPage): # be careful, this page is used in CmsoProBrowser too! diff --git a/modules/cmso/par/transfer_pages.py b/modules/cmso/par/transfer_pages.py new file mode 100644 index 0000000000..4dd54bb44a --- /dev/null +++ b/modules/cmso/par/transfer_pages.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2019 Sylvie Ye +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + +from __future__ import unicode_literals + +import datetime as dt + +from weboob.browser.pages import JsonPage, LoggedPage +from weboob.browser.elements import DictElement, ItemElement, method +from weboob.browser.filters.json import Dict +from weboob.capabilities.bank import Recipient +from weboob.capabilities.base import NotAvailable + + +class MyRecipientItemElement(ItemElement): + def condition(self): + return Dict('eligibiliteCredit', default=False) + + klass = Recipient + + obj_id = Dict('numeroContratSouscrit') + obj_label = Dict('lib') + obj_iban = NotAvailable + obj_enabled_at = dt.date.today() + obj_category = 'Interne' + obj__index = Dict('index') + + +class TransferInfoPage(LoggedPage, JsonPage): + def get_numbers(self): + # If account information is not available when asking for the + # recipients (server error for ex.), return an empty dictionary + # that will be filled later after being returned the json of the + # account page (containing the accounts IDs too). + if 'listCompteTitulaireCotitulaire' not in self.doc and 'exception' in self.doc: + return {} + + ret = {} + + ret.update({ + d['index']: d['numeroContratSouscrit'] + for d in self.doc['listCompteTitulaireCotitulaire'] + }) + ret.update({ + d['index']: d['numeroContratSouscrit'] + for p in self.doc['listCompteMandataire'].values() + for d in p + }) + ret.update({ + d['index']: d['numeroContratSouscrit'] + for p in self.doc['listCompteLegalRep'].values() + for d in p + }) + + return ret + + @method + class iter_titu_accounts(DictElement): + item_xpath = 'listCompteTitulaireCotitulaire' + + class item(MyRecipientItemElement): + pass + + @method + class iter_manda_accounts(DictElement): + item_xpath = 'listCompteMandataire/*' + + class item(MyRecipientItemElement): + pass + + @method + class iter_legal_rep_accounts(DictElement): + item_xpath = 'listCompteLegalRep/*' + + class item(MyRecipientItemElement): + pass + + @method + class iter_external_recipients(DictElement): + item_xpath = 'listBeneficiaries' + + class item(ItemElement): + klass = Recipient + + obj_id = obj_iban = Dict('iban') + obj_label = Dict('nom') + obj_category = 'Externe' + obj_enabled_at = dt.date.today() + obj__index = Dict('index') + + def condition(self): + return Dict('actif', default=False)(self) -- GitLab