diff --git a/accounting/templates/accounting/income-statement.html b/accounting/templates/accounting/income-statement.html new file mode 100644 index 0000000..08f200e --- /dev/null +++ b/accounting/templates/accounting/income-statement.html @@ -0,0 +1,198 @@ +{% 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|" %}Income Statement in {{ period }}{% endblocktrans %} + {% setvar "title" title %} + {% setvar "use_period_chooser" True %} + {% static "accounting/css/report.css" as css %} + {% setvar "css" css %} +{% endblock %} + +{% block content %} + +
+
+ + +
+ {% with current_report_icon="fas fa-file-invoice" %} + {% trans "Income Statement" context "Accounting|" as current_report_title %} + {% include "accounting/include/report-chooser.html" %} + {% endwith %} + +
+ +{% include "mia_core/include/period-chooser.html" %} + +{% if item_list %} + {# The table for large screens #} +
+
+

{{ title }}

+
+ +
+
+ + + + + + + + + + {% for section in item_list %} + + + + + + + {% for group in section.groups %} + + + + + + + {% for item in group.details %} + + + + + + + {% endfor %} + + + + + + + {% endfor %} + {% if section.cumulative_total is not None %} + + + + + + + {% endif %} + {% endfor %} + +
{% trans "Amount" context "Period|" as text %}{{ text|force_escape }}
{{ section.title|title|escape }}
{{ group.title|title|escape }}
{{ item.title|title|escape }}
{{ item.balance|accounting_amount }} + + + {% trans "View" context "Accounting|" as text %}{{ text|force_escape }} + +
{% trans "Total" context "Period|" as text %}{{ text|force_escape }}
{{ group.total|accounting_amount }}
{{ section.cumulative_total.title|title|escape }}
{{ section.cumulative_total.total|accounting_amount }}
+
+
+
+ + {# The list for small screens #} + {% comment %} +
+
+

{{ title }}

+
+ +
+
+ +
+
+
+ {% endcomment %} +{% else %} +

{{ _("There is currently no data.")|force_escape }}

+{% endif %} + +{% endblock %} diff --git a/accounting/urls.py b/accounting/urls.py index f47fcc4..244bf52 100644 --- a/accounting/urls.py +++ b/accounting/urls.py @@ -67,7 +67,7 @@ urlpatterns = [ path("income-statement", mia_core_views.todo, name="income-statement.home"), path("income-statement/", - mia_core_views.todo, name="income-statement"), + views.income_statement, name="income-statement"), path("balance-sheet", mia_core_views.todo, name="balance-sheet.home"), path("balance-sheet/", diff --git a/accounting/views/__init__.py b/accounting/views/__init__.py index 11bb534..f8266f5 100644 --- a/accounting/views/__init__.py +++ b/accounting/views/__init__.py @@ -575,3 +575,66 @@ def trial_balance(request, period_spec): "reports": ReportUrl(period=period), "period": period, }) + + +@require_GET +@digest_login_required +def income_statement(request, period_spec): + """The income statement.""" + # The period + period = _get_period(period_spec) + # The accounts + accounts = 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)) + groups = list(Subject.objects.filter( + code__in=[x.code[:2] for x in accounts])) + sections = list(Subject.objects.filter( + Q(code="4") | Q(code="5") | Q(code="6") + | Q(code="7") | Q(code="8") | Q(code="9")).order_by("code")) + cumulative_accounts = { + "4": None, + "5": Subject(title=pgettext("Accounting|", "Gross Income")), + "6": Subject(title=pgettext("Accounting|", "Operating Income")), + "7": Subject(title=pgettext("Accounting|", "Before Tax Income")), + "8": Subject(title=pgettext("Accounting|", "After Tax Income")), + "9": Subject.objects.get(code="3353"), + } + cumulative_total = 0 + 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 = None + group.total = sum([x.balance + for x in group.details]) + section.balance = None + section.total = sum([x.total for x in section.groups]) + cumulative_total = cumulative_total + section.total + if section.code in cumulative_accounts: + if cumulative_accounts[section.code] is None: + section.cumulative_total = None + else: + section.cumulative_total\ + = cumulative_accounts[section.code] + section.cumulative_total.balance = None + section.cumulative_total.total = cumulative_total + return render(request, "accounting/income-statement.html", { + "item_list": sections, + "reports": ReportUrl(period=period), + "period": period, + }) + + +