Ejemplo n.º 1
0
    def iter_investment(self, account):
        if not account.url or account.type not in (Account.TYPE_MARKET, Account.TYPE_PEA, Account.TYPE_LIFE_INSURANCE):
            return

        if account._perimeter != self.current_perimeter:
            self.go_perimeter(account._perimeter)

        if account.type == Account.TYPE_PEA and account._liquidity_url:
            yield create_french_liquidity(account.balance)
            return

        if account.type in (Account.TYPE_MARKET, Account.TYPE_PEA):
            new_location = self.moveto_market_website(account)
            # Detail unavailable
            try:
                self.location(new_location)
            except BrowserHTTPError:
                return
        elif account.type == Account.TYPE_LIFE_INSURANCE:
            new_location = self.moveto_insurance_website(account)

            if not new_location:
                return

            self.location(new_location, data={})

            if self.bgpi.is_here():
                if self.page.cgu_needed() or not self.page.go_detail():
                    return
                # Going the the life insurances details is not enough,
                # Once we are there we need to select the correct one:
                data = self.page.get_params(account.id)
                if not data:
                    return
                self.location('https://bgpi-gestionprivee.credit-agricole.fr/bgpi/CompteDetail.do', data=data)

            if self.lifeinsurance.is_here():
                self.page.go_on_detail(account.id)
                # We scrape the non-invested part as liquidities:
                if self.page.has_liquidities():
                    valuation = self.page.get_liquidities()
                    yield create_french_liquidity(valuation)

        for inv in self.page.iter_investment():
            yield inv

        if account.type in (Account.TYPE_MARKET, Account.TYPE_PEA):
            self.quit_market_website()
        elif account.type == Account.TYPE_LIFE_INSURANCE:
            self.quit_insurance_website()
Ejemplo n.º 2
0
 def get_liquidity(self):
     # Not all accounts have a Liquidity element
     liquidity_element = CleanDecimal.French(
         '//td[contains(text(), "Solde espèces en euros")]//following-sibling::td[position()=1]',
         default=None)(self.doc)
     if liquidity_element:
         return create_french_liquidity(liquidity_element)
Ejemplo n.º 3
0
    def iter_investment(self, account):
        if account.balance == 0:
            return
        # Start with liquidities:
        if account._liquidity:
            yield create_french_liquidity(account._liquidity)

        if self.old_website_connection:
            self.old_accounts.stay_or_go().go_to_account(account.id)
            if account._invpage:
                for inv in account._invpage.iter_investment(currency=account.currency):
                    if not inv.code:
                        params = {'securityId': inv._security_id}
                        self.invest_detail.go(params=params)
                        if self.invest_detail.is_here():
                            inv.code, inv.code_type = self.page.get_isin_code_and_type()
                    yield inv
            return

        self.switch_account(account.id)
        token = self.page.get_token()

        try:
            data = {'grouping': 'SecurityCategory'}
            self.investment.go(data=data, headers=token)
        except HTTPNotFound:
            return

        for inv in self.page.iter_investment(currency=account.currency):
            yield inv
Ejemplo n.º 4
0
    def get_investment(self, account):
        if account.type == Account.TYPE_LIFE_INSURANCE:
            if not account._external_website:
                self.logger.warning(
                    'This account is limited, there is no available investment.'
                )
                return

            self.assurancevie.stay_or_go()
            if account._is_calie_account:
                calie_details = self.open(account.url)
                for inv in calie_details.page.iter_investment():
                    yield inv
            else:
                self.go_life_insurance_website()
                assert self.av_list.is_here(
                ), 'Something went wrong during iter life insurance investments'
                self.av_investments.go(life_insurance_id=account.id)
                for inv in self.page.iter_investment():
                    yield inv
                self.go_back_from_life_insurance_website()

        elif hasattr(account, '_market_link') and account._market_link:
            self.connexion_bourse()
            for inv in self.location(
                    account._market_link).page.iter_investment():
                yield inv
            self.deconnexion_bourse()
        elif account.id in self.get_bourse_accounts_ids():
            yield create_french_liquidity(account.balance)
Ejemplo n.º 5
0
    def iter_investment(self, account):
        self.transactions.go()
        if account._acctype == 'bank' and account.type in (Account.TYPE_PEA, Account.TYPE_MARKET):
            if 'Liquidités' in account.label:
                return [create_french_liquidity(account.balance)]

            account = self.get_netfinca_account(account)
            self.location(account._market_link)
            assert self.bourse.is_here()
            return self.page.iter_investment()

        if account.id not in self.cache['invs']:
            # do we still need it ?...
            if account._acctype == "bank" and account._hasinv:
                self.go_account_pages(account, "investment")
            elif account._acctype == "investment":
                self.go_wealth_pages(account)
                investment_url = self.page.get_investment_url()
                if investment_url is None:
                    self.logger.warning('no investment link for account %s, returning empty', account)
                    # fake data, don't cache it
                    return []
                self.location(investment_url)
            self.cache['invs'][account.id] = list(self.page.iter_investment(currency=account.currency))
        return self.cache['invs'][account.id]
