Exemplo n.º 1
0
    def _parse_account(self, tr):
        account = Account()

        account.id = tr.xpath('.//td[@class="libelleCompte"]/input')[0].attrib['id'][len('libelleCompte'):]
        if len(str(account.id)) == 23:
            account.id = str(account.id)[5:21]

        a = tr.xpath('.//td[@class="libelleCompte"]/a')[0]
        m = re.match(r'javascript:goToStatements\(\'(\d+)\'', a.get('onclick', ''))
        if m:
            account._link_id = m.group(1)
        else:
            # Can't get history for this account.
            account._link_id = None
            # To prevent multiple-IDs for CIF (for example), add an arbitrary char in ID.
            account.id += 'C'

        account.label = u''+a.text.strip()

        tds = tr.findall('td')
        account.balance = self._parse_amount(tds[3].find('a'))
        if tds[4].find('a') is not None:
            account.coming = self._parse_amount(tds[4].find('a'))
        else:
            account.coming = NotAvailable

        return account
Exemplo n.º 2
0
    def iter_accounts(self):
        if not self.islogged:
            self.login()

        data = self.browser.open(
            "https://www.cmb.fr/domiweb/prive/particulier/releve/0-releve.act"
        ).content
        parser = etree.HTMLParser()
        tree = etree.parse(StringIO(data), parser)

        table = tree.xpath('/html/body/table')
        if len(table) == 0:
            title = tree.xpath('/html/head/title')[0].text
            if title == u"Utilisateur non identifié":
                self.login()
                data = self.browser.open(
                    "https://www.cmb.fr/domiweb/prive/particulier/releve/0-releve.act"
                ).content

                parser = etree.HTMLParser()
                tree = etree.parse(StringIO(data), parser)
                table = tree.xpath('/html/body/table')
                if len(table) == 0:
                    raise ParseError()
            else:
                raise ParseError()

        for tr in tree.xpath('/html/body//table[contains(@class, "Tb")]/tr'):
            if tr.get('class',
                      None) not in ('LnTit', 'LnTot', 'LnMnTiers', None):
                account = Account()
                td = tr.xpath('td')

                a = td[1].xpath('a')
                account.label = unicode(a[0].text).strip()
                href = a[0].get('href')
                m = match(r"javascript:releve\((.*),'(.*)','(.*)'\)", href)
                if not m:
                    continue
                account.id = unicode(m.group(1) + m.group(2) + m.group(3))
                account._cmbvaleur = m.group(1)
                account._cmbvaleur2 = m.group(2)
                account._cmbtype = m.group(3)

                balance = u''.join([txt.strip() for txt in td[2].itertext()])
                balance = balance.replace(',', '.').replace(u"\xa0", '')
                account.balance = Decimal(balance)

                span = td[4].xpath('a/span')
                if len(span):
                    coming = span[0].text.replace(' ', '').replace(',', '.')
                    coming = coming.replace(u"\xa0", '')
                    account.coming = Decimal(coming)
                else:
                    account.coming = NotAvailable

                yield account
Exemplo n.º 3
0
 def get_list(self):
     a = Account()
     a.id = '0'
     a.label = u'Compte miams'
     a.balance = Decimal(self.parser.tocleanstring(self.document.xpath('//div[@class="compteur"]//strong')[0]))
     a.currency = u'MIAM'
     try:
         a.coming = Decimal(Transaction.clean_amount(self.document.xpath('//table[@id="solde_acquisition_lignes"]//th[@class="col_montant"]')[0].text))
     except BrokenPageError:
         a.coming = Decimal('0')
     yield a
Exemplo n.º 4
0
    def iter_accounts(self):
        if not self.islogged:
            self.login()

        data = self.browser.open("https://www.cmb.fr/domiweb/prive/particulier/releve/0-releve.act").content
        parser = etree.HTMLParser()
        tree = etree.parse(StringIO(data), parser)

        table = tree.xpath('/html/body/table')
        if len(table) == 0:
            title = tree.xpath('/html/head/title')[0].text
            if title == u"Utilisateur non identifié":
                self.login()
                data = self.browser.open("https://www.cmb.fr/domiweb/prive/particulier/releve/0-releve.act").content

                parser = etree.HTMLParser()
                tree = etree.parse(StringIO(data), parser)
                table = tree.xpath('/html/body/table')
                if len(table) == 0:
                    raise ParseError()
            else:
                raise ParseError()

        for tr in tree.xpath('/html/body//table[contains(@class, "Tb")]/tr'):
            if tr.get('class', None) not in ('LnTit', 'LnTot', 'LnMnTiers', None):
                account = Account()
                td = tr.xpath('td')

                a = td[1].xpath('a')
                account.label = unicode(a[0].text).strip()
                href = a[0].get('href')
                m = match(r"javascript:releve\((.*),'(.*)','(.*)'\)",
                             href)
                if not m:
                    continue
                account.id = unicode(m.group(1) + m.group(2) + m.group(3))
                account._cmbvaleur = m.group(1)
                account._cmbvaleur2 = m.group(2)
                account._cmbtype = m.group(3)

                balance = u''.join([txt.strip() for txt in td[2].itertext()])
                balance = balance.replace(',', '.').replace(u"\xa0", '')
                account.balance = Decimal(balance)

                span = td[4].xpath('a/span')
                if len(span):
                    coming = span[0].text.replace(' ', '').replace(',', '.')
                    coming = coming.replace(u"\xa0", '')
                    account.coming = Decimal(coming)
                else:
                    account.coming = NotAvailable

                yield account
Exemplo n.º 5
0
    def get_list(self):
        for box in self.document.getroot().cssselect('div.roundedBox div.contentBox'):
            a = Account()
            a.id = self.parser.tocleanstring(box.xpath('.//tr[@id="summaryImageHeaderRow"]//div[@class="summaryTitles"]')[0])
            a.label = self.parser.tocleanstring(box.xpath('.//span[@class="cardTitle"]')[0])
            a.balance = Decimal('0.0')
            coming = self.parser.tocleanstring(self.parser.select(box, 'td#colOSBalance div.summaryValues', 1))
            if coming in (u'Indisponible', ''):
                a.coming = NotAvailable
            else:
                a.coming = - abs(Decimal(Transaction.clean_amount(coming)))
                a.currency = a.get_currency(coming)
            a._link = self.parser.select(box, 'div.summaryTitles a.summaryLink', 1).attrib['href']

            yield a
Exemplo n.º 6
0
    def get_list(self, pro=True):
        accounts = []
        for tr in self.document.xpath('//tr[@class="comptes"]'):
            cols = tr.findall('td')

            if len(cols) < 5:
                continue

            account = Account()
            account.id = self.parser.tocleanstring(cols[self.COL_ID]).replace(
                " ", "")
            account.label = self.parser.tocleanstring(cols[self.COL_LABEL])
            account.balance = Decimal(
                self.parser.tocleanstring(cols[self.COL_BALANCE]))
            try:
                account.coming = Decimal(
                    self.parser.tocleanstring(cols[self.COL_COMING]))
            except InvalidOperation:
                if self.parser.tocleanstring(cols[self.COL_COMING]) != '-':
                    self.logger.warning('Unable to parse coming value',
                                        exc_info=True)
                account.coming = NotAvailable
            account._link_id = None
            account._stp = None

            a = cols[self.COL_LABEL].find('a')
            if a is not None:
                url = urlparse(a.attrib['href'])
                p = dict(parse_qsl(url.query))
                account._link_id = p.get('ch4', None)
                account._stp = p.get('stp', None)

            accounts.append(account)

        # If there are also personnal accounts linked, display the page and iter on them.
        if pro and len(
                self.document.xpath(
                    '//div[@class="onglets"]//a[contains(@href, "afficherComptesPrives")]'
                )) > 0:
            self.browser.select_form(name='myForm')
            self.browser.set_all_readonly(False)
            self.browser['udcAction'] = '/afficherComptesPrives'
            self.browser.submit()

            for a in self.browser.page.get_list(False):
                accounts.append(a)

        return accounts
Exemplo n.º 7
0
    def get_list(self):
        div = self.document.xpath('//div[@id="descriptifdroite"]')[0]

        account = Account()

        account.id = re.search(
            u'(\d+)',
            div.xpath('.//div[@class="credithauttexte"]')[0].text).group(1)
        account.label = u'Carte PASS'
        account.balance = Decimal('0')

        for tr in div.xpath('.//table/tr'):
            tds = tr.findall('td')

            if len(tds) < 3:
                continue

            label = u''.join([txt.strip() for txt in tds[1].itertext()])
            value = u''.join([txt.strip() for txt in tds[2].itertext()])

            if 'encours depuis le dernier' in label.lower():
                coming = u'-' + value
                account.coming = Decimal(
                    FrenchTransaction.clean_amount(coming))
                account.currency = account.get_currency(coming)
            elif u'arrêté de compte' in label.lower():
                m = re.search(u'(\d+)/(\d+)/(\d+)', label)
                if m:
                    account._outstanding_date = datetime.date(
                        *reversed(map(int, m.groups())))
                    break

        yield account
Exemplo n.º 8
0
    def get_list(self):
        accounts = []
        previous_account = None

        noaccounts = self.get_from_js('_js_noMvts =', ';')
        if noaccounts is not None:
            assert 'avez aucun compte' in noaccounts
            return []

        txt = self.get_from_js('_data = new Array(', ');', is_list=True)

        if txt is None:
            raise BrowserUnavailable('Unable to find accounts list in scripts')

        data = json.loads('[%s]' % txt.replace("'", '"'))

        for line in data:
            a = Account()
            a.id = line[self.COL_ID].replace(' ', '')

            if re.match(r'Classement=(.*?):::Banque=(.*?):::Agence=(.*?):::SScompte=(.*?):::Serie=(.*)', a.id):
                a.id = str(CleanDecimal().filter(a.id))

            a._acc_nb = a.id.split('_')[0] if len(a.id.split('_')) > 1 else None
            a.label = MyStrip(line[self.COL_LABEL], xpath='.//div[@class="libelleCompteTDB"]')
            # This account can be multiple life insurance accounts
            if a.label == 'ASSURANCE VIE-BON CAPI-SCPI-DIVERS *':
                continue

            a.balance = Decimal(FrenchTransaction.clean_amount(line[self.COL_BALANCE]))
            a.currency = a.get_currency(line[self.COL_BALANCE])
            a.type = self.get_account_type(a.label)

            # The parent account must be created right before
            if a.type == Account.TYPE_CARD:
                # duplicate
                if find_object(accounts, id=a.id):
                    self.logger.warning('Ignoring duplicate card %r', a.id)
                    continue
                a.parent = previous_account

            if line[self.COL_HISTORY] == 'true':
                a._inv = False
                a._link = self.get_history_link()
                a._args = self.make__args_dict(line)
            else:
                a._inv = True
                a._args = {'_ipc_eventValue':  line[self.COL_ID],
                           '_ipc_fireEvent':   line[self.COL_FIRE_EVENT],
                          }
                a._link = self.doc.xpath('//form[@name="changePageForm"]')[0].attrib['action']

            if a.type is Account.TYPE_CARD:
                a.coming = a.balance
                a.balance = Decimal('0.0')

            accounts.append(a)
            previous_account = a

        return accounts
Exemplo n.º 9
0
    def get_list(self, accounts_ids):
        l = []
        # Read the json data
        json_data = self.browser.readurl('/banque/PA_Autonomy-war/ProxyIAService?cleOutil=IA_SMC_UDC&service=getlstcpt&dashboard=true&refreshSession=true&cre=udc&poka=true')
        json_infos = json.loads(json_data)
        for famille in json_infos['smc']['data']['familleCompte']:
            id_famille = famille['idFamilleCompte']
            for compte in famille['compte']:
                account = Account()
                account.label = u''+compte['libellePersoProduit']
                account.currency = account.get_currency(compte['devise'])
                account.balance = Decimal(compte['soldeDispo'])
                account.coming = Decimal(compte['soldeAVenir'])
                account.type = self.ACCOUNT_TYPES.get(id_famille, Account.TYPE_UNKNOWN)
                account.id = 0
                account._link_id = 'KEY'+compte['key']

                # IBAN aren't in JSON
                # Fast method, get it from transfer page.
                for i,a in accounts_ids.items():
                    if a.label == account.label:
                        account.id = i
                # But it's doesn't work with LOAN and MARKET, so use slow method : Get it from transaction page.
                if account.id == 0:
                    account.id = self.browser.get_IBAN_from_account(account)
                l.append(account)

        if len(l) == 0:
            print 'no accounts'
            # oops, no accounts? check if we have not exhausted the allowed use
            # of this password
            for img in self.document.getroot().cssselect('img[align="middle"]'):
                if img.attrib.get('alt', '') == 'Changez votre code secret':
                    raise BrowserPasswordExpired('Your password has expired')
        return l
