diff --git a/modules/s2e/browser.py b/modules/s2e/browser.py index 37f84281a58fada2b435704d77e35d52750b3918..a27487557cd919662f7da5259c6b4a6ec11cdd15 100644 --- a/modules/s2e/browser.py +++ b/modules/s2e/browser.py @@ -35,7 +35,8 @@ EtoileGestionPage, EtoileGestionCharacteristicsPage, EtoileGestionDetailsPage, BNPInvestmentsPage, BNPInvestmentDetailsPage, LyxorFundsPage, EsaliaDetailsPage, EsaliaPerformancePage, AmundiDetailsPage, AmundiPerformancePage, ProfilePage, - HsbcVideoPage, CprInvestmentPage, CprPerformancePage, EServicePage, + HsbcVideoPage, CprInvestmentPage, CprPerformancePage, CmCicInvestmentPage, + HsbcInvestmentPage, EServicePage, ) @@ -89,11 +90,18 @@ class S2eBrowser(LoginBrowser, StatesMixin): EsaliaPerformancePage ) # HSBC pages - hsbc_video = URL('https://(.*)videos-pedagogiques/fonds-hsbc-ee-dynamique', HsbcVideoPage) + hsbc_video = URL(r'https://(.*)videos-pedagogiques/fonds-hsbc-ee-dynamique', HsbcVideoPage) amfcode_hsbc = URL(r'https://www.assetmanagement.hsbc.com/feedRequest', AMFHSBCPage) + hsbc_investments = URL(r'https://www.assetmanagement.hsbc.com/fr/fcpe-closed', HsbcInvestmentPage) # CPR Asset Management pages cpr_investments = URL(r'https://www.cpr-am.fr/particuliers/product/view', CprInvestmentPage) cpr_performance = URL(r'https://www.cpr-am.fr/particuliers/ezjscore', CprPerformancePage) + # CM-CIC investments + cm_cic_investments = URL( + r'https://www.cmcic-am.fr/fr/particuliers/nos-fonds/VALE_FicheSynthese.aspx', + r'https://www.cmcic-am.fr/fr/particuliers/nos-fonds/VALE_Fiche', + CmCicInvestmentPage + ) e_service_page = URL( r'/portal/salarie-(?P\w+)/mesdonnees/eservice\?scenario=ConsulterEService', @@ -288,6 +296,37 @@ def update_investments(self, investments): if complete_performance_history: inv.performance_history = complete_performance_history + elif self.hsbc_investments.match(inv._link): + # Handle investment detail as for erehsbc subsite + m = re.search(r'id=(\w+).+SH=(\w+)', inv._link) + if m: + params = { + 'feed_data': 'fundbyiden', + 'ctry': 'FR', + 'client': 'FCPC', + 'fId': m.group(1), + 'lang': 'fr', + 'SH': m.group(2), + } + self.amfcode_hsbc.go(params=params) + if self.amfcode_hsbc.is_here(): + inv.code = self.page.get_code() + inv.code_type = Investment.CODE_TYPE_AMF + inv.asset_category = self.page.get_asset_category() + + elif self.cm_cic_investments.match(inv._link): + self.location(inv._link) + if self.cm_cic_investments.is_here(): + # Load investment details data + params = { + 'ddp': self.page.get_ddp(), + 'forceActualisation': 'O', + } + self.cm_cic_investments.go(params=params) + inv.code = self.page.get_code() + inv.code_type = Investment.CODE_TYPE_AMF + inv.performance_history = self.page.get_performance_history() + return investments @need_login diff --git a/modules/s2e/pages.py b/modules/s2e/pages.py index bed1679c05e2d77c4bb9747ce3c6586916502a01..b760cb40fd33ebb296d61f39170e8e9cb79d9438 100644 --- a/modules/s2e/pages.py +++ b/modules/s2e/pages.py @@ -42,6 +42,7 @@ Link, ) from weboob.browser.filters.json import Dict +from weboob.browser.filters.javascript import JSVar from weboob.browser.exceptions import HTTPNotFound from weboob.capabilities.bank import Account, Transaction from weboob.capabilities.wealth import Investment, Pocket @@ -252,6 +253,10 @@ class HsbcVideoPage(LoggedPage, HTMLPage): pass +class HsbcInvestmentPage(LoggedPage, HTMLPage): + pass + + class CodePage(object): ''' This class is used as a parent class to include @@ -263,7 +268,7 @@ def get_asset_category(self): # AMF codes -class AMFHSBCPage(XMLPage, CodePage): +class AMFHSBCPage(LoggedPage, XMLPage, CodePage): ENCODING = "UTF-8" CODE_TYPE = Investment.CODE_TYPE_AMF @@ -286,7 +291,31 @@ def get_asset_category(self): return CleanText('//Asset_Class')(self.doc) -class AMFAmundiPage(HTMLPage, CodePage): +class CmCicInvestmentPage(LoggedPage, HTMLPage): + def get_ddp(self): + # This value is required to access the page containing the investment data. + # For some reason they added 'ddp=' at the beginning of the ddp itself... + ddp = JSVar(CleanText('//script'), var='ddp')(self.doc) + return ddp.replace('ddp=', '') + + def get_code(self): + return CleanText( + '//th[span[contains(text(), "Code Isin")]]/following-sibling::td//span', + default=NotAvailable + )(self.doc) + + def get_performance_history(self): + durations = [CleanText('.')(el) for el in self.doc.xpath('//table[@id="t_PerformancesEnDate"]//thead//span')] + values = [CleanText('.')(el) for el in self.doc.xpath('//table[@id="t_PerformancesEnDate"]//tbody//tr[1]//td')] + matches = dict(zip(durations, values)) + perfs = {} + for k, v in {1: '1 an', 3: '3 ans', 5: '5 ans'}.items(): + if matches.get(v): + perfs[k] = percent_to_ratio(CleanDecimal.French(default=NotAvailable).filter(matches[v])) + return perfs + + +class AMFAmundiPage(LoggedPage, HTMLPage, CodePage): CODE_TYPE = Investment.CODE_TYPE_AMF def get_code(self): @@ -487,6 +516,8 @@ def parse(self, el): or url.startswith('https://www.amundi-ee.com') or url.startswith('http://www.etoile-gestion.com/productsheet') or url.startswith('https://www.cpr-am.fr') + or url.startswith('https://www.cmcic-am.fr/fr/particuliers/nos-fonds/VALE_Fiche') + or url.startswith('https://www.assetmanagement.hsbc.com/fr/fcpe-closed') ): self.env['_link'] = url @@ -524,6 +555,8 @@ def parse(self, el): 'https://www.rothschildgestion.com', # URL to the Morningstar website does not contain any useful information 'http://doc.morningstar.com', + # URL to Russell investments directly leads to the DICI PDF + 'https://russellinvestments.com', ) for useless_url in useless_urls: if url.startswith(useless_url): @@ -1029,10 +1062,14 @@ class BNPInvestmentDetailsPage(LoggedPage, JsonPage): class fill_investment(ItemElement): obj_code = IsinCode(CleanText(Dict('isin')), default=NotAvailable) obj_code_type = IsinType(CleanText(Dict('isin'))) - obj_srri = Eval(int, Dict('risque')) obj_asset_category = Dict('classification') obj_recommended_period = Dict('dureePlacement') + def obj_srri(self): + if Dict('risque')(self): + return Eval(int, Dict('risque'))(self) + return NotAvailable + def obj_performance_history(self): # Fetching the performance history (1 year, 3 years & 5 years) perfs = {}