Added thje trial balance in the accounting application.
This commit is contained in:
parent
36389623ef
commit
3cc7c5458b
212
accounting/static/accounting/css/report.css
Normal file
212
accounting/static/accounting/css/report.css
Normal file
@ -0,0 +1,212 @@
|
||||
/* The Mia Website
|
||||
* report.css: The style sheet for the accounting report
|
||||
*/
|
||||
|
||||
/* Copyright (c) 2019-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: 2019/9/12
|
||||
*/
|
||||
|
||||
|
||||
.subject-picker {
|
||||
height: auto;
|
||||
max-height: 400px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.date-subject-line {
|
||||
font-size: 0.833em;
|
||||
}
|
||||
.negative {
|
||||
color: red;
|
||||
}
|
||||
.journal-credit {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
/* The general journal tables */
|
||||
.general-journal-table th, .general-journal-table td {
|
||||
vertical-align: middle;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
/* The report block */
|
||||
.report-block {
|
||||
margin: 1em;
|
||||
background-color: #E9ECEF;
|
||||
border-radius: 0.3em;
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||
}
|
||||
.report-block .table {
|
||||
background-color: transparent;
|
||||
}
|
||||
.report-block h2 {
|
||||
border-bottom: thick double slategray;
|
||||
}
|
||||
.report-block-lg {
|
||||
padding: 2em 1.5em;
|
||||
}
|
||||
.report-block-sm {
|
||||
padding: 1em 1em;
|
||||
}
|
||||
.report-block-lg table th, .report-block-lg table td {
|
||||
vertical-align: middle;
|
||||
height: 50px;
|
||||
}
|
||||
.report-block-sm .list-group-item {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* The trial balance */
|
||||
.trial-balance-table thead {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.trial-balance-table tbody {
|
||||
border-top: thick double slategray;
|
||||
border-bottom: thick double slategray;
|
||||
}
|
||||
.trial-balance-table tfoot {
|
||||
font-size: 1.1em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
.trial-balance-list .total {
|
||||
border-top: thick double slategray;
|
||||
font-weight: bolder;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
/* The income statement */
|
||||
.income-statement-table thead {
|
||||
font-size: 1.21em;
|
||||
}
|
||||
.income-statement-table tbody {
|
||||
border-top: thick double slategray;
|
||||
border-bottom: thick double slategray;
|
||||
}
|
||||
.income-statement-table tr {
|
||||
height: 50px;
|
||||
}
|
||||
.income-statement-table td .subject {
|
||||
text-indent: 2em;
|
||||
}
|
||||
.income-statement-table tr.first-level-header {
|
||||
font-weight: bolder;
|
||||
font-size: 1.21em;
|
||||
}
|
||||
.income-statement-table tr.second-level-header {
|
||||
font-weight: bolder;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.income-statement-table td .second-level-header {
|
||||
text-indent: 1em;
|
||||
}
|
||||
.income-statement-table .total {
|
||||
border-top: 1px solid slategray;
|
||||
font-size: 1.1em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
.income-statement-table .cum-total {
|
||||
font-size: 1.21em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
.income-statement-list .list-group-item {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
.income-statement-list .first-level-header {
|
||||
font-weight: bolder;
|
||||
font-size: 1.21em;
|
||||
}
|
||||
.income-statement-list .second-level-header {
|
||||
font-weight: bolder;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.income-statement-list .total {
|
||||
border-top: 1px solid slategray;
|
||||
font-size: 1.1em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
.income-statement-list .cum-total {
|
||||
font-weight: bolder;
|
||||
font-size: 1.21em;
|
||||
}
|
||||
|
||||
/* The balance sheet */
|
||||
.balance-sheet-table thead {
|
||||
font-size: 1.21em;
|
||||
border-bottom: thick double slategray;
|
||||
}
|
||||
.balance-sheet-table tbody {
|
||||
}
|
||||
.balance-sheet-table .second-level-header {
|
||||
font-size: 1.1em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
.balance-sheet-table td .subject {
|
||||
text-indent: 1em;
|
||||
}
|
||||
.balance-sheet-table .total {
|
||||
border-top: thick double slategray;
|
||||
font-size: 1.1em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
.balance-sheet-total-table .total {
|
||||
border-top: thick double slategray;
|
||||
font-size: 1.21em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
.balance-sheet-list {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.balance-sheet-list .list-group-item {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
.balance-sheet-list .section-title {
|
||||
font-size: 1.21em;
|
||||
font-weight: bolder;
|
||||
border-bottom: thick double slategray;
|
||||
}
|
||||
.balance-sheet-list .second-level-header {
|
||||
font-size: 1.1em;
|
||||
font-weight: bolder;
|
||||
}
|
||||
.balance-sheet-list .total {
|
||||
font-size: 1.1em;
|
||||
font-weight: bolder;
|
||||
border-top: thick double slategray;
|
||||
}
|
||||
.balance-sheet-list .grand-total {
|
||||
font-size: 1.21em;
|
||||
font-weight: bolder;
|
||||
border-top: thick double slategray;
|
||||
}
|
||||
|
||||
/* The search */
|
||||
.btn-actions .btn .search-input {
|
||||
height: calc(1em + .5rem + 2px);
|
||||
border-radius: .2rem;
|
||||
}
|
||||
.btn-actions .btn .search-label {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.btn-actions .btn .search-label button {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
padding-right: 0;
|
||||
}
|
172
accounting/templates/accounting/trial-balance.html
Normal file
172
accounting/templates/accounting/trial-balance.html
Normal file
@ -0,0 +1,172 @@
|
||||
{% 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/1
|
||||
{% endcomment %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load humanize %}
|
||||
{% load mia_core %}
|
||||
{% load accounting %}
|
||||
|
||||
{% block settings %}
|
||||
{% blocktrans asvar title with period=period.description context "Accounting|" %}Trial Balance 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-book" %}
|
||||
{% trans "Journal" 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" %}
|
||||
|
||||
{% if records %}
|
||||
{% include "mia_core/include/pagination.html" %}
|
||||
|
||||
{# The table for large screens #}
|
||||
<div class="d-none d-sm-block report-block report-block-lg">
|
||||
<div class="row justify-content-center">
|
||||
<h2>{{ title|force_escape }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<table class="table table-borderless table-hover trial-balance-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{% trans "Subject" context "Accounting|" as text %}{{ text|force_escape }}</th>
|
||||
<th class="amount" scope="col">{% trans "Debit" context "Accounting|" as text %}{{ text|force_escape }}</th>
|
||||
<th class="amount" scope="col">{% trans "Credit" context "Accounting|" as text %}{{ text|force_escape }}</th>
|
||||
<th class="actions" scope="col">{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for record in records %}
|
||||
<tr>
|
||||
<td>{{ record.title }}</td>
|
||||
<td class="amount">{{ record.debit|accounting_amount }}</td>
|
||||
<td class="amount">{{ record.credit|accounting_amount }}</td>
|
||||
<td class="actions">
|
||||
<a href="{% url "accounting:ledger" record.code period.spec %}" class="btn btn-info" role="button">
|
||||
<i class="fas fa-eye"></i>
|
||||
<span class="d-none d-lg-inline">{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td>{% trans "Total" context "Accounting|" as text %}{{ text|force_escape }}</td>
|
||||
<td class="amount">{{ record_sum.debit|accounting_amount }}</td>
|
||||
<td class="amount">{{ record_sum.credit|accounting_amount }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# The list for mobile browsers #}
|
||||
<div class="d-sm-none report-block report-block-sm">
|
||||
<div class="row justify-content-center">
|
||||
<h2>{{ title|force_escape }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<ul class="list-group d-lg-none trial-balance-list">
|
||||
{% for record in records %}
|
||||
<li class="list-group-item">
|
||||
<a class="list-group-item-action d-flex justify-content-between align-items-center" href="{% url "accounting:ledger" record.code period.spec %}">
|
||||
{{ record.title }}
|
||||
<div>
|
||||
{% if record.debit is not None %}
|
||||
<span class="badge badge-success badge-pill">
|
||||
{{ record.debit|intcomma:False }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if record.credit is not None %}
|
||||
<span class="badge badge-warning badge-pill">
|
||||
{{ record.credit|intcomma:False }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center total">
|
||||
{% trans "Total" context "Accounting|" as text %}{{ text|force_escape }}
|
||||
<div>
|
||||
<span class="badge badge-success badge-pill">
|
||||
{{ record_sum.debit|intcomma:False }}
|
||||
</span>
|
||||
<span class="badge badge-warning badge-pill">
|
||||
{{ record_sum.credit|intcomma:False }}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<p>{{ _("There is currently no data.")|force_escape }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
@ -31,6 +31,7 @@ def accounting_amount(value):
|
||||
return ""
|
||||
if value == 0:
|
||||
return "-"
|
||||
print(value)
|
||||
s = str(abs(value))
|
||||
while True:
|
||||
m = re.match("^([1-9][0-9]*)([0-9]{3})", s)
|
||||
|
@ -63,7 +63,7 @@ urlpatterns = [
|
||||
path("trial-balance",
|
||||
mia_core_views.todo, name="trial-balance.home"),
|
||||
path("trial-balance/<str:period_spec>",
|
||||
mia_core_views.todo, name="trial-balance"),
|
||||
views.trial_balance, name="trial-balance"),
|
||||
path("income-statement",
|
||||
mia_core_views.todo, name="income-statement.home"),
|
||||
path("income-statement/<str:period_spec>",
|
||||
|
@ -487,3 +487,88 @@ def journal(request, period_spec):
|
||||
"pagination": pagination,
|
||||
"period": period,
|
||||
})
|
||||
|
||||
|
||||
@require_GET
|
||||
@digest_login_required
|
||||
def trial_balance(request, period_spec):
|
||||
"""The trial blanace."""
|
||||
# The period
|
||||
first_txn = Transaction.objects.order_by("date").first()
|
||||
data_start = first_txn.date if first_txn is not None else None
|
||||
last_txn = Transaction.objects.order_by("-date").first()
|
||||
data_end = last_txn.date if last_txn is not None else None
|
||||
period = Period(period_spec, data_start, data_end)
|
||||
# The accounts
|
||||
nominal = list(
|
||||
Subject.objects.filter(
|
||||
Q(record__transaction__date__gte=period.start),
|
||||
Q(record__transaction__date__lte=period.end),
|
||||
~(Q(code__startswith="1")
|
||||
| Q(code__startswith="2")
|
||||
| Q(code__startswith="3")))
|
||||
.annotate(
|
||||
balance=Sum(Case(
|
||||
When(record__is_credit=True, then=-1),
|
||||
default=1) * F("record__amount")))
|
||||
.filter(balance__isnull=False)
|
||||
.annotate(
|
||||
debit=Case(
|
||||
When(balance__gt=0, then=F("balance")),
|
||||
default=None),
|
||||
credit=Case(
|
||||
When(balance__lt=0, then=-F("balance")),
|
||||
default=None)))
|
||||
real = 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)
|
||||
.annotate(
|
||||
debit=Case(
|
||||
When(balance__gt=0, then=F("balance")),
|
||||
default=None),
|
||||
credit=Case(
|
||||
When(balance__lt=0, then=-F("balance")),
|
||||
default=None)))
|
||||
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(transaction__date__lte=period.end)
|
||||
& 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.filter(code="3351").first()
|
||||
if balance > 0:
|
||||
brought_forward.debit = balance
|
||||
brought_forward.credit = 0
|
||||
else:
|
||||
brought_forward.debit = None
|
||||
brought_forward.credit = -balance
|
||||
real.append(brought_forward)
|
||||
records = nominal + real
|
||||
records.sort(key=lambda x: x.code)
|
||||
record_sum = Subject()
|
||||
record_sum.title = pgettext("Accounting|", "Total")
|
||||
record_sum.debit = sum([x.debit for x in records
|
||||
if x.debit is not None])
|
||||
record_sum.credit = sum([x.credit for x in records
|
||||
if x.credit is not None])
|
||||
return render(request, "accounting/trial-balance.html", {
|
||||
"records": records,
|
||||
"record_sum": record_sum,
|
||||
"reports": ReportUrl(period=period),
|
||||
"period": period,
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user