Exemplo n.º 10
0
 def get_list(self):
     # TODO: no idea abount how proxy account are displayed
     for a in self.document.xpath('//a[@class="mainclic"]'):
         account = Account()
         account.currency = Currency.CUR_EUR
         account.id = unicode(a.find('span[@class="account-number"]').text)
         account._id = account.id
         account.label = unicode(a.find('span[@class="title"]').text)
         balance = a.find('span[@class="solde"]/label').text
         account.balance = Decimal(FrenchTransaction.clean_amount(balance))
         account.coming = NotAvailable
         if "Courant" in account.label:
             account.id = "CC-" + account.id
             account.type = Account.TYPE_CHECKING
         elif "Livret A" in account.label:
             account.id = "LA-" + account.id
             account.type = Account.TYPE_SAVINGS
         elif "Orange" in account.label:
             account.id = "LEO-" + account.id
             account.type = Account.TYPE_SAVINGS
         elif "Durable" in account.label:
             account.id = "LDD-" + account.id
             account.type = Account.TYPE_SAVINGS
         elif "Titres" in account.label:
             account.id = "TITRE-" + account.id
             account.type = Account.TYPE_MARKET
         elif "PEA" in account.label:
             account.id = "PEA-" + account.id
             account.type = Account.TYPE_MARKET
         jid = self.document.find('//input[@name="javax.faces.ViewState"]')
         account._jid = jid.attrib['value']
         yield account
Exemplo n.º 11
0
    def get_list(self):
        for tr in self.document.xpath('//table[@class="datas"]//tr'):
            if tr.attrib.get('class', '') == 'entete':
                continue

            cols = tr.findall('td')

            a = Account()
            a.label = unicode(cols[self.COL_ID].xpath('.//span[@class="left-underline"]')[0].text.strip())
            a.type = self.get_account_type(a.label)
            balance = self.parser.tocleanstring(cols[self.COL_BALANCE])
            a.balance = Decimal(FrenchTransaction.clean_amount(balance))
            a.currency = a.get_currency(balance)
            a._link, a._args = self.params_from_js(cols[self.COL_ID].find('a').attrib['href'])
            a._acc_nb = cols[self.COL_ID].xpath('.//span[@class="right-underline"]')[0].text.replace(' ', '').strip()
            if a._args:
                a.id = '%s%s%s' % (a._acc_nb, a._args['IndiceCompte'], a._args['Indiceclassement'])
            else:
                a.id = a._acc_nb
            # This account can be multiple life insurance accounts
            if any(a.label.startswith(lab) for lab in ['ASS.VIE-BONS CAPI-SCPI-DIVERS', 'BONS CAPI-SCPI-DIVERS']) or \
               u'Aucun d\\351tail correspondant pour ce compte' in tr.xpath('.//a/@href')[0]:
                continue

            if a.type is Account.TYPE_CARD:
                a.coming = a.balance
                a.balance = Decimal('0.0')

            a._inv = False

            yield a
Exemplo n.º 12
0
    def get_list(self, accounts_ids):
        l = []
        # Read the json data
        json_data = self.browser.readurl('/banque/PA_Autonomy-war/ProxyIAService?cleOutil=IA_SMC_UDC&service=getlstcpt&dashboard=true&refreshSession=true&cre=udc&poka=true')
        json_infos = json.loads(json_data)
        for famille in json_infos['smc']['data']['familleCompte']:
            id_famille = famille['idFamilleCompte']
            for compte in famille['compte']:
                account = Account()
                account.label = u''+compte['libellePersoProduit']
                account.currency = account.get_currency(compte['devise'])
                account.balance = Decimal(str(compte['soldeDispo']))
                account.coming = Decimal(str(compte['soldeAVenir']))
                account.type = self.ACCOUNT_TYPES.get(id_famille, Account.TYPE_UNKNOWN)
                account.id = 0
                account._link_id = 'KEY'+compte['key']

                # IBAN aren't in JSON
                # Fast method, get it from transfer page.
                for i,a in accounts_ids.items():
                    if a.label == account.label:
                        account.id = i
                # But it's doesn't work with LOAN and MARKET, so use slow method : Get it from transaction page.
                if account.id == 0:
                    account.id = self.browser.get_IBAN_from_account(account)
                l.append(account)

        if len(l) == 0:
            print 'no accounts'
            # oops, no accounts? check if we have not exhausted the allowed use
            # of this password
            for img in self.document.getroot().cssselect('img[align="middle"]'):
                if img.attrib.get('alt', '') == 'Changez votre code secret':
                    raise BrowserPasswordExpired('Your password has expired')
        return l
Exemplo n.º 13
0
    def get_list(self):
        for tr in self.document.getiterator('tr'):
            tds = tr.findall('td')
            if len(tds) != 3 or tds[0].find('a') is None or tds[0].find('a').attrib.get('class', '') != 'flecheM':
                continue

            account = Account()
            account.id = tds[1].text.strip()

            a = tds[0].findall('a')[-1]
            account.label = a.text.strip()
            account._link_id = a.attrib['href']

            m = re.search('(\w+)_IdPrestation', account._link_id)
            if not m or m.group(1) != 'CPT':
                account._link_id = None
                if m:
                    account.id += '.%s' % m.group(1)

            tag = tds[2].find('font')
            if tag is None:
                tag = tds[2]
            account.balance = Decimal(tag.text.replace('.','').replace(',','.').replace(' ', '').strip(u' \t\u20ac\xa0€\n\r'))
            account.coming = NotAvailable

            yield account
Exemplo n.º 14
0
    def get_list(self):
        for trCompte in self.document.xpath('//table[@id="compte"]/tbody/tr'):
            tds = trCompte.findall('td')

            account = Account()

            account.id = tds[self.CPT_ROW_ID].text.strip()
            account.label = unicode(tds[self.CPT_ROW_NAME].text.strip())

            account_type_str = "".join([
                td.text
                for td in tds[self.CPT_ROW_NATURE].xpath('.//td[@class="txt"]')
            ]).strip()

            account.type = self.ACCOUNT_TYPES.get(account_type_str,
                                                  Account.TYPE_UNKNOWN)

            account.balance = Decimal(
                FrenchTransaction.clean_amount(
                    self.parser.tocleanstring(tds[self.CPT_ROW_BALANCE])))
            account.coming = Decimal(
                FrenchTransaction.clean_amount(
                    self.parser.tocleanstring(tds[self.CPT_ROW_ENCOURS])))
            account.currency = account.get_currency(
                tds[self.CPT_ROW_BALANCE].find("a").text)
            yield account

        return
Exemplo n.º 15
0
    def get_list(self):
        div = self.document.xpath('//div[@id="descriptifdroite"]')[0]

        account = Account()

        account.id = re.search(u'(\d+)', div.xpath('.//div[@class="credithauttexte"]')[0].text).group(1)
        account.label = u'Carte PASS'
        account.balance = Decimal('0')

        for tr in div.xpath('.//table/tr'):
            tds = tr.findall('td')

            if len(tds) < 3:
                continue

            label = u''.join([txt.strip() for txt in tds[1].itertext()])
            value = u''.join([txt.strip() for txt in tds[2].itertext()])

            if 'encours depuis le dernier' in label.lower():
                coming = u'-' + value
                account.coming = Decimal(FrenchTransaction.clean_amount(coming))
                account.currency = account.get_currency(coming)
            elif u'arrêté de compte' in label.lower():
                m = re.search(u'(\d+)/(\d+)/(\d+)', label)
                if m:
                    account._outstanding_date = datetime.date(*reversed(map(int, m.groups())))
                    break

        yield account
Exemplo n.º 16
0
    def get_list(self):
        accounts = []
        previous_account = None

        noaccounts = self.get_from_js('_js_noMvts =', ';')
        if noaccounts is not None:
            assert 'avez aucun compte' in noaccounts
            return []

        txt = self.get_from_js('_data = new Array(', ');', is_list=True)

        if txt is None:
            raise BrowserUnavailable('Unable to find accounts list in scripts')

        data = json.loads('[%s]' % txt.replace("'", '"'))

        for line in data:
            a = Account()
            a.id = line[self.COL_ID].replace(' ', '')

            if re.match(r'Classement=(.*?):::Banque=(.*?):::Agence=(.*?):::SScompte=(.*?):::Serie=(.*)', a.id):
                a.id = str(CleanDecimal().filter(a.id))

            a._acc_nb = a.id.split('_')[0] if len(a.id.split('_')) > 1 else None
            a.label = MyStrip(line[self.COL_LABEL], xpath='.//div[@class="libelleCompteTDB"]')
            # This account can be multiple life insurance accounts
            if a.label == 'ASSURANCE VIE-BON CAPI-SCPI-DIVERS *':
                continue

            a.balance = Decimal(FrenchTransaction.clean_amount(line[self.COL_BALANCE]))
            a.currency = a.get_currency(line[self.COL_BALANCE])
            a.type = self.get_account_type(a.label)

            # The parent account must be created right before
            if a.type == Account.TYPE_CARD:
                # duplicate
                if find_object(accounts, id=a.id):
                    self.logger.warning('Ignoring duplicate card %r', a.id)
                    continue
                a.parent = previous_account

            if line[self.COL_HISTORY] == 'true':
                a._inv = False
                a._link = self.get_history_link()
                a._args = self.make__args_dict(line)
            else:
                a._inv = True
                a._args = {'_ipc_eventValue':  line[self.COL_ID],
                           '_ipc_fireEvent':   line[self.COL_FIRE_EVENT],
                          }
                a._link = self.doc.xpath('//form[@name="changePageForm"]')[0].attrib['action']

            if a.type is Account.TYPE_CARD:
                a.coming = a.balance
                a.balance = Decimal('0.0')

            accounts.append(a)
            previous_account = a

        return accounts
Exemplo n.º 17
0
    def get_list(self):
        accounts = OrderedDict()

        for tr in self.document.getiterator('tr'):
            first_td = tr.getchildren()[0]
            if (first_td.attrib.get('class', '') == 'i g' or first_td.attrib.get('class', '') == 'p g') \
               and first_td.find('a') is not None:

                a = first_td.find('a')
                link = a.get('href', '')
                if link.startswith('POR_SyntheseLst'):
                    continue

                url = urlparse(link)
                p = parse_qs(url.query)
                if not 'rib' in p:
                    continue

                for i in (2,1):
                    balance = FrenchTransaction.clean_amount(tr.getchildren()[i].text)
                    currency = Account.get_currency(tr.getchildren()[i].text)
                    if len(balance) > 0:
                        break
                balance = Decimal(balance)

                id = p['rib'][0]
                if id in accounts:
                    account = accounts[id]
                    if not account.coming:
                        account.coming = Decimal('0.0')
                    account.coming += balance
                    account._card_links.append(link)
                    continue

                account = Account()
                account.id = id
                account.label = unicode(a.text).strip().lstrip(' 0123456789').title()
                account._link_id = link
                account._card_links = []

                # Find accounting amount
                page = self.browser.get_document(self.browser.openurl(link))
                coming = self.find_amount(page, u"Opérations à venir")
                accounting = self.find_amount(page, u"Solde comptable")

                if accounting is not None and accounting + (coming or Decimal('0')) != balance:
                    self.logger.warning('%s + %s != %s' % (accounting, coming, balance))

                if accounting is not None:
                    balance = accounting

                if coming is not None:
                    account.coming = coming
                account.balance = balance
                account.currency = currency

                accounts[account.id] = account

        return accounts.itervalues()
