Added the balance sheet in the accounting application.

This commit is contained in:
依瑪貓 2020-07-21 00:31:31 +08:00
parent c2c8ee66ab
commit a18df0e928
4 changed files with 405 additions and 3 deletions

View File

@ -152,7 +152,7 @@
} }
.balance-sheet-table tbody { .balance-sheet-table tbody {
} }
.balance-sheet-table .second-level-header { .balance-sheet-table .group-title {
font-size: 1.1em; font-size: 1.1em;
font-weight: bolder; font-weight: bolder;
} }
@ -181,7 +181,7 @@
font-weight: bolder; font-weight: bolder;
border-bottom: thick double slategray; border-bottom: thick double slategray;
} }
.balance-sheet-list .second-level-header { .balance-sheet-list .group-title {
font-size: 1.1em; font-size: 1.1em;
font-weight: bolder; font-weight: bolder;
} }

View File

@ -0,0 +1,330 @@
{% extends "base.html" %}
{% comment %}
The Mia Accounting Application
cash.html: The template for the cash account reports
Copyright (c) 2020 imacat.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Author: imacat@mail.imacat.idv.tw (imacat)
First written: 2020/7/20
{% endcomment %}
{% load static %}
{% load i18n %}
{% load humanize %}
{% load mia_core %}
{% load accounting %}
{% block settings %}
{% blocktrans asvar title with period=period.description context "Accounting|" %}Balance Sheet in {{ period }}{% endblocktrans %}
{% setvar "title" title %}
{% setvar "use_period_chooser" True %}
{% static "accounting/css/report.css" as css %}
{% setvar "css" css %}
{% endblock %}
{% block content %}
<div class="btn-group btn-actions">
<div class="btn-group">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
<i class="fas fa-edit"></i>
{% trans "New" context "Accounting|" as text %}
{{ text|force_escape }}
</button>
<div class="dropdown-menu">
{% url "accounting:transaction.create" "expense" as url %}
<a class="dropdown-item" href="{% url_query url r=request.get_full_path %}">
{% trans "Cash Expense" context "Accounting|" as text %}
{{ text|force_escape }}
</a>
{% url "accounting:transaction.create" "income" as url %}
<a class="dropdown-item" href="{% url_query url r=request.get_full_path %}">
{% trans "Cash Income" context "Accounting|" as text %}
{{ text|force_escape }}
</a>
{% url "accounting:transaction.create" "transfer" as url %}
<a class="dropdown-item" href="{% url_query url r=request.get_full_path %}">
{% trans "Transfer" context "Accounting|" as text %}
{{ text|force_escape }}
</a>
</div>
</div>
{% with current_report_icon="fas fa-balance-scale" %}
{% trans "Balance Sheet" context "Accounting|" as current_report_title %}
{% include "accounting/include/report-chooser.html" %}
{% endwith %}
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#period-modal">
<i class="far fa-calendar-alt"></i>
<span class="d-none d-md-inline">{{ period.description }}</span>
<span class="d-md-none">{% trans "Period" context "Period|" as text %}{{ text|force_escape }}</span>
</button>
</div>
{% include "mia_core/include/period-chooser.html" %}
{# The table for large screens #}
<div class="d-none d-lg-block report-block report-block-lg">
<div class="row justify-content-center">
<h2>{{ title|escape }}</h2>
</div>
<div class="row">
<div class="col-sm-6">
<table class="table table-borderless table-hover table-sm balance-sheet-table">
<thead>
<tr>
<th colspan="3" scope="col">{{ section_1.title|title }}</th>
</tr>
</thead>
<tbody>
{% for group in section_1.groups %}
<tr class="group-title">
<td><div>{{ group.title|title }}</div></td>
<td class="amount"></td>
<td class="actions"></td>
</tr>
{% for item in group.details %}
<tr>
<td><div class="subject">{{ item.title|title }}</div></td>
<td class="amount {% if item.balance < 0 %} text-danger {% endif %}">{{ item.balance|accounting_amount }}</td>
<td class="actions">
<a href="{% url "accounting:ledger" item.code period.spec %}" class="btn btn-info" role="button">
<i class="fas fa-eye"></i>
{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}
</a>
</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
</div>
<div class="col-sm-6">
<table class="table table-borderless table-hover table-sm balance-sheet-table">
<thead>
<tr>
<th colspan="3" scope="col">{{ section_2.title|title }}</th>
</tr>
</thead>
<tbody>
{% for group in section_2.groups %}
<tr class="group-title">
<td><div>{{ group.title|title }}</div></td>
<td class="amount"></td>
<td class="actions"></td>
</tr>
{% for item in group.details %}
<tr>
<td><div class="subject">{{ item.title|title }}</div></td>
<td class="amount {% if item.balance < 0 %} text-danger {% endif %}">{{ item.balance|accounting_amount }}</td>
<td class="actions">
<a href="{% url "accounting:ledger" item.code period.spec %}" class="btn btn-info" role="button">
<i class="fas fa-eye"></i>
{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}
</a>
</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
<tfoot>
<tr class="total">
<td>{% trans "Total" context "Accounting|" as text %}{{ text|force_escape }}</td>
<td class="amount {% if section_2.balance < 0 %} text-danger {% endif %}">
{{ section_2.balance|accounting_amount }}
</td>
</tr>
</tfoot>
</table>
<table class="table table-borderless table-hover table-sm balance-sheet-table">
<thead>
<tr>
<th colspan="3" scope="col">{{ section_3.title|title }}</th>
</tr>
</thead>
<tbody>
{% for group in section_3.groups %}
<tr class="group-title">
<td><div>{{ group.title|title }}</div></td>
<td class="amount"></td>
<td class="actions"></td>
</tr>
{% for item in group.details %}
<tr>
<td><div class="subject">{{ item.title|title }}</div></td>
<td class="amount {% if item.balance < 0 %} text-danger {% endif %}">{{ item.balance|accounting_amount }}</td>
<td class="actions">
<a href="{% url "accounting:ledger" item.code period.spec %}" class="btn btn-info" role="button">
<i class="fas fa-eye"></i>
{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}
</a>
</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
<tfoot>
<tr class="total">
<td>{% trans "Total" context "Accounting|" as text %}{{ text|force_escape }}</td>
<td class="amount {% if section_3.balance < 0 %} text-danger {% endif %}">
{{ section_3.balance|accounting_amount }}
</td>
</tr>
</tfoot>
</table>
</div>
</div>
<div class="row">
<div class="col-sm-6 assets-total">
<table class="table table-borderless table-hover table-sm balance-sheet-total-table">
<tfoot>
<tr class="total">
<td class="align-middle">{% trans "Total" context "Accounting|" as text %}{{ text|force_escape }}</td>
<td class="text-right align-middle font-italic {% if section_1.balance < 0 %} text-danger {% endif %}">
{{ section_1.balance|accounting_amount }}
</td>
</tr>
</tfoot>
</table>
</div>
<div class="col-sm-6 liabilities-total">
<table class="table table-borderless table-hover table-sm balance-sheet-total-table">
<tfoot>
<tr class="total">
<td class="align-middle">{% trans "Total" context "Accounting|" as text %}{{ text|force_escape }}</td>
<td class="text-right align-middle font-italic {% if section_2.balance|add:section_3.balance < 0 %} text-danger {% endif %}">
{{ section_2.balance|add:section_3.balance|accounting_amount }}
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
{# The list for small screens #}
<div class="d-lg-none report-block report-block-sm">
<div class="row justify-content-center">
<h2>{{ title|escape }}</h2>
</div>
<div class="row">
<div class="col-sm-6">
<ul class="list-group balance-sheet-list">
<li class="list-group-item section-title">
{{ section_1.title|title }}
</li>
{% for group in section_1.groups %}
<li class="list-group-item d-flex justify-content-between align-items-center group-title">
{{ group.title|title }}
</li>
{% for item in group.details %}
<li class="list-group-item d-flex justify-content-between align-items-center subject">
<a class="list-group-item-action" href="{% url "accounting:ledger" item.code period.spec %}">
{{ item.title|title }}
<div class="float-right">
<span class="badge {% if item.balance < 0 %} badge-warning {% else %} badge-secondary {% endif %} badge-pill">
{{ item.balance|accounting_amount }}
</span>
</div>
</a>
</li>
{% endfor %}
{% endfor %}
<li class="list-group-item d-flex justify-content-between align-items-center grand-total">
{% trans "Total" context "Accounting|" as text %}{{ text|force_escape }}
<span class="badge {% if section_1.balance < 0 %} badge-danger {% else %} badge-info {% endif %} badge-pill">
{{ section_1.balance|accounting_amount }}
</span>
</li>
</ul>
</div>
<div class="col-sm-6">
<ul class="list-group balance-sheet-list">
<li class="list-group-item section-title">
{{ section_2.title|title }}
</li>
{% for group in section_2.groups %}
<li class="list-group-item d-flex justify-content-between align-items-center group-title">
{{ group.title|title }}
</li>
{% for item in group.details %}
<li class="list-group-item d-flex justify-content-between align-items-center subject">
<a class="list-group-item-action" href="{% url "accounting:ledger" item.code period.spec %}">
{{ item.title|title }}
<div class="float-right">
<span class="badge {% if item.balance < 0 %} badge-warning {% else %} badge-secondary {% endif %} badge-pill">
{{ item.balance|accounting_amount }}
</span>
</div>
</a>
</li>
{% endfor %}
{% endfor %}
<li class="list-group-item d-flex justify-content-between align-items-center total">
{% trans "Total" context "Accounting|" as text %}{{ text|force_escape }}
<span class="badge {% if section_2.balance < 0 %} badge-danger {% else %} badge-info {% endif %} badge-pill">
{{ section_2.balance|accounting_amount }}
</span>
</li>
</ul>
<ul class="list-group balance-sheet-list">
<li class="list-group-item section-title">
{{ section_3.title|title }}
</li>
{% for group in section_3.groups %}
<li class="list-group-item d-flex justify-content-between align-items-center group-title">
{{ group.title|title }}
</li>
{% for item in group.details %}
<li class="list-group-item d-flex justify-content-between align-items-center subject">
<a class="list-group-item-action" href="{% url "accounting:ledger" item.code period.spec %}">
{{ item.title|title }}
<div class="float-right">
<span class="badge {% if item.balance < 0 %} badge-warning {% else %} badge-secondary {% endif %} badge-pill">
{{ item.balance|accounting_amount }}
</span>
</div>
</a>
</li>
{% endfor %}
{% endfor %}
<li class="list-group-item d-flex justify-content-between align-items-center total">
{% trans "Total" context "Accounting|" as text %}{{ text|force_escape }}
<span class="badge {% if section_3.balance < 0 %} badge-danger {% else %} badge-info {% endif %} badge-pill">
{{ section_3.balance|accounting_amount }}
</span>
</li>
</ul>
<ul class="list-group balance-sheet-list">
<li class="list-group-item d-flex justify-content-between align-items-center grand-total">
{% trans "Total" context "Accounting|" as text %}{{ text|force_escape }}
<span class="badge {% if section_2.balance|add:section_3.balance < 0 %} badge-danger {% else %} badge-info {% endif %} badge-pill">
{{ section_2.balance|add:section_3.balance|accounting_amount }}
</span>
</li>
</ul>
</div>
</div>
</div>
{% endblock %}

View File

@ -71,7 +71,7 @@ urlpatterns = [
path("balance-sheet", path("balance-sheet",
mia_core_views.todo, name="balance-sheet.home"), mia_core_views.todo, name="balance-sheet.home"),
path("balance-sheet/<str:period_spec>", path("balance-sheet/<str:period_spec>",
mia_core_views.todo, name="balance-sheet"), views.balance_sheet, name="balance-sheet"),
path("search", path("search",
mia_core_views.todo, name="search"), mia_core_views.todo, name="search"),
path("transactions/<txn-type:type>/create", path("transactions/<txn-type:type>/create",

View File

@ -637,4 +637,76 @@ def income_statement(request, period_spec):
}) })
@require_GET
@digest_login_required
def balance_sheet(request, period_spec):
"""The balance sheet."""
# The period
period = _get_period(period_spec)
# The accounts
accounts = list(
Subject.objects
.filter(Q(record__transaction__date__lte=period.end),
(Q(code__startswith="1")
| Q(code__startswith="2")
| Q(code__startswith="3")),
~Q(code="3351"))
.annotate(
balance=Sum(Case(
When(record__is_credit=True, then=-1),
default=1) * F("record__amount")))
.filter(balance__isnull=False))
balance = Record.objects\
.filter(
Q(transaction__date__lt=period.start)
& ~((Q(subject__code__startswith="1")
| Q(subject__code__startswith="2")
| Q(subject__code__startswith="3"))
& ~Q(subject__code="3351")))\
.aggregate(
balance=Sum(Case(
When(is_credit=True, then=-1),
default=1) * F("amount")))["balance"]
if balance is not None and balance != 0:
brought_forward = Subject.objects.get(code="3351")
brought_forward.balance = -balance
accounts.append(brought_forward)
balance = Record.objects\
.filter(
Q(transaction__date__gte=period.start)
& Q(transaction__date__lte=period.end)
& ~((Q(subject__code__startswith="1")
| Q(subject__code__startswith="2")
| Q(subject__code__startswith="3"))
& ~Q(subject__code="3351")))\
.aggregate(
balance=Sum(Case(
When(is_credit=True, then=-1),
default=1) * F("amount")))["balance"]
if balance is not None and balance != 0:
net_income = Subject.objects.get(code="3353")
net_income.balance = -balance
accounts.append(net_income)
groups = list(Subject.objects.filter(
code__in=[x.code[:2] for x in accounts]))
sections = list(Subject.objects.filter(
Q(code="1") | Q(code="2") | Q(code="3")).order_by("code"))
for section in sections:
section.groups = [x for x in groups
if x.code[:1] == section.code]
for group in section.groups:
group.details = [x for x in accounts
if x.code[:2] == group.code]
group.balance = sum([x.balance
for x in group.details])
section.balance = sum([x.balance for x in section.groups])
by_code = {x.code: x for x in sections}
return render(request, "accounting/balance-sheet.html", {
"section_1": by_code["1"],
"section_2": by_code["2"],
"section_3": by_code["3"],
"reports": ReportUrl(period=period),
"period": period,
})