Ejemplo n.º 6
0
    def get_investments(self, account):
        if account is not None:
            # the balance is highly dynamic, fetch it along with the investments to grab a snapshot
            account.balance = CleanDecimal(None, replace_dots=True).filter(self.get_balance(account.type))

        for line in self.doc.xpath('//table[@id="t_intraday"]/tbody/tr'):
            if line.find_class('categorie') or line.find_class('detail') or line.find_class('detail02'):
                continue

            cols = line.findall('td')

            inv = Investment()
            inv.label = CleanText(None).filter(cols[self.COL_LABEL])
            link = cols[self.COL_LABEL].xpath('./a[contains(@href, "cdReferentiel")]')[0]
            inv.id = re.search('cdReferentiel=(.*)', link.attrib['href']).group(1)
            inv.code = re.match('^[A-Z]+[0-9]+(.*)$', inv.id).group(1)
            inv.quantity = self.parse_decimal(cols[self.COL_QUANTITY], True)
            inv.unitprice = self.parse_decimal(cols[self.COL_UNITPRICE], True)
            inv.unitvalue = self.parse_decimal(cols[self.COL_UNITVALUE], False)
            inv.valuation = self.parse_decimal(cols[self.COL_VALUATION], True)
            diff = cols[self.COL_PERF].text.strip()
            if diff == "-":
                inv.diff = NotAvailable
            else:
                inv.diff = CleanDecimal(None, replace_dots=True).filter(diff)

            if is_isin_valid(inv.code):
                inv.code_type = Investment.CODE_TYPE_ISIN

            yield inv
        if account.type != account.TYPE_MARKET:
            valuation = CleanDecimal(None, True).filter(self.doc.xpath('//*[@id="valorisation_compte"]/table/tr[3]/td[2]'))
            yield create_french_liquidity(valuation)
Ejemplo n.º 7
0
    def iter_investment(self, account):
        today = datetime.date.today()

        self.coming.go()

        # unfortunately there doesn't seem to be a page indicating what's
        # left to be repaid on each project, so let's sum...
        valuations = {}
        commissions = {}
        for tr in self.page.iter_transactions():
            if tr.date <= today:
                continue

            if tr.raw not in valuations:
                valuations[tr.raw] = tr.amount
                commissions[tr.raw] = tr.commission
            else:
                valuations[tr.raw] += tr.amount
                commissions[tr.raw] += tr.commission

        for label, value in valuations.items():
            inv = Investment()
            inv.label = label
            inv.valuation = value
            inv.diff = commissions[label]
            yield inv

        yield create_french_liquidity(account._liquidities)
Ejemplo n.º 8
0
    def iter_investment(self, account):
        # Start with liquidities:
        if account._liquidity:
            yield create_french_liquidity(account._liquidity)

        ''' Delete this part when old website is obsolete '''
        if self.old_website_connection:
            self.old_accounts.stay_or_go().go_to_account(account.id)
            if account._invpage:
                for inv in account._invpage.iter_investment(currency=account.currency):
                    if not inv.code:
                        params = {'securityId': inv._security_id}
                        self.invest_detail.go(params=params)
                        if self.invest_detail.is_here():
                            inv.code, inv.code_type = self.page.get_isin_code_and_type()
                    yield inv
            return

        self.switch_account(account.id)
        token = self.page.get_token()

        try:
            data = {'grouping': 'SecurityCategory'}
            self.investment.go(data=data, headers=token)
        except HTTPNotFound:
            return

        for inv in self.page.iter_investment(currency=account.currency):
            yield inv
Ejemplo n.º 9
0
    def get_investments(self, account):
        if account is not None:
            # the balance is highly dynamic, fetch it along with the investments to grab a snapshot
            account.balance = CleanDecimal(None, replace_dots=True).filter(self.get_balance(account.type))

        for line in self.doc.xpath('//table[@id="t_intraday"]/tbody/tr'):
            if line.find_class('categorie') or line.find_class('detail') or line.find_class('detail02'):
                continue

            cols = line.findall('td')

            inv = Investment()
            inv.label = CleanText(None).filter(cols[self.COL_LABEL])
            link = cols[self.COL_LABEL].xpath('./a[contains(@href, "cdReferentiel")]')[0]
            inv.id = re.search('cdReferentiel=(.*)', link.attrib['href']).group(1)
            inv.code = re.match('^[A-Z]+[0-9]+(.*)$', inv.id).group(1)
            inv.quantity = self.parse_decimal(cols[self.COL_QUANTITY], True)
            inv.unitprice = self.parse_decimal(cols[self.COL_UNITPRICE], True)
            inv.unitvalue = self.parse_decimal(cols[self.COL_UNITVALUE], False)
            inv.valuation = self.parse_decimal(cols[self.COL_VALUATION], True)
            diff = cols[self.COL_PERF].text.strip()
            if diff == "-":
                inv.diff = NotAvailable
            else:
                inv.diff = CleanDecimal(None, replace_dots=True).filter(diff)

            if is_isin_valid(inv.code):
                inv.code_type = Investment.CODE_TYPE_ISIN

            yield inv
        if account.type != account.TYPE_MARKET:
            valuation = CleanDecimal(None, True).filter(self.doc.xpath('//*[@id="valorisation_compte"]/table/tr[3]/td[2]'))
            yield create_french_liquidity(valuation)
Ejemplo n.º 10
0
    def iter_investment(self, account):
        self.transactions.go()
        if account._acctype == 'bank' and account.type in (Account.TYPE_PEA, Account.TYPE_MARKET):
            if 'Liquidités' in account.label:
                return [create_french_liquidity(account.balance)]

            account = self.get_netfinca_account(account)
            self.location(account._market_link)
            assert self.bourse.is_here()
            return self.page.iter_investment()

        if account.id not in self.cache['invs']:
            # do we still need it ?...
            if account._acctype == "bank" and account._hasinv:
                self.go_account_pages(account, "investment")
            elif account._acctype == "investment":
                self.go_wealth_pages(account)
                investment_url = self.page.get_investment_url()
                if investment_url is None:
                    self.logger.warning('no investment link for account %s, returning empty', account)
                    # fake data, don't cache it
                    return []
                self.location(investment_url)
            self.cache['invs'][account.id] = list(self.page.iter_investment(currency=account.currency))
        return self.cache['invs'][account.id]