Exemplo n.º 18
0
    def get_list(self, pro=True):
        accounts = []
        for tr in self.document.xpath('//tr[@class="comptes"]'):
            cols = tr.findall('td')

            if len(cols) < 5:
                continue

            account = Account()
            account.id = self.parser.tocleanstring(cols[self.COL_ID]).replace(" ", "")
            account.label = self.parser.tocleanstring(cols[self.COL_LABEL])
            account.balance = Decimal(self.parser.tocleanstring(cols[self.COL_BALANCE]))
            try:
                account.coming = Decimal(self.parser.tocleanstring(cols[self.COL_COMING]))
            except InvalidOperation:
                if self.parser.tocleanstring(cols[self.COL_COMING]) != '-':
                    self.logger.warning('Unable to parse coming value', exc_info=True)
                account.coming = NotAvailable
            account._link_id = None
            account._stp = None

            a = cols[self.COL_LABEL].find('a')
            if a is not None:
                url = urlparse(a.attrib['href'])
                p = dict(parse_qsl(url.query))
                account._link_id = p.get('ch4', None)
                account._stp = p.get('stp', None)

            for input_tag in tr.xpath('.//input[starts-with(@id, "urlRib")]'):
                m = re.search('ch4=(\w+)', input_tag.get('value', ''))
                if m:
                    account.iban = unicode(m.group(1))

            accounts.append(account)

        # If there are also personnal accounts linked, display the page and iter on them.
        if pro and len(self.document.xpath('//div[@class="onglets"]//a[contains(@href, "afficherComptesPrives")]')) > 0:
            self.browser.select_form(name='myForm')
            self.browser.set_all_readonly(False)
            self.browser['udcAction'] = '/afficherComptesPrives'
            self.browser.submit()

            for a in self.browser.page.get_list(False):
                accounts.append(a)

        return accounts
Exemplo n.º 19
0
    def get_list(self):
        l = []
        ids = set()
        for a in self.document.getiterator('a'):
            link = a.attrib.get('href')
            if link is None:
                continue
            if link.startswith("/outil/UWLM/ListeMouvements"):
                account = Account()
                account._link_id = link + "&mode=45"
                account._coming_links = []
                parameters = link.split("?").pop().split("&")
                for parameter in parameters:
                    list = parameter.split("=")
                    value = list.pop()
                    name = list.pop()
                    if name == "agence":
                        account.id = value
                    elif name == "compte":
                        account.id += value
                    elif name == "nature":
                        # TODO parse this string to get the right Account.TYPE_* to
                        # store in account.type.
                        account._type = value

                if account.id in ids:
                    continue

                ids.add(account.id)
                div = a.getparent().getprevious()
                if not div.text.strip():
                    div = div.find('div')
                account.label = u'' + div.text.strip()
                balance = FrenchTransaction.clean_amount(a.text)
                if '-' in balance:
                    balance = '-' + balance.replace('-', '')
                account.balance = Decimal(balance)
                account.currency = account.get_currency(a.text)
                self.logger.debug('%s Type: %s' %
                                  (account.label, account._type))
                l.append(account)
            if link.startswith('/outil/UWCB/UWCBEncours'):
                if len(l) == 0:
                    self.logger.warning(
                        'There is a card account but not any check account')
                    continue

                account = l[-1]

                coming = FrenchTransaction.clean_amount(a.text)
                if '-' in coming:
                    coming = '-' + coming.replace('-', '')
                if not account.coming:
                    account.coming = Decimal('0')
                account.coming += Decimal(coming)
                account._coming_links.append(link)

        return l
Exemplo n.º 20
0
    def get_list(self):
        l = []
        ids = set()
        for a in self.document.getiterator('a'):
            link=a.attrib.get('href')
            if link is None:
                continue
            if link.startswith("/outil/UWLM/ListeMouvements"):
                account = Account()
                #by default the website propose the last 7 days or last 45 days but we can force to have the last 55days
                account._link_id=link+"&mode=55"
                account._coming_links = []
                parameters=link.split("?").pop().split("&")
                for parameter in parameters:
                    list=parameter.split("=")
                    value=list.pop()
                    name=list.pop()
                    if name=="agence":
                        account.id=value
                    elif name=="compte":
                        account.id+=value
                    elif name=="nature":
                        # TODO parse this string to get the right Account.TYPE_* to
                        # store in account.type.
                        account._type=value

                if account.id in ids:
                    continue

                ids.add(account.id)
                div = a.getparent().getprevious()
                if not div.text.strip():
                    div = div.find('div')
                account.label=u''+div.text.strip()
                balance = FrenchTransaction.clean_amount(a.text)
                if '-' in balance:
                    balance='-'+balance.replace('-', '')
                account.balance=Decimal(balance)
                account.currency = account.get_currency(a.text)
                self.logger.debug('%s Type: %s' % (account.label, account._type))
                l.append(account)
            if link.startswith('/outil/UWCB/UWCBEncours'):
                if len(l) == 0:
                    self.logger.warning('There is a card account but not any check account')
                    continue

                account = l[-1]

                coming = FrenchTransaction.clean_amount(a.text)
                if '-' in coming:
                    coming = '-'+coming.replace('-', '')
                if not account.coming:
                    account.coming = Decimal('0')
                account.coming += Decimal(coming)
                account._coming_links.append(link)

        return l
Exemplo n.º 21
0
    def get_single_card(self, parent_id):
        div, = self.doc.xpath('//div[@class="infosynthese"]')

        ret = Account()
        ret.type = Account.TYPE_CARD
        ret.coming = CleanDecimal(Regexp(CleanText('.'), r'En cours prélevé au \d+/\d+/\d+ : ([\d\s,-]+) euros'), replace_dots=True)(div)
        ret.number = Regexp(CleanText('.'), 'sur votre carte n°([\d*]+)')(div)
        ret.id = '%s.%s' % (parent_id, ret.number)
        ret.currency = 'EUR'
        ret.label = 'CARTE %s' % ret.number
        ret.url = self.url
        return ret
Exemplo n.º 22
0
    def get_list(self):
        l = []
        for tr in self.document.getiterator('tr'):
            if tr.attrib.get('class', '') == 'comptes':
                account = Account()
                for td in tr.getiterator('td'):
                    if td.attrib.get('headers', '').startswith('Numero_'):
                        id = td.text
                        account.id = ''.join(id.split(' ')).strip()
                    elif td.attrib.get('headers', '').startswith('Libelle_'):
                        a = td.findall('a')
                        label = unicode(a[0].text)
                        account.label = label.strip()
                        m = self.LINKID_REGEXP.match(a[0].attrib.get('href', ''))
                        if m:
                            account.link_id = m.group(1)
                    elif td.attrib.get('headers', '').startswith('Solde'):
                        a = td.findall('a')
                        balance = a[0].text
                        balance = balance.replace('.','').replace(',','.')
                        account.balance = float(balance)
                    elif td.attrib.get('headers', '').startswith('Avenir'):
                        a = td.findall('a')
                        # Some accounts don't have a "coming"
                        if len(a):
                            coming = a[0].text
                            coming = coming.replace('.','').replace(',','.')
                            account.coming = float(coming)
                        else:
                            account.coming = NotAvailable

                l.append(account)

        if len(l) == 0:
            # oops, no accounts? check if we have not exhausted the allowed use
            # of this password
            for div in self.document.getroot().cssselect('div.Style_texte_gras'):
                if div.text.strip() == 'Vous avez atteint la date de fin de vie de votre code secret.':
                    raise PasswordExpired(div.text.strip())
        return l
Exemplo n.º 23
0
 def iter_cards(self, account):
     for el in account._cards:
         if el['carteDebitDiffere']:
             card = Account()
             card.id = card.number = el['numeroCompteFormate'].replace(' ', '')
             card.label = el['labelToDisplay']
             card.balance = Decimal('0')
             card.coming = Decimal(str(el['montantProchaineEcheance']))
             card.type = Account.TYPE_CARD
             card.currency = account.currency
             card._internal_id = el['idTechnique']
             card._prestation_id = el['id']
             yield card
Exemplo n.º 24
0
    def get_list(self):
        for tr in self.document.getiterator('tr'):
            if 'LGNTableRow' not in tr.attrib.get('class', '').split():
                continue

            account = Account()
            for td in tr.getiterator('td'):
                if td.attrib.get('headers', '') == 'TypeCompte':
                    a = td.find('a')
                    if a is None:
                        break
                    account.label = self.parser.tocleanstring(a)
                    for pattern, actype in self.TYPES.iteritems():
                        if account.label.startswith(pattern):
                            account.type = actype
                    account._link_id = a.get('href', '')

                elif td.attrib.get('headers', '') == 'NumeroCompte':
                    account.id = self.parser.tocleanstring(td).replace(
                        u'\xa0', '')

                elif td.attrib.get('headers', '') == 'Libelle':
                    text = self.parser.tocleanstring(td)
                    if text != '':
                        account.label = text

                elif td.attrib.get('headers', '') == 'Solde':
                    div = td.xpath('./div[@class="Solde"]')
                    if len(div) > 0:
                        balance = self.parser.tocleanstring(div[0])
                        if len(balance) > 0 and balance not in ('ANNULEE',
                                                                'OPPOSITION'):
                            try:
                                account.balance = Decimal(
                                    FrenchTransaction.clean_amount(balance))
                            except InvalidOperation:
                                raise BrokenPageError(
                                    'Unable to parse balance %r' % balance)
                            account.currency = account.get_currency(balance)
                        else:
                            account.balance = NotAvailable

            if not account.label or empty(account.balance):
                continue

            if 'CARTE_' in account._link_id:
                account.type = account.TYPE_CARD
                account.coming = account.balance
                account.balance = Decimal('0')

            yield account
Exemplo n.º 25
0
    def get_list(self):
        l = []
        for a in self.document.getiterator('a'):
            link=a.attrib.get('href')
            if link is None:
                continue
            if link.startswith("/outil/UWLM/ListeMouvements"):
                account = Account()
                account._link_id=link+"&mode=45"
                account._coming_links = []
                parameters=link.split("?").pop().split("&")
                for parameter in parameters:
                    list=parameter.split("=")
                    value=list.pop()
                    name=list.pop()
                    if name=="agence":
                        account.id=value
                    elif name=="compte":
                        account.id+=value
                    elif name=="nature":
                        # TODO parse this string to get the right Account.TYPE_* to
                        # store in account.type.
                        account._type=value
                div = a.getparent().getprevious()
                if not div.text.strip():
                    div = div.find('div')
                account.label=u''+div.text.strip()
                balance=a.text.replace(u"\u00A0",'').replace(' ','').replace('.','').replace('+','').replace(',','.').strip()
                if '-' in balance:
                    balance='-'+balance.replace('-', '')
                account.balance=Decimal(balance)
                self.logger.debug('%s Type: %s' % (account.label, account._type))
                l.append(account)
            if link.startswith('/outil/UWCB/UWCBEncours'):
                if len(l) == 0:
                    self.logger.warning('There is a card account but not any check account')
                    continue

                account = l[-1]

                coming = a.text.replace(u"\u00A0",'').replace(' ','').replace('.','').replace('+','').replace(',','.').strip()
                if '-' in coming:
                    coming = '-'+coming.replace('-', '')
                if not account.coming:
                    account.coming = Decimal('0')
                account.coming += Decimal(coming)
                account._coming_links.append(link)

        return l
Exemplo n.º 26
0
    def get_list(self):
        for box in self.document.getroot().cssselect(
                'div.roundedBox div.contentBox'):
            a = Account()
            a.id = self.parser.tocleanstring(
                box.xpath(
                    './/tr[@id="summaryImageHeaderRow"]//div[@class="summaryTitles"]'
                )[0])
            a.label = self.parser.tocleanstring(
                box.xpath('.//span[@class="cardTitle"]')[0])
            a.balance = Decimal('0.0')
            coming = self.parser.tocleanstring(
                self.parser.select(box, 'td#colOSBalance div.summaryValues',
                                   1))
            if coming in (u'Indisponible', ''):
                a.coming = NotAvailable
            else:
                a.coming = -abs(Decimal(Transaction.clean_amount(coming)))
                a.currency = a.get_currency(coming)
            a._link = self.parser.select(box,
                                         'div.summaryTitles a.summaryLink',
                                         1).attrib['href']

            yield a
