def iter_transactions(self): for row in self.doc.xpath('//tr/th[@headers=' '"postedHeader transactionDateHeader"]/..'): tdate = row.xpath('th[@headers="postedHeader ' 'transactionDateHeader"]/text()')[0] pdate = row.xpath('td[@headers="postedHeader ' 'postingDateHeader"]/text()')[0] desc = row.xpath('td[@headers="postedHeader ' 'descriptionHeader"]/span/text()')[0] ref = row.xpath('td[@headers="postedHeader ' 'descriptionHeader"]/text()')[0] amount = row.xpath('td[@headers="postedHeader ' 'amountHeader"]/text()')[0] tdate = datetime.datetime.strptime(tdate, '%m/%d/%y') pdate = datetime.datetime.strptime(pdate, '%m/%d/%y') desc = clean_label(desc) ref = re.match('.*<REFERENCE ([^>]+)>.*', ref).group(1) if amount.startswith('+'): amount = AmTr.decimal_amount(amount[1:]) else: amount = -AmTr.decimal_amount(amount) trans = Transaction(ref) trans.date = tdate trans.rdate = pdate trans.type = Transaction.TYPE_UNKNOWN trans.raw = desc trans.label = desc trans.amount = amount yield trans
def unsorted_trans(self): for jnl in self.doc['accountDetailsAndActivity']['accountActivity'] \ ['postedTransactionJournals']: tdate = jnl['columns'][0]['activityColumn'][0] label = jnl['columns'][1]['activityColumn'][0] amount = jnl['columns'][3]['activityColumn'][0] xdescs = dict((x['label'], x['value'][0]) for x in jnl['extendedDescriptions']) pdate = xdescs[u'Posted Date :'] ref = xdescs.get(u'Reference Number:') or u'' if amount.startswith(u'(') and amount.endswith(u')'): amount = AmTr.decimal_amount(amount[1:-1]) else: amount = -AmTr.decimal_amount(amount) label = clean_label(label) trans = Transaction(ref) trans.date = datetime.strptime(tdate, '%m-%d-%Y') trans.rdate = datetime.strptime(pdate, '%m-%d-%Y') trans.type = Transaction.TYPE_UNKNOWN trans.raw = label trans.label = label trans.amount = amount yield trans
def iter_history(self, account): if account.id not in self.histories: histories = [] self.open('/user/%s/project/%s/activity' % (self.users['userId'], account.number), method="OPTIONS") for activity in [acc for acc in self.request('/user/%s/project/%s/activity' % (self.users['userId'], account.number), headers=self.request_headers)['activities'] \ if acc['details'] is not None]: m = re.search(u'([\d\,]+)(?=[\s]+€|[\s]+euro)', activity['details']) if "Souscription" not in activity['title'] and not m: continue t = Transaction() t.label = "%s - %s" % (" ".join( activity['type'].split("_")), activity['title']) t.date = Date().filter(activity['date']) t.type = Transaction.TYPE_BANK amount = account._startbalance if not m else "-%s" % m.group( 1) if "FRAIS" in activity['type'] else m.group(1) t.amount = CleanDecimal(replace_dots=True).filter(amount) histories.append(t) self.histories[account.id] = histories return self.histories[account.id]
def read_transaction(self, pos, date_from, date_to): startPos = pos pos, tdate = self.read_date(pos) pos, pdate_layout = self.read_layout_td(pos) pos, pdate = self.read_date(pos) pos, ref_layout = self.read_layout_td(pos) pos, ref = self.read_ref(pos) pos, desc_layout = self.read_layout_td(pos) pos, desc = self.read_text(pos) pos, amount_layout = self.read_layout_td(pos) pos, amount = self.read_amount(pos) if tdate is None or pdate is None \ or desc is None or amount is None or amount == 0: return startPos, None else: tdate = closest_date(tdate, date_from, date_to) pdate = closest_date(pdate, date_from, date_to) desc = u' '.join(desc.split()) trans = Transaction(ref or u'') trans.date = tdate trans.rdate = pdate trans.type = Transaction.TYPE_UNKNOWN trans.raw = desc trans.label = desc trans.amount = amount return pos, trans
def iter_history(self, account): # Load i18n for type translation self.i18np.go(lang1=self.LANG, lang2=self.LANG).load_i18n() # For now detail for each account is not available. History is global for all accounts and very simplist data = { 'clang': self.LANG, 'ctcc': self.CTCC, 'login': self.username, 'session': self.sessionId } for trans in self.historyp.go(data=data).get_transactions(): t = Transaction() t.date = datetime.strptime(trans["dateHeureSaisie"], "%d/%m/%Y") t.rdate = datetime.strptime(trans["dateHeureSaisie"], "%d/%m/%Y") t.type = Transaction.TYPE_DEPOSIT if trans[ "montantNetEuro"] > 0 else Transaction.TYPE_PAYBACK t.raw = trans["typeOperation"] try: t.label = self.i18n["OPERATION_TYPE_" + trans["casDeGestion"]] except KeyError: t.label = self.i18n["OPERATION_TYPE_TOTAL_" + trans["casDeGestion"]] t.amount = Decimal(trans["montantNetEuro"]).quantize( Decimal('.01')) yield t
def iter_history(self, account): for hist in self.doc['operationsIndividuelles']: if len(hist['instructions']) > 0: if self.belongs(hist['instructions'], account): tr = Transaction() tr.amount = self.get_amount(hist['instructions'], account) tr.rdate = datetime.strptime( hist['dateComptabilisation'].split('T')[0], '%Y-%m-%d') tr.date = tr.rdate tr.label = hist[ 'libelleOperation'] if 'libelleOperation' in hist else hist[ 'libelleCommunication'] tr.type = Transaction.TYPE_UNKNOWN # Bypassed because we don't have the ISIN code # tr.investments = [] # for ins in hist['instructions']: # inv = Investment() # inv.code = NotAvailable # inv.label = ins['nomFonds'] # inv.description = ' '.join([ins['type'], ins['nomDispositif']]) # inv.vdate = datetime.strptime(ins.get('dateVlReel', ins.get('dateVlExecution')).split('T')[ # 0], '%Y-%m-%d') # inv.valuation = Decimal(ins['montantNet']) # inv.quantity = Decimal(ins['nombreDeParts']) # inv.unitprice = inv.unitvalue = Decimal(ins['vlReel']) # tr.investments.append(inv) yield tr
def iter_transactions(self): for row in self.doc.xpath('//tr/th[@headers=' '"postedHeader dateHeader"]/..'): date = row.xpath('th[@headers="postedHeader ' 'dateHeader"]/text()')[0] desc = row.xpath('td[@headers="postedHeader descriptionHeader"]' '//span[@class="OneLinkNoTx"]/text()')[0] deposit = row.xpath('td[@headers="postedHeader ' 'depositsConsumerHeader"]/span/text()')[0] withdraw = row.xpath('td[@headers="postedHeader ' 'withdrawalsConsumerHeader"]/span/text()')[0] date = datetime.datetime.strptime(date, '%m/%d/%y') desc = clean_label(desc) deposit = deposit.strip() deposit = AmTr.decimal_amount(deposit or '0') withdraw = withdraw.strip() withdraw = AmTr.decimal_amount(withdraw or '0') amount = deposit - withdraw trans = Transaction(u'') trans.date = date trans.rdate = date trans.type = Transaction.TYPE_UNKNOWN trans.raw = desc trans.label = desc trans.amount = amount yield trans
def read_transaction(self, pos, date_from, date_to): startPos = pos pos, tdate = self.read_date(pos) pos, pdate = self.read_date(pos) # Early check to call read_multiline_desc() only when needed. if tdate is None: return startPos, None pos, desc = self.read_multiline_desc(pos) pos, amount = self.read_amount(pos) if desc is None or amount is None: return startPos, None else: # Sometimes one date is missing. pdate = pdate or tdate tdate = closest_date(tdate, date_from, date_to) pdate = closest_date(pdate, date_from, date_to) trans = Transaction() trans.date = tdate trans.rdate = pdate trans.type = Transaction.TYPE_UNKNOWN trans.raw = desc trans.label = desc trans.amount = -amount return pos, trans
def read_card_transaction(self, pos, date_from, date_to): INDENT_CHARGES = 520 startPos = pos pos, tdate = self.read_date(pos) pos, pdate_layout = self.read_layout_tm(pos) pos, pdate = self.read_date(pos) pos, ref_layout = self.read_layout_tm(pos) pos, ref = self.read_ref(pos) pos, desc = self.read_multiline_desc(pos) pos, amount = self.read_indent_amount(pos, range_minus=(INDENT_CHARGES, 9999), range_plus=(0, INDENT_CHARGES)) if tdate is None or pdate_layout is None or pdate is None \ or ref_layout is None or ref is None or desc is None or amount is None: return startPos, None else: tdate = closest_date(tdate, date_from, date_to) pdate = closest_date(pdate, date_from, date_to) trans = Transaction(ref) trans.date = tdate trans.rdate = pdate trans.type = Transaction.TYPE_UNKNOWN trans.raw = desc trans.label = desc trans.amount = amount return pos, trans
def read_cash_transaction(self, pos, date_from, date_to): INDENT_BALANCE = 520 INDENT_WITHDRAWAL = 470 startPos = pos pos, date = self.read_date(pos) pos, _ = self.read_star(pos) pos, desc = self.read_multiline_desc(pos) pos, amount = self.read_indent_amount( pos, range_plus=(0, INDENT_WITHDRAWAL), range_minus=(INDENT_WITHDRAWAL, INDENT_BALANCE), range_skip=(INDENT_BALANCE, 9999)) if desc is None or date is None or amount is None: return startPos, None else: date = closest_date(date, date_from, date_to) trans = Transaction(u'') trans.date = date trans.rdate = date trans.type = Transaction.TYPE_UNKNOWN trans.raw = desc trans.label = desc trans.amount = amount return pos, trans
def parse(self): emonths = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ] date_format, time_format, months = self.guess_format() for row in self.document.xpath( '//table[@id="transactionTable"]/tbody/tr'): if len(row.xpath('.//td')) < 5: continue amount = row.xpath( './/td[@headers="gross"]')[-1].text_content().strip() if re.search('\d', amount): currency = Account.get_currency(amount) amount = AmTr.decimal_amount(amount) else: continue idtext = row.xpath('.//td[@class="detailsNoPrint"]//span[@class="accessAid"]')[0] \ .text_content().replace(u'\xa0', u' ').strip().rpartition(' ')[-1] trans = Transaction(idtext) trans.amount = amount trans._currency = currency datetext = row.xpath( './/td[@class="dateInfo"]')[0].text_content().strip() for i in range(0, 12): datetext = datetext.replace(months[i], emonths[i]) date = dateutil.parser.parse(datetext) trans.date = date trans.rdate = date trans.label = to_unicode( row.xpath('.//td[@class="emailInfo"]') [0].text_content().strip()) info = to_unicode( row.xpath('.//td[@class="paymentTypeInfo"]') [0].text_content().strip()) trans.raw = info + u' ' + trans.label if u'Authorization' in info or u'Autorisation' in info or \ u'Order' in info: continue if u'Credit Card' in trans.label or u'Carte bancaire' in trans.label: trans.type = Transaction.TYPE_CARD elif info.startswith(u'Payment') or info.startswith(u'Paiement'): trans.type = Transaction.TYPE_ORDER elif u'Currency Conversion' in info or u'Conversion de devise' in info: trans.type = Transaction.TYPE_BANK else: trans.type = Transaction.TYPE_UNKNOWN yield trans
def get_history(self): i = 0 ignore = False for tr in self.doc.xpath( '//table[@cellpadding="1"]/tr') + self.doc.xpath( '//tr[@class="rowClick" or @class="rowHover"]'): tds = tr.findall('td') if len(tds) < 4: continue # if there are more than 4 columns, ignore the first one. i = min(len(tds) - 4, 1) if tr.attrib.get('class', '') == 'DataGridHeader': if tds[2].text == u'Titulaire': ignore = True else: ignore = False continue if ignore: continue # Remove useless details detail = tr.cssselect('div.detail') if len(detail) > 0: detail[0].drop_tree() t = Transaction() date = u''.join([txt.strip() for txt in tds[i + 0].itertext()]) raw = u' '.join([txt.strip() for txt in tds[i + 1].itertext()]) debit = u''.join([txt.strip() for txt in tds[-2].itertext()]) credit = u''.join([txt.strip() for txt in tds[-1].itertext()]) t.parse(date, re.sub(r'[ ]+', ' ', raw)) card_debit_date = self.doc.xpath( u'//span[@id="MM_HISTORIQUE_CB_m_TableTitle3_lblTitle"] | //label[contains(text(), "débiter le")]' ) if card_debit_date: t.rdate = Date(dayfirst=True).filter(date) m = re.search('(\d{2}\/\d{2}\/\d{4})', card_debit_date[0].text) assert m t.date = Date(dayfirst=True).filter(m.group(1)) if t.date is NotAvailable: continue if 'tot dif' in t.raw.lower(): t.deleted = True t.set_amount(credit, debit) yield t i += 1
def iter_history(self): for tr in self.doc.xpath( u'//table[@class="boursedetail"]/tbody/tr[td]'): t = Transaction() t.label = CleanText('.')(tr.xpath('./td[2]')[0]) t.date = Date(dayfirst=True).filter( CleanText('.')(tr.xpath('./td[1]')[0])) t.amount = self.parse_decimal(tr.xpath('./td[3]')[0]) yield t
def iter_history(self, account): for hist in self.doc['operationsIndividuelles']: if len(hist['instructions']) > 0: if self.belongs(hist['instructions'], account): tr = Transaction() tr.amount = self.get_amount(hist['instructions'], account) tr.rdate = datetime.strptime(hist['dateComptabilisation'].split('T')[0], '%Y-%m-%d') tr.date = tr.rdate tr.label = hist.get('libelleOperation') or hist['libelleCommunication'] tr.type = Transaction.TYPE_UNKNOWN yield tr
def iter_transactions(self): for li in self.doc.xpath('//section[@class="transactions"]//div/li'): date = li.xpath('p[@data-type="date"]//text()')[0].strip() label = li.xpath('p[@data-type="description"]//text()')[0].strip() amount = li.xpath('p[@data-type="amount"]//text()')[0].strip() t = Transaction() t.date = datetime.strptime(date, '%m/%d/%Y') t.rdate = datetime.strptime(date, '%m/%d/%Y') t.type = Transaction.TYPE_UNKNOWN t.raw = unicode(label) t.label = unicode(label) t.amount = -AmTr.decimal_amount(amount) yield t
def get_history(self, account): if not account._consultable: raise NotImplementedError() if account._univers != self.current_univers: self.move_to_univers(account._univers) offset = 0 next_page = True seen = set() while next_page: r = self.api_open( '/transactionnel/services/applications/operations/get/%(number)s/%(nature)s/00/%(currency)s/%(startDate)s/%(endDate)s/%(offset)s/%(limit)s' % { 'number': account._number, 'nature': account._nature, 'currency': account.currency, 'startDate': '2000-01-01', 'endDate': date.today().strftime('%Y-%m-%d'), 'offset': offset, 'limit': 50 }) next_page = False offset += 50 transactions = [] for op in reversed(r.json()['content']['operations']): next_page = True t = Transaction() if op['id'] in seen: raise ParseError( 'There are several transactions with the same ID, probably an infinite loop' ) t.id = op['id'] seen.add(t.id) t.amount = Decimal(str(op['montant'])) t.date = date.fromtimestamp( op.get('dateDebit', op.get('dateOperation')) / 1000) t.rdate = date.fromtimestamp( op.get('dateOperation', op.get('dateDebit')) / 1000) t.vdate = date.fromtimestamp( op.get('dateValeur', op.get('dateDebit', op.get('dateOperation'))) / 1000) if 'categorie' in op: t.category = op['categorie'] t.label = op['libelle'] t.raw = ' '.join([op['libelle']] + op['details']) transactions.append(t) # Transactions are unsorted for t in sorted(transactions, key=lambda t: t.rdate, reverse=True): yield t
def generate_single_transaction(self): """ Generate a fake transaction. """ now = datetime.datetime.now() transaction = Transaction() transaction.type = self.generate_type() n = random.randrange(100) if n < 2: # with a 2% rate, generate a special operation to test duplicates # (happening on 4th of current month). duplicate_date = datetime.datetime(now.year, now.month, 4) transaction.amount = Decimal(-300.0) transaction.label = "Loyer" transaction.raw = "Loyer habitation" transaction.date = self.generate_date(duplicate_date, duplicate_date) return transaction # Get transactions for the previous month. min_date = now - datetime.timedelta(days=30) transaction.date = self.generate_date(min_date, now) if n < 15: transaction.label, transaction.raw = self.generate_label( positive=True) transaction.amount = Decimal( random.randint(100, 800) + random.random()) return transaction if n < 30: transaction.rdate = transaction.date elif n < 60: transaction.rdate = None transaction.amount = Decimal(random.randint(-60, 0) + random.random()) transaction.label, transaction.raw = self.generate_label() transaction.type = self.generate_type() # Randomly set the date properties to date class instead of datetime. maybe_date_object = random.randrange(3) if maybe_date_object == 0: transaction.date = transaction.date.date() if maybe_date_object == 1 and transaction.rdate: transaction.rdate = transaction.rdate.date() return transaction
def iter_transactions(self): for ntrans in reversed(self.doc.xpath('//TRANSACTION')): desc = u' '.join( ntrans.xpath('TRANSDESCRIPTION/text()')[0].split()) tdate = u''.join(ntrans.xpath('TRANSACTIONDATE/text()')) pdate = u''.join(ntrans.xpath('POSTDATE/text()')) t = Transaction() t.date = datetime.strptime(tdate, '%m/%d/%Y') t.rdate = datetime.strptime(pdate or tdate, '%m/%d/%Y') t.type = Transaction.TYPE_UNKNOWN t.raw = desc t.label = desc t.amount = -AmTr.decimal_amount(ntrans.xpath('AMOUNT/text()')[0]) yield t
def iter_recent(self): records = json.loads( self.doc.xpath( '//div[@id="completedActivityRecords"]//input[1]/@value')[0]) recent = [x for x in records if x['PDF_LOC'] is None] for rec in sorted(recent, ActivityPage.cmp_records, reverse=True): desc = u' '.join(rec['TRANS_DESC'].split()) trans = Transaction((rec['REF_NUM'] or u'').strip()) trans.date = ActivityPage.parse_date(rec['TRANS_DATE']) trans.rdate = ActivityPage.parse_date(rec['POST_DATE']) trans.type = Transaction.TYPE_UNKNOWN trans.raw = desc trans.label = desc trans.amount = -AmTr.decimal_amount(rec['TRANS_AMOUNT']) yield trans
def iter_transactions(self): for ntrans in reversed(self.doc.xpath('//TRANSACTION')): desc = u' '.join(ntrans.xpath( 'TRANSDESCRIPTION/text()')[0].split()) tdate = u''.join(ntrans.xpath('TRANSACTIONDATE/text()')) pdate = u''.join(ntrans.xpath('POSTDATE/text()')) # Skip transactions which are not posted, # because they are not accounted for in balance calculation. if not pdate: continue t = Transaction() t.date = datetime.strptime(tdate, '%m/%d/%Y') t.rdate = datetime.strptime(pdate, '%m/%d/%Y') t.type = Transaction.TYPE_UNKNOWN t.raw = desc t.label = desc t.amount = -AmTr.decimal_amount(ntrans.xpath('AMOUNT/text()')[0]) yield t
def _internal_get_transactions(self, categories, filter_func): TYPES = { 'PT': Transaction.TYPE_CARD, 'AA': Transaction.TYPE_CARD, 'CT': Transaction.TYPE_TRANSFER, 'WEE': Transaction.TYPE_BANK, } transactions = self.request('/api/smrt/transactions?limit=1000') for t in transactions: if not filter_func(t) or t["amount"] == 0: continue new = Transaction() new.date = datetime.fromtimestamp(t["createdTS"] / 1000) new.rdate = datetime.fromtimestamp(t["visibleTS"] / 1000) new.id = t['id'] new.amount = Decimal(str(t["amount"])) if "merchantName" in t: new.raw = new.label = t["merchantName"] elif "partnerName" in t: new.raw = CleanText().filter( t["referenceText"]) if "referenceText" in t else CleanText( ).filter(t["partnerName"]) new.label = t["partnerName"] else: new.raw = new.label = '' if "originalCurrency" in t: new.original_currency = t["originalCurrency"] if "originalAmount" in t: new.original_amount = Decimal(str(t["originalAmount"])) new.type = TYPES.get(t["type"], Transaction.TYPE_UNKNOWN) if t["category"] in categories: new.category = categories[t["category"]] yield new
def iter_history_recent(self, account): self.start() if account.id != self._account_id(): raise AccountNotFound() self._account_link().click() self.wait_ajax() for span in self.find('span.cM-maximizeButton'): span.click() for tr in self.find('tr.payments,tr.purchase'): trdata = lambda n: tr.find_element_by_css_selector( 'td.cT-bodyTableColumn%i span.cT-line1' % n).text treid = tr.get_attribute('id').replace('rowID', 'rowIDExt') tredata = {} for tre in self.find('tr#%s' % treid): labels = [x.text for x in tre.find_elements_by_css_selector( 'div.cT-labelItem')] values = [x.text for x in tre.find_elements_by_css_selector( 'div.cT-valueItem')] tredata = dict(zip(labels, values)) ref = tredata.get(u'Reference Number:', u'') tdate = trdata(1) pdate = tredata.get(u'Posted Date :', tdate) desc = clean_label(trdata(2)) amount = trdata(4) tdate = datetime.datetime.strptime(tdate, '%m-%d-%Y') pdate = datetime.datetime.strptime(pdate, '%m-%d-%Y') if amount.startswith(u'(') and amount.endswith(u')'): amount = AmTr.decimal_amount(amount[1:-1]) else: amount = -AmTr.decimal_amount(amount) trans = Transaction(ref) trans.date = tdate trans.rdate = pdate trans.type = Transaction.TYPE_UNKNOWN trans.raw = desc trans.label = desc trans.amount = amount yield trans self.finish()
def _parse_transaction(self, payment): transaction = Transaction() transaction_id = Dict('transaction_number', default=None)(payment) # Check if transaction_id is None which indicates failed transaction if transaction_id is None: return transaction.id = transaction_id transaction.date = DateTime(Dict('executed_at'))(payment) transaction.rdate = DateTime(Dict('created_at'))(payment) types = { 'ORDER': Transaction.TYPE_CARD, # order on lunchr website 'LUNCHR_CARD_PAYMENT': Transaction.TYPE_CARD, # pay in shop 'MEAL_VOUCHER_CREDIT': Transaction.TYPE_DEPOSIT, # type can be null for refunds } transaction.type = types.get(Dict('type')(payment), Transaction.TYPE_UNKNOWN) transaction.label = Dict('name')(payment) transaction.amount = CleanDecimal(Dict('amount/value'))(payment) return transaction
def get_transactions(self): table = self.document.findall('//tbody')[0] for tr in table.xpath('tr'): textdate = tr.find('td[@class="op_date"]').text_content() textraw = tr.find('td[@class="op_label"]').text_content().strip() # The id will be rewrite op = Transaction(1) amount = op.clean_amount( tr.find('td[@class="op_amount"]').text_content()) id = hashlib.md5(textdate + textraw.encode('utf-8') + amount.encode('utf-8')).hexdigest() op.id = id op.parse(date=date(*reversed([int(x) for x in textdate.split('/')])), raw=textraw) # force the use of website category op.category = unicode(tr.find('td[@class="op_type"]').text) op.amount = Decimal(amount) yield op
def generate_single_transaction(self): """ Generate a fake transaction. """ now = datetime.datetime.now() transaction = Transaction() transaction.type = self.generate_type() n = random.randrange(100) if n < 2: # with a 2% rate, generate a special operation to test duplicates # (happening on 4th of current month). transaction.amount = Decimal(-300.0) transaction.label = "Loyer" transaction.raw = "Loyer habitation" transaction.date = self.generate_date(4, 4, now.month, now.month) return transaction transaction.date = self.generate_date(1, min(now.day, 28), 1, max(1, now.month - 1)) if n < 15: transaction.label, transaction.raw = self.generate_label( positive=True ) transaction.amount = Decimal( random.randint(100, 800) + random.random() ) return transaction if n < 30: transaction.rdate = transaction.date elif n < 60: transaction.rdate = None transaction.amount = Decimal(random.randint(-60, 0) + random.random()) transaction.label, transaction.raw = self.generate_label() transaction.type = self.generate_type() return transaction
def get_history(self, account): if not account._consultable: raise NotImplementedError() offset = 0 next_page = True while next_page: r = self.open( '/transactionnel/services/applications/operations/get/%(number)s/%(nature)s/00/%(currency)s/%(startDate)s/%(endDate)s/%(offset)s/%(limit)s' % { 'number': account._number, 'nature': account._nature, 'currency': account.currency, 'startDate': '2000-01-01', 'endDate': date.today().strftime('%Y-%m-%d'), 'offset': offset, 'limit': 50 }) next_page = False offset += 50 next_page = True for op in r.json()['content']['operations']: t = Transaction() t.id = op['id'] t.amount = Decimal(str(op['montant'])) t.date = date.fromtimestamp( op.get('dateDebit', op.get('dateOperation')) / 1000) t.rdate = date.fromtimestamp( op.get('dateOperation', op.get('dateDebit')) / 1000) t.vdate = date.fromtimestamp( op.get('dateValeur', op.get('dateDebit', op.get('dateOperation'))) / 1000) if 'categorie' in op: t.category = op['categorie'] t.label = op['libelle'] t.raw = ' '.join([op['libelle']] + op['details']) yield t
def get_transactions(self, index): i = 0 for table in self.document.xpath('//table'): try: textdate = table.find('.//td[@class="date"]').text_content() except AttributeError: continue # Do not parse transactions already parsed if i < index: i += 1 continue if textdate == 'hier': textdate = (date.today() - timedelta(days=1)).strftime('%d/%m/%Y') elif textdate == "aujourd'hui": textdate = date.today().strftime('%d/%m/%Y') else: frenchmonth = textdate.split(' ')[1] month = self.monthvalue[frenchmonth] textdate = textdate.replace(' ', '') textdate = textdate.replace(frenchmonth, '/%s/' %month) # We use lower for compatibility with old website textraw = table.find('.//td[@class="lbl"]').text_content().strip().lower() # The id will be rewrite op = Transaction(1) amount = op.clean_amount(table.xpath('.//td[starts-with(@class, "amount")]')[0].text_content()) id = hashlib.md5(textdate.encode('utf-8') + textraw.encode('utf-8') + amount.encode('utf-8')).hexdigest() op.id = id op.parse(date = date(*reversed([int(x) for x in textdate.split('/')])), raw = textraw) category = table.find('.//td[@class="picto"]/span') category = unicode(category.attrib['class'].split('-')[0].lower()) try: op.category = self.catvalue[category] except: op.category = category op.amount = Decimal(amount) yield op
def iter_history(self, data): for hist in self.doc['operationsIndividuelles']: if len(hist['instructions']) > 0: if 'nomDispositif' in hist['instructions'][0] and \ hist['instructions'][0]['nomDispositif'] + hist['instructions'][0]['codeDispositif'] == data['acc'].label + data['acc'].id: tr = Transaction() tr.amount = Decimal(hist['montantNet']) + Decimal( hist['montantNetAbondement']) tr.rdate = datetime.strptime( hist['dateComptabilisation'].split('T')[0], '%Y-%m-%d') tr.date = tr.rdate tr.label = hist[ 'libelleOperation'] if 'libelleOperation' in hist else hist[ 'libelleCommunication'] tr.type = Transaction.TYPE_UNKNOWN yield tr if data['total'] > data['params']['limit'] * ( data['params']['offset'] + 1): offset = data['params']['offset'] self.url = self.url.replace('&offset=' + str(offset), '&offset=' + str(offset + 1)) data['params']['offset'] += 1 raise NextPage(self.url)
def iter_history(self, account): if account not in self.histories: histories = [] for activity in self.request( '/user/%s/project/%s/activity' % (self.users['userId'], account.number))['activities']: m = re.search(u'([\d\.]+)(?=[\s]+€|[\s]+euro)', activity['details']) if "Souscription" not in activity['title'] and not m: continue t = Transaction() t.label = "%s - %s" % (" ".join( activity['type'].split("_")), activity['title']) t.date = Date().filter(activity['date']) t.type = Transaction.TYPE_BANK amount = account._startbalance if not m else "-%s" % m.group( 1) if "FRAIS" in activity['type'] else m.group(1) t.amount = CleanDecimal().filter(amount) histories.append(t) self.histories[account] = histories return self.histories[account]
def iter_history(self, account): if not self.islogged: self.login() page = "https://www.cmb.fr/domiweb/prive/particulier/releve/" if account._cmbtype == 'D': page += "10-releve.act" else: page += "2-releve.act" page += "?noPageReleve=1&indiceCompte=" page += account._cmbvaleur page += "&typeCompte=" page += account._cmbvaleur2 page += "&deviseOrigineEcran=EUR" data = self.browser.open(page).content parser = etree.HTMLParser() tree = etree.parse(StringIO(data), parser) tables = tree.xpath('/html/body/table') if len(tables) == 0: title = tree.xpath('/html/head/title')[0].text if title == u"Utilisateur non identifié": self.login() data = self.browser.open(page).content parser = etree.HTMLParser() tree = etree.parse(StringIO(data), parser) tables = tree.xpath('/html/body/table') if len(tables) == 0: raise ParseError() else: raise ParseError() i = 0 for table in tables: if table.get('id') != "tableMouvements": continue for tr in table.getiterator('tr'): if (tr.get('class') != 'LnTit' and tr.get('class') != 'LnTot'): operation = Transaction(i) td = tr.xpath('td') div = td[1].xpath('div') d = div[0].text.split('/') operation.date = date(*reversed([int(x) for x in d])) div = td[2].xpath('div') label = div[0].xpath('a')[0].text.replace('\n', '') operation.raw = unicode(' '.join(label.split())) for pattern, _type, _label in self.LABEL_PATTERNS: mm = pattern.match(operation.raw) if mm: operation.type = _type operation.label = sub('[ ]+', ' ', _label % mm.groupdict()).strip() break amount = td[3].text if amount.count(',') != 1: amount = td[4].text amount = amount.replace(',', '.').replace(u'\xa0', '') operation.amount = Decimal(amount) else: amount = amount.replace(',', '.').replace(u'\xa0', '') operation.amount = -Decimal(amount) i += 1 yield operation