Ejemplo n.º 11
0
    def iter_investment(self):
        # Xpath can be h3/h4 or div/span; in both cases
        # the first node contains "Solde Espèces":
        valuation = CleanDecimal('//li/*[contains(text(), "Solde Espèces")]/following-sibling::*', replace_dots=True, default=None)(self.doc)
        if valuation:
            yield create_french_liquidity(valuation)

        for inv in self.get_investment():
            yield inv
Ejemplo n.º 12
0
    def iter_investment(self, account):
        if account.type in (Account.TYPE_PERP, Account.TYPE_PERCO, Account.TYPE_LIFE_INSURANCE, Account.TYPE_CAPITALISATION):
            if account.label == "Vers l'avenir":
                # Website crashes when clicking on these Life Insurances...
                return
            self.go_to_account_space(account._contract)
            token = self.token_page.go().get_token()
            data = {
                'situation_travail': 'CONTRAT',
                'idelco': account.id,
                ':cq_csrf_token': token,
            }
            self.predica_redirection.go(data=data)
            self.predica_investments.go()
            for inv in self.page.iter_investments():
                yield inv

        elif account.type == Account.TYPE_PEA and account.label == 'Compte espèce PEA':
            yield create_french_liquidity(account.balance)
            return

        elif account.type in (Account.TYPE_PEA, Account.TYPE_MARKET):
            # Do not try to get to Netfinca if there is no money
            # on the account or the server will return an error 500
            if account.balance == 0:
                return
            self.go_to_account_space(account._contract)
            token = self.token_page.go().get_token()
            data = {
                'situation_travail': 'BANCAIRE',
                'num_compte': account.id,
                'code_fam_produit': account._fam_product_code,
                'code_fam_contrat_compte': account._fam_contract_code,
                ':cq_csrf_token': token,
            }

            # For some market accounts, investments are not even accessible,
            # and the only way to know if there are investments is to try
            # to go to the Netfinca space with the accounts parameters.
            try:
                self.netfinca_redirection.go(data=data)
            except BrowserHTTPNotFound:
                self.logger.info('Investments are not available for this account.')
                self.go_to_account_space(account._contract)
                return
            url = self.page.get_url()
            if 'netfinca' in url:
                self.location(url)
                self.netfinca.session.cookies.update(self.session.cookies)
                self.netfinca.accounts.go()
                for inv in self.netfinca.iter_investments(account):
                    if inv.code == 'XX-liquidity' and account.type == Account.TYPE_PEA:
                        # Liquidities are already fetched on the "PEA espèces"
                        continue
                    yield inv
Ejemplo n.º 13
0
    def get_investment(self, account):
        if account.type in (Account.TYPE_LOAN, ):
            self.investments[account.id] = []
            return []

        # Add "Liquidities" investment if the account is a "Compte titres PEA":
        if account.type == Account.TYPE_PEA and account.id.startswith('CPT'):
            self.investments[account.id] = [
                create_french_liquidity(account.balance)
            ]
            return self.investments[account.id]

        if account.id in self.investments.keys(
        ) and self.investments[account.id] is False:
            raise NotImplementedError()

        if account.id not in self.investments.keys():
            self.investments[account.id] = []
            try:
                if self.go_investments(account, get_account=True):
                    # Redirection URL is https://www.linebourse.fr/ReroutageSJR
                    if "linebourse" in self.url:
                        # Eliminating the 3 letters prefix to match IDs on Linebourse:
                        linebourse_id = account.id[3:]
                        for inv in self.linebourse.iter_investment(
                                linebourse_id):
                            self.investments[account.id].append(inv)

                    if self.etna.is_here():
                        params = self.page.params
                    elif self.natixis_redirect.is_here():
                        # the url may contain a "#", so we cannot make a request to it, the params after "#" would be dropped
                        url = self.page.get_redirect()
                        self.logger.debug('using redirect url %s', url)
                        m = self.etna.match(url)
                        if not m:
                            # url can be contratPrev which is not investments
                            self.logger.debug(
                                'Unable to handle this kind of contract')
                            raise NotImplementedError()

                        params = m.groupdict()

                    if self.natixis_redirect.is_here() or self.etna.is_here():
                        try:
                            self.natixis_invest.go(**params)
                        except ServerError:
                            # Broken website .. nothing to do.
                            self.investments[account.id] = iter([])
                            return self.investments[account.id]
                        self.investments[account.id] = list(
                            self.page.get_investments())
            except NotImplementedError:
                self.investments[account.id] = []
        return self.investments[account.id]