Exemplo n.º 27
0
 def iter_cards(self, account):
     for el in account._cards:
         if el['carteDebitDiffere']:
             card = Account()
             card.id = card.number = el['numeroCompteFormate'].replace(
                 ' ', '')
             card.label = el['labelToDisplay']
             card.balance = Decimal('0')
             card.coming = Decimal(str(el['montantProchaineEcheance']))
             card.type = Account.TYPE_CARD
             card.currency = account.currency
             card._internal_id = el['idTechnique']
             card._prestation_id = el['id']
             card.owner_type = AccountOwnerType.PRIVATE
             yield card
Exemplo n.º 28
0
    def get_single_card(self, parent_id):
        div, = self.doc.xpath('//div[@class="infosynthese"]')

        ret = Account()
        ret.type = Account.TYPE_CARD
        ret.coming = CleanDecimal(Regexp(
            CleanText('.'),
            r'En cours prélevé au \d+/\d+/\d+ : ([\d\s,-]+) euros'),
                                  replace_dots=True)(div)
        ret.number = Regexp(CleanText('.'), 'sur votre carte n°([\d*]+)')(div)
        ret.id = '%s.%s' % (parent_id, ret.number)
        ret.currency = 'EUR'
        ret.label = 'CARTE %s' % ret.number
        ret.url = self.url
        return ret
Exemplo n.º 29
0
    def get_list(self):

        no_accounts_message = self.doc.xpath(
            u'//span/b[contains(text(),"Votre abonnement est clôturé. Veuillez contacter votre conseiller.")]/text()'
        )
        if no_accounts_message:
            raise ActionNeeded(no_accounts_message[0])

        for tr in self.doc.xpath('//table[has-class("datas")]//tr'):
            if tr.attrib.get('class', '') == 'entete':
                continue

            cols = tr.findall('td')

            a = Account()
            a.label = unicode(cols[self.COL_ID].xpath(
                './/span[@class="left-underline"] | .//span[@class="left"]/a')
                              [0].text.strip())
            a.type = self.get_account_type(a.label)
            balance = CleanText('.')(cols[self.COL_BALANCE])
            if balance == '':
                continue
            a.balance = CleanDecimal(replace_dots=True).filter(balance)
            a.currency = a.get_currency(balance)
            if cols[self.COL_ID].find('a'):
                a._link, a._args = self.params_from_js(
                    cols[self.COL_ID].find('a').attrib['href'])
            a._acc_nb = cols[self.COL_ID].xpath(
                './/span[@class="right-underline"] | .//span[@class="right"]'
            )[0].text.replace(' ', '').strip()

            if hasattr(a, '_args') and a._args:
                a.id = '%s%s%s' % (a._acc_nb, a._args['IndiceCompte'],
                                   a._args['Indiceclassement'])
            else:
                a.id = a._acc_nb
            # This account can be multiple life insurance accounts
            if any(a.label.startswith(lab) for lab in ['ASS.VIE-BONS CAPI-SCPI-DIVERS', 'BONS CAPI-SCPI-DIVERS']) or \
               u'Aucun d\\351tail correspondant pour ce compte' in tr.xpath('.//a/@href')[0]:
                continue

            if a.type is Account.TYPE_CARD:
                a.coming = a.balance
                a.balance = Decimal('0.0')

            a._inv = False

            yield a
Exemplo n.º 30
0
    def get_list(self):
        for tr in self.document.getiterator('tr'):
            if not 'LGNTableRow' in tr.attrib.get('class', '').split():
                continue

            account = Account()
            for td in tr.getiterator('td'):
                if td.attrib.get('headers', '') == 'TypeCompte':
                    a = td.find('a')
                    if a is None:
                        break
                    account.label = self.parser.tocleanstring(a)
                    for pattern, actype in self.TYPES.iteritems():
                        if account.label.startswith(pattern):
                            account.type = actype
                    account._link_id = a.get('href', '')

                elif td.attrib.get('headers', '') == 'NumeroCompte':
                    account.id = self.parser.tocleanstring(td).replace(u'\xa0', '')

                elif td.attrib.get('headers', '') == 'Libelle':
                    text = self.parser.tocleanstring(td)
                    if text != '':
                        account.label = text

                elif td.attrib.get('headers', '') == 'Solde':
                    div = td.xpath('./div[@class="Solde"]')
                    if len(div) > 0:
                        balance = self.parser.tocleanstring(div[0])
                        if len(balance) > 0 and balance not in ('ANNULEE', 'OPPOSITION'):
                            try:
                                account.balance = Decimal(FrenchTransaction.clean_amount(balance))
                            except InvalidOperation:
                                raise BrokenPageError('Unable to parse balance %r' % balance)
                            account.currency = account.get_currency(balance)
                        else:
                            account.balance = NotAvailable

            if not account.label or empty(account.balance):
                continue

            if 'CARTE_' in account._link_id:
                account.type = account.TYPE_CARD
                account.coming = account.balance
                account.balance = Decimal('0')

            yield account
Exemplo n.º 31
0
    def get_list(self):
        accounts = []

        txt = self.get_from_js('_data = new Array(', ');', is_list=True)

        if txt is None:
            raise BrokenPageError('Unable to find accounts list in scripts')

        data = json.loads('[%s]' % txt.replace("'", '"'))

        for line in data:
            a = Account()
            a.id = line[self.COL_ID].replace(' ', '')
            a._acc_nb = a.id.split('_')[0] if len(a.id.split('_')) > 1 else None
            fp = StringIO(unicode(line[self.COL_LABEL]).encode(self.browser.ENCODING))
            a.label = self.parser.tocleanstring(self.parser.parse(fp, self.browser.ENCODING).xpath('//div[@class="libelleCompteTDB"]')[0])
            # This account can be multiple life insurance accounts
            if a.label == 'ASSURANCE VIE-BON CAPI-SCPI-DIVERS *':
                continue

            a.balance = Decimal(FrenchTransaction.clean_amount(line[self.COL_BALANCE]))
            a.currency = a.get_currency(line[self.COL_BALANCE])
            a.type = self.get_account_type(a.label)
            if line[self.COL_HISTORY] == 'true':
                a._inv = False
                a._link = self.get_history_link()
                a._args = {'_eventId':         'clicDetailCompte',
                           '_ipc_eventValue':  '',
                           '_ipc_fireEvent':   '',
                           'deviseAffichee':   'DEVISE',
                           'execution':        self.get_execution(),
                           'idCompteClique':   line[self.COL_ID],
                          }
            else:
                a._inv = True
                a._args = {'_ipc_eventValue':  line[self.COL_ID],
                           '_ipc_fireEvent':   line[self.COL_FIRE_EVENT],
                          }
                a._link = self.document.xpath('//form[@name="changePageForm"]')[0].attrib['action']

            if a.type is Account.TYPE_CARD:
                a.coming = a.balance
                a.balance = Decimal('0.0')

            accounts.append(a)

        return accounts
Exemplo n.º 32
0
    def get_list(self):
        for trCompte in self.document.xpath('//table[@id="compte"]/tbody/tr'):
            tds = trCompte.findall('td')

            account = Account()

            account.id = tds[self.CPT_ROW_ID].text.strip()
            account.label = tds[self.CPT_ROW_NAME].text.strip()

            account_type_str = "".join([td.text for td in tds[self.CPT_ROW_NATURE].xpath('.//td[@class="txt"]')]).strip()

            account.type = self.ACCOUNT_TYPES.get(account_type_str,  Account.TYPE_UNKNOWN)

            account.balance = Decimal(FrenchTransaction.clean_amount(tds[self.CPT_ROW_BALANCE].find("a").text))
            account.coming = Decimal(FrenchTransaction.clean_amount( tds[self.CPT_ROW_ENCOURS].find("a").text))
            yield account

        return
Exemplo n.º 33
0
 def get_list(self):
     ids = set()
     for td in self.document.xpath('.//td[@nowrap="nowrap"]'):
         account = Account()
         link = td.xpath('.//a')[0]
         account._index = int(re.search('\d', link.attrib['href']).group(0))
         if not account._index in ids:
             ids.add(account._index)
             account.id = unicode(link.text.strip())
             account.label = account.id
             urltofind = './/a[@href="' + link.attrib['href'] + '"]'
             linkbis = self.document.xpath(urltofind).pop()
             if linkbis.text == link.text:
                 linkbis = self.document.xpath(urltofind)[1]
             account.balance = Decimal(linkbis.text.replace('.', '').\
                                       replace(' ', '').replace(',', '.'))
             account.coming = NotAvailable
             yield account
Exemplo n.º 34
0
 def get_list(self):
     ids = set()
     for td in self.document.xpath('.//td[@nowrap="nowrap"]'):
         account = Account()
         link = td.xpath('.//a')[0]
         account._index = int(re.search('\d', link.attrib['href']).group(0))
         if not account._index in ids:
             ids.add(account._index)
             account.id = unicode(link.text.strip())
             account.label = account.id
             urltofind = './/a[@href="' + link.attrib['href'] + '"]'
             linkbis = self.document.xpath(urltofind).pop()
             if linkbis.text == link.text:
                 linkbis = self.document.xpath(urltofind)[1]
             account.balance = Decimal(linkbis.text.replace('.', '').\
                                       replace(' ', '').replace(',', '.'))
             account.coming = NotAvailable
             yield account
