Rename "currency" to "commodity"
Apologies to hypothetical API users
This commit is contained in:
parent
5080aa7ba7
commit
b200501e37
@ -1,7 +1,7 @@
|
||||
# Set up how we will call Ledger
|
||||
ledger_file: /path/to/ledger.journal
|
||||
ledger_args: ['--pedantic', '--recursive-aliases']
|
||||
report_currency: ['$', True] # True if prefix, False if suffix
|
||||
report_commodity: ['$', True] # True if prefix, False if suffix
|
||||
|
||||
# Tell ledger-pyreport about the top-level account categories
|
||||
assets_account: Assets
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Set up how we will call Ledger
|
||||
ledger_file: demo/ledger.journal
|
||||
ledger_args: []
|
||||
report_currency: ['$', True] # True if prefix, False if suffix
|
||||
report_commodity: ['$', True] # True if prefix, False if suffix
|
||||
|
||||
# Tell ledger-pyreport about the top-level account categories
|
||||
assets_account: Assets
|
||||
|
@ -40,27 +40,27 @@ def trial():
|
||||
compare = int(flask.request.args['compare'])
|
||||
cash = flask.request.args.get('cash', False)
|
||||
|
||||
report_currency = Currency(*config['report_currency'])
|
||||
report_commodity = Commodity(*config['report_commodity'])
|
||||
|
||||
if compare == 0:
|
||||
# Get trial balance
|
||||
l = ledger.raw_transactions_at_date(date)
|
||||
if cash:
|
||||
l = accounting.ledger_to_cash(l, report_currency)
|
||||
trial_balance = accounting.trial_balance(l, date, pstart, report_currency)
|
||||
l = accounting.ledger_to_cash(l, report_commodity)
|
||||
trial_balance = accounting.trial_balance(l, date, pstart, report_commodity)
|
||||
|
||||
total_dr = Amount(0, report_currency)
|
||||
total_cr = Amount(0, report_currency)
|
||||
total_dr = Amount(0, report_commodity)
|
||||
total_cr = Amount(0, report_commodity)
|
||||
|
||||
for account in l.accounts.values():
|
||||
# Display in "cost basis" as we have already accounted for unrealised gains
|
||||
balance = trial_balance.get_balance(account).exchange(report_currency, True)
|
||||
balance = trial_balance.get_balance(account).exchange(report_commodity, True)
|
||||
if balance > 0:
|
||||
total_dr += balance
|
||||
else:
|
||||
total_cr -= balance
|
||||
|
||||
return flask.render_template('trial.html', date=date, pstart=pstart, trial_balance=trial_balance, accounts=sorted(l.accounts.values(), key=lambda a: a.name), total_dr=total_dr, total_cr=total_cr, report_currency=report_currency)
|
||||
return flask.render_template('trial.html', date=date, pstart=pstart, trial_balance=trial_balance, accounts=sorted(l.accounts.values(), key=lambda a: a.name), total_dr=total_dr, total_cr=total_cr, report_commodity=report_commodity)
|
||||
else:
|
||||
# Get multiple trial balances for comparison
|
||||
dates = [date.replace(year=date.year - i) for i in range(0, compare + 1)]
|
||||
@ -68,16 +68,16 @@ def trial():
|
||||
|
||||
l = ledger.raw_transactions_at_date(date)
|
||||
if cash:
|
||||
l = accounting.ledger_to_cash(l, report_currency)
|
||||
trial_balances = [accounting.trial_balance(l.clone(), d, p, report_currency) for d, p in zip(dates, pstarts)]
|
||||
l = accounting.ledger_to_cash(l, report_commodity)
|
||||
trial_balances = [accounting.trial_balance(l.clone(), d, p, report_commodity) for d, p in zip(dates, pstarts)]
|
||||
|
||||
# Delete accounts with always zero balances
|
||||
accounts = sorted(l.accounts.values(), key=lambda a: a.name)
|
||||
for account in accounts[:]:
|
||||
if all(t.get_balance(account).exchange(report_currency, True).near_zero for t in trial_balances):
|
||||
if all(t.get_balance(account).exchange(report_commodity, True).near_zero for t in trial_balances):
|
||||
accounts.remove(account)
|
||||
|
||||
return flask.render_template('trial_multiple.html', trial_balances=trial_balances, accounts=accounts, report_currency=report_currency, cash=cash)
|
||||
return flask.render_template('trial_multiple.html', trial_balances=trial_balances, accounts=accounts, report_commodity=report_commodity, cash=cash)
|
||||
|
||||
@app.route('/balance')
|
||||
def balance():
|
||||
@ -89,19 +89,19 @@ def balance():
|
||||
dates = [date.replace(year=date.year - i) for i in range(0, compare + 1)]
|
||||
pstarts = [pstart.replace(year=pstart.year - i) for i in range(0, compare + 1)]
|
||||
|
||||
report_currency = Currency(*config['report_currency'])
|
||||
report_commodity = Commodity(*config['report_commodity'])
|
||||
l = ledger.raw_transactions_at_date(date)
|
||||
if cash:
|
||||
l = accounting.ledger_to_cash(l, report_currency)
|
||||
balance_sheets = [accounting.balance_sheet(accounting.trial_balance(l.clone(), d, p, report_currency)) for d, p in zip(dates, pstarts)]
|
||||
l = accounting.ledger_to_cash(l, report_commodity)
|
||||
balance_sheets = [accounting.balance_sheet(accounting.trial_balance(l.clone(), d, p, report_commodity)) for d, p in zip(dates, pstarts)]
|
||||
|
||||
# Delete accounts with always zero balances
|
||||
accounts = list(l.accounts.values())
|
||||
for account in accounts[:]:
|
||||
if all(b.get_balance(account).exchange(report_currency, True).near_zero and b.get_total(account).exchange(report_currency, True).near_zero for b in balance_sheets):
|
||||
if all(b.get_balance(account).exchange(report_commodity, True).near_zero and b.get_total(account).exchange(report_commodity, True).near_zero for b in balance_sheets):
|
||||
accounts.remove(account)
|
||||
|
||||
return flask.render_template('balance.html', ledger=l, balance_sheets=balance_sheets, accounts=accounts, config=config, report_currency=report_currency, cash=cash)
|
||||
return flask.render_template('balance.html', ledger=l, balance_sheets=balance_sheets, accounts=accounts, config=config, report_commodity=report_commodity, cash=cash)
|
||||
|
||||
def describe_period(date_end, date_beg):
|
||||
if date_end == (date_beg.replace(year=date_beg.year + 1) - timedelta(days=1)):
|
||||
@ -122,11 +122,11 @@ def pandl():
|
||||
dates_beg = [date_beg.replace(year=date_beg.year - i) for i in range(0, compare + 1)]
|
||||
dates_end = [date_end.replace(year=date_end.year - i) for i in range(0, compare + 1)]
|
||||
|
||||
report_currency = Currency(*config['report_currency'])
|
||||
report_commodity = Commodity(*config['report_commodity'])
|
||||
l = ledger.raw_transactions_at_date(date_end)
|
||||
if cash:
|
||||
l = accounting.ledger_to_cash(l, report_currency)
|
||||
pandls = [accounting.trial_balance(l.clone(), de, db, report_currency) for de, db in zip(dates_end, dates_beg)]
|
||||
l = accounting.ledger_to_cash(l, report_commodity)
|
||||
pandls = [accounting.trial_balance(l.clone(), de, db, report_commodity) for de, db in zip(dates_end, dates_beg)]
|
||||
|
||||
# Delete accounts with always zero balances
|
||||
accounts = list(l.accounts.values())
|
||||
@ -134,7 +134,7 @@ def pandl():
|
||||
if all(p.get_balance(account) == 0 and p.get_total(account) == 0 for p in pandls):
|
||||
accounts.remove(account)
|
||||
|
||||
return flask.render_template('pandl.html', period=describe_period(date_end, date_beg), ledger=l, pandls=pandls, accounts=accounts, config=config, report_currency=report_currency, cash=cash, scope=scope)
|
||||
return flask.render_template('pandl.html', period=describe_period(date_end, date_beg), ledger=l, pandls=pandls, accounts=accounts, config=config, report_commodity=report_commodity, cash=cash, scope=scope)
|
||||
|
||||
@app.route('/cashflow')
|
||||
def cashflow():
|
||||
@ -146,7 +146,7 @@ def cashflow():
|
||||
dates_beg = [date_beg.replace(year=date_beg.year - i) for i in range(0, compare + 1)]
|
||||
dates_end = [date_end.replace(year=date_end.year - i) for i in range(0, compare + 1)]
|
||||
|
||||
report_currency = Currency(*config['report_currency'])
|
||||
report_commodity = Commodity(*config['report_commodity'])
|
||||
l = ledger.raw_transactions_at_date(date_end)
|
||||
|
||||
cash_accounts = [a for a in l.accounts.values() if a.is_cash]
|
||||
@ -157,18 +157,18 @@ def cashflow():
|
||||
cashflows = []
|
||||
profits = []
|
||||
for de, db in zip(dates_end, dates_beg):
|
||||
tb = accounting.trial_balance(l.clone(), db - timedelta(days=1), db, report_currency)
|
||||
opening_balances.append(sum((tb.get_balance(a) for a in cash_accounts), Balance()).exchange(report_currency, True))
|
||||
tb = accounting.trial_balance(l.clone(), db - timedelta(days=1), db, report_commodity)
|
||||
opening_balances.append(sum((tb.get_balance(a) for a in cash_accounts), Balance()).exchange(report_commodity, True))
|
||||
|
||||
tb = accounting.trial_balance(l.clone(), de, db, report_currency)
|
||||
closing_balances.append(sum((tb.get_balance(a) for a in cash_accounts), Balance()).exchange(report_currency, True))
|
||||
tb = accounting.trial_balance(l.clone(), de, db, report_commodity)
|
||||
closing_balances.append(sum((tb.get_balance(a) for a in cash_accounts), Balance()).exchange(report_commodity, True))
|
||||
|
||||
if method == 'direct':
|
||||
# Determine transactions affecting cash assets
|
||||
cashflows.append(accounting.account_flows(tb.ledger, de, db, cash_accounts, True))
|
||||
else:
|
||||
# Determine net profit (loss)
|
||||
profits.append(-(tb.get_total(tb.ledger.get_account(config['income_account'])) + tb.get_total(tb.ledger.get_account(config['expenses_account'])) + tb.get_total(tb.ledger.get_account(config['oci_account']))).exchange(report_currency, True))
|
||||
profits.append(-(tb.get_total(tb.ledger.get_account(config['income_account'])) + tb.get_total(tb.ledger.get_account(config['expenses_account'])) + tb.get_total(tb.ledger.get_account(config['oci_account']))).exchange(report_commodity, True))
|
||||
|
||||
# Determine transactions affecting equity, liabilities and non-cash assets
|
||||
noncash_accounts = [a for a in l.accounts.values() if a.is_equity or a.is_liability or (a.is_asset and not a.is_cash)]
|
||||
@ -181,9 +181,9 @@ def cashflow():
|
||||
accounts.remove(account)
|
||||
|
||||
if method == 'direct':
|
||||
return flask.render_template('cashflow_direct.html', period=describe_period(date_end, date_beg), ledger=l, cashflows=cashflows, opening_balances=opening_balances, closing_balances=closing_balances, accounts=accounts, config=config, report_currency=report_currency)
|
||||
return flask.render_template('cashflow_direct.html', period=describe_period(date_end, date_beg), ledger=l, cashflows=cashflows, opening_balances=opening_balances, closing_balances=closing_balances, accounts=accounts, config=config, report_commodity=report_commodity)
|
||||
else:
|
||||
return flask.render_template('cashflow_indirect.html', period=describe_period(date_end, date_beg), ledger=l, cashflows=cashflows, profits=profits, opening_balances=opening_balances, closing_balances=closing_balances, accounts=accounts, config=config, report_currency=report_currency)
|
||||
return flask.render_template('cashflow_indirect.html', period=describe_period(date_end, date_beg), ledger=l, cashflows=cashflows, profits=profits, opening_balances=opening_balances, closing_balances=closing_balances, accounts=accounts, config=config, report_commodity=report_commodity)
|
||||
|
||||
@app.route('/transactions')
|
||||
def transactions():
|
||||
@ -193,24 +193,24 @@ def transactions():
|
||||
cash = flask.request.args.get('cash', False)
|
||||
commodity = flask.request.args.get('commodity', False)
|
||||
|
||||
report_currency = Currency(*config['report_currency'])
|
||||
report_commodity = Commodity(*config['report_commodity'])
|
||||
|
||||
# General ledger
|
||||
l = ledger.raw_transactions_at_date(date_end)
|
||||
if cash:
|
||||
l = accounting.ledger_to_cash(l, report_currency)
|
||||
l = accounting.ledger_to_cash(l, report_commodity)
|
||||
|
||||
# Unrealized gains
|
||||
l = accounting.trial_balance(l, date_end, date_beg, report_currency).ledger
|
||||
l = accounting.trial_balance(l, date_end, date_beg, report_commodity).ledger
|
||||
|
||||
if not account:
|
||||
# General Ledger
|
||||
transactions = [t for t in l.transactions if t.date <= date_end and t.date >= date_beg]
|
||||
|
||||
total_dr = sum((p.amount for t in transactions for p in t.postings if p.amount > 0), Balance()).exchange(report_currency, True)
|
||||
total_cr = sum((p.amount for t in transactions for p in t.postings if p.amount < 0), Balance()).exchange(report_currency, True)
|
||||
total_dr = sum((p.amount for t in transactions for p in t.postings if p.amount > 0), Balance()).exchange(report_commodity, True)
|
||||
total_cr = sum((p.amount for t in transactions for p in t.postings if p.amount < 0), Balance()).exchange(report_commodity, True)
|
||||
|
||||
return flask.render_template('transactions.html', date_beg=date_beg, date_end=date_end, period=describe_period(date_end, date_beg), account=None, ledger=l, transactions=transactions, total_dr=total_dr, total_cr=total_cr, report_currency=report_currency, cash=cash)
|
||||
return flask.render_template('transactions.html', date_beg=date_beg, date_end=date_end, period=describe_period(date_end, date_beg), account=None, ledger=l, transactions=transactions, total_dr=total_dr, total_cr=total_cr, report_commodity=report_commodity, cash=cash)
|
||||
elif commodity:
|
||||
# Account Transactions with commodity detail
|
||||
account = l.get_account(account)
|
||||
@ -221,18 +221,18 @@ def transactions():
|
||||
closing_balance = accounting.trial_balance_raw(l, date_end, date_beg).get_balance(account).clean()
|
||||
|
||||
def matching_posting(transaction, amount):
|
||||
return next((p for p in transaction.postings if p.account == account and p.amount.currency == amount.currency), None)
|
||||
return next((p for p in transaction.postings if p.account == account and p.amount.commodity == amount.commodity), None)
|
||||
|
||||
return flask.render_template('transactions_commodity.html', date_beg=date_beg, date_end=date_end, period=describe_period(date_end, date_beg), account=account, ledger=l, transactions=transactions, opening_balance=opening_balance, closing_balance=closing_balance, report_currency=report_currency, cash=cash, timedelta=timedelta, matching_posting=matching_posting)
|
||||
return flask.render_template('transactions_commodity.html', date_beg=date_beg, date_end=date_end, period=describe_period(date_end, date_beg), account=account, ledger=l, transactions=transactions, opening_balance=opening_balance, closing_balance=closing_balance, report_commodity=report_commodity, cash=cash, timedelta=timedelta, matching_posting=matching_posting)
|
||||
else:
|
||||
# Account Transactions
|
||||
account = l.get_account(account)
|
||||
transactions = [t for t in l.transactions if t.date <= date_end and t.date >= date_beg and any(p.account == account for p in t.postings)]
|
||||
|
||||
opening_balance = accounting.trial_balance_raw(l, date_beg - timedelta(days=1), date_beg).get_balance(account).exchange(report_currency, True)
|
||||
closing_balance = accounting.trial_balance_raw(l, date_end, date_beg).get_balance(account).exchange(report_currency, True)
|
||||
opening_balance = accounting.trial_balance_raw(l, date_beg - timedelta(days=1), date_beg).get_balance(account).exchange(report_commodity, True)
|
||||
closing_balance = accounting.trial_balance_raw(l, date_end, date_beg).get_balance(account).exchange(report_commodity, True)
|
||||
|
||||
return flask.render_template('transactions.html', date_beg=date_beg, date_end=date_end, period=describe_period(date_end, date_beg), account=account, ledger=l, transactions=transactions, opening_balance=opening_balance, closing_balance=closing_balance, report_currency=report_currency, cash=cash, timedelta=timedelta)
|
||||
return flask.render_template('transactions.html', date_beg=date_beg, date_end=date_end, period=describe_period(date_end, date_beg), account=account, ledger=l, transactions=transactions, opening_balance=opening_balance, closing_balance=closing_balance, report_commodity=report_commodity, cash=cash, timedelta=timedelta)
|
||||
|
||||
@app.route('/transaction')
|
||||
def transaction():
|
||||
@ -240,12 +240,12 @@ def transaction():
|
||||
cash = flask.request.args.get('cash', False)
|
||||
commodity = flask.request.args.get('commodity', False)
|
||||
|
||||
report_currency = Currency(*config['report_currency'])
|
||||
report_commodity = Commodity(*config['report_commodity'])
|
||||
|
||||
# General ledger
|
||||
l = ledger.raw_transactions_at_date(None)
|
||||
if cash:
|
||||
l = accounting.ledger_to_cash(l, report_currency)
|
||||
l = accounting.ledger_to_cash(l, report_commodity)
|
||||
|
||||
transaction = next((t for t in l.transactions if str(t.id) == tid))
|
||||
|
||||
@ -253,11 +253,11 @@ def transaction():
|
||||
total_dr = sum((p.amount for p in transaction.postings if p.amount > 0), Balance()).clean()
|
||||
total_cr = sum((p.amount for p in transaction.postings if p.amount < 0), Balance()).clean()
|
||||
totals = itertools.zip_longest(total_dr.amounts, total_cr.amounts)
|
||||
return flask.render_template('transaction_commodity.html', ledger=l, transaction=transaction, totals=totals, total_dr=total_dr.exchange(report_currency, True), total_cr=total_cr.exchange(report_currency, True), report_currency=report_currency, cash=cash)
|
||||
return flask.render_template('transaction_commodity.html', ledger=l, transaction=transaction, totals=totals, total_dr=total_dr.exchange(report_commodity, True), total_cr=total_cr.exchange(report_commodity, True), report_commodity=report_commodity, cash=cash)
|
||||
else:
|
||||
total_dr = sum((p.amount for p in transaction.postings if p.amount > 0), Balance()).exchange(report_currency, True)
|
||||
total_cr = sum((p.amount for p in transaction.postings if p.amount < 0), Balance()).exchange(report_currency, True)
|
||||
return flask.render_template('transaction.html', ledger=l, transaction=transaction, total_dr=total_dr, total_cr=total_cr, report_currency=report_currency, cash=cash)
|
||||
total_dr = sum((p.amount for p in transaction.postings if p.amount > 0), Balance()).exchange(report_commodity, True)
|
||||
total_cr = sum((p.amount for p in transaction.postings if p.amount < 0), Balance()).exchange(report_commodity, True)
|
||||
return flask.render_template('transaction.html', ledger=l, transaction=transaction, total_dr=total_dr, total_cr=total_cr, report_commodity=report_commodity, cash=cash)
|
||||
|
||||
# Template filters
|
||||
|
||||
@ -289,21 +289,21 @@ def filter_amount_positive(amt):
|
||||
return flask.Markup('<span title="{}">{:,.2f}</span>'.format(amt.tostr(False), amt.amount).replace(',', ' '))
|
||||
|
||||
@app.template_filter('bc')
|
||||
def filter_currency_positive(amt):
|
||||
if amt.currency.is_prefix:
|
||||
return flask.Markup('<span title="{}">{}{:,.2f}</span>'.format(amt.tostr(False), amt.currency.name, amt.amount).replace(',', ' '))
|
||||
def filter_commodity_positive(amt):
|
||||
if amt.commodity.is_prefix:
|
||||
return flask.Markup('<span title="{}">{}{:,.2f}</span>'.format(amt.tostr(False), amt.commodity.name, amt.amount).replace(',', ' '))
|
||||
else:
|
||||
return flask.Markup('<span title="{}">{:,.2f} {}</span>'.format(amt.tostr(False), amt.amount, amt.currency.name).replace(',', ' '))
|
||||
return flask.Markup('<span title="{}">{:,.2f} {}</span>'.format(amt.tostr(False), amt.amount, amt.commodity.name).replace(',', ' '))
|
||||
|
||||
@app.template_filter('bt')
|
||||
def filter_currency_table_positive(amt, show_price, link=None):
|
||||
def filter_commodity_table_positive(amt, show_price, link=None):
|
||||
result = []
|
||||
if amt.currency.is_prefix:
|
||||
amt_str = filter_currency_positive(amt)
|
||||
if amt.commodity.is_prefix:
|
||||
amt_str = filter_commodity_positive(amt)
|
||||
cur_str = ''
|
||||
else:
|
||||
amt_str = '{:,.2f}'.format(amt.amount).replace(',', ' ')
|
||||
cur_str = amt.currency.name
|
||||
cur_str = amt.commodity.name
|
||||
|
||||
amt_full = amt.tostr(False)
|
||||
|
||||
@ -311,8 +311,8 @@ def filter_currency_table_positive(amt, show_price, link=None):
|
||||
result.append('<td><span title="{}">{}</span></td>'.format(amt_full, cur_str))
|
||||
|
||||
if show_price:
|
||||
if amt.currency.price:
|
||||
result.append('<td><span title="{}">{{{}}}</span></td>'.format(amt_full, filter_currency_positive(amt.currency.price)))
|
||||
if amt.commodity.price:
|
||||
result.append('<td><span title="{}">{{{}}}</span></td>'.format(amt_full, filter_commodity_positive(amt.commodity.price)))
|
||||
else:
|
||||
result.append('<td></td>')
|
||||
|
||||
@ -326,16 +326,16 @@ def debug_noncash_transactions():
|
||||
pstart = datetime.strptime(flask.request.args['pstart'], '%Y-%m-%d')
|
||||
account = flask.request.args.get('account')
|
||||
|
||||
report_currency = Currency(*config['report_currency'])
|
||||
report_commodity = Commodity(*config['report_commodity'])
|
||||
|
||||
l = ledger.raw_transactions_at_date(date)
|
||||
account = l.get_account(account)
|
||||
|
||||
transactions = [t for t in l.transactions if any(p.account == account for p in t.postings)]
|
||||
|
||||
accounting.account_to_cash(account, report_currency)
|
||||
accounting.account_to_cash(account, report_commodity)
|
||||
|
||||
return flask.render_template('debug_noncash_transactions.html', date=date, pstart=pstart, period=describe_period(date, pstart), account=account, ledger=l, transactions=transactions, report_currency=report_currency)
|
||||
return flask.render_template('debug_noncash_transactions.html', date=date, pstart=pstart, period=describe_period(date, pstart), account=account, ledger=l, transactions=transactions, report_commodity=report_commodity)
|
||||
|
||||
@app.route('/debug/imbalances')
|
||||
def debug_imbalances():
|
||||
@ -343,15 +343,15 @@ def debug_imbalances():
|
||||
pstart = datetime.strptime(flask.request.args['pstart'], '%Y-%m-%d')
|
||||
cash = flask.request.args.get('cash', False)
|
||||
|
||||
report_currency = Currency(*config['report_currency'])
|
||||
report_commodity = Commodity(*config['report_commodity'])
|
||||
|
||||
l = ledger.raw_transactions_at_date(date)
|
||||
if cash:
|
||||
l = accounting.ledger_to_cash(l, report_currency)
|
||||
l = accounting.ledger_to_cash(l, report_commodity)
|
||||
|
||||
transactions = [t for t in l.transactions if t.date <= date and t.date >= pstart and not sum((p.amount for p in t.postings), Balance()).exchange(report_currency, True).near_zero]
|
||||
transactions = [t for t in l.transactions if t.date <= date and t.date >= pstart and not sum((p.amount for p in t.postings), Balance()).exchange(report_commodity, True).near_zero]
|
||||
|
||||
total_dr = sum((p.amount for t in transactions for p in t.postings if p.amount > 0), Balance()).exchange(report_currency, True)
|
||||
total_cr = sum((p.amount for t in transactions for p in t.postings if p.amount < 0), Balance()).exchange(report_currency, True)
|
||||
total_dr = sum((p.amount for t in transactions for p in t.postings if p.amount > 0), Balance()).exchange(report_commodity, True)
|
||||
total_cr = sum((p.amount for t in transactions for p in t.postings if p.amount < 0), Balance()).exchange(report_commodity, True)
|
||||
|
||||
return flask.render_template('transactions.html', date=date, pstart=pstart, period=describe_period(date, pstart), account=None, ledger=l, transactions=transactions, total_dr=total_dr, total_cr=total_cr, report_currency=report_currency, cash=cash)
|
||||
return flask.render_template('transactions.html', date=date, pstart=pstart, period=describe_period(date, pstart), account=None, ledger=l, transactions=transactions, total_dr=total_dr, total_cr=total_cr, report_commodity=report_commodity, cash=cash)
|
||||
|
@ -41,9 +41,9 @@ def trial_balance_raw(ledger, date, pstart):
|
||||
return tb
|
||||
|
||||
# Trial balance with unrealized gains and OCI
|
||||
def trial_balance(ledger, date, pstart, currency):
|
||||
tb_date, r_date = _add_unrealized_gains(trial_balance_raw(ledger, date, pstart), currency)
|
||||
tb_pstart, r_pstart = _add_unrealized_gains(trial_balance_raw(ledger, pstart - timedelta(days=1), pstart), currency)
|
||||
def trial_balance(ledger, date, pstart, commodity):
|
||||
tb_date, r_date = _add_unrealized_gains(trial_balance_raw(ledger, date, pstart), commodity)
|
||||
tb_pstart, r_pstart = _add_unrealized_gains(trial_balance_raw(ledger, pstart - timedelta(days=1), pstart), commodity)
|
||||
|
||||
for account in set(list(r_date.keys()) + list(r_pstart.keys())):
|
||||
if account in r_pstart:
|
||||
@ -66,7 +66,7 @@ def trial_balance(ledger, date, pstart, currency):
|
||||
return tb_date
|
||||
|
||||
# Adjust (in place) a trial balance for unrealized gains without accumulating OCI
|
||||
def _add_unrealized_gains(tb, currency):
|
||||
def _add_unrealized_gains(tb, commodity):
|
||||
results = {}
|
||||
unrealized_gain_account = tb.ledger.get_account(config['unrealized_gains'])
|
||||
|
||||
@ -74,8 +74,8 @@ def _add_unrealized_gains(tb, currency):
|
||||
if not account.is_market:
|
||||
continue
|
||||
|
||||
total_cost = tb.get_balance(account).exchange(currency, True)
|
||||
total_market = tb.get_balance(account).exchange(currency, False, tb.date, tb.ledger)
|
||||
total_cost = tb.get_balance(account).exchange(commodity, True)
|
||||
total_market = tb.get_balance(account).exchange(commodity, False, tb.date, tb.ledger)
|
||||
unrealized_gain = total_market - total_cost
|
||||
|
||||
if unrealized_gain != 0:
|
||||
@ -105,7 +105,7 @@ def balance_sheet(tb):
|
||||
|
||||
return tb
|
||||
|
||||
def account_to_cash(account, currency):
|
||||
def account_to_cash(account, commodity):
|
||||
# Apply FIFO methodology to match postings
|
||||
balance = [] # list of [posting, amount to balance, amount remaining, balancing list of [posting, amount balanced]]
|
||||
|
||||
@ -117,7 +117,7 @@ def account_to_cash(account, currency):
|
||||
pass
|
||||
else:
|
||||
# Try to balance postings
|
||||
amount_to_balance = posting.amount.exchange(currency, True).amount
|
||||
amount_to_balance = posting.amount.exchange(commodity, True).amount
|
||||
|
||||
while amount_to_balance != 0:
|
||||
balancing_posting = next((b for b in balance if b[2] != 0 and math.copysign(1, b[2]) != math.copysign(1, amount_to_balance)), None)
|
||||
@ -142,11 +142,11 @@ def account_to_cash(account, currency):
|
||||
|
||||
# Finalise balanced postings
|
||||
for orig_posting, amount_to_balance, amount_remaining, balancing_postings in balance:
|
||||
posting = Posting(orig_posting.transaction, orig_posting.account, Amount(amount_to_balance, currency))
|
||||
posting = Posting(orig_posting.transaction, orig_posting.account, Amount(amount_to_balance, commodity))
|
||||
posting.transaction.postings.append(posting)
|
||||
|
||||
for balancing_posting, amount_balanced in balancing_postings:
|
||||
posting.transaction.postings.append(Posting(posting.transaction, balancing_posting.account, Amount(amount_balanced, currency)))
|
||||
posting.transaction.postings.append(Posting(posting.transaction, balancing_posting.account, Amount(amount_balanced, commodity)))
|
||||
|
||||
if balancing_posting in balancing_posting.transaction.postings:
|
||||
balancing_posting.transaction.postings.remove(balancing_posting)
|
||||
@ -154,16 +154,16 @@ def account_to_cash(account, currency):
|
||||
if amount_remaining != 0:
|
||||
if posting.account.is_asset:
|
||||
# Cash - charge any unbalanced remainder to Other Income
|
||||
posting.transaction.postings.append(Posting(posting.transaction, account.ledger.get_account(config['cash_other_income']), Amount(-amount_remaining, currency)))
|
||||
posting.transaction.postings.append(Posting(posting.transaction, account.ledger.get_account(config['cash_other_income']), Amount(-amount_remaining, commodity)))
|
||||
else:
|
||||
# Liabilities, etc. - discard any unbalanced remainder
|
||||
posting.amount.amount -= amount_remaining
|
||||
|
||||
# Adjust (in place) a ledger to convert accounting to a cash basis
|
||||
def ledger_to_cash(ledger, currency):
|
||||
def ledger_to_cash(ledger, commodity):
|
||||
for account in list(ledger.accounts.values()):
|
||||
if not (account.is_cash or account.is_income or account.is_expense or account.is_equity):
|
||||
account_to_cash(account, currency)
|
||||
account_to_cash(account, commodity)
|
||||
|
||||
return ledger
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
{% for balance_sheet in balance_sheets %}
|
||||
{% set amount = (-balance_sheet.get_balance(account) if invert else balance_sheet.get_balance(account)).exchange(report_currency, True) %}
|
||||
{% set amount = (-balance_sheet.get_balance(account) if invert else balance_sheet.get_balance(account)).exchange(report_commodity, True) %}
|
||||
<td>
|
||||
{% if not amount.near_zero %}
|
||||
{% if account.name == config['current_year_earnings'] %}
|
||||
@ -74,14 +74,14 @@
|
||||
|
||||
<tr class="total">
|
||||
<td>Total {{ account_class.bits[-1] }} {{ label }}</td>
|
||||
{% for balance_sheet in balance_sheets %}<td>{{ (-balance_sheet.get_total(account_class) if invert else balance_sheet.get_total(account_class)).exchange(report_currency, True)|a }}</td>{% endfor %}
|
||||
{% for balance_sheet in balance_sheets %}<td>{{ (-balance_sheet.get_total(account_class) if invert else balance_sheet.get_total(account_class)).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
<tr><td colspan="2"> </td></tr>
|
||||
{% endfor %}
|
||||
|
||||
<tr class="total">
|
||||
<td>Total {{ label }}</td>
|
||||
{% for balance_sheet in balance_sheets %}<td>{{ (-balance_sheet.get_total(root) if invert else balance_sheet.get_total(root)).exchange(report_currency, True)|a }}</td>{% endfor %}
|
||||
{% for balance_sheet in balance_sheets %}<td>{{ (-balance_sheet.get_total(root) if invert else balance_sheet.get_total(root)).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
{% endmacro %}
|
||||
|
||||
@ -113,7 +113,7 @@
|
||||
|
||||
<tr class="total">
|
||||
<td>Total Equity</td>
|
||||
{% for balance_sheet in balance_sheets %}<td>{{ -balance_sheet.get_total(ledger.get_account(config['equity_account'])).exchange(report_currency, True)|a }}</td>{% endfor %}
|
||||
{% for balance_sheet in balance_sheets %}<td>{{ -balance_sheet.get_total(ledger.get_account(config['equity_account'])).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
</table>
|
||||
{% endblock %}
|
||||
|
@ -28,7 +28,7 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
{% for cashflow in cashflows %}
|
||||
{% set amount = (-cashflow.get_balance(account) if invert else cashflow.get_balance(account)).exchange(report_currency, True) %}
|
||||
{% set amount = (-cashflow.get_balance(account) if invert else cashflow.get_balance(account)).exchange(report_commodity, True) %}
|
||||
<td>{% if not amount.near_zero %}{{ amount|a('/transactions?' + {'date': cashflow.date.strftime('%Y-%m-%d'), 'pstart': cashflow.pstart.strftime('%Y-%m-%d'), 'account': account.name, 'cash': 'on' if cash else ''}|urlencode) }}{% endif %}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
@ -55,7 +55,7 @@
|
||||
{% endfor %}
|
||||
<tr class="total">
|
||||
<td>Net Cash Inflow (Outflow)</td>
|
||||
{% for cashflow in cashflows %}<td>{{ cashflow.get_total(ledger.root_account).exchange(report_currency, True)|a }}</td>{% endfor %}
|
||||
{% for cashflow in cashflows %}<td>{{ cashflow.get_total(ledger.root_account).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
<tr><td colspan="{{ cashflows|length + 1 }}"> </td></tr>
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Net Cash Inflow (Outflow)</td>
|
||||
{% for cashflow in cashflows %}<td>{{ cashflow.get_total(ledger.root_account).exchange(report_currency, True)|a }}</td>{% endfor %}
|
||||
{% for cashflow in cashflows %}<td>{{ cashflow.get_total(ledger.root_account).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
<tr class="total">
|
||||
<td>Closing Cash</td>
|
||||
|
@ -28,7 +28,7 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
{% for cashflow in cashflows %}
|
||||
{% set amount = (-cashflow.get_balance(account) if invert else cashflow.get_balance(account)).exchange(report_currency, True) %}
|
||||
{% set amount = (-cashflow.get_balance(account) if invert else cashflow.get_balance(account)).exchange(report_commodity, True) %}
|
||||
<td>{% if not amount.near_zero %}{{ amount|a('/transactions?' + {'date': cashflow.date.strftime('%Y-%m-%d'), 'pstart': cashflow.pstart.strftime('%Y-%m-%d'), 'account': account.name, 'cash': 'on' if cash else ''}|urlencode) }}{% endif %}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
@ -65,11 +65,11 @@
|
||||
{% endfor %}
|
||||
<tr class="total">
|
||||
<td>Total Adjustments</td>
|
||||
{% for cashflow in cashflows %}<td>{{ cashflow.get_total(ledger.root_account).exchange(report_currency, True)|a }}</td>{% endfor %}
|
||||
{% for cashflow in cashflows %}<td>{{ cashflow.get_total(ledger.root_account).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
<tr class="total">
|
||||
<td>Net Cash Inflow (Outflow)</td>
|
||||
{% for cashflow in cashflows %}<td>{{ (profits[loop.index0] + cashflow.get_total(ledger.root_account).exchange(report_currency, True))|a }}</td>{% endfor %}
|
||||
{% for cashflow in cashflows %}<td>{{ (profits[loop.index0] + cashflow.get_total(ledger.root_account).exchange(report_commodity, True))|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
<tr><td colspan="{{ cashflows|length + 1 }}"> </td></tr>
|
||||
|
||||
@ -80,7 +80,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Net Cash Inflow (Outflow)</td>
|
||||
{% for cashflow in cashflows %}<td>{{ (profits[loop.index0] + cashflow.get_total(ledger.root_account).exchange(report_currency, True))|a }}</td>{% endfor %}
|
||||
{% for cashflow in cashflows %}<td>{{ (profits[loop.index0] + cashflow.get_total(ledger.root_account).exchange(report_commodity, True))|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
<tr class="total">
|
||||
<td>Closing Cash</td>
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
{% for transaction in transactions %}
|
||||
{% for posting in transaction.postings %}
|
||||
{% set amount = posting.exchange(report_currency, transaction.date) %}
|
||||
{% set amount = posting.exchange(report_commodity, transaction.date) %}
|
||||
<tr>
|
||||
<td>{% if loop.first %}{{ transaction.date.strftime('%Y-%m-%d') }}{% endif %}</td>
|
||||
<td>{% if loop.first %}{{ transaction.description }}{% endif %}</td>
|
||||
|
@ -28,7 +28,7 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
{% for pandl in pandls %}
|
||||
{% set amount = (-pandl.get_balance(account) if invert else pandl.get_balance(account)).exchange(report_currency, True) %}
|
||||
{% set amount = (-pandl.get_balance(account) if invert else pandl.get_balance(account)).exchange(report_commodity, True) %}
|
||||
<td>{% if not amount.near_zero %}{{ amount|a('/transactions?' + {'date': pandl.date.strftime('%Y-%m-%d'), 'pstart': pandl.pstart.strftime('%Y-%m-%d'), 'account': account.name, 'cash': 'on' if cash else ''}|urlencode) }}{% endif %}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
@ -55,7 +55,7 @@
|
||||
|
||||
<tr class="total">
|
||||
<td>Total {{ label }}</td>
|
||||
{% for pandl in pandls %}<td>{{ (-pandl.get_total(root) if invert else pandl.get_total(root)).exchange(report_currency, True)|a }}</td>{% endfor %}
|
||||
{% for pandl in pandls %}<td>{{ (-pandl.get_total(root) if invert else pandl.get_total(root)).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
{% endmacro %}
|
||||
|
||||
@ -76,7 +76,7 @@
|
||||
|
||||
<tr class="total">
|
||||
<td>Net Profit (Loss)</td>
|
||||
{% for pandl in pandls %}<td>{{ -(pandl.get_total(ledger.get_account(config['income_account'])) + pandl.get_total(ledger.get_account(config['expenses_account']))).exchange(report_currency, True)|a }}</td>{% endfor %}
|
||||
{% for pandl in pandls %}<td>{{ -(pandl.get_total(ledger.get_account(config['income_account'])) + pandl.get_total(ledger.get_account(config['expenses_account']))).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
@ -85,7 +85,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Net Profit (Loss)</td>
|
||||
{% for pandl in pandls %}<td>{{ -(pandl.get_total(ledger.get_account(config['income_account'])) + pandl.get_total(ledger.get_account(config['expenses_account']))).exchange(report_currency, True)|a }}</td>{% endfor %}
|
||||
{% for pandl in pandls %}<td>{{ -(pandl.get_total(ledger.get_account(config['income_account'])) + pandl.get_total(ledger.get_account(config['expenses_account']))).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
@ -99,13 +99,13 @@
|
||||
|
||||
<tr class="total">
|
||||
<td>Total Other Comprehensive Income</td>
|
||||
{% for pandl in pandls %}<td>{{ -pandl.get_total(ledger.get_account(config['oci_account'])).exchange(report_currency, True)|a }}</td>{% endfor %}
|
||||
{% for pandl in pandls %}<td>{{ -pandl.get_total(ledger.get_account(config['oci_account'])).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
<tr><td colspan="{{ pandls|length + 1}}"> </td></tr>
|
||||
|
||||
<tr class="total">
|
||||
<td>Total Comprehensive Income</td>
|
||||
{% for pandl in pandls %}<td>{{ -(pandl.get_total(ledger.get_account(config['income_account'])) + pandl.get_total(ledger.get_account(config['expenses_account'])) + pandl.get_total(ledger.get_account(config['oci_account']))).exchange(report_currency, True)|a }}</td>{% endfor %}
|
||||
{% for pandl in pandls %}<td>{{ -(pandl.get_total(ledger.get_account(config['income_account'])) + pandl.get_total(ledger.get_account(config['expenses_account'])) + pandl.get_total(ledger.get_account(config['oci_account']))).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
@ -51,7 +51,7 @@
|
||||
</tr>
|
||||
|
||||
{% for posting in transaction.postings %}
|
||||
{% set amount = posting.exchange(report_currency, transaction.date) %}
|
||||
{% set amount = posting.exchange(report_commodity, transaction.date) %}
|
||||
{% set trn_url = '/transaction?' + {'tid': transaction.id, 'cash': 'on' if cash else ''}|urlencode %}
|
||||
<tr>
|
||||
<td>{{ posting.comment }}</td>
|
||||
|
@ -42,7 +42,7 @@
|
||||
<th style="width: 50%;">Description</th>
|
||||
<th style="width: 50%;">Account</th>
|
||||
<th style="text-align: right; min-width: 4em;">Dr</th> {# Amount #}
|
||||
<th style="min-width: 2em;"></th> {# Currency #}
|
||||
<th style="min-width: 2em;"></th> {# Commodity #}
|
||||
<th style="min-width: 2em;"></th> {# Price #}
|
||||
<th style="text-align: right; min-width: 4em;">Cr</th>
|
||||
<th style="min-width: 2em;"></th>
|
||||
|
@ -68,7 +68,7 @@
|
||||
|
||||
{% for transaction in transactions %}
|
||||
{% for posting in transaction.postings if posting.account != account %}
|
||||
{% set amount = posting.exchange(report_currency, transaction.date) %}
|
||||
{% set amount = posting.exchange(report_commodity, transaction.date) %}
|
||||
{% set trn_url = '/transaction?' + {'tid': transaction.id, 'cash': 'on' if cash else ''}|urlencode %}
|
||||
<tr>
|
||||
<td>{% if loop.first %}{% if transaction.id %}<a href="{{ trn_url }}">{% endif %}{{ transaction.date.strftime('%Y-%m-%d') }}{% if transaction.id %}</a>{% endif %}{% endif %}</td>
|
||||
|
@ -31,9 +31,9 @@
|
||||
<th style="width: 100%;">Description</th>
|
||||
<th style="min-width: 1em;"></th> {# Dr/Cr #}
|
||||
<th style="text-align: right; min-width: 4em;">Amount</th>
|
||||
<th style="min-width: 2em;"></th> {# Currency #}
|
||||
<th style="min-width: 2em;"></th> {# Commodity #}
|
||||
<th style="text-align: right; min-width: 4em;">Balance</th>
|
||||
<th style="min-width: 2em;"></th> {# Currency #}
|
||||
<th style="min-width: 2em;"></th> {# Commodity #}
|
||||
<th style="min-width: 2em;"></th> {# Price #}
|
||||
<th style="min-width: 1em;"></th>
|
||||
</tr>
|
||||
@ -106,7 +106,7 @@
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
{% set closing_balance = closing_balance.exchange(report_currency, True) %}
|
||||
{% set closing_balance = closing_balance.exchange(report_commodity, True) %}
|
||||
{{ closing_balance|abs|bt(True) }}
|
||||
<td>{% if closing_balance >= 0 %}Dr{% else %}Cr{% endif %}</td>
|
||||
</tr>
|
||||
|
@ -32,7 +32,7 @@
|
||||
</tr>
|
||||
{% for account in accounts %}
|
||||
{# Display in "cost basis" as we have already accounted for unrealised gains #}
|
||||
{% set balance = trial_balance.get_balance(account).exchange(report_currency, True) %}
|
||||
{% set balance = trial_balance.get_balance(account).exchange(report_commodity, True) %}
|
||||
{% set trn_url = "/transactions?" + {'date_end': trial_balance.date.strftime('%Y-%m-%d'), 'date_beg': trial_balance.pstart.strftime('%Y-%m-%d'), 'account': account.name, 'cash': 'on' if cash else ''}|urlencode %}
|
||||
{% if not balance.near_zero %}
|
||||
<tr>
|
||||
|
@ -33,7 +33,7 @@
|
||||
<tr>
|
||||
<td>{{ account.name }}</td>
|
||||
{% for trial_balance in trial_balances %}
|
||||
{% set balance = trial_balance.get_balance(account).exchange(report_currency, True) %}
|
||||
{% set balance = trial_balance.get_balance(account).exchange(report_commodity, True) %}
|
||||
<td>{% if not balance.near_zero %}<a href="/transactions?{{ {'date_end': trial_balance.date.strftime('%Y-%m-%d'), 'date_beg': trial_balance.pstart.strftime('%Y-%m-%d'), 'account': account.name, 'cash': 'on' if cash else ''}|urlencode }}">{{ balance|abs|b }} {% if balance >= 0 %}Dr{% else %}Cr{% endif %}</a>{% endif %}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
|
@ -61,19 +61,19 @@ def parse_amount(amount):
|
||||
price_str = None
|
||||
|
||||
if amount_str[0] in list('0123456789-'):
|
||||
# Currency follows number
|
||||
# Commodity follows number
|
||||
bits = amount_str.split()
|
||||
amount_num = Decimal(bits[0])
|
||||
currency = Currency(bits[1].strip('"'), False)
|
||||
commodity = Commodity(bits[1].strip('"'), False)
|
||||
else:
|
||||
# Currency precedes number
|
||||
currency = Currency(amount_str[0], True)
|
||||
# Commodity precedes number
|
||||
commodity = Commodity(amount_str[0], True)
|
||||
amount_num = Decimal(amount_str[1:])
|
||||
|
||||
if price_str:
|
||||
currency.price = parse_amount(price_str)
|
||||
commodity.price = parse_amount(price_str)
|
||||
|
||||
return Amount(amount_num, currency)
|
||||
return Amount(amount_num, commodity)
|
||||
|
||||
def get_pricedb():
|
||||
output = run_ledger('prices', '--prices-format', '%(quoted(format_date(date))),%(quoted(display_account)),%(quoted(display_amount))\n')
|
||||
@ -81,8 +81,8 @@ def get_pricedb():
|
||||
prices = []
|
||||
|
||||
reader = csv.reader(output.splitlines(), dialect='ledger')
|
||||
for date_str, currency, price_str in reader:
|
||||
prices.append((datetime.strptime(date_str, '%Y-%m-%d'), currency.strip('"'), parse_amount(price_str)))
|
||||
for date_str, commodity, price_str in reader:
|
||||
prices.append((datetime.strptime(date_str, '%Y-%m-%d'), commodity.strip('"'), parse_amount(price_str)))
|
||||
|
||||
return prices
|
||||
|
||||
|
@ -51,11 +51,11 @@ class Ledger:
|
||||
|
||||
return account
|
||||
|
||||
def get_price(self, currency_from, currency_to, date):
|
||||
prices = [p for p in self.prices if p[1] == currency_from.name and p[2].currency == currency_to and p[0].date() <= date.date()]
|
||||
def get_price(self, commodity_from, commodity_to, date):
|
||||
prices = [p for p in self.prices if p[1] == commodity_from.name and p[2].commodity == commodity_to and p[0].date() <= date.date()]
|
||||
|
||||
if not prices:
|
||||
raise Exception('No price information for {} to {} at {:%Y-%m-%d}'.format(currency_from, currency_to, date))
|
||||
raise Exception('No price information for {} to {} at {:%Y-%m-%d}'.format(commodity_from, commodity_to, date))
|
||||
|
||||
return max(prices, key=lambda p: p[0])[2]
|
||||
|
||||
@ -88,11 +88,11 @@ class Posting:
|
||||
def __repr__(self):
|
||||
return '<Posting "{}" {}>'.format(self.account.name, self.amount.tostr(False))
|
||||
|
||||
def exchange(self, currency, date):
|
||||
if self.amount.currency.name == currency.name and self.amount.currency.is_prefix == currency.is_prefix:
|
||||
def exchange(self, commodity, date):
|
||||
if self.amount.commodity.name == commodity.name and self.amount.commodity.is_prefix == commodity.is_prefix:
|
||||
return Amount(self.amount)
|
||||
|
||||
return self.amount.exchange(currency, True) # Cost basis
|
||||
return self.amount.exchange(commodity, True) # Cost basis
|
||||
|
||||
class Account:
|
||||
def __init__(self, ledger, name):
|
||||
@ -150,24 +150,24 @@ class Account:
|
||||
return self.is_asset or self.is_liability
|
||||
|
||||
class Amount:
|
||||
def __init__(self, amount, currency=None):
|
||||
def __init__(self, amount, commodity=None):
|
||||
if isinstance(amount, Amount):
|
||||
self.amount = amount.amount
|
||||
self.currency = amount.currency
|
||||
elif currency is None:
|
||||
raise TypeError('currency is required')
|
||||
self.commodity = amount.commodity
|
||||
elif commodity is None:
|
||||
raise TypeError('commodity is required')
|
||||
else:
|
||||
self.amount = Decimal(amount)
|
||||
self.currency = currency
|
||||
self.commodity = commodity
|
||||
|
||||
def tostr(self, round=True):
|
||||
if self.currency.is_prefix:
|
||||
amount_str = ('{}{:.2f}' if round else '{}{}').format(self.currency.name, self.amount)
|
||||
if self.commodity.is_prefix:
|
||||
amount_str = ('{}{:.2f}' if round else '{}{}').format(self.commodity.name, self.amount)
|
||||
else:
|
||||
amount_str = ('{:.2f} {}' if round else '{} {}').format(self.amount, self.currency.name)
|
||||
amount_str = ('{:.2f} {}' if round else '{} {}').format(self.amount, self.commodity.name)
|
||||
|
||||
if self.currency.price:
|
||||
return '{} {{{}}}'.format(amount_str, self.currency.price.tostr(round))
|
||||
if self.commodity.price:
|
||||
return '{} {{{}}}'.format(amount_str, self.commodity.price.tostr(round))
|
||||
return amount_str
|
||||
|
||||
def __repr__(self):
|
||||
@ -176,12 +176,12 @@ class Amount:
|
||||
def __str__(self):
|
||||
return self.tostr()
|
||||
|
||||
def compatible_currency(func):
|
||||
def compatible_commodity(func):
|
||||
@functools.wraps(func)
|
||||
def wrapped(self, other):
|
||||
if isinstance(other, Amount):
|
||||
if other.currency != self.currency:
|
||||
raise TypeError('Cannot combine Amounts of currency {} and {}'.format(self.currency.name, other.currency.name))
|
||||
if other.commodity != self.commodity:
|
||||
raise TypeError('Cannot combine Amounts of commodity {} and {}'.format(self.commodity.name, other.commodity.name))
|
||||
other = other.amount
|
||||
elif other != 0:
|
||||
raise TypeError('Cannot combine Amount with non-zero number')
|
||||
@ -189,15 +189,15 @@ class Amount:
|
||||
return wrapped
|
||||
|
||||
def __neg__(self):
|
||||
return Amount(-self.amount, self.currency)
|
||||
return Amount(-self.amount, self.commodity)
|
||||
def __abs__(self):
|
||||
return Amount(abs(self.amount), self.currency)
|
||||
return Amount(abs(self.amount), self.commodity)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Amount):
|
||||
if self.amount == 0 and other.amount == 0:
|
||||
return True
|
||||
if other.currency != self.currency:
|
||||
if other.commodity != self.commodity:
|
||||
return False
|
||||
return self.amount == other.amount
|
||||
|
||||
@ -205,46 +205,46 @@ class Amount:
|
||||
return self.amount == 0
|
||||
|
||||
raise TypeError('Cannot compare Amount with non-zero number')
|
||||
@compatible_currency
|
||||
@compatible_commodity
|
||||
def __ne__(self, other):
|
||||
return self.amount != other
|
||||
@compatible_currency
|
||||
@compatible_commodity
|
||||
def __gt__(self, other):
|
||||
return self.amount > other
|
||||
@compatible_currency
|
||||
@compatible_commodity
|
||||
def __ge__(self, other):
|
||||
return self.amount >= other
|
||||
@compatible_currency
|
||||
@compatible_commodity
|
||||
def __lt__(self, other):
|
||||
return self.amount < other
|
||||
@compatible_currency
|
||||
@compatible_commodity
|
||||
def __le__(self, other):
|
||||
return self.amount <= other
|
||||
|
||||
@compatible_currency
|
||||
@compatible_commodity
|
||||
def __add__(self, other):
|
||||
return Amount(self.amount + other, self.currency)
|
||||
@compatible_currency
|
||||
return Amount(self.amount + other, self.commodity)
|
||||
@compatible_commodity
|
||||
def __radd__(self, other):
|
||||
return Amount(other + self.amount, self.currency)
|
||||
@compatible_currency
|
||||
return Amount(other + self.amount, self.commodity)
|
||||
@compatible_commodity
|
||||
def __sub__(self, other):
|
||||
return Amount(self.amount - other, self.currency)
|
||||
@compatible_currency
|
||||
return Amount(self.amount - other, self.commodity)
|
||||
@compatible_commodity
|
||||
def __rsub__(self, other):
|
||||
return Amount(other - self.amount, self.currency)
|
||||
return Amount(other - self.amount, self.commodity)
|
||||
|
||||
def exchange(self, currency, is_cost, price=None):
|
||||
if self.currency.name == currency.name and self.currency.is_prefix == currency.is_prefix:
|
||||
def exchange(self, commodity, is_cost, price=None):
|
||||
if self.commodity.name == commodity.name and self.commodity.is_prefix == commodity.is_prefix:
|
||||
return Amount(self)
|
||||
|
||||
if is_cost and self.currency.price and self.currency.price.currency.name == currency.name and self.currency.price.currency.is_prefix == currency.is_prefix:
|
||||
return Amount(self.amount * self.currency.price.amount, currency)
|
||||
if is_cost and self.commodity.price and self.commodity.price.commodity.name == commodity.name and self.commodity.price.commodity.is_prefix == commodity.is_prefix:
|
||||
return Amount(self.amount * self.commodity.price.amount, commodity)
|
||||
|
||||
if price:
|
||||
return Amount(self.amount * price.amount, currency)
|
||||
return Amount(self.amount * price.amount, commodity)
|
||||
|
||||
raise TypeError('Cannot exchange {} to {}'.format(self.currency, currency))
|
||||
raise TypeError('Cannot exchange {} to {}'.format(self.commodity, commodity))
|
||||
|
||||
@property
|
||||
def near_zero(self):
|
||||
@ -259,26 +259,26 @@ class Balance:
|
||||
def tidy(self):
|
||||
new_amounts = []
|
||||
for amount in self.amounts:
|
||||
new_amount = next((a for a in new_amounts if a.currency == amount.currency), None)
|
||||
new_amount = next((a for a in new_amounts if a.commodity == amount.commodity), None)
|
||||
return Balance(new_amounts)
|
||||
|
||||
def clean(self):
|
||||
return Balance([a for a in self.amounts if a != 0])
|
||||
|
||||
def exchange(self, currency, is_cost, date=None, ledger=None):
|
||||
result = Amount(0, currency)
|
||||
def exchange(self, commodity, is_cost, date=None, ledger=None):
|
||||
result = Amount(0, commodity)
|
||||
for amount in self.amounts:
|
||||
if is_cost or (amount.currency.name == currency.name and amount.currency.is_prefix == amount.currency.is_prefix):
|
||||
result += amount.exchange(currency, is_cost)
|
||||
if is_cost or (amount.commodity.name == commodity.name and amount.commodity.is_prefix == amount.commodity.is_prefix):
|
||||
result += amount.exchange(commodity, is_cost)
|
||||
else:
|
||||
if any(p[1] == amount.currency.name for p in ledger.prices):
|
||||
# This currency has price information
|
||||
if any(p[1] == amount.commodity.name for p in ledger.prices):
|
||||
# This commodity has price information
|
||||
# Measured at fair value
|
||||
result += amount.exchange(currency, is_cost, ledger.get_price(amount.currency, currency, date))
|
||||
result += amount.exchange(commodity, is_cost, ledger.get_price(amount.commodity, commodity, date))
|
||||
else:
|
||||
# This currency has no price information
|
||||
# This commodity has no price information
|
||||
# Measured at historical cost
|
||||
result += amount.exchange(currency, True)
|
||||
result += amount.exchange(commodity, True)
|
||||
return result
|
||||
|
||||
def __neg__(self):
|
||||
@ -299,18 +299,18 @@ class Balance:
|
||||
|
||||
if isinstance(other, Balance):
|
||||
for amount in other.amounts:
|
||||
new_amount = next((a for a in new_amounts if a.currency == amount.currency), None)
|
||||
new_amount = next((a for a in new_amounts if a.commodity == amount.commodity), None)
|
||||
if new_amount is None:
|
||||
new_amount = Amount(0, amount.currency)
|
||||
new_amount = Amount(0, amount.commodity)
|
||||
new_amounts.append(new_amount)
|
||||
new_amount.amount += amount.amount
|
||||
|
||||
#if new_amount == 0:
|
||||
# new_amounts.remove(new_amount)
|
||||
elif isinstance(other, Amount):
|
||||
new_amount = next((a for a in new_amounts if a.currency == other.currency), None)
|
||||
new_amount = next((a for a in new_amounts if a.commodity == other.commodity), None)
|
||||
if new_amount is None:
|
||||
new_amount = Amount(0, other.currency)
|
||||
new_amount = Amount(0, other.commodity)
|
||||
new_amounts.append(new_amount)
|
||||
new_amount.amount += other.amount
|
||||
|
||||
@ -326,17 +326,17 @@ class Balance:
|
||||
def __sub__(self, other):
|
||||
return self + (-other)
|
||||
|
||||
class Currency:
|
||||
class Commodity:
|
||||
def __init__(self, name, is_prefix, price=None):
|
||||
self.name = name
|
||||
self.is_prefix = is_prefix
|
||||
self.price = price
|
||||
|
||||
def __repr__(self):
|
||||
return '<Currency {} ({})>'.format(self.name, 'prefix' if self.is_prefix else 'suffix')
|
||||
return '<Commodity {} ({})>'.format(self.name, 'prefix' if self.is_prefix else 'suffix')
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Currency):
|
||||
if not isinstance(other, Commodity):
|
||||
return False
|
||||
return self.name == other.name and self.is_prefix == other.is_prefix and self.price == other.price
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user