Ejemplo n.º 14
0
    def iter_investments(self, account):
        if account.type not in (Account.TYPE_LIFE_INSURANCE, Account.TYPE_PEA,
                                Account.TYPE_MARKET, Account.TYPE_PERP):
            return

        # Add "Liquidities" investment if the account is a "Compte titres PEA":
        if account.type == Account.TYPE_PEA and account.id.startswith('CPT'):
            yield create_french_liquidity(account.balance)
            return

        if self.go_investments(account, get_account=True):
            # Redirection URL is https://www.linebourse.fr/ReroutageSJR
            if 'linebourse' in self.url:
                self.logger.warning(
                    'Going to Linebourse space to fetch investments.')
                # Eliminating the 3 letters prefix to match IDs on Linebourse:
                linebourse_id = account.id[3:]
                for inv in self.linebourse.iter_investment(linebourse_id):
                    yield inv
                return

            if self.etna.is_here():
                self.logger.warning(
                    'Going to Etna space to fetch investments.')
                params = self.page.params

            elif self.natixis_redirect.is_here():
                self.logger.warning(
                    'Going to Natixis space to fetch investments.')
                # the url may contain a "#", so we cannot make a request to it, the params after "#" would be dropped
                url = self.page.get_redirect()
                self.logger.debug('using redirect url %s', url)
                m = self.etna.match(url)
                if not m:
                    # URL can be contratPrev which is not investments
                    self.logger.warning(
                        'Unable to handle this kind of contract.')
                    return

                params = m.groupdict()

            if self.natixis_redirect.is_here() or self.etna.is_here():
                try:
                    self.natixis_invest.go(**params)
                except ServerError:
                    # Broken website... nothing to do.
                    return
                for inv in self.page.iter_investments():
                    yield inv
Ejemplo n.º 15
0
 def get_investment(self, account):
     if account._is_inv:
         if account.type in (Account.TYPE_MARKET, Account.TYPE_PEA):
             self.por.go(subbank=self.currentSubBank)
             self.page.send_form(account)
         elif account.type == Account.TYPE_LIFE_INSURANCE:
             if not account._link_inv:
                 return iter([])
             self.location(account._link_inv)
         return self.page.iter_investment()
     if account.type is Account.TYPE_PEA:
         liquidities = create_french_liquidity(account.balance)
         liquidities.label = account.label
         return [liquidities]
     return iter([])
Ejemplo n.º 16
0
 def get_investment(self, account):
     if account._is_inv:
         if account.type in (Account.TYPE_MARKET, Account.TYPE_PEA):
             self.por.go(subbank=self.currentSubBank)
             self.page.send_form(account)
         elif account.type == Account.TYPE_LIFE_INSURANCE:
             if not account._link_inv:
                 return iter([])
             self.location(account._link_inv)
         return self.page.iter_investment()
     if account.type is Account.TYPE_PEA:
         liquidities = create_french_liquidity(account.balance)
         liquidities.label = account.label
         return [liquidities]
     return iter([])
Ejemplo n.º 17
0
 def iter_investment(self, account):
     if account.id not in self.invs:
         staging = '_s' if 'staging' in self.sessionId else ''
         self.accounts.stay_or_go(staging=staging,
                                  accountId=self.intAccount,
                                  sessionId=self.sessionId)
         invests = list(
             self.page.iter_investment(currency=account.currency))
         # Replace as liquidities investments that are cash
         self.invs[account.id] = [
             create_french_liquidity(inv.valuation) if len(inv.label) < 4
             and Currency.get_currency(inv.label) else inv
             for inv in invests
         ]
     return self.invs[account.id]
Ejemplo n.º 18
0
    def iter_investment(self, account):
        if account.type == Account.TYPE_PEA and 'espèces' in account.label.lower(
        ):
            return [create_french_liquidity(account.balance)]

        # Life insurances and PERP may be scraped from the API or from the "Assurance Vie" space,
        # so we need to discriminate between both using account._details:
        if account.type in (account.TYPE_LIFE_INSURANCE, account.TYPE_PERP,
                            account.TYPE_CAPITALISATION):
            if hasattr(account, '_details'):
                # Going to the "Assurances Vie" page
                natiovie_params = self.natio_vie_pro.go().get_params()
                self.capitalisation_page.go(params=natiovie_params)
                # Fetching the form to get the contract investments:
                capitalisation_params = self.page.get_params(account)
                self.capitalisation_page.go(params=capitalisation_params)
                return self.page.iter_investments()
            else:
                # No capitalisation contract has yet been found in the API:
                assert account.type != account.TYPE_CAPITALISATION
                self.lifeinsurances.go(json={
                    "ibanCrypte": account.id,
                })
                return self.page.iter_investments()

        elif account.type in (account.TYPE_MARKET, account.TYPE_PEA):
            try:
                self.market_list.go(json={}, method='POST')
            except ServerError:
                self.logger.warning("An Internal Server Error occurred")
                return iter([])
            for market_acc in self.page.get_list():
                if account.number[-4:] == market_acc['securityAccountNumber'][
                        -4:] and not account.iban:
                    # Sometimes generate an Internal Server Error ...
                    try:
                        self.market.go(
                            json={
                                "securityAccountNumber":
                                market_acc['securityAccountNumber'],
                            })
                    except ServerError:
                        self.logger.warning(
                            "An Internal Server Error occurred")
                        break
                    return self.page.iter_investments()

        return iter([])
Ejemplo n.º 19
0
    def get_investment(self, account):
        if 'LIQUIDIT' in account.label:
            return [create_french_liquidity(account.balance)]

        if not account._inv:
            return []

        if account.type in (Account.TYPE_MARKET, Account.TYPE_PEA):
            self.location(account._link, data=account._args)
            if self.page.can_iter_investments() and self.page.not_restrained():
                return self.page.get_market_investment()

        elif account.type in (Account.TYPE_LIFE_INSURANCE, Account.TYPE_CAPITALISATION):
            self.location(account._link, data=account._args)
            self.location(account._link.replace("_attente", "_detail_contrat_rep"), data=account._args)
            if self.page.can_iter_investments():
                return self.page.get_li_investments()
        return []