Exemplo n.º 35
0
    def get_list(self):
        for table in self.has_accounts():
            tds = table.xpath('./tbody/tr')[0].findall('td')
            if len(tds) < 3:
                if tds[0].text_content() == u'Pr\xeat Personnel':

                    account = Account()
                    args = self.js2args(table.xpath('.//a')[0].attrib['onclick'])
                    account._args = args
                    account.label = CleanText().filter(tds[0].xpath('./ancestor::table[has-class("tableaux-pret-personnel")]/caption'))
                    account.id = account.label.split()[-1] + args['paramNumContrat']
                    loan_details = self.browser.open("/webapp/axabanque/jsp/panorama.faces",data=args)
                    # Need to go back on home page after open
                    self.browser.bank_accounts.open()
                    account.balance = -CleanDecimal().filter(loan_details.page.doc.xpath('//*[@id="table-detail"]/tbody/tr/td[7]/text()'))
                    account.currency = Currency().filter(loan_details.page.doc.xpath('//*[@id="table-detail"]/tbody/tr/td[7]/text()'))
                    account.type = Account.TYPE_LOAN
                    account._acctype = "bank"
                    account._hasinv = False
                    account._is_debit_card = False
                    yield account

                continue

            boxes = table.xpath('./tbody//tr[not(.//strong[contains(text(), "Total")])]')
            foot = table.xpath('./tfoot//tr')

            for box in boxes:
                account = Account()
                account._url = None

                if len(box.xpath('.//a')) != 0 and 'onclick' in box.xpath('.//a')[0].attrib:
                    args = self.js2args(box.xpath('.//a')[0].attrib['onclick'])
                    account.label =  u'{0} {1}'.format(unicode(table.xpath('./caption')[0].text.strip()), unicode(box.xpath('.//a')[0].text.strip()))
                elif len(foot[0].xpath('.//a')) != 0 and 'onclick' in foot[0].xpath('.//a')[0].attrib:
                    args = self.js2args(foot[0].xpath('.//a')[0].attrib['onclick'])
                    account.label =  unicode(table.xpath('./caption')[0].text.strip())
                else:
                    continue

                self.logger.debug('Args: %r' % args)
                if 'paramNumCompte' not in args:
                    #The displaying of life insurances is very different from the other
                    if args.get('idPanorama:_idcl').split(":")[1] == 'tableaux-direct-solution-vie':
                        account_details = self.browser.open("#", data=args)
                        scripts = account_details.page.doc.xpath('//script[@type="text/javascript"]/text()')
                        script = filter(lambda x: "src" in x, scripts)[0]
                        iframe_url = re.search("src:(.*),", script).group()[6:-2]
                        account_details_iframe = self.browser.open(iframe_url, data=args)
                        account.id = CleanText('//span[contains(@id,"NumeroContrat")]/text()')(account_details_iframe.page.doc)
                        account._url = iframe_url
                        account.type = account.TYPE_LIFE_INSURANCE
                        account.balance = MyDecimal('//span[contains(@id,"MontantEpargne")]/text()')(account_details_iframe.page.doc)
                        account._acctype = "bank"
                        account._is_debit_card = False
                    else:
                        try:
                            label = unicode(table.xpath('./caption')[0].text.strip())
                        except Exception:
                            label = 'Unable to determine'
                        self.logger.warning('Unable to get account ID for %r' % label)
                        continue

                if account.type != account.TYPE_LIFE_INSURANCE:
                    # get accounts type
                    account_type_str = ''
                    for l in table.attrib['class'].split(' '):
                        if 'tableaux-comptes-' in l:
                            account_type_str = l[len('tableaux-comptes-'):].lower()
                            break

                    account.type = Account.TYPE_UNKNOWN
                    for pattern, type in self.ACCOUNT_TYPES.items():
                        if pattern in account_type_str or pattern in account.label.lower():
                            account.type = type
                            break

                    # get accounts id
                    try:
                        account.id = args['paramNumCompte'] + args['paramNumContrat']
                        if 'Visa' in account.label:
                            card_id = re.search('(\d+)', box.xpath('./td[2]')[0].text.strip())
                            if card_id:
                                account.id += card_id.group(1)
                        if u'Valorisation' in account.label or u'Liquidités' in account.label:
                            account.id += args[next(k for k in args.keys() if "_idcl" in k)].split('Jsp')[-1]
                    except KeyError:
                        account.id = args['paramNumCompte']

                    # get accounts balance
                    try:
                        balance_value = CleanText('.//td[has-class("montant")]')(box)

                        # skip debit card
                        # some cards don't have information in balance tab, skip them
                        if balance_value == u'Débit immédiat' or balance_value == '':
                            account._is_debit_card = True
                        else:
                            account._is_debit_card = False

                        account.balance = Decimal(FrenchTransaction.clean_amount(self.parse_number(balance_value)))
                        if account.type == Account.TYPE_CARD:
                            account.coming = account.balance
                            account.balance = Decimal(0)

                    except InvalidOperation:
                        #The account doesn't have a amount
                        pass

                    account._url = self.doc.xpath('//form[contains(@action, "panorama")]/@action')[0]
                    account._acctype = "bank"

                # get accounts currency
                currency_title = table.xpath('./thead//th[@class="montant"]')[0].text.strip()
                m = re.match('Montant \((\w+)\)', currency_title)
                if not m:
                    self.logger.warning('Unable to parse currency %r' % currency_title)
                else:
                    account.currency = account.get_currency(m.group(1))

                account._args = args
                account._hasinv = True if "Valorisation" in account.label else False

                yield account
Exemplo n.º 36
0
    def get_list(self):
        no_accounts_message = self.doc.xpath(u'//span/b[contains(text(),"Votre abonnement est clôturé. Veuillez contacter votre conseiller.")]/text()')
        if no_accounts_message:
            raise ActionNeeded(no_accounts_message[0])

        previous_checking_account = None
        # Several deposit accounts ('Compte à terme') have the same id and the same label
        # So a number is added to distinguish them
        previous_deposit_account = None
        deposit_count = 1
        for tr in self.doc.xpath('//table[has-class("datas")]//tr'):
            if tr.attrib.get('class', '') == 'entete':
                owner = CleanText('.')(tr.findall('td')[0])
                continue

            cols = tr.findall('td')

            a = Account()
            a.label = unicode(cols[self.COL_ID].xpath('.//span[@class="left-underline"] | .//span[@class="left"]/a')[0].text.strip())
            a.type = self.get_account_type(a.label)
            a.ownership = self.get_account_ownership(owner)
            balance = CleanText('.')(cols[self.COL_BALANCE])
            if balance == '':
                continue
            a.balance = CleanDecimal(replace_dots=True).filter(balance)
            a.currency = a.get_currency(balance)
            if cols[self.COL_ID].find('a'):
                a._link, a._args = self.params_from_js(cols[self.COL_ID].find('a').attrib['href'])
            # There may be a href with 'javascript:NoDetail();'
            # The _link and _args should be None
            else:
                a._link, a._args = None, None
            a._acc_nb = cols[self.COL_ID].xpath('.//span[@class="right-underline"] | .//span[@class="right"]')[0].text.replace(' ', '').strip()

            a.id = a._acc_nb

            # If available we add 'IndiceCompte' and 'IndiceClassement' to the id due to the lack of information
            # on the website. This method is not enough because on some connections, if there are multiple account with the
            # same id and the same label, but with different currencies, we will add an index at the end of the id relative to the
            # order the accounts appear on the website. This will cause the accounts to be shifted when the user will add a new account
            # with same label/id, if this happens the new account will appear first on the website and it will take the index of '1'
            # previously used by the first account. the already gathered transactions of the previously first account will appear on
            # the new first account, the already gathered transactions of the previously second account will appear on the new
            # second account (the previous one), etc.

            if hasattr(a, '_args') and a._args:
                if a._args['IndiceCompte'].isdigit():
                    a.id = '%s%s' % (a.id, a._args['IndiceCompte'])
                if a._args['Indiceclassement'].isdigit():
                    a.id = '%s%s' % (a.id, a._args['Indiceclassement'])

            # This account can be multiple life insurance accounts
            if (any(a.label.startswith(lab) for lab in ['ASS.VIE-BONS CAPI-SCPI-DIVERS', 'BONS CAPI-SCPI-DIVERS'])
                or (u'Aucun d\\351tail correspondant pour ce compte' in tr.xpath('.//a/@href')[0])
                    and 'COMPTE A TERME' not in tr.xpath('.//span[contains(@class, "left")]/text()')[0]):
                continue

            if a.type is Account.TYPE_CARD:
                a.coming = a.balance
                a.balance = Decimal('0.0')

                # Take the predecessiong checking account as parent
                if previous_checking_account:
                    a.parent = previous_checking_account
                else:
                    self.logger.warning('The card account %s has no parent account' % a.id)

            a._inv = True

            if a.type == Account.TYPE_CHECKING:
                previous_checking_account = a

            if previous_deposit_account and previous_deposit_account.id == a.id:
                a.id = a.id + '_%s' % deposit_count
                deposit_count += 1
                previous_deposit_account = a

            if a.type == Account.TYPE_DEPOSIT:
                previous_deposit_account = a

            yield a
Exemplo n.º 37
0
    def get_list(self):
        accounts = []

        for block in self.document.xpath('//div[@class="pave"]/div'):
            head_type = block.xpath(
                './div/span[@class="accGroupLabel"]')[0].text.strip()
            account_type = self.ACCOUNT_TYPES.get(head_type,
                                                  Account.TYPE_UNKNOWN)
            for tr in block.cssselect('ul li.tbord_account'):
                id = tr.attrib.get('id', '')
                if id.find('contratId') != 0:
                    self.logger.warning('Unable to parse contract ID: %r' % id)
                    continue
                id = id[id.find('contratId') + len('contratId'):]

                link = tr.cssselect('span.accountLabel a')[0]
                balance = Decimal(
                    FrenchTransaction.clean_amount(
                        tr.cssselect('span.accountTotal')[0].text))

                if id.endswith('CRT'):
                    account = accounts[-1]
                    account._card_links.append(link.attrib['href'])
                    if not account.coming:
                        account.coming = Decimal('0.0')
                    account.coming += balance
                    continue

                account = Account()
                account.id = id
                account.label = unicode(link.text.strip())
                account.type = account_type
                account.balance = balance
                account.currency = account.get_currency(
                    tr.cssselect('span.accountDev')[0].text)
                account._link = link.attrib['href']
                account._card_links = []
                accounts.append(account)

        if len(accounts) == 0:
            # Sometimes, accounts are only in javascript...
            for script in self.document.xpath('//script'):
                text = script.text
                if text is None:
                    continue
                if 'remotePerso' not in text:
                    continue

                account = None
                card_account = None
                attribs = {}
                account_type = Account.TYPE_UNKNOWN
                for line in text.split('\n'):
                    line = line.strip()
                    m = re.match("data.libelle = '(.*)';", line)
                    if m:
                        account_type = self.ACCOUNT_TYPES.get(
                            m.group(1), Account.TYPE_UNKNOWN)
                    elif line == 'var remotePerso = new Object;':
                        account = Account()
                    elif account is not None:
                        m = re.match("remotePerso.(\w+) = '?(.*?)'?;", line)
                        if m:
                            attribs[m.group(1)] = m.group(2)
                        elif line.startswith('listProduitsGroup'):
                            account.id = attribs['refContrat']

                            account.label = attribs['libelle']
                            account.type = account_type
                            account.balance = Decimal(
                                FrenchTransaction.clean_amount(
                                    attribs['soldeDateOpeValeurFormatted']))
                            account.currency = account.get_currency(
                                attribs['codeDevise'])
                            account._link = 'tbord.do?id=%s&%s' % (
                                attribs['id'], self.browser.SESSION_PARAM)
                            account._card_links = []

                            if account.id.endswith('CRT'):
                                if not len(accounts):
                                    card_account = account
                                else:
                                    a = accounts[-1]
                                    a._card_links.append(account._link)
                                    if not a.coming:
                                        a.coming = Decimal('0.0')
                                    a.coming += account.balance
                            else:
                                if 'COURANT' in account.label:
                                    account.type = account.TYPE_CHECKING
                                elif account.id.endswith('TTR'):
                                    account.type = account.TYPE_MARKET
                                elif re.match('^\d+C$', account.id):
                                    account.type = account.TYPE_LIFE_INSURANCE
                                elif re.match('^\d+PRT$', account.id):
                                    account.type = account.TYPE_LOAN
                                elif not account.type:
                                    account.type = account.TYPE_SAVINGS

                                if card_account:
                                    account._card_links.append(
                                        card_account._link)
                                    if not account.coming:
                                        account.coming = Decimal('0.0')
                                    account.coming += card_account.balance
                                    card_account = None
                                accounts.append(account)
                            account = None

        return accounts
Exemplo n.º 38
0
    def iter_accounts(self):
        if not self.cookie:
            self.login()

        def do_http():
            if 'no_check' in self.config and self.config['no_check'].get() == "y":
                conn = HellHTTPS("www.cmb.fr")
            else:
                conn = HellHTTPS("www.cmb.fr", ca_file=self.AUTH_CERT, callBack=self.sslCallBack)
            conn.connect()
            headers = self.headers
            headers['Cookie'] = self.cookie
            conn.request("GET",
                         '/domiweb/prive/particulier/releve/0-releve.act',
                         {},
                         headers)
            response = conn.getresponse()
            data = response.read()
            conn.close()
            return data

        data = do_http()
        parser = etree.HTMLParser()
        tree = etree.parse(StringIO(data), parser)

        table = tree.xpath('/html/body/table')
        if len(table) == 0:
            title = tree.xpath('/html/head/title')[0].text
            if title == u"Utilisateur non identifié":
                self.login()
                data = do_http()

                parser = etree.HTMLParser()
                tree = etree.parse(StringIO(data), parser)
                table = tree.xpath('/html/body/table')
                if len(table) == 0:
                    raise BrokenPageError()
            else:
                raise BrokenPageError()

        for tr in tree.xpath('/html/body//table[contains(@class, "Tb")]/tr'):
            if tr.get('class', None) not in ('LnTit', 'LnTot', 'LnMnTiers', None):
                account = Account()
                td = tr.xpath('td')

                a = td[1].xpath('a')
                account.label = unicode(a[0].text).strip()
                href = a[0].get('href')
                m = match(r"javascript:releve\((.*),'(.*)','(.*)'\)",
                             href)
                if not m:
                    continue
                account.id = unicode(m.group(1) + m.group(2) + m.group(3))
                account._cmbvaleur = m.group(1)
                account._cmbvaleur2 = m.group(2)
                account._cmbtype = m.group(3)

                balance = u''.join([txt.strip() for txt in td[2].itertext()])
                balance = balance.replace(',', '.').replace(u"\xa0", '')
                account.balance = Decimal(balance)

                span = td[4].xpath('a/span')
                if len(span):
                    coming = span[0].text.replace(' ', '').replace(',', '.')
                    coming = coming.replace(u"\xa0", '')
                    account.coming = Decimal(coming)
                else:
                    account.coming = NotAvailable

                yield account
