def iter_history(self, account): # Load i18n for type translation self.i18np.open(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.open(data=data).get_transactions(): t = Transaction() t.id = trans["referenceOperationIndividuelle"] 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 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 for op in r.json()['content']['operations']: next_page = True 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 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 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 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 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_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 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 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 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, 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 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['Posted Date :'] ref = xdescs.get('Reference Number:') or '' if amount.startswith('(') and amount.endswith(')'): 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 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 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 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/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 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 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 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_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_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 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 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_history(self, account): if not account._consultable: raise NotImplementedError() 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 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 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 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 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 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, account): # Load i18n for type translation self.i18np.open(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.open(data=data).get_transactions(): t = Transaction() t.id = trans["referenceOperationIndividuelle"] 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 _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 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 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, 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 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 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
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 iter_transactions(self, account): csv = self.document if len(csv.header) == 42 or len(csv.header) == 43: # Merchant multi-currency account # 42 is for when the user can't access the balance on the website # 43 is for full acces to the account DATE = 0 TIME = 1 NAME = 3 TYPE = 4 if csv.header[7] == "Devise": CURRENCY = 7 GROSS = 8 FEE = 9 NET = 10 FROM = 11 TO = 12 TRANS_ID = 13 ITEM = 16 SITE = -1 else: CURRENCY = 6 GROSS = 7 FEE = 8 NET = 9 FROM = 10 TO = 11 TRANS_ID = 12 ITEM = 15 SITE = 24 elif len(csv.header) == 11: # Regular multi-currency account DATE = 0 TIME = 1 NAME = 3 TYPE = 4 CURRENCY = 6 GROSS = -1 FEE = -1 NET = 7 FROM = -1 TO = -1 TRANS_ID = -1 ITEM = -1 SITE = -1 else: raise ValueError('CSV fields count of %i is not supported' % len(csv.header)) for row in csv.rows: # we filter transaction currceny to match account currency, except if we don't now the account currency # we ignore canceled transactions if (account.balance != NotAvailable and account.get_currency(row[CURRENCY]) != account.currency) or row[NET] == '...': continue # analog to dict.get() get = lambda i, v=None: row[i] if 0 <= i < len(row) else v trans = Transaction(get(TRANS_ID, u'')) # silly American locale if re.search(r'\d\.\d\d$', row[NET]): date = datetime.datetime.strptime(row[DATE] + ' ' + row[TIME], "%m/%d/%Y %H:%M:%S") else: date = datetime.datetime.strptime(row[DATE] + ' ' + row[TIME], "%d/%m/%Y %H:%M:%S") trans.date = date trans.rdate = date line = row[NAME] if get(ITEM): line += u' ' + row[ITEM] if get(SITE): line += u"(" + row[SITE] + u")" trans.raw = line trans.label = row[NAME] if row[TYPE].startswith(u'Update to eCheck') or \ row[TYPE].startswith(u'Order'): continue if row[TYPE].endswith(u'Credit Card') or row[TYPE].endswith(u'carte bancaire'): trans.type = Transaction.TYPE_CARD elif row[TYPE].endswith(u'Payment Sent') or row[TYPE].startswith(u'Paiement'): trans.type = Transaction.TYPE_ORDER elif row[TYPE] in (u'Currency Conversion', u'Conversion de devise'): trans.type = Transaction.TYPE_BANK else: trans.type = Transaction.TYPE_UNKNOWN # Net is what happens after the fee (0 for most users), so what is the most "real" trans.amount = AmTr.decimal_amount(row[NET]) trans._gross = AmTr.decimal_amount(get(GROSS, row[NET])) trans._fees = AmTr.decimal_amount(get(FEE, u'0.00')) trans._to = get(TO) trans._from = get(FROM) yield trans
def iter_transactions(self, account): DATE = 0 TIME = 1 NAME = 3 TYPE = 4 CURRENCY = 6 GROSS = 7 FEE = 8 NET = 9 FROM = 10 TO = 11 TRANS_ID = 12 ITEM = 15 SITE = 24 csv = self.document for row in csv.rows: # we filter accounts by currency if account.get_currency(row[CURRENCY]) != account.currency: continue trans = Transaction(row[TRANS_ID]) # silly American locale if re.search(r'\d\.\d\d$', row[NET]): date = datetime.datetime.strptime(row[DATE] + ' ' + row[TIME], "%m/%d/%Y %I:%M:%S %p") else: date = datetime.datetime.strptime(row[DATE] + ' ' + row[TIME], "%d/%m/%Y %H:%M:%S") trans.date = date trans.rdate = date line = row[NAME] if row[ITEM]: line += u' ' + row[ITEM] if row[SITE]: line += u"(" + row[SITE] + u")" trans.raw = line trans.label = row[NAME] if row[TYPE].endswith(u'Credit Card') or row[TYPE].endswith(u'carte bancaire'): trans.type = Transaction.TYPE_CARD elif row[TYPE].endswith(u'Payment Sent') or row[TYPE].startswith(u'Paiement'): trans.type = Transaction.TYPE_ORDER elif row[TYPE] in (u'Currency Conversion', u'Conversion de devise'): trans.type = Transaction.TYPE_BANK else: trans.type = Transaction.TYPE_UNKNOWN # Net is what happens after the fee (0 for most users), so what is the most "real" trans.amount = clean_amount(row[NET]) trans._gross = clean_amount(row[GROSS]) trans._fees = clean_amount(row[FEE]) trans._to = row[TO] or None trans._from = row[FROM] or None yield trans
def _internal_get_transactions(self, categories, filter_func): transactions = self.request('/api/smrt/transactions?limit=1000') for t in transactions: if not filter_func(t): 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"])) if t["type"] == 'PT': new.type = Transaction.TYPE_CARD elif t["type"] == 'CT': new.type = Transaction.TYPE_TRANSFER elif t["type"] == 'WEE': new.type = Transaction.TYPE_BANK if t["category"] in categories: new.category = categories[t["category"]] yield new
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 __init__(self, id='', *args, **kwargs): Transaction.__init__(self, id, *args, **kwargs) self._logger = getLogger('FrenchTransaction')
def __init__(self, id="", *args, **kwargs): Transaction.__init__(self, id, *args, **kwargs) self._logger = getLogger("FrenchTransaction")
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(self, account): if not self.cookie: self.login() page = "/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" 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", page, {}, headers) response = conn.getresponse() data = response.read() conn.close return data data = do_http() 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 = do_http() parser = etree.HTMLParser() tree = etree.parse(StringIO(data), parser) tables = tree.xpath('/html/body/table') if len(tables) == 0: raise BrokenPageError() else: raise BrokenPageError() 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
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() 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