Ejemplo n.º 20
0
    def get_investment(self, account):
        if account.type == Account.TYPE_LIFE_INSURANCE:
            if not account._form:
                self.logger.warning('This account is limited, there is no available investment.')
                return

            self.assurancevie.stay_or_go()
            # The website often returns an error so we try again:
            # "L’accès au service est momentanément indisponible."
            try:
                account._form.submit()
            except BrowserUnavailable:
                self.logger.warning("Service unavailable, we submit the form again.")
                self.assurancevie.stay_or_go()
                account._form.submit()

            if self.calie.is_here():
                for inv in self.page.iter_investment():
                    yield inv
                # Get back to Life Insurance space
                self.assurancevie.go()
                return

            # Some users will get a message : "Ne détenant pas de compte dépôt
            # chez LCL, l'accès à ce service vous est indisponible."
            if self.form2.is_here() and self.page.assurancevie_hist_not_available():
                return

            self.avdetail.go()
            self.av_investments.go()

            for inv in self.page.iter_investment():
                yield inv

            self.avdetail.go()
            self.page.come_back()

        elif hasattr(account, '_market_link') and account._market_link:
            self.connexion_bourse()
            for inv in self.location(account._market_link).page.iter_investment():
                yield inv
            self.deconnexion_bourse()
        elif account.id in self.get_bourse_accounts_ids():
            yield create_french_liquidity(account.balance)
Ejemplo n.º 21
0
    def iter_investment(self, account):
        if account.balance == 0:
            return

        handled_invest_accounts = (
            Account.TYPE_MARKET,
            Account.TYPE_PEA,
            Account.TYPE_LIFE_INSURANCE,
            Account.TYPE_CAPITALISATION,
            Account.TYPE_PERP,
            Account.TYPE_PERCO,
        )
        if account.type not in handled_invest_accounts:
            self.unhandled_method(account.id)
            return

        if account.label == 'DAV PEA':
            # 'PEA Espèces'
            yield create_french_liquidity(account.balance)
            return

        if account.url:
            if 'PREDICA' in account.url:
                # Fetch investments on Predica space
                for inv in self.get_predica_investments(account):
                    yield inv

            elif 'CATITRES' in account.url:
                # Fetch investments on Netfinca space
                for inv in self.get_netfinca_investments(account):
                    yield inv

            elif 'bgpi' in account.url:
                # Fetch investments on BGPI space
                self.location(account.url)
                if self.bgpi_investments.is_here():
                    for inv in self.page.iter_investments():
                        yield inv

            # Go back to the main Cragr website afterwards
            self.accounts.stay_or_go()
Ejemplo n.º 22
0
    def get_investment(self, account):
        if 'LIQUIDIT' in account.label:
            return [create_french_liquidity(account.balance)]

        if not account._inv:
            return []

        if account.type in (Account.TYPE_MARKET, Account.TYPE_PEA):
            self.location(account._link, data=account._args)
            if self.page.can_iter_investments() and self.page.not_restrained():
                return self.page.get_market_investment()

        elif account.type in (Account.TYPE_LIFE_INSURANCE,
                              Account.TYPE_CAPITALISATION):
            self.location(account._link, data=account._args)
            self.location(account._link.replace("_attente",
                                                "_detail_contrat_rep"),
                          data=account._args)
            if self.page.can_iter_investments():
                return self.page.get_li_investments()
        return []
Ejemplo n.º 23
0
    def iter_investment(self, account):
        if account.type == Account.TYPE_LIFE_INSURANCE:
            if not self.goto_spirica(account):
                return iter([])

            return self.spirica.iter_investment(account)
        elif account.type in (Account.TYPE_MARKET, Account.TYPE_PEA):
            bourse_account = self.get_bourse_account(account)
            if not bourse_account:
                return iter([])

            self.location(bourse_account._market_link)
            assert self.bourse.is_here()
            invs = list(self.page.iter_investment())
            # _especes is set during BoursePage accounts parsing. BoursePage
            # inherits from lcl module BoursePage
            if bourse_account._especes:
                invs.append(create_french_liquidity(bourse_account._especes))

            self.leave_espace_bourse()

            return invs

        raise NotImplementedError()
Ejemplo n.º 24
0
    def iter_investment(self, account):
        if account.type == Account.TYPE_LIFE_INSURANCE:
            if not self.goto_spirica(account):
                return iter([])

            return self.spirica.iter_investment(account)
        elif account.type in (Account.TYPE_MARKET, Account.TYPE_PEA):
            bourse_account = self.get_bourse_account(account)
            if not bourse_account:
                return iter([])

            self.location(bourse_account._market_link)
            assert self.bourse.is_here()
            invs = list(self.page.iter_investment())
            # _especes is set during BoursePage accounts parsing. BoursePage
            # inherits from lcl module BoursePage
            if bourse_account._especes:
                invs.append(create_french_liquidity(bourse_account._especes))

            self.leave_espace_bourse()

            return invs

        raise NotImplementedError()