Exemplo n.º 39
0
    def get_list(self):
        accounts = []

        for cpt in self.doc.xpath('//div[contains(@class, " compte") and not(contains(@class, "compte_selected"))]'):

            # ignore auto assurance accounts
            if 'aut' in cpt.get('class'):
                continue

            account = Account()
            account._history_link = Link('./ul/li/a[contains(@id, "consulter_solde") '
                                         'or contains(@id, "historique") '
                                         'or contains(@id, "contrat") '
                                         'or contains(@id, "assurance_vie_operations")]')(cpt)

            # this is to test if access to the accounts info is blocked for different reasons
            page = self.browser.open(account._history_link).page
            if isinstance(page, LoanPage):
                account = Loan()

            account._history_link = Link('./ul/li/a[contains(@id, "consulter_solde") '
                                         'or contains(@id, "historique") '
                                         'or contains(@id, "contrat") '
                                         'or contains(@id, "assurance_vie_operations")]')(cpt)
            if isinstance(page, LoanPage):
                account.id = CleanText('(//p[@id="c_montantEmprunte"]//span[@class="valStatic"]//strong)[1]')(cpt)
                account.label = CleanText('(//p[@id="c_montantEmprunte"]//span[@class="valStatic"]//strong)[1]')(cpt)
                account.type = Account.TYPE_LOAN
                account_history_page = page
                account.total_amount = account_history_page.get_total_amount()
                account.next_payment_amount = account_history_page.get_next_payment_amount()
                account.next_payment_date = account_history_page.get_next_payment_date()
                account.account_label = account_history_page.get_account_label()
                account.subscription_date = account_history_page.get_subscription_date()
                account.maturity_date = account_history_page.get_maturity_date()

            if len(accounts) == 0:
                global_error_message = page.doc.xpath('//div[@id="as_renouvellementMIFID.do_"]/div[contains(text(), "Bonjour")] '
                                                      '| //div[@id="as_afficherMessageBloquantMigration.do_"]//div[@class="content_message"] '
                                                      '| //p[contains(text(), "Et si vous faisiez de Fortuneo votre banque principale")] '
                                                      '| //div[@id="as_renouvellementMotDePasse.do_"]//p[contains(text(), "votre mot de passe")]'
                                                      '| //div[@id="as_afficherSecuriteForteOTPIdentification.do_"]//span[contains(text(), "Pour valider ")]')
                if global_error_message:
                    raise ActionNeeded(CleanText('.')(global_error_message[0]))
            local_error_message = page.doc.xpath('//div[@id="error"]/p[@class="erreur_texte1"]')
            if local_error_message:
                raise BrowserUnavailable(CleanText('.')(local_error_message[0]))

            number = RawText('./a[contains(@class, "numero_compte")]')(cpt).replace(u'N° ', '')

            account.id = CleanText(None).filter(number).replace(u'N°', '')

            account._card_links = []
            card_link = Link('./ul/li/a[contains(text(), "Carte bancaire")]', default='')(cpt)
            if len(card_link) > 0:
                account._card_links.append(card_link)

            account.label = CleanText('./a[contains(@class, "numero_compte")]/@title')(cpt)

            for pattern, type in self.ACCOUNT_TYPES.items():
                if pattern in account._history_link:
                    account.type = type
                    break

            investment_page = None
            if account.type in {Account.TYPE_PEA, Account.TYPE_MARKET, Account.TYPE_LIFE_INSURANCE}:
                account._investment_link = Link('./ul/li/a[contains(@id, "portefeuille")]')(cpt)
                investment_page = self.browser.open(account._investment_link).page
                balance = investment_page.get_balance(account.type)
                if account.type in {Account.TYPE_PEA, Account.TYPE_MARKET}:
                    self.browser.investments[account.id] = list(self.browser.open(account._investment_link).page.get_investments(account))
            else:
                balance = page.get_balance()
                if account.type is not Account.TYPE_LOAN:
                    account.coming = page.get_coming()

            if account.type in {Account.TYPE_PEA, Account.TYPE_MARKET}:
                account.currency = investment_page.get_currency()
            else:
                account.currency = account.get_currency(balance)
            account.balance = CleanDecimal(None, replace_dots=True).filter(balance)

            if account.type in (Account.TYPE_CHECKING, Account.TYPE_SAVINGS):
                # Need a token sent by SMS to customers
                account.iban = NotAvailable

            if (account.label, account.id, account.balance) not in [(a.label, a.id, a.balance) for a in accounts]:
                accounts.append(account)
        return accounts
Exemplo n.º 40
0
    def get_list(self, pro=True):
        accounts = []
        for tr in self.document.xpath('//tr[@class="comptes"]'):
            cols = tr.findall('td')

            if len(cols) < 5:
                continue

            account = Account()
            account.id = self.parser.tocleanstring(cols[self.COL_ID]).replace(
                " ", "")
            account.label = self.parser.tocleanstring(cols[self.COL_LABEL])
            account.balance = Decimal(
                self.parser.tocleanstring(cols[self.COL_BALANCE]))
            try:
                account.coming = Decimal(
                    self.parser.tocleanstring(cols[self.COL_COMING]))
            except InvalidOperation:
                if self.parser.tocleanstring(cols[self.COL_COMING]) != '-':
                    self.logger.warning('Unable to parse coming value',
                                        exc_info=True)
                account.coming = NotAvailable
            account._link_id = None
            account._stp = None

            a = cols[self.COL_LABEL].find('a')
            if a is not None:
                url = urlparse(a.attrib['href'])
                p = dict(parse_qsl(url.query))
                account._link_id = p.get('ch4', None)
                account._stp = p.get('stp', None)

            for input_tag in tr.xpath('.//input[starts-with(@id, "urlRib")]'):
                m = re.search('ch4=(\w+)', input_tag.get('value', ''))
                if m:
                    account.iban = unicode(m.group(1))
                    break
            else:
                select = tr.xpath('.//select//@onchange')[0]
                m = re.search("\(this,'(\w+)", select)
                if m:
                    iban = unicode(m.group(1))
                    if iban.startswith('FR') and len(iban) == 27:
                        account.iban = unicode(m.group(1))

            accounts.append(account)

        # If there are also personnal accounts linked, display the page and iter on them.
        if pro and len(
                self.document.xpath(
                    '//div[@class="onglets"]//a[contains(@href, "afficherComptesPrives")]'
                )) > 0:
            self.browser.select_form(name='myForm')
            self.browser.set_all_readonly(False)
            self.browser['udcAction'] = '/afficherComptesPrives'
            self.browser.submit()

            for a in self.browser.page.get_list(False):
                accounts.append(a)

        return accounts
Exemplo n.º 41
0
    def iter_accounts(self):
        if not self.cookie:
            self.login()

        def do_http():
            if 'no_check' in self.config and self.config['no_check'].get(
            ) == "y":
                conn = HellHTTPS("www.cmb.fr")
            else:
                conn = HellHTTPS("www.cmb.fr",
                                 ca_file=self.AUTH_CERT,
                                 callBack=self.sslCallBack)
            conn.connect()
            headers = self.headers
            headers['Cookie'] = self.cookie
            conn.request("GET",
                         '/domiweb/prive/particulier/releve/0-releve.act', {},
                         headers)
            response = conn.getresponse()
            data = response.read()
            conn.close()
            return data

        data = do_http()
        parser = etree.HTMLParser()
        tree = etree.parse(StringIO(data), parser)

        table = tree.xpath('/html/body/table')
        if len(table) == 0:
            title = tree.xpath('/html/head/title')[0].text
            if title == u"Utilisateur non identifié":
                self.login()
                data = do_http()

                parser = etree.HTMLParser()
                tree = etree.parse(StringIO(data), parser)
                table = tree.xpath('/html/body/table')
                if len(table) == 0:
                    raise BrokenPageError()
            else:
                raise BrokenPageError()

        for tr in table[1].getiterator('tr'):
            if tr.get('class') != 'LnTit' and tr.get('class') != 'LnTot':
                account = Account()
                td = tr.xpath('td')

                a = td[1].xpath('a')
                account.label = unicode(a[0].text).strip()
                href = a[0].get('href')
                m = match(r"javascript:releve\((.*),'(.*)','(.*)'\)", href)
                if not m:
                    continue
                account.id = unicode(m.group(1) + m.group(2) + m.group(3))
                account._cmbvaleur = m.group(1)
                account._cmbvaleur2 = m.group(2)
                account._cmbtype = m.group(3)

                balance = td[2].text
                balance = balance.replace(',', '.').replace(u"\xa0", '')
                account.balance = Decimal(balance)

                span = td[4].xpath('a/span')
                if len(span):
                    coming = span[0].text.replace(' ', '').replace(',', '.')
                    coming = coming.replace(u"\xa0", '')
                    account.coming = Decimal(coming)
                else:
                    account.coming = NotAvailable

                yield account
