Implement separate reporting of Other Comprehensive Income (e.g. unrealised gains)
This commit is contained in:
parent
0d7e68592b
commit
04860845b6
@ -15,6 +15,7 @@ ledger-pyreport is a lightweight Flask webapp for generating interactive and pri
|
|||||||
|
|
||||||
* Correctly values assets/liabilities at market value, and income/expenses at cost (pursuant to [AASB 121](https://www.aasb.gov.au/admin/file/content105/c9/AASB121_08-15_COMPfeb16_01-19.pdf)/[IAS 21](https://www.ifrs.org/issued-standards/list-of-standards/ias-21-the-effects-of-changes-in-foreign-exchange-rates/) para 39)
|
* Correctly values assets/liabilities at market value, and income/expenses at cost (pursuant to [AASB 121](https://www.aasb.gov.au/admin/file/content105/c9/AASB121_08-15_COMPfeb16_01-19.pdf)/[IAS 21](https://www.ifrs.org/issued-standards/list-of-standards/ias-21-the-effects-of-changes-in-foreign-exchange-rates/) para 39)
|
||||||
* Correctly computes unrealised gains ([even when Ledger does not](https://yingtongli.me/blog/2020/03/31/ledger-gains.html))
|
* Correctly computes unrealised gains ([even when Ledger does not](https://yingtongli.me/blog/2020/03/31/ledger-gains.html))
|
||||||
|
* Accounts for both profit and loss, and other comprehensive income
|
||||||
* Simulates annual closing of books, with presentation of income/expenses on the balance sheet as retained earnings and current year earnings
|
* Simulates annual closing of books, with presentation of income/expenses on the balance sheet as retained earnings and current year earnings
|
||||||
* Can simulate cash basis accounting, using FIFO methodology to recode transactions involving liabilities and non-cash assets
|
* Can simulate cash basis accounting, using FIFO methodology to recode transactions involving liabilities and non-cash assets
|
||||||
|
|
||||||
|
@ -9,9 +9,13 @@ liabilities_account: Liabilities
|
|||||||
equity_account: Equity
|
equity_account: Equity
|
||||||
income_account: Income
|
income_account: Income
|
||||||
expenses_account: Expenses
|
expenses_account: Expenses
|
||||||
|
oci_account: OCI # Other Comprehensive Income
|
||||||
|
|
||||||
# These accounts will automatically be populated on reports
|
# These accounts will automatically be populated on reports
|
||||||
unrealized_gains: 'Equity:Unrealized Gains'
|
unrealized_gains: 'OCI:Unrealized Gains'
|
||||||
|
|
||||||
|
accumulated_oci: 'Equity:Accumulated Other Comprehensive Income'
|
||||||
|
current_year_oci: 'Equity:Current Year Other Comprehensive Income'
|
||||||
retained_earnings: 'Equity:Retained Earnings'
|
retained_earnings: 'Equity:Retained Earnings'
|
||||||
current_year_earnings: 'Equity:Current Year Earnings'
|
current_year_earnings: 'Equity:Current Year Earnings'
|
||||||
|
|
||||||
|
@ -9,9 +9,13 @@ liabilities_account: Liabilities
|
|||||||
equity_account: Equity
|
equity_account: Equity
|
||||||
income_account: Income
|
income_account: Income
|
||||||
expenses_account: Expenses
|
expenses_account: Expenses
|
||||||
|
oci_account: OCI # Other Comprehensive Income
|
||||||
|
|
||||||
# These accounts will automatically be populated on reports
|
# These accounts will automatically be populated on reports
|
||||||
unrealized_gains: 'Equity:Unrealized Gains'
|
unrealized_gains: 'OCI:Unrealized Gains'
|
||||||
|
|
||||||
|
accumulated_oci: 'Equity:Accumulated Other Comprehensive Income'
|
||||||
|
current_year_oci: 'Equity:Current Year Other Comprehensive Income'
|
||||||
retained_earnings: 'Equity:Retained Earnings'
|
retained_earnings: 'Equity:Retained Earnings'
|
||||||
current_year_earnings: 'Equity:Current Year Earnings'
|
current_year_earnings: 'Equity:Current Year Earnings'
|
||||||
|
|
||||||
|
@ -47,9 +47,7 @@ def trial():
|
|||||||
l = ledger.raw_transactions_at_date(date)
|
l = ledger.raw_transactions_at_date(date)
|
||||||
if cash:
|
if cash:
|
||||||
l = accounting.ledger_to_cash(l, report_currency)
|
l = accounting.ledger_to_cash(l, report_currency)
|
||||||
trial_balance = accounting.trial_balance(l, date, pstart)
|
trial_balance = accounting.trial_balance(l, date, pstart, report_currency)
|
||||||
|
|
||||||
trial_balance = accounting.add_unrealized_gains(trial_balance, report_currency)
|
|
||||||
|
|
||||||
total_dr = Amount(0, report_currency)
|
total_dr = Amount(0, report_currency)
|
||||||
total_cr = Amount(0, report_currency)
|
total_cr = Amount(0, report_currency)
|
||||||
@ -71,7 +69,7 @@ def trial():
|
|||||||
l = ledger.raw_transactions_at_date(date)
|
l = ledger.raw_transactions_at_date(date)
|
||||||
if cash:
|
if cash:
|
||||||
l = accounting.ledger_to_cash(l, report_currency)
|
l = accounting.ledger_to_cash(l, report_currency)
|
||||||
trial_balances = [accounting.add_unrealized_gains(accounting.trial_balance(l, d, p), report_currency) for d, p in zip(dates, pstarts)]
|
trial_balances = [accounting.trial_balance(l, d, p, report_currency) for d, p in zip(dates, pstarts)]
|
||||||
|
|
||||||
# Delete accounts with always zero balances
|
# Delete accounts with always zero balances
|
||||||
accounts = sorted(l.accounts.values(), key=lambda a: a.name)
|
accounts = sorted(l.accounts.values(), key=lambda a: a.name)
|
||||||
@ -95,7 +93,7 @@ def balance():
|
|||||||
l = ledger.raw_transactions_at_date(date)
|
l = ledger.raw_transactions_at_date(date)
|
||||||
if cash:
|
if cash:
|
||||||
l = accounting.ledger_to_cash(l, report_currency)
|
l = accounting.ledger_to_cash(l, report_currency)
|
||||||
balance_sheets = [accounting.balance_sheet(accounting.add_unrealized_gains(accounting.trial_balance(l, d, p), report_currency)) for d, p in zip(dates, pstarts)]
|
balance_sheets = [accounting.balance_sheet(accounting.trial_balance(l, d, p, report_currency)) for d, p in zip(dates, pstarts)]
|
||||||
|
|
||||||
# Delete accounts with always zero balances
|
# Delete accounts with always zero balances
|
||||||
accounts = list(l.accounts.values())
|
accounts = list(l.accounts.values())
|
||||||
@ -119,6 +117,7 @@ def pandl():
|
|||||||
date_end = datetime.strptime(flask.request.args['date_end'], '%Y-%m-%d')
|
date_end = datetime.strptime(flask.request.args['date_end'], '%Y-%m-%d')
|
||||||
compare = int(flask.request.args['compare'])
|
compare = int(flask.request.args['compare'])
|
||||||
cash = flask.request.args.get('cash', False)
|
cash = flask.request.args.get('cash', False)
|
||||||
|
scope = flask.request.args['scope']
|
||||||
|
|
||||||
dates_beg = [date_beg.replace(year=date_beg.year - i) for i in range(0, compare + 1)]
|
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)]
|
dates_end = [date_end.replace(year=date_end.year - i) for i in range(0, compare + 1)]
|
||||||
@ -127,7 +126,7 @@ def pandl():
|
|||||||
l = ledger.raw_transactions_at_date(date_end)
|
l = ledger.raw_transactions_at_date(date_end)
|
||||||
if cash:
|
if cash:
|
||||||
l = accounting.ledger_to_cash(l, report_currency)
|
l = accounting.ledger_to_cash(l, report_currency)
|
||||||
pandls = [accounting.trial_balance(l, de, db) for de, db in zip(dates_end, dates_beg)]
|
pandls = [accounting.trial_balance(l, de, db, report_currency) for de, db in zip(dates_end, dates_beg)]
|
||||||
|
|
||||||
# Delete accounts with always zero balances
|
# Delete accounts with always zero balances
|
||||||
accounts = list(l.accounts.values())
|
accounts = list(l.accounts.values())
|
||||||
@ -135,7 +134,7 @@ def pandl():
|
|||||||
if all(p.get_balance(account) == 0 and p.get_total(account) == 0 for p in pandls):
|
if all(p.get_balance(account) == 0 and p.get_total(account) == 0 for p in pandls):
|
||||||
accounts.remove(account)
|
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)
|
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)
|
||||||
|
|
||||||
@app.route('/transactions')
|
@app.route('/transactions')
|
||||||
def transactions():
|
def transactions():
|
||||||
@ -153,7 +152,7 @@ def transactions():
|
|||||||
l = accounting.ledger_to_cash(l, report_currency)
|
l = accounting.ledger_to_cash(l, report_currency)
|
||||||
|
|
||||||
# Unrealized gains
|
# Unrealized gains
|
||||||
l = accounting.add_unrealized_gains(accounting.trial_balance(l, date_end, date_beg), report_currency).ledger
|
l = accounting.trial_balance(l, date_end, date_beg, report_currency).ledger
|
||||||
|
|
||||||
if not account:
|
if not account:
|
||||||
# General Ledger
|
# General Ledger
|
||||||
@ -168,8 +167,8 @@ def transactions():
|
|||||||
account = l.get_account(account)
|
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)]
|
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(l, date_beg - timedelta(days=1), date_beg).get_balance(account).clean()
|
opening_balance = accounting.trial_balance(l, date_beg - timedelta(days=1), date_beg, report_currency).get_balance(account).clean()
|
||||||
closing_balance = accounting.trial_balance(l, date_end, date_beg).get_balance(account).clean()
|
closing_balance = accounting.trial_balance(l, date_end, date_beg, report_currency).get_balance(account).clean()
|
||||||
|
|
||||||
def matching_posting(transaction, amount):
|
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.currency == amount.currency), None)
|
||||||
@ -180,8 +179,8 @@ def transactions():
|
|||||||
account = l.get_account(account)
|
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)]
|
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(l, date_beg - timedelta(days=1), date_beg).get_balance(account).exchange(report_currency, True)
|
opening_balance = accounting.trial_balance(l, date_beg - timedelta(days=1), date_beg, report_currency).get_balance(account).exchange(report_currency, True)
|
||||||
closing_balance = accounting.trial_balance(l, date_end, date_beg).get_balance(account).exchange(report_currency, True)
|
closing_balance = accounting.trial_balance(l, date_end, date_beg, report_currency).get_balance(account).exchange(report_currency, 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_currency=report_currency, cash=cash, timedelta=timedelta)
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import csv
|
import csv
|
||||||
|
from datetime import timedelta
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
import math
|
import math
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ from .model import *
|
|||||||
|
|
||||||
# Generate a trial balance
|
# Generate a trial balance
|
||||||
# Perform closing of books based on specified dates
|
# Perform closing of books based on specified dates
|
||||||
def trial_balance(ledger, date, pstart):
|
def trial_balance_raw(ledger, date, pstart):
|
||||||
tb = TrialBalance(ledger, date, pstart)
|
tb = TrialBalance(ledger, date, pstart)
|
||||||
|
|
||||||
for transaction in ledger.transactions:
|
for transaction in ledger.transactions:
|
||||||
@ -32,13 +33,43 @@ def trial_balance(ledger, date, pstart):
|
|||||||
for posting in transaction.postings:
|
for posting in transaction.postings:
|
||||||
if (posting.account.is_income or posting.account.is_expense) and transaction.date < pstart:
|
if (posting.account.is_income or posting.account.is_expense) and transaction.date < pstart:
|
||||||
tb.balances[config['retained_earnings']] = tb.get_balance(ledger.get_account(config['retained_earnings'])) + posting.amount
|
tb.balances[config['retained_earnings']] = tb.get_balance(ledger.get_account(config['retained_earnings'])) + posting.amount
|
||||||
|
elif posting.account.is_oci and transaction.date < pstart:
|
||||||
|
tb.balances[config['accumulated_oci']] = tb.get_balance(ledger.get_account(config['retained_earnings'])) + posting.amount
|
||||||
else:
|
else:
|
||||||
tb.balances[posting.account.name] = tb.get_balance(posting.account) + posting.amount
|
tb.balances[posting.account.name] = tb.get_balance(posting.account) + posting.amount
|
||||||
|
|
||||||
return tb
|
return tb
|
||||||
|
|
||||||
# Adjust (in place) a trial balance for unrealized gains
|
# Trial balance with unrealized gains and OCI
|
||||||
def add_unrealized_gains(tb, currency):
|
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)
|
||||||
|
|
||||||
|
for account in set(list(r_date.keys()) + list(r_pstart.keys())):
|
||||||
|
if account in r_pstart:
|
||||||
|
# Charge previous unrealized gains to Accumulated OCI
|
||||||
|
#r_pstart[account].postings[1].account = ledger.get_account(config['accumulated_oci'])
|
||||||
|
accumulated = r_pstart[account].postings[0].amount
|
||||||
|
|
||||||
|
tb_date.balances[account.name] = tb_date.get_balance(account) + accumulated
|
||||||
|
tb_date.balances[config['accumulated_oci']] = tb_date.get_balance(ledger.get_account(config['accumulated_oci'])) - accumulated
|
||||||
|
|
||||||
|
if account in r_date:
|
||||||
|
if account in r_pstart:
|
||||||
|
# Adjust for this year's unrealized gains only
|
||||||
|
r_date[account].postings[0].amount -= accumulated
|
||||||
|
r_date[account].postings[1].amount += accumulated
|
||||||
|
|
||||||
|
tb_date.balances[account.name] = tb_date.get_balance(account) + r_date[account].postings[0].amount
|
||||||
|
tb_date.balances[config['unrealized_gains']] = tb_date.get_balance(ledger.get_account(config['unrealized_gains'])) - r_date[account].postings[0].amount
|
||||||
|
|
||||||
|
return tb_date
|
||||||
|
|
||||||
|
# Adjust (in place) a trial balance for unrealized gains without accumulating OCI
|
||||||
|
def _add_unrealized_gains(tb, currency):
|
||||||
|
results = {}
|
||||||
|
unrealized_gain_account = tb.ledger.get_account(config['unrealized_gains'])
|
||||||
|
|
||||||
for account in list(tb.ledger.accounts.values()):
|
for account in list(tb.ledger.accounts.values()):
|
||||||
if not account.is_market:
|
if not account.is_market:
|
||||||
continue
|
continue
|
||||||
@ -50,10 +81,12 @@ def add_unrealized_gains(tb, currency):
|
|||||||
if unrealized_gain != 0:
|
if unrealized_gain != 0:
|
||||||
transaction = Transaction(tb.ledger, None, tb.date, '<Unrealized Gains>')
|
transaction = Transaction(tb.ledger, None, tb.date, '<Unrealized Gains>')
|
||||||
transaction.postings.append(Posting(transaction, account, unrealized_gain))
|
transaction.postings.append(Posting(transaction, account, unrealized_gain))
|
||||||
transaction.postings.append(Posting(transaction, tb.ledger.get_account(config['unrealized_gains']), -unrealized_gain))
|
transaction.postings.append(Posting(transaction, unrealized_gain_account, -unrealized_gain))
|
||||||
tb.ledger.transactions.append(transaction)
|
tb.ledger.transactions.append(transaction)
|
||||||
|
|
||||||
return trial_balance(tb.ledger, tb.date, tb.pstart)
|
results[account] = transaction
|
||||||
|
|
||||||
|
return tb, results
|
||||||
|
|
||||||
# Adjust (in place) a trial balance to include a Current Year Earnings account
|
# Adjust (in place) a trial balance to include a Current Year Earnings account
|
||||||
# Suitable for display on a balance sheet
|
# Suitable for display on a balance sheet
|
||||||
@ -64,6 +97,12 @@ def balance_sheet(tb):
|
|||||||
# Add Current Year Earnings account
|
# Add Current Year Earnings account
|
||||||
tb.balances[config['current_year_earnings']] = tb.get_balance(tb.ledger.get_account(config['current_year_earnings'])) + total_pandl
|
tb.balances[config['current_year_earnings']] = tb.get_balance(tb.ledger.get_account(config['current_year_earnings'])) + total_pandl
|
||||||
|
|
||||||
|
# Calculate OCI
|
||||||
|
total_oci = tb.get_total(tb.ledger.get_account(config['oci_account']))
|
||||||
|
|
||||||
|
# Add Current Year OCI account
|
||||||
|
tb.balances[config['current_year_oci']] = tb.get_balance(tb.ledger.get_account(config['current_year_oci'])) + total_oci
|
||||||
|
|
||||||
return tb
|
return tb
|
||||||
|
|
||||||
def account_to_cash(account, currency):
|
def account_to_cash(account, currency):
|
||||||
|
@ -48,6 +48,11 @@
|
|||||||
<label>End date: <input name="date_end" data-inputgroup="date" value="{{ date.strftime('%Y-%m-%d') }}" style="width: 6em;" oninput="txtc(this)"></label>
|
<label>End date: <input name="date_end" data-inputgroup="date" value="{{ date.strftime('%Y-%m-%d') }}" style="width: 6em;" oninput="txtc(this)"></label>
|
||||||
<label>Compare <input name="compare" data-inputgroup="compare" value="0" style="width: 2em;" oninput="txtc(this)"> periods</label>
|
<label>Compare <input name="compare" data-inputgroup="compare" value="0" style="width: 2em;" oninput="txtc(this)"> periods</label>
|
||||||
<label><input name="cash" data-inputgroup="cash" type="checkbox" oninput="chbc(this)"> Cash basis</label>
|
<label><input name="cash" data-inputgroup="cash" type="checkbox" oninput="chbc(this)"> Cash basis</label>
|
||||||
|
<label>Scope: <select name="scope">
|
||||||
|
<option value="pandl" selected>P&L only</option>
|
||||||
|
<option value="oci">OCI only</option>
|
||||||
|
<option value="both">P&L and OCI</option>
|
||||||
|
</select></label>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -66,15 +66,47 @@
|
|||||||
<h2>For the {{ period }}</h2>
|
<h2>For the {{ period }}</h2>
|
||||||
|
|
||||||
<table class="ledger onedesc">
|
<table class="ledger onedesc">
|
||||||
{{ do_accounts(ledger.get_account(config['income_account']), 'Income', True, True) }}
|
{# Profit and loss #}
|
||||||
<tr><td colspan="2"> </td></tr>
|
{% if scope != 'oci' %}
|
||||||
|
{{ do_accounts(ledger.get_account(config['income_account']), 'Income', True, True) }}
|
||||||
|
<tr><td colspan="{{ pandls|length + 1}}"> </td></tr>
|
||||||
|
|
||||||
{{ do_accounts(ledger.get_account(config['expenses_account']), 'Expenses', False, False) }}
|
{{ do_accounts(ledger.get_account(config['expenses_account']), 'Expenses', False, False) }}
|
||||||
<tr><td colspan="2"> </td></tr>
|
<tr><td colspan="{{ pandls|length + 1}}"> </td></tr>
|
||||||
|
|
||||||
<tr class="total">
|
<tr class="total">
|
||||||
<td>Net Surplus (Loss)</td>
|
<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_currency, True)|a }}</td>{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
{% for pandl in pandls %}<th class="h2">{{ pandl.date.strftime('%Y') }} </th>{% endfor %}
|
||||||
|
</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 %}
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# Other comprehensive income #}
|
||||||
|
{% if scope != 'pandl' %}
|
||||||
|
<tr><td colspan="{{ pandls|length + 1}}"> </td></tr>
|
||||||
|
<tr><th class="{% if scope == 'both' %}h1{% else %}h2{% endif %}" colspan="{{ pandls|length + 1 }}">Other Comprehensive Income</th></tr>
|
||||||
|
{% for child in ledger.get_account(config['oci_account']).children|sort(attribute='name') if child in accounts %}
|
||||||
|
{{ print_rows(child, True, 0) }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<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 %}
|
||||||
|
</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 %}
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
</table>
|
</table>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -130,6 +130,9 @@ class Account:
|
|||||||
def is_cash(self):
|
def is_cash(self):
|
||||||
# Is this a cash asset?
|
# Is this a cash asset?
|
||||||
return any(self.matches(a) for a in config['cash_asset_accounts'])
|
return any(self.matches(a) for a in config['cash_asset_accounts'])
|
||||||
|
@property
|
||||||
|
def is_oci(self):
|
||||||
|
return self.matches(config['oci_account'])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_cost(self):
|
def is_cost(self):
|
||||||
|
@ -86,6 +86,10 @@ table.ledger a:hover {
|
|||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-left: 1ex;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen {
|
@media screen {
|
||||||
body {
|
body {
|
||||||
padding: 2em;
|
padding: 2em;
|
||||||
|
Reference in New Issue
Block a user