Ejemplo n.º 25
0
    def get_investment(self, account):
        self.deleteCTX()
        if account.type not in (Account.TYPE_LIFE_INSURANCE, Account.TYPE_CAPITALISATION, Account.TYPE_MARKET, Account.TYPE_PEA) or 'measure_id' in account._info:
            raise NotImplementedError()

        if account.type == Account.TYPE_PEA and account.label == 'PEA NUMERAIRE':
            yield create_french_liquidity(account.balance)
            return

        if self.home.is_here():
            self.page.go_list()
        else:
            self.home.go()

        self.page.go_history(account._info)
        if account.type in (Account.TYPE_MARKET, Account.TYPE_PEA):
            # Some users may not have access to this.
            if not self.market.is_here():
                return
            self.page.submit()

            if 'offrebourse.com' in self.url:
                # Some users may not have access to this.
                if self.page.is_error():
                    return

                self.update_linebourse_token()
                for investment in self.linebourse.iter_investments(account.id):
                    yield investment
                return

        elif account.type in (Account.TYPE_LIFE_INSURANCE, Account.TYPE_CAPITALISATION):
            if self.page.is_account_inactive(account.id):
                self.logger.warning('Account %s %s is inactive.' % (account.label, account.id))
                return
            if "MILLEVIE" in account.label:
                self.page.go_life_insurance(account)
                label = account.label.split()[-1]
                self.natixis_life_ins_inv.go(id1=label[:3], id2=label[3:5], id3=account.id)
                for tr in self.page.get_investments():
                    yield tr
                return

            try:
                self.page.go_life_insurance(account)

                if not self.market.is_here() and not self.message.is_here():
                    # life insurance website is not always available
                    raise BrowserUnavailable()

                self.page.submit()
                self.location('https://www.extranet2.caisse-epargne.fr%s' % self.page.get_cons_repart())
            except (IndexError, AttributeError) as e:
                self.logger.error(e)
                return
        if self.garbage.is_here():
            self.page.come_back()
            return
        for i in self.page.iter_investment():
            yield i
        if self.market.is_here():
            self.page.come_back()
Ejemplo n.º 26
0
 def get_liquidities(self):
     value = CleanDecimal.French(CleanText('//a[starts-with(text(),"Compte de paiement")]'))(self.doc)
     return create_french_liquidity(value)
Ejemplo n.º 27
0
 def get_liquidity(self):
     liquidity = CleanDecimal(
         '//table//tr[@class="titreAvant"]/td[contains(text(), "Liquidit")]/following-sibling::td',
         replace_dots=True)(self.doc)
     if liquidity:
         return create_french_liquidity(liquidity)
Ejemplo n.º 28
0
    def get_investment(self, account):
        self.deleteCTX()
        if account.type not in (
                Account.TYPE_LIFE_INSURANCE, Account.TYPE_CAPITALISATION,
                Account.TYPE_MARKET,
                Account.TYPE_PEA) or 'measure_id' in account._info:
            raise NotImplementedError()

        if account.type == Account.TYPE_PEA and account.label == 'PEA NUMERAIRE':
            yield create_french_liquidity(account.balance)
            return

        if self.home.is_here():
            self.page.go_list()
        else:
            self.home.go()

        self.page.go_history(account._info)
        if account.type in (Account.TYPE_MARKET, Account.TYPE_PEA):
            # Some users may not have access to this.
            if not self.market.is_here():
                return
            self.page.submit()

            if 'offrebourse.com' in self.url:
                # Some users may not have access to this.
                if self.page.is_error():
                    return

                self.update_linebourse_token()
                for investment in self.linebourse.iter_investments(account.id):
                    yield investment

                # We need to go back to the synthesis, else we can not go home later
                self.home_tache.go(tache='CPTSYNT0')
                return

        elif account.type in (Account.TYPE_LIFE_INSURANCE,
                              Account.TYPE_CAPITALISATION):
            if self.page.is_account_inactive(account.id):
                self.logger.warning('Account %s %s is inactive.' %
                                    (account.label, account.id))
                return
            if "MILLEVIE" in account.label:
                try:
                    self.page.go_life_insurance(account)
                except ServerError as ex:
                    if ex.response.status_code == 500 and 'MILLEVIE PREMIUM' in account.label:
                        self.logger.info(
                            "Can not reach investment page for MILLEVIE PREMIUM account"
                        )
                        return
                    raise

                label = account.label.split()[-1]
                self.natixis_life_ins_inv.go(id1=label[:3],
                                             id2=label[3:5],
                                             id3=account.id)
                for tr in self.page.get_investments():
                    yield tr
                return

            try:
                self.page.go_life_insurance(account)

                if not self.market.is_here() and not self.message.is_here():
                    # life insurance website is not always available
                    raise BrowserUnavailable()

                self.page.submit()
                self.location('https://www.extranet2.caisse-epargne.fr%s' %
                              self.page.get_cons_repart())
            except (IndexError, AttributeError) as e:
                self.logger.error(e)
                return
        if self.garbage.is_here():
            self.page.come_back()
            return
        for i in self.page.iter_investment():
            yield i
        if self.market.is_here():
            self.page.come_back()
Ejemplo n.º 29
0
 def iter_investments(self, account):
     yield (create_french_liquidity(account.balance))
Ejemplo n.º 30
0
 def iter_investments(self, account):
     yield (create_french_liquidity(account.balance))
Ejemplo n.º 31
0
 def get_liquidity(self):
     liquidity_element = self.doc.xpath('//td[contains(text(), "Solde espèces en euros")]//following-sibling::td[position()=1]')
     assert len(liquidity_element) <= 1
     if liquidity_element:
         valuation = CleanDecimal(replace_dots=True).filter(liquidity_element[0])
         return create_french_liquidity(valuation)
Ejemplo n.º 32
0
 def get_liquidity(self):
     liquidity = CleanDecimal('//table//tr[@class="titreAvant"]/td[contains(text(), "Liquidit")]/following-sibling::td', replace_dots=True)(self.doc)
     if liquidity:
         return create_french_liquidity(liquidity)