Exemplo n.º 42
0
    def get_list(self):
        accounts = []

        for cpt in self.doc.xpath('//div[contains(@class, " compte") and not(contains(@class, "compte_selected"))]'):

            # ignore auto assurance accounts
            if 'aut' in cpt.get('class'):
                continue

            account = Account()
            account._history_link = Link('./ul/li/a[contains(@id, "consulter_solde") '
                                         'or contains(@id, "historique") '
                                         'or contains(@id, "contrat") '
                                         'or contains(@id, "assurance_vie_operations")]')(cpt)

            # this is to test if access to the accounts info is blocked for different reasons
            page = self.browser.open(account._history_link).page
            if isinstance(page, LoanPage):
                account = Loan()

            account._history_link = Link('./ul/li/a[contains(@id, "consulter_solde") '
                                         'or contains(@id, "historique") '
                                         'or contains(@id, "contrat") '
                                         'or contains(@id, "assurance_vie_operations")]')(cpt)
            if isinstance(page, LoanPage):
                account.id = CleanText('(//p[@id="c_montantEmprunte"]//span[@class="valStatic"]//strong)[1]')(cpt)
                account.label = CleanText('(//p[@id="c_montantEmprunte"]//span[@class="valStatic"]//strong)[1]')(cpt)
                account.type = Account.TYPE_LOAN
                account_history_page = page
                account.total_amount = account_history_page.get_total_amount()
                account.next_payment_amount = account_history_page.get_next_payment_amount()
                account.next_payment_date = account_history_page.get_next_payment_date()
                account.account_label = account_history_page.get_account_label()
                account.subscription_date = account_history_page.get_subscription_date()
                account.maturity_date = account_history_page.get_maturity_date()
                account.ownership = account_history_page.get_owner()

            if len(accounts) == 0:
                global_error_message = page.doc.xpath('//div[@id="as_renouvellementMIFID.do_"]/div[contains(text(), "Bonjour")] '
                                                      '| //div[@id="as_afficherMessageBloquantMigration.do_"]//div[@class="content_message"] '
                                                      '| //p[contains(text(), "Et si vous faisiez de Fortuneo votre banque principale")] '
                                                      '| //div[@id="as_renouvellementMotDePasse.do_"]//p[contains(text(), "votre mot de passe")]'
                                                      '| //div[@id="as_afficherSecuriteForteOTPIdentification.do_"]//span[contains(text(), "Pour valider ")]')
                if global_error_message:
                    if "Et si vous faisiez de Fortuneo votre banque principale" in CleanText(global_error_message)(self):
                        self.browser.location('/ReloadContext', data={'action': 4})
                        return
                    raise ActionNeeded(CleanText('.')(global_error_message[0]))
            local_error_message = page.doc.xpath('//div[@id="error"]/p[@class="erreur_texte1"]')
            if local_error_message:
                raise BrowserUnavailable(CleanText('.')(local_error_message[0]))

            account.id = account.number = CleanText('./a[contains(@class, "numero_compte")]/div')(cpt).replace(u'N° ', '')
            account._ca = CleanText('./a[contains(@class, "numero_compte")]/@rel')(cpt)

            account._card_links = []
            card_link = Link('./ul/li/a[contains(text(), "Carte bancaire")]', default='')(cpt)
            if len(card_link) > 0:
                account._card_links.append(card_link)

            account.label = CleanText('./a[contains(@class, "numero_compte")]/@title')(cpt)

            for pattern, type in self.ACCOUNT_TYPES.items():
                if pattern in account._history_link:
                    account.type = type
                    break

            investment_page = None
            if account.type in (Account.TYPE_PEA, Account.TYPE_MARKET, Account.TYPE_LIFE_INSURANCE):
                account._investment_link = Link('./ul/li/a[contains(@id, "portefeuille")]')(cpt)
                investment_page = self.browser.location(account._investment_link).page
                balance = investment_page.get_balance(account.type)
                if account.type in (Account.TYPE_PEA, Account.TYPE_MARKET):
                    self.browser.investments[account.id] = list(self.browser.open(account._investment_link).page.get_investments(account))
            else:
                balance = page.get_balance()
                if account.type is not Account.TYPE_LOAN:
                    account.coming = page.get_coming()

            if account.type in (Account.TYPE_PEA, Account.TYPE_MARKET):
                account.currency = investment_page.get_currency()
            elif balance:
                account.currency = account.get_currency(balance)

            account.balance = CleanDecimal.French().filter(balance)

            if account.type in (Account.TYPE_CHECKING, Account.TYPE_SAVINGS):
                # Need a token sent by SMS to customers
                account.iban = NotAvailable

            if account.type is not Account.TYPE_LOAN:
                regexp = re.search(r'(m\. |mme\. )(.+)', CleanText('//span[has-class("mon_espace_nom")]')(self.doc), re.IGNORECASE)
                if regexp and len(regexp.groups()) == 2:
                    gender = regexp.group(1).replace('.', '').rstrip()
                    name = regexp.group(2)
                    label = account.label
                    if re.search(r'(m|mr|me|mme|mlle|mle|ml)\.? (.*)\bou (m|mr|me|mme|mlle|mle|ml)\b(.*)', label, re.IGNORECASE):
                        account.ownership = AccountOwnership.CO_OWNER
                    elif re.search(r'{} {}'.format(gender, name), label, re.IGNORECASE):
                        account.ownership = AccountOwnership.OWNER
                    else:
                        account.ownership = AccountOwnership.ATTORNEY

            if (account.label, account.id, account.balance) not in [(a.label, a.id, a.balance) for a in accounts]:
                accounts.append(account)
        return accounts
Exemplo n.º 43
0
    def get_list(self):
        no_accounts_message = self.doc.xpath(u'//span/b[contains(text(),"Votre abonnement est clôturé. Veuillez contacter votre conseiller.")]/text()')
        if no_accounts_message:
            raise ActionNeeded(no_accounts_message[0])

        previous_checking_account = None
        # Several deposit accounts ('Compte à terme') have the same id and the same label
        # So a number is added to distinguish them
        previous_deposit_account = None
        deposit_count = 1
        for tr in self.doc.xpath('//table[has-class("datas")]//tr'):
            if tr.attrib.get('class', '') == 'entete':
                continue

            cols = tr.findall('td')

            a = Account()
            a.label = unicode(cols[self.COL_ID].xpath('.//span[@class="left-underline"] | .//span[@class="left"]/a')[0].text.strip())
            a.type = self.get_account_type(a.label)
            balance = CleanText('.')(cols[self.COL_BALANCE])
            if balance == '':
                continue
            a.balance = CleanDecimal(replace_dots=True).filter(balance)
            a.currency = a.get_currency(balance)
            if cols[self.COL_ID].find('a'):
                a._link, a._args = self.params_from_js(cols[self.COL_ID].find('a').attrib['href'])
            # There may be a href with 'javascript:NoDetail();'
            # The _link and _args should be None
            else:
                a._link, a._args = None, None
            a._acc_nb = cols[self.COL_ID].xpath('.//span[@class="right-underline"] | .//span[@class="right"]')[0].text.replace(' ', '').strip()

            if hasattr(a, '_args') and a._args:
                a.id = '%s%s%s' % (a._acc_nb, a._args['IndiceCompte'], a._args['Indiceclassement'])
            else:
                a.id = a._acc_nb
            # This account can be multiple life insurance accounts
            if (any(a.label.startswith(lab) for lab in ['ASS.VIE-BONS CAPI-SCPI-DIVERS', 'BONS CAPI-SCPI-DIVERS'])
                or (u'Aucun d\\351tail correspondant pour ce compte' in tr.xpath('.//a/@href')[0])
                    and 'COMPTE A TERME' not in tr.xpath('.//span[contains(@class, "left")]/text()')[0]):
                continue

            if a.type is Account.TYPE_CARD:
                a.coming = a.balance
                a.balance = Decimal('0.0')

                # Take the predecessiong checking account as parent
                if previous_checking_account:
                    a.parent = previous_checking_account
                else:
                    self.logger.warning('The card account %s has no parent account' % a.id)

            a._inv = False

            if a.type == Account.TYPE_CHECKING:
                previous_checking_account = a

            if previous_deposit_account and previous_deposit_account.id == a.id:
                a.id = a.id + '_%s' % deposit_count
                deposit_count += 1
                previous_deposit_account = a

            if a.type == Account.TYPE_DEPOSIT:
                previous_deposit_account = a

            yield a
Exemplo n.º 44
0
    def get_list(self):
        no_accounts_message = self.doc.xpath(u'//span/b[contains(text(),"Votre abonnement est clôturé. Veuillez contacter votre conseiller.")]/text()')
        if no_accounts_message:
            raise ActionNeeded(no_accounts_message[0])

        previous_checking_account = None
        # Several deposit accounts ('Compte à terme') have the same id and the same label
        # So a number is added to distinguish them
        previous_deposit_account = None
        deposit_count = 1
        for tr in self.doc.xpath('//table[has-class("datas")]//tr'):
            if tr.attrib.get('class', '') == 'entete':
                continue

            cols = tr.findall('td')

            a = Account()
            a.label = unicode(cols[self.COL_ID].xpath('.//span[@class="left-underline"] | .//span[@class="left"]/a')[0].text.strip())
            a.type = self.get_account_type(a.label)
            balance = CleanText('.')(cols[self.COL_BALANCE])
            if balance == '':
                continue
            a.balance = CleanDecimal(replace_dots=True).filter(balance)
            a.currency = a.get_currency(balance)
            if cols[self.COL_ID].find('a'):
                a._link, a._args = self.params_from_js(cols[self.COL_ID].find('a').attrib['href'])
            # There may be a href with 'javascript:NoDetail();'
            # The _link and _args should be None
            else:
                a._link, a._args = None, None
            a._acc_nb = cols[self.COL_ID].xpath('.//span[@class="right-underline"] | .//span[@class="right"]')[0].text.replace(' ', '').strip()

            a.id = a._acc_nb
            if hasattr(a, '_args') and a._args:
                if a._args['IndiceCompte'].isdigit():
                    a.id = '%s%s' % (a.id, a._args['IndiceCompte'])
                if a._args['Indiceclassement'].isdigit():
                    a.id = '%s%s' % (a.id, a._args['Indiceclassement'])

            # This account can be multiple life insurance accounts
            if (any(a.label.startswith(lab) for lab in ['ASS.VIE-BONS CAPI-SCPI-DIVERS', 'BONS CAPI-SCPI-DIVERS'])
                or (u'Aucun d\\351tail correspondant pour ce compte' in tr.xpath('.//a/@href')[0])
                    and 'COMPTE A TERME' not in tr.xpath('.//span[contains(@class, "left")]/text()')[0]):
                continue

            if a.type is Account.TYPE_CARD:
                a.coming = a.balance
                a.balance = Decimal('0.0')

                # Take the predecessiong checking account as parent
                if previous_checking_account:
                    a.parent = previous_checking_account
                else:
                    self.logger.warning('The card account %s has no parent account' % a.id)

            a._inv = True

            if a.type == Account.TYPE_CHECKING:
                previous_checking_account = a

            if previous_deposit_account and previous_deposit_account.id == a.id:
                a.id = a.id + '_%s' % deposit_count
                deposit_count += 1
                previous_deposit_account = a

            if a.type == Account.TYPE_DEPOSIT:
                previous_deposit_account = a

            yield a
Exemplo n.º 45
0
    def get_list(self):
        for table in self.has_accounts():
            tds = table.xpath('./tbody/tr')[0].findall('td')
            if len(tds) < 3:
                if tds[0].text_content() == u'Pr\xeat Personnel':

                    account = Account()
                    args = self.js2args(table.xpath('.//a')[0].attrib['onclick'])
                    account._args = args
                    account.label = CleanText().filter(tds[0].xpath('./ancestor::table[has-class("tableaux-pret-personnel")]/caption'))
                    account.id = account.label.split()[-1] + args['paramNumContrat']
                    loan_details = self.browser.open('/webapp/axabanque/jsp/panorama.faces', data=args).page
                    # Need to go back on home page after open
                    self.browser.bank_accounts.open()
                    account.balance = loan_details.get_loan_balance()
                    account.currency = loan_details.get_loan_currency()
                    # Skip loans without any balance (already fully reimbursed)
                    if empty(account.balance):
                        continue
                    account.type = Account.TYPE_LOAN
                    account._acctype = "bank"
                    account._hasinv = False
                    account._is_debit_card = False
                    yield account

                continue

            boxes = table.xpath('./tbody//tr[not(.//strong[contains(text(), "Total")])]')
            foot = table.xpath('./tfoot//tr')

            for box in boxes:
                account = Account()
                account._url = None

                if len(box.xpath('.//a')) != 0 and 'onclick' in box.xpath('.//a')[0].attrib:
                    args = self.js2args(box.xpath('.//a')[0].attrib['onclick'])
                    account.label =  u'{0} {1}'.format(unicode(table.xpath('./caption')[0].text.strip()), unicode(box.xpath('.//a')[0].text.strip()))
                elif len(foot[0].xpath('.//a')) != 0 and 'onclick' in foot[0].xpath('.//a')[0].attrib:
                    args = self.js2args(foot[0].xpath('.//a')[0].attrib['onclick'])
                    account.label =  unicode(table.xpath('./caption')[0].text.strip())
                else:
                    continue

                self.logger.debug('Args: %r' % args)
                if 'paramNumCompte' not in args:
                    #The displaying of life insurances is very different from the other
                    if args.get('idPanorama:_idcl').split(":")[1] == 'tableaux-direct-solution-vie':
                        account_details = self.browser.open("#", data=args)
                        scripts = account_details.page.doc.xpath('//script[@type="text/javascript"]/text()')
                        script = filter(lambda x: "src" in x, scripts)[0]
                        iframe_url = re.search("src:(.*),", script).group()[6:-2]
                        account_details_iframe = self.browser.open(iframe_url, data=args)
                        account.id = CleanText('//span[contains(@id,"NumeroContrat")]/text()')(account_details_iframe.page.doc)
                        account._url = iframe_url
                        account.type = account.TYPE_LIFE_INSURANCE
                        account.balance = MyDecimal('//span[contains(@id,"MontantEpargne")]/text()')(account_details_iframe.page.doc)
                        account._acctype = "bank"
                        account._is_debit_card = False
                    else:
                        try:
                            label = unicode(table.xpath('./caption')[0].text.strip())
                        except Exception:
                            label = 'Unable to determine'
                        self.logger.warning('Unable to get account ID for %r' % label)
                        continue

                if account.type != account.TYPE_LIFE_INSURANCE:
                    # get accounts type
                    account_type_str = ''
                    for l in table.attrib['class'].split(' '):
                        if 'tableaux-comptes-' in l:
                            account_type_str = l[len('tableaux-comptes-'):].lower()
                            break

                    account.type = Account.TYPE_UNKNOWN
                    for pattern, type in self.ACCOUNT_TYPES.items():
                        if pattern in account_type_str or pattern in account.label.lower():
                            account.type = type
                            break

                    # get accounts id
                    try:
                        account.id = args['paramNumCompte'] + args['paramNumContrat']
                        if 'Visa' in account.label:
                            card_id = re.search('(\d+)', box.xpath('./td[2]')[0].text.strip())
                            if card_id:
                                account.id += card_id.group(1)
                        if u'Valorisation' in account.label or u'Liquidités' in account.label:
                            account.id += args[next(k for k in args.keys() if "_idcl" in k)].split('Jsp')[-1]
                    except KeyError:
                        account.id = args['paramNumCompte']

                    # get accounts balance
                    try:
                        balance_value = CleanText('.//td[has-class("montant")]')(box)

                        # skip debit card
                        # some cards don't have information in balance tab, skip them
                        if balance_value == u'Débit immédiat' or balance_value == '':
                            account._is_debit_card = True
                        else:
                            account._is_debit_card = False

                        account.balance = Decimal(FrenchTransaction.clean_amount(self.parse_number(balance_value)))
                        if account.type == Account.TYPE_CARD:
                            account.coming = account.balance
                            account.balance = Decimal(0)

                    except InvalidOperation:
                        #The account doesn't have a amount
                        pass

                    account._url = self.doc.xpath('//form[contains(@action, "panorama")]/@action')[0]
                    account._acctype = "bank"

                # get accounts currency
                currency_title = table.xpath('./thead//th[@class="montant"]')[0].text.strip()
                m = re.match('Montant \((\w+)\)', currency_title)
                if not m:
                    self.logger.warning('Unable to parse currency %r' % currency_title)
                else:
                    account.currency = account.get_currency(m.group(1))

                account._args = args
                account._hasinv = True if "Valorisation" in account.label else False

                yield account
