Implement separate accounting of specified P&L accounts
This commit is contained in:
parent
50c2522654
commit
0c8f4a2ad4
@ -21,6 +21,7 @@ ledger-pyreport is a lightweight Flask webapp for generating interactive and pri
|
||||
* 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
|
||||
* Can simulate cash basis accounting, using FIFO methodology to recode transactions involving liabilities and non-cash assets
|
||||
* Can separately report specified categories of income and expense, reporting per-category net profit
|
||||
* Extensible through custom programming hooks
|
||||
|
||||
## Background, demo and screenshots
|
||||
|
@ -11,6 +11,9 @@ income_account: Income
|
||||
expenses_account: Expenses
|
||||
oci_account: OCI # Other Comprehensive Income
|
||||
|
||||
# These income and expense categories appear separately on the income statement
|
||||
separate_pandl: []
|
||||
|
||||
# These accounts will automatically be populated on reports
|
||||
unrealized_gains: 'OCI:Unrealized Gains'
|
||||
|
||||
|
@ -11,6 +11,9 @@ income_account: Income
|
||||
expenses_account: Expenses
|
||||
oci_account: OCI # Other Comprehensive Income
|
||||
|
||||
# These income and expense categories appear separately on the income statement
|
||||
separate_pandl: ['Business']
|
||||
|
||||
# These accounts will automatically be populated on reports
|
||||
unrealized_gains: 'OCI:Unrealized Gains'
|
||||
|
||||
|
@ -17,6 +17,14 @@
|
||||
Assets:Current:Inventory 50 Widgets {$7.00}
|
||||
Assets:Current:Cash at Bank
|
||||
|
||||
2019-07-04 Sale
|
||||
Assets:Current:Cash at Bank $100
|
||||
Income:Business:Sales
|
||||
|
||||
2019-07-04 Sale
|
||||
Expenses:Business:Cost of Goods Sold 10 Widgets {$5.00}
|
||||
Assets:Current:Inventory
|
||||
|
||||
2019-08-01 Interest on business loan
|
||||
Expenses:Interest $100.00
|
||||
Liabilities:Non-current:Business Loan
|
||||
|
@ -136,13 +136,35 @@ def pandl():
|
||||
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)]
|
||||
|
||||
# Process separate P&L accounts
|
||||
separate_pandls = []
|
||||
for separate_pandl_name in config['separate_pandl']:
|
||||
acc_income = l.get_account(config['income_account'] + ':' + separate_pandl_name)
|
||||
acc_expenses = l.get_account(config['expenses_account'] + ':' + separate_pandl_name)
|
||||
separate_pandls.append((acc_income, acc_expenses))
|
||||
|
||||
# Unlink from parents so raw figures not counted in income/expense total
|
||||
acc_income.parent.children.remove(acc_income)
|
||||
acc_expenses.parent.children.remove(acc_expenses)
|
||||
|
||||
# Add summary account
|
||||
for i, de, db in zip(range(compare + 1), dates_end, dates_beg):
|
||||
balance = (pandls[i].get_total(acc_income) + pandls[i].get_total(acc_expenses)).exchange(report_commodity, True)
|
||||
|
||||
if balance <= 0: # Credit
|
||||
summary_account = l.get_account(config['income_account'] + ':' + separate_pandl_name + ' Profit')
|
||||
else:
|
||||
summary_account = l.get_account(config['expenses_account'] + ':' + separate_pandl_name + ' Loss')
|
||||
|
||||
pandls[i].balances[summary_account.name] = pandls[i].get_balance(summary_account) + balance
|
||||
|
||||
# Delete accounts with always zero balances
|
||||
accounts = list(l.accounts.values())
|
||||
for account in accounts[:]:
|
||||
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_commodity=report_commodity, cash=cash, scope=scope)
|
||||
return flask.render_template('pandl.html', period=describe_period(date_end, date_beg), ledger=l, pandls=pandls, accounts=accounts, separate_pandls=separate_pandls, config=config, report_commodity=report_commodity, cash=cash, scope=scope)
|
||||
|
||||
@app.route('/cashflow')
|
||||
def cashflow():
|
||||
|
@ -68,7 +68,55 @@
|
||||
<table class="ledger onedesc">
|
||||
{# Profit and loss #}
|
||||
{% if scope != 'oci' %}
|
||||
{{ do_accounts(ledger.get_account(config['income_account']), 'Income', True, True) }}
|
||||
{# Separate P&L accounts #}
|
||||
{% for acc_income, acc_expenses in separate_pandls %}
|
||||
<tr><th class="h1" colspan="{{ pandls|length + 1 }}">{{ acc_income.bits[-1] }} Account</th></tr>
|
||||
|
||||
{# Income #}
|
||||
|
||||
<tr>
|
||||
{% if loop.first %}
|
||||
<th class="h2">{{ acc_income.bits[-1] }} Income</th>
|
||||
{% for pandl in pandls %}<th class="h2">{{ pandl.date.strftime('%Y') }} </th>{% endfor %}
|
||||
{% else %}
|
||||
<th class="h2" colspan="{{ pandls|length + 1 }}">{{ acc_income.bits[-1] }} Income</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
|
||||
{% for account in acc_income.children|sort(attribute='name') if account in accounts %}
|
||||
{{ print_rows(account, invert=True) }}
|
||||
{% endfor %}
|
||||
|
||||
<tr class="total">
|
||||
<td>Total {{ acc_income.bits[-1] }} Income</td>
|
||||
{% for pandl in pandls %}<td>{{ -pandl.get_total(acc_income).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
<tr><td colspan="{{ pandls|length + 1}}"> </td></tr>
|
||||
|
||||
{# Expenses #}
|
||||
|
||||
<tr><th class="h2" colspan="{{ pandls|length + 1 }}">{{ acc_income.bits[-1] }} Expenses</th></tr>
|
||||
|
||||
{% for account in acc_expenses.children|sort(attribute='name') if account in accounts %}
|
||||
{{ print_rows(account) }}
|
||||
{% endfor %}
|
||||
|
||||
<tr class="total">
|
||||
<td>Total {{ acc_income.bits[-1] }} Expenses</td>
|
||||
{% for pandl in pandls %}<td>{{ pandl.get_total(acc_expenses).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
<tr><td colspan="{{ pandls|length + 1}}"> </td></tr>
|
||||
|
||||
{# Net Profit #}
|
||||
|
||||
<tr class="total">
|
||||
<td>{{ acc_income.bits[-1] }} Profit (Loss)</td>
|
||||
{% for pandl in pandls %}<td>{{ -(pandl.get_total(acc_income) + pandl.get_total(acc_expenses)).exchange(report_commodity, True)|a }}</td>{% endfor %}
|
||||
</tr>
|
||||
<tr><td colspan="{{ pandls|length + 1}}"> </td></tr>
|
||||
{% endfor %}
|
||||
|
||||
{{ do_accounts(ledger.get_account(config['income_account']), 'Income', True, separate_pandls|length == 0) }}
|
||||
<tr><td colspan="{{ pandls|length + 1}}"> </td></tr>
|
||||
|
||||
{{ do_accounts(ledger.get_account(config['expenses_account']), 'Expenses', False, False) }}
|
||||
|
Reference in New Issue
Block a user