def test_deduplicate_both_unknown(): bank_to_accounts_map = { 'bankA': ['accountA'], 'bankB': ['accountB'], } transactions = [ schema.Transaction('bankA', 'accountA', 'unknownB', schema.Date(2017, 1, 1), 'a transaction', Decimal('10.00')), schema.Transaction('bankB', 'unknownA', 'accountB', schema.Date(2017, 1, 1), 'same transaction!', Decimal('10.00')), ] deduped = deduplicate.deduplicate(transactions, bank_to_accounts_map) assert_equals(len(deduped), 2) assert_in( schema.Transaction('bankA', 'accountA', 'unknownB', schema.Date(2017, 1, 1), 'a transaction', Decimal('10.00')), deduped) assert_in( schema.Transaction('bankB', 'unknownA', 'accountB', schema.Date(2017, 1, 1), 'same transaction!', Decimal('10.00')), deduped)
def test_deduplicate_ok(): bank_to_accounts_map = { 'bankA': ['accountA'], 'bankB': ['accountB'], } transactions = [ schema.Transaction('bankA', 'accountA', 'accountB', schema.Date(2017, 1, 1), 'a transaction', Decimal('10.00')), schema.Transaction('bankB', 'accountA', 'accountB', schema.Date(2017, 1, 1), 'same transaction!', Decimal('10.00')), ] deduped = deduplicate.deduplicate(transactions, bank_to_accounts_map) assert_equals(len(deduped), 1) expected = [ schema.Transaction('bankA + bankB', 'accountA', 'accountB', schema.Date(2017, 1, 1), 'a transaction + same transaction!', Decimal('10.00')), ] assert_equals(deduped, expected)
def transactions_by_account(fileobj): result = [] account = fileobj.readline().rstrip('\n') data = json.load(fileobj, parse_float=Decimal)['data'] # not sure if this is a valid assumption, but i'd rather wait for # it to break than introduce maybe dead code for injecting a # a starting balance. assert data['start_balance'] == 0 for transaction in data['transactions']: date_string, _ = transaction['datetime_created'].split('T') date = schema.Date(*map(int, date_string.split('-'))) if transaction['payment'] is not None: a = transaction['payment']['actor']['username'] b = transaction['payment']['target']['user']['username'] action = transaction['payment']['action'] if a == account: other = b b = '' elif b == account: other = a a = '' else: assert False if action == 'pay': from_to = [a, b] else: assert action == 'charge' from_to = [b, a] elif transaction['capture'] is not None: assert transaction['capture']['authorization']['user'][ 'username'] == account transaction['note'] = transaction['capture']['authorization'][ 'descriptor'] other = transaction['note'] from_to = [account, ''] else: assert False funding = transaction.get('funding_source') if funding is not None and funding['name'] != 'Venmo balance': assert from_to[0] == account result.append( schema.Transaction( '', account, date, json.dumps({ 'other': funding['name'], 'note': 'fund ' + transaction['note'] }), Decimal(transaction['amount']))) result.append( schema.Transaction( from_to[0], from_to[1], date, json.dumps({ 'other': other, 'note': transaction['note'] }), Decimal(transaction['amount']))) assert compute_balance(account, result) == data['end_balance'] return {account: result}
def test_deduplicate_unmatched_missing(): bank_to_accounts_map = { 'bankA': ['accountA'], 'bankB': ['accountB'], } transactions = [ schema.Transaction('bankA', 'accountA', 'accountB', schema.Date(2017, 1, 1), 'a transaction', Decimal('10.00')), ] deduped = deduplicate.deduplicate(transactions, bank_to_accounts_map) expected = [ schema.Transaction('bankA', 'accountA', 'unmatched: accountB', schema.Date(2017, 1, 1), 'a transaction', Decimal('10.00')), ] assert_equals(deduped, expected)
def transactions_by_account(fileobj): account_name = fileobj.readline().rstrip('\n') balance = Decimal(fileobj.readline().rstrip('\n')) result = [] lines = list(csv.reader(fileobj))[1:] for date, transaction_type, description, _, signed_amount_str in lines: signed_amount = Decimal(signed_amount_str.replace(',', '')) frm, to = '', account_name if signed_amount > 0: assert transaction_type == 'CREDIT' else: assert signed_amount < 0 assert transaction_type == 'DEBIT' frm, to = to, frm month, day, year = map(int, date.split('/')) result.append( schema.Transaction(frm, to, schema.Date(year, month, day), description, signed_amount.copy_abs())) correct_balance(account_name, balance, result) return {account_name: result}
def test_generate_data_json(): transactions = [ schema.Transaction( 'bankA', 'src', 'dest', schema.Date(1940, '3', 26), 'something', Decimal('29.99'), 'foo', ), ] actual_parsed = json.loads( report._generate_data_json(transactions, ['some_account']) ) expected_parsed = { 'columns': ['bank', 'source', 'to', 'date', 'description', 'amount', 'category'], 'transactions': [['bankA', 'src', 'dest', '1940/03/26', 'something', '29.99', 'foo']], 'accounts': ['some_account'], } assert_equal(actual_parsed, expected_parsed)
def _statement_transactions(st): result = [] acctname = str(st.invacctfrom.acctid) for t in st.transactions: if hasattr(t, 'total'): # ignore investment buy/sell continue amount = t.trnamt frm, to = '', acctname if amount < 0: frm, to = to, frm amount *= -1 result.append( schema.Transaction( frm, to, schema.Date(t.dtposted.year, t.dtposted.month, t.dtposted.day), str(t.memo), Decimal(amount), )) net = _networth(st) correct_balance(acctname, net, result) return result
def _oldest_transaction_date(transactions): if len(transactions) == 0: now = datetime.datetime.now() return schema.Date(now.year, now.month, now.day) return min(t.date for t in transactions)