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
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
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
def get_accounts_list(self): #Parse CCP compte_table = self.document.xpath("//table[@id='comptes']", smart_strings=False)[0] compte_ligne = compte_table.xpath("./tbody/tr") for compte in compte_ligne: account = Account() tp = compte.xpath("./td/a")[0] account.label = tp.text account.link_id = tp.get("href") account.id = compte.xpath("./td")[1].text account.balance = float(''.join( compte.xpath("./td/span")[0].text.replace('.','').replace(',','.').split() )) self.Account_List.append(account) #Parse epargne epargne_table = self.document.xpath("//table[@id='comptesEpargne']", smart_strings=False)[0] epargne_ligne = epargne_table.xpath("./tbody/tr") for epargne in epargne_ligne: account = Account() tp = epargne.xpath("./td/a")[0] account.label = tp.text account.link_id = tp.get("href") account.id = epargne.xpath("./td")[1].text account.balance = float(''.join( epargne.xpath("./td/span")[0].text.replace('.','').replace(',','.').split() ) ) self.Account_List.append(account) return self.Account_List
def get_list(self): """ Returns the list of available bank accounts """ l = [] for div in self.document.getiterator('div'): if div.attrib.get('class', '') == 'dv' and div.getchildren()[0].tag in ('a', 'br'): account = Account() if div.getchildren()[0].tag == 'a': # This is at least present on CA Nord-Est account.label = ' '.join(div.find('a').text.split()[:-1]) account.link_id = div.find('a').get('href', '') account.id = div.find('a').text.split()[-1] s = div.find('div').find('b').find('span').text else: # This is at least present on CA Toulouse account.label = div.find('a').text.strip() account.link_id = div.find('a').get('href', '') account.id = div.findall('br')[1].tail.strip() s = div.find('div').find('span').find('b').text balance = u'' for c in s: if c.isdigit(): balance += c if c == ',': balance += '.' account.balance = float(balance) l.append(account) return l
def get_loan_list(self): accounts = OrderedDict() # Old website for tr in self.doc.xpath('//table[@cellpadding="1"]/tr[not(@class) and td[a]]'): tds = tr.findall('td') account = Account() account.id = CleanText('./a')(tds[2]).split('-')[0].strip() account.label = CleanText('./a')(tds[2]).split('-')[-1].strip() account.type = Account.TYPE_LOAN account.balance = -CleanDecimal('./a', replace_dots=True)(tds[4]) account.currency = account.get_currency(CleanText('./a')(tds[4])) accounts[account.id] = account if len(accounts) == 0: # New website for table in self.doc.xpath('//div[@class="panel"]'): title = table.getprevious() if title is None: continue account_type = self.ACCOUNT_TYPES.get(CleanText('.')(title), Account.TYPE_UNKNOWN) for tr in table.xpath('./table/tbody/tr[contains(@id,"MM_SYNTHESE_CREDITS") and contains(@id,"IdTrGlobal")]'): tds = tr.findall('td') if len(tds) == 0 : continue for i in tds[0].xpath('.//a/strong'): label = i.text.strip() break if len(tds) == 3 and Decimal(FrenchTransaction.clean_amount(CleanText('.')(tds[-2]))) and any(cls in Attr('.', 'id')(tr) for cls in ['dgImmo', 'dgConso']) == False: # in case of Consumer credit or revolving credit, we substract avalaible amount with max amout # to get what was spend balance = Decimal(FrenchTransaction.clean_amount(CleanText('.')(tds[-2]))) - Decimal(FrenchTransaction.clean_amount(CleanText('.')(tds[-1]))) else: balance = Decimal(FrenchTransaction.clean_amount(CleanText('.')(tds[-1]))) account = Loan() account.id = label.split(' ')[-1] account.label = unicode(label) account.type = account_type account.balance = -abs(balance) account.currency = account.get_currency(CleanText('.')(tds[-1])) account._card_links = [] if "immobiliers" in CleanText('.')(title): xp = './/div[contains(@id, "IdDivDetail")]/table/tbody/tr[contains(@id, "%s")]/td' account.maturity_date = Date(CleanText(xp % 'IdDerniereEcheance'), dayfirst=True, default=NotAvailable)(tr) account.total_amount = CleanDecimal(CleanText(xp % 'IdCapitalEmprunte'), replace_dots=True, default=NotAvailable)(tr) account.subscription_date = Date(CleanText(xp % 'IdDateOuverture'), dayfirst=True, default=NotAvailable)(tr) account.next_payment_date = Date(CleanText(xp % 'IdDateProchaineEcheance'), dayfirst=True, default=NotAvailable)(tr) account.rate = CleanDecimal(CleanText(xp % 'IdTaux'), replace_dots=True, default=NotAvailable)(tr) account.next_payment_amount = CleanDecimal(CleanText(xp % 'IdMontantEcheance'), replace_dots=True, default=NotAvailable)(tr) elif "renouvelables" in CleanText('.')(title): self.go_loans_conso(tr) d = self.browser.loans_conso() if d: account.total_amount = d['contrat']['creditMaxAutorise'] account.available_amount = d['situationCredit']['disponible'] account.next_payment_amount = d['situationCredit']['mensualiteEnCours'] accounts[account.id] = account return accounts.values()
def get_accounts(self): accounts = {} content = self.document.xpath('//div[@id="main"]//div[@class="col first"]')[0] # Total currency balance. # If there are multiple currencies, this balance is all currencies # converted to the main currency. balance = content.xpath('.//h3/span[@class="balance"]') if not balance: balance = content.xpath('.//li[@class="balance"]//span/strong') balance = balance[0].text_content().strip() # Primary currency account primary_account = Account() primary_account.type = Account.TYPE_CHECKING primary_account.balance = clean_amount(balance) primary_account.currency = Account.get_currency(balance) primary_account.id = unicode(primary_account.currency) primary_account.label = u'%s %s*' % (self.browser.username, balance.split()[-1]) accounts[primary_account.id] = primary_account # The following code will only work if the user enabled multiple currencies. balance = content.xpath('.//div[@class="body"]//ul/li[@class="balance"]/span') table = content.xpath('.//table[@id="balanceDetails"]//tbody//tr') # sanity check if bool(balance) is not bool(table): raise BrokenPageError('Unable to find all required multiple currency entries') # Primary currency balance. # If the user enabled multiple currencies, we get this one instead. # An Account object has only one currency; secondary currencies should be other accounts. if balance: balance = balance[0].text_content().strip() primary_account.balance = clean_amount(balance) # The primary currency of the "head balance" is the same; ensure we got the right one assert primary_account.currency == primary_account.get_currency(balance) for row in table: balance = row.xpath('.//td')[-1].text_content().strip() account = Account() account.type = Account.TYPE_CHECKING # XXX it ignores 5+ devises, so it's bad, but it prevents a crash, cf #1216 try: account.balance = clean_amount(balance) except InvalidOperation: continue account.currency = Account.get_currency(balance) account.id = unicode(account.currency) account.label = u'%s %s' % (self.browser.username, balance.split()[-1]) if account.id == primary_account.id: assert account.balance == primary_account.balance assert account.currency == primary_account.currency elif account.currency: accounts[account.id] = account return accounts
def get_list(self): for table in self.document.getroot().cssselect('div#table-panorama table.table-produit'): tds = table.xpath('./tbody/tr')[0].findall('td') if len(tds) < 3: continue boxes = table.xpath('./tbody//tr') foot = table.xpath('./tfoot//tr') for box in boxes: account = Account() 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: 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 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 'Valorisation' in account.label or u'Liquidités' in account.label: account.id += args['idPanorama:_idcl'].split('Jsp')[-1] except KeyError: account.id = args['paramNumCompte'] account_type_str = table.attrib['class'].split(' ')[-1][len('tableaux-comptes-'):] account.type = self.ACCOUNT_TYPES.get(account_type_str, Account.TYPE_UNKNOWN) 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)) try: account.balance = Decimal(FrenchTransaction.clean_amount(self.parse_number(u''.join([txt.strip() for txt in box.cssselect("td.montant")[0].itertext()])))) except InvalidOperation: #The account doesn't have a amount pass account._args = args yield account
def get_list(self): names = set() for li in self.document.xpath('//div[@class="affichMontant"]/ul/li/a'): account = Account() account.label = unicode(li.cssselect('div.row-lib u')[0].text.strip()) account.id = re.sub('[ \.\-]+', '', account.label) while account.id in names: account.id = account.id + '1' names.add(account.id) account.balance = Decimal(li.cssselect('p.row-right')[0].text.strip().replace(' ', '').replace(u'\xa0', '').replace(',', '')) account._link = li.attrib['href'] yield account
def get_list(self): for div in self.document.getiterator('div'): if div.attrib.get('id', '') == 'synthese-list': for tr in div.getiterator('tr'): account = Account() account.id = None account._link_id = None for td in tr.getiterator('td'): if td.attrib.get('class', '') == 'account-cb': break elif td.attrib.get('class', '') == 'account-name': try: span = td.xpath('./span[@class="label"]')[0] except IndexError: # ignore account break account.label = self.parser.tocleanstring(span) try: account._link_id = td.xpath('.//a')[0].attrib['href'] except KeyError: pass elif td.attrib.get('class', '') == 'account-more-actions': for a in td.getiterator('a'): # For normal account, two "account-more-actions" # One for the account, one for the credit card. Take the good one if "mouvements.phtml" in a.attrib['href'] and "/cartes/" not in a.attrib['href']: account._link_id = a.attrib['href'] elif td.attrib.get('class', '') == 'account-number': id = td.text id = id.strip(u' \n\t') account.id = id elif td.attrib.get('class', '') == 'account-total': span = td.find('span') if span is None: balance = td.text else: balance = span.text account.currency = account.get_currency(balance) balance = FrenchTransaction.clean_amount(balance) if balance != "": account.balance = Decimal(balance) else: account.balance = Decimal(0) else: # because of some weird useless <tr> if account.id is not None: yield account
def get_list(self): for trCompte in self.doc.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" and @width="99%"]') ]).strip() account.type = self.ACCOUNT_TYPES.get(account_type_str, Account.TYPE_UNKNOWN) cleaner = CleanText('.') account.balance = Decimal( FrenchTransaction.clean_amount( cleaner(tds[self.CPT_ROW_BALANCE]))) account.coming = Decimal( FrenchTransaction.clean_amount( cleaner(tds[self.CPT_ROW_ENCOURS]))) account.currency = account.get_currency( tds[self.CPT_ROW_BALANCE].find("a").text) yield account return
def iter_accounts(self): if self.accounts: for account in self.accounts: yield account return for project in self.users['projects']: me = self.request('/user/%s/project/%s/' % (self.users['userId'], project['projectId'])) a = Account() a.id = "".join(me['numeroContrat'].split()) a.label = " ".join(me['supportEpargne'].split("_")) a.type = Account.TYPE_LIFE_INSURANCE if "assurance vie" in a.label.lower() else \ Account.TYPE_MARKET if "compte titre" in a.label.lower() else \ Account.TYPE_UNKNOWN a.balance = CleanDecimal().filter(me['solde']) a.iban = me['ibancompteTitre'] if me[ 'ibancompteTitre'] else NotAvailable a.number = project['projectId'] a.valuation_diff = CleanDecimal().filter(me['performanceEuro']) a._startbalance = me['montantDepart'] self.accounts.append(a) self.iter_investment(a, me['sousJacents']) yield a
def get_list(self): r = self.api_open('/transactionnel/services/rest/Account/accounts') for content in r.json()['content']: if self.accnum != '00000000000' and content['numero'] != self.accnum: continue for poste in content['postes']: a = Account() a._number = content['numeroLong'] iban_response = self.api_open('/transactionnel/services/rest/Account/account/%s/iban' % a._number).json() a.iban = iban_response['content']['iban'] if 'content' in iban_response else NotAvailable a._nature = poste['codeNature'] a._consultable = poste['consultable'] a._univers = self.current_univers a.id = '%s.%s' % (a._number, a._nature) a.type = self.ACCOUNT_TYPES.get(poste['codeNature'], Account.TYPE_UNKNOWN) if 'numeroDossier' in poste and poste['numeroDossier']: a._file_number = poste['numeroDossier'] a.id += '.%s' % a._file_number if poste['postePortefeuille']: a.label = u'Portefeuille Titres' a.balance = Decimal(str(poste['montantTitres']['valeur'])) a.currency = poste['montantTitres']['monnaie']['code'].strip() yield a if 'libelle' not in poste: continue a.label = ' '.join([content['intitule'].strip(), poste['libelle'].strip()]) a.balance = Decimal(str(poste['solde']['valeur'])) a.currency = poste['solde']['monnaie']['code'].strip() yield a
def parse_table(self, what): tables = self.document.xpath("//table[@id='%s']" % what, smart_strings=False) if len(tables) < 1: return lines = tables[0].xpath(".//tbody/tr") for line in lines: account = Account() tmp = line.xpath("./td//a")[0] account.label = to_unicode(tmp.text) account._link_id = tmp.get("href") if "BourseEnLigne" in account._link_id: continue tmp = line.xpath("./td/span/strong") if len(tmp) >= 2: tmp_id = tmp[0].text tmp_balance = tmp[1].text else: tmp_id = line.xpath("./td//span")[1].text tmp_balance = tmp[0].text account.id = tmp_id account.balance = Decimal("".join(tmp_balance.replace(".", "").replace(",", ".").split())) self.account_list.append(account)
def get_list(self): account_type = Account.TYPE_UNKNOWN params = {} for field in self.document.xpath('//input'): params[field.attrib['name']] = field.attrib.get('value', '') for div in self.document.xpath('//div[@class="btit"]'): account_type = self.ACCOUNT_TYPES.get(div.text.strip(), Account.TYPE_UNKNOWN) for tr in div.getnext().xpath('.//tbody/tr'): args = dict(parse_qsl(tr.attrib['id'])) tds = tr.findall('td') account = Account() account.id = args['identifiant'] account.label = u' '.join([ u''.join([txt.strip() for txt in tds[1].itertext()]), u''.join([txt.strip() for txt in tds[2].itertext()]) ]).strip() account.type = account_type link = tds[3].find('a') account.balance = Decimal( FrenchTransaction.clean_amount(link.find('span').text)) account._params = params.copy() account._params['dialogActionPerformed'] = 'SOLDE' account._params[ 'attribute($SEL_$%s)' % tr.attrib['id'].split('_')[0]] = tr.attrib['id'].split( '_', 1)[1] yield account return
def get_list(self): account_type = Account.TYPE_UNKNOWN for tr in self.document.xpath('//table[@class="ca-table"]/tr'): try: title = tr.xpath('.//h3/text()')[0].lower().strip() except IndexError: pass else: account_type = self.TYPES.get(title, Account.TYPE_UNKNOWN) if not tr.attrib.get('class', '').startswith('colcelligne'): continue cols = tr.findall('td') if not cols or len(cols) < self.NB_COLS: continue account = Account() account.id = self.parser.tocleanstring(cols[self.COL_ID]) account.label = self.parser.tocleanstring(cols[self.COL_LABEL]) account.type = account_type or self.TYPES.get(account.label, Account.TYPE_UNKNOWN) balance = self.parser.tocleanstring(cols[self.COL_VALUE]) # we have to ignore those accounts, because using NotAvailable # makes boobank and probably many others crash if balance in ('indisponible', ''): continue account.balance = Decimal(Transaction.clean_amount(balance)) account.currency = account.get_currency(self.parser.tocleanstring(cols[self.COL_CURRENCY])) account._link = None self.set_link(account, cols) account._perimeter = self.browser.current_perimeter yield account
def get_list(self): account_type = Account.TYPE_UNKNOWN params = {} for field in self.document.xpath('//input'): params[field.attrib['name']] = field.attrib.get('value', '') for div in self.document.xpath('//div[@class="btit"]'): account_type = self.ACCOUNT_TYPES.get(div.text.strip(), Account.TYPE_UNKNOWN) for tr in div.getnext().xpath('.//tbody/tr'): args = dict(parse_qsl(tr.attrib['id'])) tds = tr.findall('td') account = Account() account.id = args['identifiant'] account.label = u' '.join([u''.join([txt.strip() for txt in tds[1].itertext()]), u''.join([txt.strip() for txt in tds[2].itertext()])]).strip() account.type = account_type link = tds[3].find('a') account.balance = Decimal(FrenchTransaction.clean_amount(link.find('span').text)) account._params = params.copy() account._params['dialogActionPerformed'] = 'SOLDE' account._params['attribute($SEL_$%s)' % tr.attrib['id'].split('_')[0]] = tr.attrib['id'].split('_', 1)[1] yield account return
def get_accounts_list(self): for table in self.doc.xpath('//div[@class="comptestabl"]/table'): try: account_type = self.ACCOUNT_TYPES[table.get('summary').lower()] if not account_type: account_type = self.ACCOUNT_TYPES[table.xpath( './caption/text()')[0].strip().lower()] except (IndexError, KeyError): account_type = Account.TYPE_UNKNOWN for tr in table.xpath('./tbody/tr'): cols = tr.findall('td') link = cols[0].find('a') if link is None: continue a = Account() a.type = account_type a.id = unicode( re.search('([A-Z\d]{4}[A-Z\d\*]{3}[A-Z\d]{4})', link.attrib['title']).group(1)) a.label = unicode(link.attrib['title'].replace( '%s ' % a.id, '')) # We use '.text_content()' to avoid HTML comments like '<!-- ... -->' tmp_balance = CleanText(None).filter(cols[1].text_content()) a.currency = a.get_currency(tmp_balance) if not a.currency: a.currency = u'EUR' a.balance = Decimal(Transaction.clean_amount(tmp_balance)) a._has_cards = False a.url = urljoin(self.url, link.attrib['href']) yield a
def get_accounts_list(self): r = self.api_open("/transactionnel/services/rest/Account/accounts") for content in r.json()["content"]: if self.accnum != "00000000000" and content["numero"] != self.accnum: continue for poste in content["postes"]: a = Account() a._number = content["numeroLong"] a._nature = poste["codeNature"] a._consultable = poste["consultable"] a.id = "%s.%s" % (a._number, a._nature) a.type = self.ACCOUNT_TYPES.get(poste["codeNature"], Account.TYPE_UNKNOWN) if "numeroDossier" in poste and poste["numeroDossier"]: a._file_number = poste["numeroDossier"] a.id += ".%s" % a._file_number if poste["postePortefeuille"]: a.label = u"Portefeuille Titres" a.balance = Decimal(str(poste["montantTitres"]["valeur"])) a.currency = poste["montantTitres"]["monnaie"]["code"].strip() yield a if "libelle" not in poste: continue a.label = " ".join([content["intitule"].strip(), poste["libelle"].strip()]) a.balance = Decimal(str(poste["solde"]["valeur"])) a.currency = poste["solde"]["monnaie"]["code"].strip() yield a
def get_list(self): table = self.find_table() for tr in self.parser.select(table, 'tr', 'many'): tds = self.parser.select(tr, 'td') if len(tds) != 6: continue tdlabel, tdid, tdcur, tdupdated, tdbal, tdbalcur = tds account = Account() account.label = to_unicode(tdlabel.text_content().strip()) # this is important - and is also the last part of the id (considering spaces) # we can't use only the link as it does not goes where we want try: link = self.parser.select(tdlabel, 'a', 1) except BrokenPageError: # probably an account we can't display the history account._link_id = None else: account._link_id = parse_qs(link.attrib['href'])['ch4'][0] account.id = to_unicode(tdid.text.strip().replace(' ', '')) # just in case we are showing the converted balances account._main_currency = Account.get_currency(tdcur.text) # we have to ignore those accounts, because using NotAvailable # makes boobank and probably many others crash if tdbal.text_content().strip() == 'indisponible': continue account.balance = Decimal( Transaction.clean_amount(tdbal.text_content())) account.currency = Account.get_currency(tdbalcur.text) account._updated = datetime.strptime(tdupdated.text, '%d/%m/%Y') yield account
def account(self): id_ = self.doc.xpath( u'//strong[contains(text(),' '"credit card account ending in")]/text()')[0].strip()[-4:] balance = self.doc.xpath( u'//span[@class="description" and text()="Current Balance"]/../span[@class="total"]/text()' )[0].strip() cardlimit = self.doc.xpath(u'//span[contains(text(),"Credit limit")]' '/text()')[0].split()[-1] paymin = self.doc.xpath( u'//section[@id=" account_summary"]' '//strong[text()="Minimum Payment Due"]/../../span[2]/text()' )[0].strip() a = Account() a.id = id_ a.label = u'ACCOUNT ENDING IN %s' % id_ a.currency = Account.get_currency(balance) a.balance = -AmTr.decimal_amount(balance) a.type = Account.TYPE_CARD a.cardlimit = AmTr.decimal_amount(cardlimit) a.paymin = AmTr.decimal_amount(paymin) #TODO: Add paydate. #Oleg: I don't have an account with scheduled payment. # Need to wait for a while... return a
def _add_account(self, accounts, link, label, account_type, balance): info = self._get_account_info(link) if info is None: self.logger.warning('Unable to parse account %r: %r' % (label, link)) return account = Account() account.id = info['id'] if is_rib_valid(info['id']): account.iban = rib2iban(info['id']) account._info = info account.label = label account.type = info['acc_type'] if 'acc_type' in info else account_type account.balance = Decimal(FrenchTransaction.clean_amount( balance)) if balance else self.get_balance(account) account.currency = account.get_currency(balance) account._card_links = [] if account._info['type'] == 'HISTORIQUE_CB' and account.id in accounts: a = accounts[account.id] if not a.coming: a.coming = Decimal('0.0') a.coming += account.balance a._card_links.append(account._info) return accounts[account.id] = account
def get_accounts_list(self): data = {'clang': self.LANG, 'ctcc': self.CTCC, 'login': self.username, 'session': self.sessionId} for dispositif in self.accountsp.open(data=data).get_list(): if dispositif['montantBrutDispositif'] == 0: continue a = Account() a.id = dispositif['codeDispositif'] a.type = Account.TYPE_MARKET a.balance = Decimal(dispositif["montantBrutDispositif"]).quantize(Decimal('.01')) a.label = dispositif['titreDispositif'] a.currency = u"EUR" # Don't find any possbility to get that from configuration. a._investments = [] for fund in dispositif['listeFonds']: if fund['montantValeurEuro'] == 0: continue i = Investment() i.id = i.code = dispositif['codeEntreprise'] + dispositif["codeDispositif"] + fund["codeSupport"] i.label = fund['libelleSupport'] i.unitvalue = Decimal(fund["montantValeur"]).quantize(Decimal('.01')) i.valuation = Decimal(fund["montantValeurEuro"]).quantize(Decimal('.01')) i.quantity = i.valuation / i.unitvalue i.vdate = parse_date(fund['dateValeur'], dayfirst=True) a._investments.append(i) yield a
def get_loan_list(self): accounts = OrderedDict() # New website for table in self.document.xpath('//div[@class="panel"]'): title = table.getprevious() if title is None: continue account_type = self.ACCOUNT_TYPES.get( self.parser.tocleanstring(title), Account.TYPE_UNKNOWN) for tr in table.xpath( './table/tbody/tr[contains(@id,"MM_SYNTHESE_CREDITS") and contains(@id,"IdTrGlobal")]' ): tds = tr.findall('td') if len(tds) == 0: continue for i in tds[0].xpath('.//a/strong'): label = i.text.strip() break balance = Decimal( FrenchTransaction.clean_amount( self.parser.tocleanstring(tds[-1]))) account = Account() account.id = label.split(' ')[-1] account.label = unicode(label) account.type = account_type account.balance = -abs(balance) account.currency = account.get_currency( self.parser.tocleanstring(tds[-1])) account._card_links = [] accounts[account.id] = account return accounts.itervalues()
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
def get_accounts_list(self): r = self.open('/transactionnel/services/rest/Account/accounts') for content in r.json()['content']: if self.accnum != '00000000000' and content['numero'] != self.accnum: continue for poste in content['postes']: a = Account() a._number = content['numeroLong'] a._nature = poste['codeNature'] a._consultable = poste['consultable'] a.id = '%s.%s' % (a._number, a._nature) a.type = self.ACCOUNT_TYPES.get(poste['codeNature'], Account.TYPE_UNKNOWN) if poste['postePortefeuille']: a.label = u'Portefeuille Titres' a.balance = Decimal(str(poste['montantTitres']['valeur'])) a.currency = poste['montantTitres']['monnaie']['code'] yield a if not 'libelle' in poste: continue a.label = ' '.join([content['intitule'].strip(), poste['libelle'].strip()]) a.balance = Decimal(str(poste['solde']['valeur'])) a.currency = poste['solde']['monnaie']['code'] yield a
def get_accounts_list(self): r = self.open('/transactionnel/services/rest/Account/accounts') for content in r.json()['content']: if self.accnum != '00000000000' and content[ 'numero'] != self.accnum: continue for poste in content['postes']: a = Account() a._number = content['numeroLong'] a._nature = poste['codeNature'] a._consultable = poste['consultable'] a.id = '%s.%s' % (a._number, a._nature) a.type = self.ACCOUNT_TYPES.get(poste['codeNature'], Account.TYPE_UNKNOWN) if poste['postePortefeuille']: a.label = u'Portefeuille Titres' a.balance = Decimal(str(poste['montantTitres']['valeur'])) a.currency = poste['montantTitres']['monnaie']['code'] yield a if 'libelle' not in poste: continue a.label = ' '.join( [content['intitule'].strip(), poste['libelle'].strip()]) a.balance = Decimal(str(poste['solde']['valeur'])) a.currency = poste['solde']['monnaie']['code'] yield a
def get_list(self): account_type = Account.TYPE_UNKNOWN accounts = [] for tr in self.document.xpath('//table[@class="ecli"]/tr'): if tr.attrib.get('class', '') == 'entete': account_type = self.ACCOUNT_TYPES.get(tr.find('th').text.strip(), Account.TYPE_UNKNOWN) continue tds = tr.findall('td') balance = tds[-1].text.strip() if balance == '': continue account = Account() account.label = u' '.join([txt.strip() for txt in tds[0].itertext()]) account.label = re.sub(u'[ \xa0\u2022\r\n\t]+', u' ', account.label).strip() account.id = re.findall('(\d+)', account.label)[0] account.balance = Decimal(FrenchTransaction.clean_amount(balance)) account.currency = account.get_currency(balance) account.type = account_type m = re.search(r"javascript:submitForm\(([\w_]+),'([^']+)'\);", tds[0].find('a').attrib['onclick']) if not m: self.logger.warning('Unable to find link for %r' % account.label) account._link = None else: account._link = m.group(2) accounts.append(account) return accounts
def parse_table(self, what): tables = self.document.xpath("//table[@id='%s']" % what, smart_strings=False) if len(tables) < 1: return lines = tables[0].xpath(".//tbody/tr") for line in lines: account = Account() tmp = line.xpath("./td//a")[0] account.label = to_unicode(tmp.text) account._link_id = tmp.get("href") if "BourseEnLigne" in account._link_id: continue tmp = line.xpath("./td/span/strong") if len(tmp) >= 2: tmp_id = tmp[0].text tmp_balance = tmp[1].text else: tmp_id = line.xpath("./td//span")[1].text tmp_balance = tmp[0].text account.id = tmp_id account.currency = account.get_currency(tmp_balance) account.balance = Decimal(FrenchTransaction.clean_amount(tmp_balance)) if account.id in self.accounts: a = self.accounts[account.id] a._card_links.append(account._link_id) if not a.coming: a.coming = Decimal("0.0") a.coming += account.balance else: account._card_links = [] self.accounts[account.id] = account
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
def _add_account(self, accounts, link, label, account_type, balance): info = self._get_account_info(link) if info is None: self.logger.warning('Unable to parse account %r: %r' % (label, link)) return account = Account() account.id = info['id'] account._info = info account.label = label account.type = account_type account.balance = Decimal(FrenchTransaction.clean_amount(balance)) account.currency = account.get_currency(balance) account._card_links = [] if account._info['type'] == 'CB' and account.id in accounts: a = accounts[account.id] if not a.coming: a.coming = Decimal('0.0') a.coming += account.balance a._card_links.append(account._info) return accounts[account.id] = account
def _add_account(self, accounts, link, label, account_type, balance): info = self._get_account_info(link) if info is None: self.logger.warning('Unable to parse account %r: %r' % (label, link)) return account = Account() account.id = info['id'] account.iban = u'FR76' + info['id'] account._info = info account.label = label account.type = info['acc_type'] if 'acc_type' in info else account_type account.balance = Decimal(FrenchTransaction.clean_amount(balance)) if balance else self.get_balance(account) account.currency = account.get_currency(balance) account._card_links = [] if account._info['type'] == 'HISTORIQUE_CB' and account.id in accounts: a = accounts[account.id] if not a.coming: a.coming = Decimal('0.0') a.coming += account.balance a._card_links.append(account._info) return accounts[account.id] = account
def _add_account(self, accounts, link, label, account_type, balance): info = self._get_account_info(link, accounts) if info is None: self.logger.warning('Unable to parse account %r: %r' % (label, link)) return account = Account() account.id = info['id'] if is_rib_valid(info['id']): account.iban = rib2iban(info['id']) account._info = info account.label = label account.type = self.ACCOUNT_TYPES.get(label, info['acc_type'] if 'acc_type' in info else account_type) balance = balance or self.get_balance(account) account.balance = Decimal(FrenchTransaction.clean_amount(balance)) if balance and balance is not NotAvailable else NotAvailable account.currency = account.get_currency(balance) if balance and balance is not NotAvailable else NotAvailable account._card_links = [] if account._info['type'] == 'HISTORIQUE_CB' and account.id in accounts: a = accounts[account.id] if not a.coming: a.coming = Decimal('0.0') if account.balance and account.balance is not NotAvailable: a.coming += account.balance a._card_links.append(account._info) return accounts[account.id] = account
def get_loan_list(self): accounts = OrderedDict() # New website for table in self.document.xpath('//div[@class="panel"]'): title = table.getprevious() if title is None: continue account_type = self.ACCOUNT_TYPES.get(self.parser.tocleanstring(title), Account.TYPE_UNKNOWN) for tr in table.xpath('./table/tbody/tr[contains(@id,"MM_SYNTHESE_CREDITS") and contains(@id,"IdTrGlobal")]'): tds = tr.findall('td') if len(tds) == 0 : continue for i in tds[0].xpath('.//a/strong'): label = i.text.strip() break balance = Decimal(FrenchTransaction.clean_amount(self.parser.tocleanstring(tds[-1]))) account = Account() account.id = label.split(' ')[-1] account.label = unicode(label) account.type = account_type account.balance = -abs(balance) account.currency = account.get_currency(self.parser.tocleanstring(tds[-1])) account._card_links = [] accounts[account.id] = account return accounts.itervalues()
def account(self): label = u' '.join(self.doc.xpath( '//div[contains(@class,"myCreditCardDetails")]')[0]\ .text_content().split()) balance = self.amount(u'Balance') cardlimit = self.doc.xpath( u'//li[text()="Available to Spend"]')[0].text_content()\ .replace(u'Available to Spend', u'').replace(u'Limit', u'').strip() paymin = self.amount(u'Payment Due') if self.doc.xpath(u'//li[@class="noPaymentDue"]'): # If payment date is not scheduled yet, set it somewhere in a # distant future, so that we always have a valid date. paydate = datetime.now() + timedelta(days=999) else: rawtext = self.doc.xpath( u'//li[contains(text(),"Due Date")]')[0].text_content() datetext = re.match('.*(\d\d/\d\d/\d\d\d\d).*', rawtext).group(1) paydate = datetime.strptime(datetext, '%m/%d/%Y') a = Account() a.id = label[-4:] a.label = label a.currency = Account.get_currency(balance) a.balance = -AmTr.decimal_amount(balance) a.type = Account.TYPE_CARD a.cardlimit = AmTr.decimal_amount(cardlimit) a.paymin = AmTr.decimal_amount(paymin) if paydate is not None: a.paydate = paydate return a
def get_list(self): for tr in self.document.xpath('//table[@class="ca-table"]/tr'): if not tr.attrib.get('class', '').startswith('colcelligne'): continue cols = tr.findall('td') if not cols or len(cols) < 7: continue account = Account() account.id = self.parser.tocleanstring(cols[self.COL_ID]) account.label = self.parser.tocleanstring(cols[self.COL_LABEL]) account.type = self.TYPES.get(account.label, Account.TYPE_UNKNOWN) balance = self.parser.tocleanstring(cols[self.COL_VALUE]) # we have to ignore those accounts, because using NotAvailable # makes boobank and probably many others crash if balance in ('indisponible', ''): continue account.balance = Decimal(Transaction.clean_amount(balance)) account.currency = account.get_currency( self.parser.tocleanstring(cols[self.COL_CURRENCY])) account._link = None a = cols[0].find('a') if a is not None: account._link = a.attrib['href'].replace(' ', '%20') yield account
def get_list(self): account_type = Account.TYPE_UNKNOWN params = {} for field in self.document.xpath('//input'): params[field.attrib['name']] = field.attrib.get('value', '') for div in self.document.xpath('//div[@class="btit"]'): account_type = self.ACCOUNT_TYPES.get(div.text.strip(), Account.TYPE_UNKNOWN) for tr in div.getnext().xpath('.//tbody/tr'): if not 'id' in tr.attrib: continue args = dict(parse_qsl(tr.attrib['id'])) tds = tr.findall('td') if len(tds) < 4 or not 'identifiant' in args: self.logger.warning('Unable to parse an account') continue account = Account() account.id = args['identifiant'] account.label = u' '.join([u''.join([txt.strip() for txt in tds[1].itertext()]), u''.join([txt.strip() for txt in tds[2].itertext()])]).strip() account.type = account_type balance = u''.join([txt.strip() for txt in tds[3].itertext()]) account.balance = Decimal(FrenchTransaction.clean_amount(balance)) account.currency = account.get_currency(balance) account._params = params.copy() account._params['dialogActionPerformed'] = 'SOLDE' account._params['attribute($SEL_$%s)' % tr.attrib['id'].split('_')[0]] = tr.attrib['id'].split('_', 1)[1] yield account return
def get_cards(self, account_id): divs = self.doc.xpath('//div[@class="content-boxed"]') assert len(divs) msgs = re.compile(u'Vous avez fait opposition sur cette carte bancaire.' + '|Votre carte bancaire a été envoyée.' + '|BforBank a fait opposition sur votre carte' + '|Pour des raisons de sécurité, la demande de réception du code confidentiel de votre carte par SMS est indisponible') divs = [d for d in divs if not msgs.search(CleanText('.//div[has-class("alert")]', default='')(d))] divs = [d.xpath('.//div[@class="m-card-infos"]')[0] for d in divs] divs = [d for d in divs if not d.xpath('.//div[@class="m-card-infos-body-text"][text()="Débit immédiat"]')] if not len(divs): self.logger.warning('all cards are cancelled, acting as if there is no card') return [] cards = [] for div in divs: label = CleanText('.//div[@class="m-card-infos-body-title"]')(div) number = CleanText('.//div[@class="m-card-infos-body-num"]', default='')(div) number = re.sub('[^\d*]', '', number).replace('*', 'x') debit = CleanText(u'.//div[@class="m-card-infos-body-text"][contains(text(),"Débit")]')(div) assert debit == u'Débit différé', 'unrecognized card type %s: %s' % (number, debit) card = Account() card.id = '%s.%s' % (account_id, number) card.label = label card.number = number card.type = Account.TYPE_CARD cards.append(card) return cards
def get_list(self): table = self.find_table() for tr in self.parser.select(table, 'tr', 'many'): tds = self.parser.select(tr, 'td') if len(tds) != 6: continue tdlabel, tdid, tdcur, tdupdated, tdbal, tdbalcur = tds account = Account() account.label = to_unicode(tdlabel.text_content().strip()) # this is important - and is also the last part of the id (considering spaces) # we can't use only the link as it does not goes where we want try: link = self.parser.select(tdlabel, 'a', 1) except BrokenPageError: # probably an account we can't display the history account._link_id = None else: account._link_id = parse_qs(link.attrib['href'])['ch4'][0] account.id = to_unicode(tdid.text.strip().replace(' ', '')) account.iban = 'FR76' + account.id # just in case we are showing the converted balances account._main_currency = Account.get_currency(tdcur.text) # we have to ignore those accounts, because using NotAvailable # makes boobank and probably many others crash if tdbal.text_content().strip() == 'indisponible': continue account.balance = Decimal(Transaction.clean_amount(tdbal.text_content())) account.currency = Account.get_currency(tdbalcur.text) account._updated = datetime.strptime(tdupdated.text, '%d/%m/%Y') yield account
def get_list(self): for div in self.doc.xpath('.//div[@id="card-details"]'): a = Account() a.id = CleanText().filter(div.xpath('.//span[@class="acc-num"]')) a.label = CleanText().filter( div.xpath('.//span[@class="card-desc"]')) if "carte" in a.label.lower(): a.type = Account.TYPE_CARD balance = CleanText().filter( div.xpath('.//span[@class="balance-data"]')) if balance in (u'Indisponible', u'Indisponible Facturation en cours', ''): a.balance = NotAvailable else: a.currency = a.get_currency(balance) a.balance = -abs( CleanDecimal( replace_dots=a.currency == 'EUR').filter(balance)) # Cancel card don't have a link to watch history link = self.doc.xpath('.//div[@class="wide-bar"]/h3/a') if len(link) == 1: a._link = link[0].attrib['href'] else: a._link = None yield a
def get_list(self): for tr in self.document.xpath('//table[@class="ca-table"]/tr'): if not tr.attrib.get('class', '').startswith('colcelligne'): continue cols = tr.findall('td') if not cols: continue account = Account() account.id = self.parser.tocleanstring(cols[self.COL_ID]) account.label = self.parser.tocleanstring(cols[self.COL_LABEL]) account.type = self.TYPES.get(account.label, Account.TYPE_UNKNOWN) balance = self.parser.tocleanstring(cols[self.COL_VALUE]) # we have to ignore those accounts, because using NotAvailable # makes boobank and probably many others crash if balance in ('indisponible', ''): continue account.balance = Decimal(Transaction.clean_amount(balance)) account.currency = account.get_currency(self.parser.tocleanstring(cols[self.COL_CURRENCY])) account._link = None a = cols[0].find('a') if a is not None: account._link = a.attrib['href'].replace(' ', '%20') yield account
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
def get_accounts_list(self): for table in self.doc.xpath('//div[@class="comptestabl"]/table'): try: account_type = self.ACCOUNT_TYPES[table.get('summary').lower()] if not account_type: account_type = self.ACCOUNT_TYPES[table.xpath('./caption/text()')[0].strip().lower()] except (IndexError,KeyError): account_type = Account.TYPE_UNKNOWN for tr in table.xpath('./tbody/tr'): cols = tr.findall('td') link = cols[0].find('a') if link is None: continue a = Account() a.type = account_type a.id = unicode(re.search('([A-Z\d]{4}[A-Z\d\*]{3}[A-Z\d]{4})', link.attrib['title']).group(1)) a.label = unicode(link.attrib['title'].replace('%s ' % a.id, '')) tmp_balance = CleanText(None).filter(cols[1]) a.currency = a.get_currency(tmp_balance) if not a.currency: a.currency = u'EUR' a.balance = Decimal(Transaction.clean_amount(tmp_balance)) a._has_cards = False a.url = urljoin(self.url, link.attrib['href']) yield a
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.id.find('_CarteVisa') >= 0: accounts[-1]._card_ids.append(a._args) if not accounts[-1].coming: accounts[-1].coming = Decimal('0.0') accounts[-1].coming += a.balance continue a._card_ids = [] accounts.append(a) return accounts
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()
def get_list(self): """ Returns the list of available bank accounts """ for div in self.document.getiterator('div'): if div.attrib.get('class', '') in ( 'dv', 'headline') and div.getchildren()[0].tag in ('a', 'br'): self.logger.debug("Analyzing div %s" % div) # Step 1: extract text tokens tokens = [] required_tokens = {} optional_tokens = {} token_extractor = TokenExtractor() for token in token_extractor.extract_tokens(div): self.logger.debug('Extracted text token: "%s"' % token) tokens.append(token) # Step 2: analyse tokens for token in tokens: if self.look_like_account_number(token): required_tokens['account_number'] = token elif self.look_like_amount(token): required_tokens['account_amount'] = token elif self.look_like_account_name(token): required_tokens['account_name'] = token elif self.look_like_account_owner(token): if 'account_owner' in optional_tokens and 'account_name' not in required_tokens: required_tokens['account_name'] = optional_tokens[ 'account_owner'] optional_tokens['account_owner'] = token # Step 3: create account objects if len(required_tokens) >= 3: account = Account() account.label = required_tokens['account_name'] account.id = required_tokens['account_number'] account.balance = FrenchTransaction.clean_amount( required_tokens['account_amount']) account.currency = account.get_currency( required_tokens['account_amount']) # we found almost all required information to create an account object self.logger.debug( 'Found account %s with number %s and balance = %.2f' % (account.label, account.id, account.balance)) # we may have found the owner name too if optional_tokens.get('account_owner') is not None: # well, we could add it to the label, but is this really required? self.logger.debug(' the owner appears to be %s' % optional_tokens['account_owner']) # we simply lack the link to the account history... which remains optional first_link = div.find('a') if first_link is not None: account._link_id = first_link.get('href') self.logger.debug( ' the history link appears to be %s' % account._link_id) else: account._link_id = None yield account
def get_accounts_list(self): self.location('%s://%s/summarySearch.do?reqCode=search' % (self.PROTOCOL, self.DOMAIN)) account = Account() account.id = u'1' account.currency = 'EUR' account.balance = self.page.get_balance() account.label = u'Synthèse financière' return [account]
def get_accounts_list(self): balance = self.index.stay_or_go().get_balance() account = Account() account.id = self.username account.label = u'Carte Oney' account.balance = balance account.currency = u'EUR' return [account]
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
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
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
def get_list(self): call_response = self.location( '/transactionnel/services/rest/Account/accounts' ).json().get('content', []) seen = set() for content in call_response: if self.accnum != '00000000000' and content['numero'] != self.accnum: continue for poste in content['postes']: a = Account() a._number = content['numeroLong'] a._nature = poste['codeNature'] a._codeSousPoste = poste['codeSousPoste'] if 'codeSousPoste' in poste else None a._consultable = poste['consultable'] a._univers = self.current_univers a.id = '%s.%s' % (a._number, a._nature) if a.id in seen: # some accounts like "compte à terme fidélis" have the same _number and _nature # but in fact are kind of closed, so worthless... self.logger.warning('ignored account id %r (%r) because it is already used', a.id, poste.get('numeroDossier')) continue seen.add(a.id) a.type = self.ACCOUNT_TYPES.get(poste['codeNature'], Account.TYPE_UNKNOWN) if a.type == Account.TYPE_CHECKING: iban_response = self.location( '/transactionnel/services/rest/Account/account/%s/iban' % a._number ).json().get('content', {}) a.iban = iban_response.get('iban', NotAvailable) else: a.iban = NotAvailable if 'numeroDossier' in poste and poste['numeroDossier']: a._file_number = poste['numeroDossier'] a.id += '.%s' % a._file_number if poste['postePortefeuille']: a.label = u'Portefeuille Titres' a.balance = Decimal(str(poste['montantTitres']['valeur'])) a.currency = poste['montantTitres']['monnaie']['code'].strip() if not a.balance and not a.currency and 'dateTitres' not in poste: continue yield a if 'libelle' not in poste: continue a.label = ' '.join([content['intitule'].strip(), poste['libelle'].strip()]) a.balance = Decimal(str(poste['solde']['valeur'])) a.currency = poste['solde']['monnaie']['code'].strip() # Some accounts may have balance currency if 'Solde en devises' in a.label and a.currency != u'EUR': a.id += str(poste['monnaie']['codeSwift']) yield a
def get_accounts(self): accounts = {} content = self.doc.xpath('//div[@id="moneyPage"]')[0] # Multiple accounts lines = content.xpath('//div[@class="col-md-8 multi-currency"]/ul/li') for li in lines: account = Account() account.type = Account.TYPE_CHECKING account.id = CleanText().filter( li.xpath('./span[@class="currencyUnit"]/span')) account.currency = CleanText().filter( li.xpath('./span[@class="currencyUnit"]/span')) account.balance = CleanDecimal(replace_dots=True).filter( li.xpath('./span[@class="amount"]/text()')) account.label = u'%s %s*' % (self.browser.username, account.currency) accounts[account.id] = account self.browser.account_currencies.append(account.currency) if not accounts: # Primary currency account primary_account = Account() primary_account.type = Account.TYPE_CHECKING try: balance = CleanText('.')(content.xpath( '//div[contains(@class, "col-md-6")][contains(@class, "available")]' )[0]) except IndexError: primary_account.id = 'EUR' primary_account.currency = u'EUR' primary_account.balance = NotAvailable primary_account.label = u'%s' % (self.browser.username) else: primary_account.currency = Account.get_currency(balance) primary_account.id = unicode(primary_account.currency) primary_account.balance = Decimal( FrenchTransaction.clean_amount(balance)) primary_account.label = u'%s %s*' % (self.browser.username, primary_account.currency) accounts[primary_account.id] = primary_account return accounts
def _get_account(self, line): tds = line.findall('td') account = Account() account.id = self.parser.tocleanstring(tds[self.COL_ID]) account.label = self.parser.tocleanstring(tds[self.COL_LABEL]) balance_str = self.parser.tocleanstring(tds[self.COL_AMOUNT]) account.balance = Decimal(FrenchTransaction.clean_amount(balance_str)) account.currency = account.get_currency(balance_str) return account
def iter_accounts(self): self.start() bal = self.wait('div.cT-valueItem span.cT-balanceIndicator1')[0].text account = Account() account.id = self._account_id() account.label = self._account_link().text account.currency = Account.get_currency(bal) account.balance = -AmTr.decimal_amount(bal) account.type = Account.TYPE_CARD self.finish() yield account
def iter_accounts(self): """ Generates accounts. """ # Throw error from password value or random error self.maybe_generate_error(8) accounts = [] first_account = Account() first_account.id = 'FR235711131719@fakebank' first_account.label = 'Compte chèque' first_account.currency = Currency.get_currency('42 €') first_account.iban = 'FR235711131719' first_account.balance = Decimal(random.uniform(0, 150)) first_account.type = Account.TYPE_CHECKING accounts.append(first_account) second_account = Account() second_account.id = 'livretA@fakebank' second_account.label = 'Livret A' second_account.currency = Currency.get_currency('$42') second_account.balance = Decimal(500.0) second_account.type = Account.TYPE_SAVINGS accounts.append(second_account) third_account = Account() third_account.id = 'PEL@fakebank' third_account.label = 'Plan Epargne Logement' third_account.balance = Decimal(0.0) third_account.type = Account.TYPE_SAVINGS accounts.append(third_account) fourth_account = Account() fourth_account.id = CREDIT_CARD_ACCOUNT_ID fourth_account.label = 'Debit Card' fourth_account.balance = Decimal(0.0) fourth_account.type = Account.TYPE_CARD accounts.append(fourth_account) return accounts
def get_loans_list(self): call_response = self.location('/transactionnel/services/applications/prets/liste').json().get('content', []) for content in call_response: a = Account() a.id = "%s.%s" % (content['comptePrets'].strip(), content['numeroDossier'].strip()) a.type = Account.TYPE_LOAN a.label = ' '.join([content['intitule'].strip(), content['libellePrets'].strip()]) a.balance = -Decimal(str(content['montantCapitalDu']['valeur'])) a.currency = content['montantCapitalDu']['monnaie']['code'].strip() a._univers = self.current_univers yield a
def iter_loans(self, current_univers): for content in self.get_content(): a = Account() a.id = "%s.%s" % (content['comptePrets'].strip(), content['numeroDossier'].strip()) a.type = Account.TYPE_LOAN a.label = ' '.join( [content['intitule'].strip(), content['libellePrets'].strip()]) a.balance = -Decimal(str(content['montantCapitalDu']['valeur'])) a.currency = content['montantCapitalDu']['monnaie']['code'].strip() a._univers = current_univers yield a
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