Ejemplo n.º 33
0
    def iter_investment(self, account):
        if account.type == Account.TYPE_LIFE_INSURANCE and (
                'rothschild' in account.label.lower() or re.match(
                    r'^open (perspective|strat)', account.label, re.I)):
            self.life_insurance_investments.go(space=self.space,
                                               idx=account._index,
                                               category=account._category)
            # TODO
            #for inv in self.page.iter_investments():
            #    yield inv

        elif account.type in (Account.TYPE_PERP, Account.TYPE_PERCO,
                              Account.TYPE_LIFE_INSURANCE,
                              Account.TYPE_CAPITALISATION):
            if account.label == "Vers l'avenir":
                # Website crashes when clicking on these Life Insurances...
                return

            self.go_to_account_space(account._contract)
            token = self.token_page.go().get_token()
            data = {
                'situation_travail': 'CONTRAT',
                'idelco': account.id,
                ':cq_csrf_token': token,
            }
            try:
                self.predica_redirection.go(space=self.space, data=data)
            except ServerError:
                self.logger.warning(
                    'Got ServerError when fetching investments for account id %s',
                    account.id)
            else:
                self.predica_investments.go()
                for inv in self.page.iter_investments():
                    yield inv

        elif account.type == Account.TYPE_PEA and account.label == 'Compte espèce PEA':
            yield create_french_liquidity(account.balance)
            return

        elif account.type in (Account.TYPE_PEA, Account.TYPE_MARKET):
            # Do not try to get to Netfinca if there is no money
            # on the account or the server will return an error 500
            if account.balance == 0:
                return
            self.go_to_account_space(account._contract)
            token = self.token_page.go().get_token()
            data = {
                'situation_travail': 'BANCAIRE',
                'num_compte': account.id,
                'code_fam_produit': account._fam_product_code,
                'code_fam_contrat_compte': account._fam_contract_code,
                ':cq_csrf_token': token,
            }

            # For some market accounts, investments are not even accessible,
            # and the only way to know if there are investments is to try
            # to go to the Netfinca space with the accounts parameters.
            try:
                self.netfinca_redirection.go(space=self.space, data=data)
            except BrowserHTTPNotFound:
                self.logger.info(
                    'Investments are not available for this account.')
                self.go_to_account_space(account._contract)
                return
            url = self.page.get_url()
            if 'netfinca' in url:
                self.location(url)
                self.netfinca.session.cookies.update(self.session.cookies)
                self.netfinca.accounts.go()
                for inv in self.netfinca.iter_investments(account):
                    if inv.code == 'XX-liquidity' and account.type == Account.TYPE_PEA:
                        # Liquidities are already fetched on the "PEA espèces"
                        continue
                    yield inv
Ejemplo n.º 34
0
 def iter_investments(self):
     self.portfolio.go()
     yield create_french_liquidity(self.page.get_liquidity())
     for inv in self.page.iter_investments():
         yield inv
Ejemplo n.º 35
0
    def iter_investments(self, account):
        # We did not get some html, but something like that (XX is a quantity, YY a price):
        # "message='<total> &euro;{<total> &euro;{0,01 &euro;{<liquidity> &euro;{0,00{{05/17{{03/05/2017{11:06{-XX &euro;{710TI81000029397EUR{XX &euro;{XX &euro;{|OPHTHOTECH(NASDAQ)#cotationValeur.php?val=OPHT&amp;pl=11&amp;nc=2&amp;
        # popup=2{6{E:ALO{PAR{{reel{695{380{ALSTOM REGROUPT#XX#YY,YY &euro;#YY,YY &euro;#1 YYY,YY &euro;#-YYY,YY &euro;#-42,42%#-0,98 %#42,42 %#|1|AXA#cotationValeur.php?val=E:CS&amp;pl=6&amp;nc=1&amp;
        # popup=2{6{E:CS{PAR{{reel{695{380{AXA#XX#YY,YY &euro;#YY,YYY &euro;#YYY,YY &euro;#YY,YY &euro;#3,70%#42,42 %#42,42 %#|1|blablablab #cotationValeur.php?val=P:CODE&amp;pl=6&amp;nc=1&amp;
        # [...]
        data = self.browser.cache["investments_data"].get(account.id, self.doc)
        lines = data.split("|1|")
        message = lines[0]
        if len(lines) > 1:
            start = 1
            lines[0] = lines[0].split("|")[1]
        else:
            start = 0
            lines = data.split("popup=2")
            lines.pop(0)
        invests = []
        for line in lines:
            _id, _pl = None, None
            columns = line.split('#')
            if columns[1] != '':
                _pl = columns[start].split('{')[1]
                _id = columns[start].split('{')[2]
            invest = Investment()
            # If the link with the label and ISIN code is present we use it to fill the label and code.
            # If not, the label can still be found in the first column of the row but the ISIN is unavailable.
            invest.label = columns[start].split('{')[-1] or columns[0]
            invest.code = _id or NotAvailable
            if invest.code and ':' in invest.code:
                invest.code = self.browser.titrevalue.open(val=invest.code,
                                                           pl=_pl).get_isin()
            # The code we got is not a real ISIN code.
            if invest.code and not re.match(
                    '^[A-Z]{2}[\d]{10}$|^[A-Z]{2}[\d]{5}[A-Z]{1}[\d]{4}$',
                    invest.code):
                m = re.search(
                    '\{([A-Z]{2}[\d]{10})\{|\{([A-Z]{2}[\d]{5}[A-Z]{1}[\d]{4})\{',
                    line)
                if m:
                    invest.code = m.group(1) or m.group(2)

            for x, attr in enumerate(
                ['quantity', 'unitprice', 'unitvalue', 'valuation', 'diff'],
                    1):
                currency = FrenchTransaction.Currency().filter(columns[start +
                                                                       x])
                amount = CleanDecimal(default=NotAvailable).filter(
                    FrenchTransaction.clean_amount(columns[start + x]))
                if currency and currency != account.currency:
                    invest.original_currency = currency
                    attr = "original_" + attr
                setattr(invest, attr, amount)
            # valuation is not nullable, use 0 as default value
            if not invest.valuation:
                invest.valuation = Decimal('0')

            # On some case we have a multine investment with a total column
            # for now we have only see this on 2 lines, we will need to adapt it when o
            if columns[9 if start ==
                       0 else 0] == '|Total' and _id == 'fichevaleur':
                prev_inv = invest
                invest = invests.pop(-1)
                if prev_inv.quantity:
                    invest.quantity = invest.quantity + prev_inv.quantity
                if prev_inv.valuation:
                    invest.valuation = invest.valuation + prev_inv.valuation
                if prev_inv.diff:
                    invest.diff = invest.diff + prev_inv.diff

            invests.append(invest)

        # There is no investment on life insurance in the process to be created.
        if len(message.split('&')) >= 4:
            # We also have to get the liquidity as an investment.
            valuation = CleanDecimal(None, True).filter(
                message.split('&')[3].replace('euro;{', '').strip())
            invests.append(create_french_liquidity(valuation))
        for invest in invests:
            yield invest