Exemplo n.º 46
0
    def get_list(self):
        accounts = []

        for block in self.document.xpath('//div[@class="pave"]/div'):
            head_type = block.xpath('./div/span[@class="accGroupLabel"]')[0].text.strip()
            account_type = self.ACCOUNT_TYPES.get(head_type, Account.TYPE_UNKNOWN)
            for tr in block.cssselect('ul li.tbord_account'):
                id = tr.attrib.get('id', '')
                if id.find('contratId') != 0:
                    self.logger.warning('Unable to parse contract ID: %r' % id)
                    continue
                id = id[id.find('contratId')+len('contratId'):]

                link = tr.cssselect('span.accountLabel a')[0]
                balance = Decimal(FrenchTransaction.clean_amount(tr.cssselect('span.accountTotal')[0].text))

                if id.endswith('CRT'):
                    account = accounts[-1]
                    account._card_links.append(link.attrib['href'])
                    if not account.coming:
                        account.coming = Decimal('0.0')
                    account.coming += balance
                    continue

                account = Account()
                account.id = id
                account.label = unicode(link.text.strip())
                account.type = account_type
                account.balance = balance
                account.currency = account.get_currency(tr.cssselect('span.accountDev')[0].text)
                account._link = link.attrib['href']
                account._card_links = []
                accounts.append(account)

        if len(accounts) == 0:
            # Sometimes, accounts are only in javascript...
            for script in self.document.xpath('//script'):
                text = script.text
                if text is None:
                    continue
                if 'remotePerso' not in text:
                    continue

                account = None
                card_account = None
                attribs = {}
                account_type = Account.TYPE_UNKNOWN
                for line in text.split('\n'):
                    line = line.strip()
                    m = re.match("data.libelle = '(.*)';", line)
                    if m:
                        account_type = self.ACCOUNT_TYPES.get(m.group(1), Account.TYPE_UNKNOWN)
                    elif line == 'var remotePerso = new Object;':
                        account = Account()
                    elif account is not None:
                        m = re.match("remotePerso.(\w+) = '?(.*?)'?;", line)
                        if m:
                            attribs[m.group(1)] = m.group(2)
                        elif line.startswith('listProduitsGroup'):
                            account.id = attribs['refContrat']

                            account.label = attribs['libelle']
                            account.type = account_type
                            account.balance = Decimal(FrenchTransaction.clean_amount(attribs['soldeDateOpeValeurFormatted']))
                            account.currency = account.get_currency(attribs['codeDevise'])
                            account._link = 'tbord.do?id=%s&%s' % (attribs['id'], self.browser.SESSION_PARAM)
                            account._card_links = []

                            if account.id.endswith('CRT'):
                                if not len(accounts):
                                    card_account = account
                                else:
                                    a = accounts[-1]
                                    a._card_links.append(account._link)
                                    if not a.coming:
                                        a.coming = Decimal('0.0')
                                    a.coming += account.balance
                            else:
                                if 'COURANT' in account.label:
                                    account.type = account.TYPE_CHECKING
                                elif account.id.endswith('TTR'):
                                    account.type = account.TYPE_MARKET
                                elif re.match('^\d+C$', account.id):
                                    account.type = account.TYPE_LIFE_INSURANCE
                                elif re.match('^\d+PRT$', account.id):
                                    account.type = account.TYPE_LOAN
                                elif not account.type:
                                    account.type = account.TYPE_SAVINGS

                                if card_account:
                                    account._card_links.append(card_account._link)
                                    if not account.coming:
                                        account.coming = Decimal('0.0')
                                    account.coming += card_account.balance
                                    card_account = None
                                accounts.append(account)
                            account = None

        return accounts
Exemplo n.º 47
0
    def get_list(self):
        accounts = []

        for cpt in self.doc.xpath(
                '//div[contains(@class, " compte") and not(contains(@class, "compte_selected"))]'
        ):

            # ignore auto assurance accounts
            if 'aut' in cpt.get('class'):
                continue

            account = Account()
            account._history_link = Link(
                './ul/li/a[contains(@id, "consulter_solde") '
                'or contains(@id, "historique") '
                'or contains(@id, "contrat") '
                'or contains(@id, "assurance_vie_operations")]')(cpt)

            # this is to test if access to the accounts info is blocked for different reasons
            page = self.browser.open(account._history_link).page
            if isinstance(page, LoanPage):
                account = Loan()

            account._history_link = Link(
                './ul/li/a[contains(@id, "consulter_solde") '
                'or contains(@id, "historique") '
                'or contains(@id, "contrat") '
                'or contains(@id, "assurance_vie_operations")]')(cpt)
            if isinstance(page, LoanPage):
                account.id = CleanText(
                    '(//p[@id="c_montantEmprunte"]//span[@class="valStatic"]//strong)[1]'
                )(cpt)
                account.label = CleanText(
                    '(//p[@id="c_montantEmprunte"]//span[@class="valStatic"]//strong)[1]'
                )(cpt)
                account.type = Account.TYPE_LOAN
                account_history_page = self.browser.open(
                    account._history_link).page
                account.total_amount = account_history_page.get_total_amount()
                account.next_payment_amount = account_history_page.get_next_payment_amount(
                )
                account.next_payment_date = account_history_page.get_next_payment_date(
                )
                account.account_label = account_history_page.get_account_label(
                )
                account.subscription_date = account_history_page.get_subscription_date(
                )
                account.maturity_date = account_history_page.get_maturity_date(
                )

            if len(accounts) == 0:
                global_error_message = page.doc.xpath(
                    '//div[@id="as_renouvellementMIFID.do_"]/div[contains(text(), "Bonjour")] '
                    '| //div[@id="as_afficherMessageBloquantMigration.do_"]//div[@class="content_message"] '
                    '| //p[contains(text(), "Et si vous faisiez de Fortuneo votre banque principale")] '
                    '| //div[@id="as_renouvellementMotDePasse.do_"]//p[contains(text(), "votre mot de passe")]'
                    '| //div[@id="as_afficherSecuriteForteOTPIdentification.do_"]//span[contains(text(), "Pour valider ")]'
                )
                if global_error_message:
                    raise ActionNeeded(CleanText('.')(global_error_message[0]))
            local_error_message = page.doc.xpath(
                '//div[@id="error"]/p[@class="erreur_texte1"]')
            if local_error_message:
                raise BrowserUnavailable(
                    CleanText('.')(local_error_message[0]))

            number = RawText('./a[contains(@class, "numero_compte")]')(
                cpt).replace(u'N° ', '')

            account.id = CleanText(None).filter(number).replace(u'N°', '')

            account._card_links = []
            card_link = Link('./ul/li/a[contains(text(), "Carte bancaire")]',
                             default='')(cpt)
            if len(card_link) > 0:
                account._card_links.append(card_link)

            account.label = CleanText(
                './a[contains(@class, "numero_compte")]/@title')(cpt)

            for pattern, type in self.ACCOUNT_TYPES.items():
                if pattern in account._history_link:
                    account.type = type
                    break

            if account.type in {
                    Account.TYPE_PEA, Account.TYPE_MARKET,
                    Account.TYPE_LIFE_INSURANCE
            }:
                account._investment_link = Link(
                    './ul/li/a[contains(@id, "portefeuille")]')(cpt)
                balance = self.browser.open(
                    account._investment_link).page.get_balance(account.type)
                if account.type in {Account.TYPE_PEA, Account.TYPE_MARKET}:
                    self.browser.investments[account.id] = list(
                        self.browser.open(
                            account._investment_link).page.get_investments(
                                account))
            else:
                balance = self.browser.open(
                    account._history_link).page.get_balance()
                if account.type is not Account.TYPE_LOAN:
                    account.coming = self.browser.open(
                        account._history_link).page.get_coming()

            if account.type in {Account.TYPE_PEA, Account.TYPE_MARKET}:
                account.currency = self.browser.open(
                    account._investment_link).page.get_currency()
            else:
                account.currency = account.get_currency(balance)
            account.balance = CleanDecimal(None,
                                           replace_dots=True).filter(balance)

            if account.type in (Account.TYPE_CHECKING, Account.TYPE_SAVINGS):
                # Need a token sent by SMS to customers
                account.iban = NotAvailable

            if (account.label, account.id, account.balance) not in [
                (a.label, a.id, a.balance) for a in accounts
            ]:
                accounts.append(account)
        return accounts
Exemplo n.º 48
0
    def get_list(self):
        accounts = OrderedDict()

        for tr in self.document.getiterator('tr'):
            first_td = tr.getchildren()[0]
            if (first_td.attrib.get('class', '') == 'i g' or first_td.attrib.get('class', '') == 'p g') \
               and first_td.find('a') is not None:

                a = first_td.find('a')
                link = a.get('href', '')
                if link.startswith('POR_SyntheseLst'):
                    continue

                url = urlparse(link)
                p = parse_qs(url.query)
                if not 'rib' in p:
                    continue

                for i in (2, 1):
                    balance = FrenchTransaction.clean_amount(
                        tr.getchildren()[i].text)
                    currency = Account.get_currency(tr.getchildren()[i].text)
                    if len(balance) > 0:
                        break
                balance = Decimal(balance)

                id = p['rib'][0]
                if id in accounts:
                    account = accounts[id]
                    if not account.coming:
                        account.coming = Decimal('0.0')
                    account.coming += balance
                    account._card_links.append(link)
                    continue

                account = Account()
                account.id = id
                account.label = unicode(
                    a.text).strip().lstrip(' 0123456789').title()
                account._link_id = link
                account._card_links = []

                # Find accounting amount
                page = self.browser.get_document(self.browser.openurl(link))
                coming = self.find_amount(page, u"Opérations à venir")
                accounting = self.find_amount(page, u"Solde comptable")

                if accounting is not None and accounting + (
                        coming or Decimal('0')) != balance:
                    self.logger.warning('%s + %s != %s' %
                                        (accounting, coming, balance))

                if accounting is not None:
                    balance = accounting

                if coming is not None:
                    account.coming = coming
                account.balance = balance
                account.currency = currency

                accounts[account.id] = account

        return accounts.itervalues()