Ejemplo n.º 36
0
    def iter_investments(self, account):
        # We did not get some html, but something like that (XX is a quantity, YY a price):
        # "message='<total> &euro;{<total> &euro;{0,01 &euro;{<liquidity> &euro;{0,00{{05/17{{03/05/2017{11:06{-XX &euro;{710TI81000029397EUR{XX &euro;{XX &euro;{|OPHTHOTECH(NASDAQ)#cotationValeur.php?val=OPHT&amp;pl=11&amp;nc=2&amp;
        # popup=2{6{E:ALO{PAR{{reel{695{380{ALSTOM REGROUPT#XX#YY,YY &euro;#YY,YY &euro;#1 YYY,YY &euro;#-YYY,YY &euro;#-42,42%#-0,98 %#42,42 %#|1|AXA#cotationValeur.php?val=E:CS&amp;pl=6&amp;nc=1&amp;
        # popup=2{6{E:CS{PAR{{reel{695{380{AXA#XX#YY,YY &euro;#YY,YYY &euro;#YYY,YY &euro;#YY,YY &euro;#3,70%#42,42 %#42,42 %#|1|blablablab #cotationValeur.php?val=P:CODE&amp;pl=6&amp;nc=1&amp;
        # [...]
        data = self.browser.cache["investments_data"].get(account.id, self.doc)
        lines = data.split("|1|")
        message = lines[0]
        if len(lines) > 1:
            start = 1
            lines[0] = lines[0].split("|")[1]
        else:
            start = 0
            lines = data.split("popup=2")
            lines.pop(0)
        invests = []
        for line in lines:
            _id, _pl = None, None
            columns = line.split('#')
            if columns[1] != '':
                _pl = columns[start].split('{')[1]
                _id = columns[start].split('{')[2]
            invest = Investment()
            invest.label = columns[start].split('{')[-1]
            invest.code = _id or NotAvailable
            if invest.code and ':' in invest.code:
                invest.code = self.browser.titrevalue.open(val=invest.code,pl=_pl).get_isin()
            # The code we got is not a real ISIN code.
            if invest.code and not re.match('^[A-Z]{2}[\d]{10}$|^[A-Z]{2}[\d]{5}[A-Z]{1}[\d]{4}$', invest.code):
                m = re.search('\{([A-Z]{2}[\d]{10})\{|\{([A-Z]{2}[\d]{5}[A-Z]{1}[\d]{4})\{', line)
                if m:
                    invest.code = m.group(1) or m.group(2)

            for x, attr in enumerate(['quantity', 'unitprice', 'unitvalue', 'valuation', 'diff'], 1):
                currency = FrenchTransaction.Currency().filter(columns[start + x])
                amount = CleanDecimal(default=NotAvailable).filter(FrenchTransaction.clean_amount(columns[start + x]))
                if currency and currency != account.currency:
                    invest.original_currency = currency
                    attr = "original_" + attr
                setattr(invest, attr, amount)
            # valuation is not nullable, use 0 as default value
            if not invest.valuation:
                invest.valuation = Decimal('0')

            # On some case we have a multine investment with a total column
            # for now we have only see this on 2 lines, we will need to adapt it when o
            if columns[9 if start == 0 else 0] == u'|Total' and _id == 'fichevaleur':
                prev_inv = invest
                invest = invests.pop(-1)
                if prev_inv.quantity:
                    invest.quantity = invest.quantity + prev_inv.quantity
                if prev_inv.valuation:
                    invest.valuation = invest.valuation + prev_inv.valuation
                if prev_inv.diff:
                    invest.diff = invest.diff + prev_inv.diff

            invests.append(invest)

        # There is no investment on life insurance in the process to be created.
        if len(message.split('&')) >= 4:
            # We also have to get the liquidity as an investment.
            valuation = CleanDecimal(None, True).filter(message.split('&')[3].replace('euro;{','').strip())
            invests.append(create_french_liquidity(valuation))
        for invest in invests:
            yield invest