Added the ledger summary in the accounting application.
This commit is contained in:
		| @@ -324,6 +324,7 @@ class RecordSummary(models.Model): | |||||||
|     month = models.DateField(primary_key=True) |     month = models.DateField(primary_key=True) | ||||||
|     credit_amount = models.PositiveIntegerField() |     credit_amount = models.PositiveIntegerField() | ||||||
|     debit_amount = models.PositiveIntegerField() |     debit_amount = models.PositiveIntegerField() | ||||||
|  |     balance = models.IntegerField() | ||||||
|  |  | ||||||
|     _label = None |     _label = None | ||||||
|  |  | ||||||
| @@ -337,10 +338,6 @@ class RecordSummary(models.Model): | |||||||
|     def label(self, value): |     def label(self, value): | ||||||
|         self._label = value |         self._label = value | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def balance(self): |  | ||||||
|         return self.credit_amount - self.debit_amount |  | ||||||
|  |  | ||||||
|     _cumulative_balance = None |     _cumulative_balance = None | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|   | |||||||
							
								
								
									
										169
									
								
								accounting/templates/accounting/ledger_summary.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								accounting/templates/accounting/ledger_summary.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | |||||||
|  | {% extends "base.html" %} | ||||||
|  | {% comment %} | ||||||
|  | The Mia Accounting Application | ||||||
|  | ledger_summary.html: The template for the ledger summary 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/17 | ||||||
|  | {% endcomment %} | ||||||
|  | {% load i18n %} | ||||||
|  | {% load humanize %} | ||||||
|  | {% load mia_core %} | ||||||
|  | {% load accounting %} | ||||||
|  |  | ||||||
|  | {% block settings %} | ||||||
|  |   {% blocktrans asvar title with subject=current_subject.title|title context "Accounting|" %}Ledger Summary for {{ subject }}{% endblocktrans %} | ||||||
|  |   {% setvar "title" title %} | ||||||
|  | {% 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-file-invoice-dollar" %} | ||||||
|  |     {% trans "Ledger Summary" context "Accounting|" as current_report_title %} | ||||||
|  |     {% include "accounting/include/report-chooser.html" %} | ||||||
|  |   {% endwith %} | ||||||
|  |   <div class="btn-group"> | ||||||
|  |     <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown"> | ||||||
|  |       <span class="d-none d-md-inline">{{ current_subject.title|title }}</span> | ||||||
|  |       <span class="d-md-none">{% trans "Subject" context "Accounting|" as text %}{{ text|force_escape }}</span> | ||||||
|  |     </button> | ||||||
|  |     <div class="dropdown-menu subject-picker"> | ||||||
|  |       {% for subject in subjects %} | ||||||
|  |         <a class="dropdown-item {% if subject.code == current_subject.code %} active {% endif %}>" href="{% url "accounting:cash-summary" subject.code %}"> | ||||||
|  |           {{ subject.title|title }} | ||||||
|  |         </a> | ||||||
|  |       {% endfor %} | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | {% if records %} | ||||||
|  |   {% include "mia_core/include/pagination.html" %} | ||||||
|  |  | ||||||
|  |   {# The table for large screens #} | ||||||
|  |   <table class="table table-striped table-hover d-none d-sm-table general-journal-table"> | ||||||
|  |     <thead> | ||||||
|  |       <tr> | ||||||
|  |         <th scope="col">{% trans "Month" 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="amount" scope="col">{% trans "Balance" context "Accounting|" as text %}{{ text|force_escape }}</th> | ||||||
|  |         <th class="amount" scope="col">{% trans "Cumulative Balance" 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 class="{% if current_subject.code|first in "12" and record.balance < 0 %} table-danger {% endif %}"> | ||||||
|  |           <td>{{ record.label }}</td> | ||||||
|  |           <td class="amount">{{ record.debit_amount|accounting_amount }}</td> | ||||||
|  |           <td class="amount">{{ record.credit_amount|accounting_amount }}</td> | ||||||
|  |           <td class="amount {% if record.balance < 0 %} text-danger {% endif %}">{{ record.balance|accounting_amount }}</td> | ||||||
|  |           <td class="amount {% if record.cumulative_balance < 0 %} text-danger {% endif %}">{{ record.cumulative_balance|accounting_amount }}</td> | ||||||
|  |           <td class="actions"> | ||||||
|  |             {% if record.month is not None %} | ||||||
|  |               <a class="btn btn-info" role="button" href="{% url "accounting:ledger" current_subject.code record.month|date:"Y-m" %}"> | ||||||
|  |                 <i class="fas fa-eye"></i> | ||||||
|  |                 <span class="d-none d-lg-inline">{% trans "View" context "Accounting|" as text %}{{ text|force_escape }}</span> | ||||||
|  |               </a> | ||||||
|  |             {% endif %} | ||||||
|  |           </td> | ||||||
|  |         </tr> | ||||||
|  |       {% endfor %} | ||||||
|  |     </tbody> | ||||||
|  |   </table> | ||||||
|  |  | ||||||
|  |   {# The list for small screens #} | ||||||
|  |   <ul class="list-group d-sm-none"> | ||||||
|  |     {% for record in records %} | ||||||
|  |       <li class="list-group-item {% if current_subject.code|first in "12" and record.balance < 0 %} list-group-item-danger {% endif %}"> | ||||||
|  |         {% if record.month is not None %} | ||||||
|  |           <a class="list-group-item-action d-flex justify-content-between align-items-center" href="{% url "accounting:ledger" current_subject.code record.month|date:"Y-m" %}"> | ||||||
|  |             {{ record.label }} | ||||||
|  |             <div> | ||||||
|  |               <span class="badge badge-success badge-pill"> | ||||||
|  |                 {{ record.debit_amount|accounting_amount }} | ||||||
|  |               </span> | ||||||
|  |               <span class="badge badge-warning badge-pill"> | ||||||
|  |                 {{ record.credit_amount|accounting_amount }} | ||||||
|  |               </span> | ||||||
|  |               <span class="badge {% if record.balance < 0 %} badge-danger {% else %} badge-info {% endif %} badge-pill"> | ||||||
|  |                 {{ record.balance|intcomma:False }} | ||||||
|  |               </span> | ||||||
|  |               <span class="badge {% if record.cumulative_balance < 0 %} badge-danger {% else %} badge-info {% endif %} badge-pill"> | ||||||
|  |                 {{ record.cumulative_balance|intcomma:False }} | ||||||
|  |               </span> | ||||||
|  |               <span class="badge {% if record.balance < 0 %} badge-danger {% else %} badge-info {% endif %} badge-pill"> | ||||||
|  |                 {{ record.balance|intcomma:False }} | ||||||
|  |               </span> | ||||||
|  |               <span class="badge {% if record.cumulative_balance < 0 %} badge-danger {% else %} badge-primary {% endif %} badge-pill"> | ||||||
|  |                 {{ record.cumulative_balance|intcomma:False }} | ||||||
|  |               </span> | ||||||
|  |             </div> | ||||||
|  |           </a> | ||||||
|  |         {% else %} | ||||||
|  |           <div class="d-flex justify-content-between align-items-center"> | ||||||
|  |             {{ record.label }} | ||||||
|  |             <div> | ||||||
|  |               <span class="badge badge-success badge-pill"> | ||||||
|  |                 {{ record.debit_amount|accounting_amount }} | ||||||
|  |               </span> | ||||||
|  |               <span class="badge badge-warning badge-pill"> | ||||||
|  |                 {{ record.credit_amount|accounting_amount }} | ||||||
|  |               </span> | ||||||
|  |               <span class="badge {% if record.balance < 0 %} badge-danger {% else %} badge-info {% endif %} badge-pill"> | ||||||
|  |                 {{ record.balance|intcomma:False }} | ||||||
|  |               </span> | ||||||
|  |               <span class="badge {% if record.cumulative_balance < 0 %} badge-danger {% else %} badge-primary {% endif %} badge-pill"> | ||||||
|  |                 {{ record.cumulative_balance|intcomma:False }} | ||||||
|  |               </span> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         {% endif %} | ||||||
|  |       </li> | ||||||
|  |     {% endfor %} | ||||||
|  |   </ul> | ||||||
|  | {% else %} | ||||||
|  |   <p>{{ _("There is currently no data.")|force_escape }}</p> | ||||||
|  | {% endif %} | ||||||
|  |  | ||||||
|  | {% endblock %} | ||||||
| @@ -55,7 +55,7 @@ urlpatterns = [ | |||||||
|     path("ledger-summary", |     path("ledger-summary", | ||||||
|          mia_core_views.todo, name="ledger-summary.home"), |          mia_core_views.todo, name="ledger-summary.home"), | ||||||
|     path("ledger-summary/<str:subject_code>", |     path("ledger-summary/<str:subject_code>", | ||||||
|          mia_core_views.todo, name="ledger-summary"), |          views.ledger_summary, name="ledger-summary"), | ||||||
|     path("journal", |     path("journal", | ||||||
|          mia_core_views.todo, name="journal.home"), |          mia_core_views.todo, name="journal.home"), | ||||||
|     path("journal/<str:period_spec>", |     path("journal/<str:period_spec>", | ||||||
|   | |||||||
| @@ -455,3 +455,53 @@ def ledger(request, subject_code, period_spec): | |||||||
|         "reports": ReportUrl(ledger=current_subject, period=period), |         "reports": ReportUrl(ledger=current_subject, period=period), | ||||||
|         "subjects": subjects, |         "subjects": subjects, | ||||||
|     }) |     }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def ledger_summary(request, subject_code): | ||||||
|  |     """The ledger summary report.""" | ||||||
|  |     # The subject | ||||||
|  |     subjects = _ledger_subjects() | ||||||
|  |     current_subject = None | ||||||
|  |     for subject in subjects: | ||||||
|  |         if subject.code == subject_code: | ||||||
|  |             current_subject = subject | ||||||
|  |     if current_subject is None: | ||||||
|  |         raise Http404() | ||||||
|  |     if connection.vendor == "postgresql": | ||||||
|  |         month_definition = "CAST(DATE_TRUNC('month', t.date) AS date)" | ||||||
|  |     elif connection.vendor == "sqlite": | ||||||
|  |         month_definition = "DATE(t.date, 'start of month')" | ||||||
|  |     else: | ||||||
|  |         month_definition = None | ||||||
|  |     # The SQL query | ||||||
|  |     records = list(RecordSummary.objects.raw( | ||||||
|  |         f"""SELECT | ||||||
|  |   {month_definition} AS month, | ||||||
|  |   SUM(CASE WHEN r.is_credit THEN 0 ELSE r.amount END) AS debit_amount, | ||||||
|  |   SUM(CASE WHEN r.is_credit THEN r.amount ELSE 0 END) AS credit_amount, | ||||||
|  |   SUM(CASE WHEN r.is_credit THEN -1 ELSE 1 END * r.amount) AS balance | ||||||
|  | FROM accounting_records AS r | ||||||
|  |   INNER JOIN accounting_transactions AS t ON r.transaction_sn = t.sn | ||||||
|  |   INNER JOIN accounting_subjects AS s ON r.subject_sn = s.sn | ||||||
|  | WHERE s.code LIKE %s | ||||||
|  | GROUP BY month | ||||||
|  | ORDER BY month""", | ||||||
|  |         [current_subject.code + "%"])) | ||||||
|  |     cumulative_balance = 0 | ||||||
|  |     for record in records: | ||||||
|  |         cumulative_balance = cumulative_balance + record.balance | ||||||
|  |         record.cumulative_balance = cumulative_balance | ||||||
|  |     records.append(RecordSummary( | ||||||
|  |         label=pgettext("Accounting|", "Total"), | ||||||
|  |         credit_amount=sum([x.credit_amount for x in records]), | ||||||
|  |         debit_amount=sum([x.debit_amount for x in records]), | ||||||
|  |         cumulative_balance=cumulative_balance, | ||||||
|  |     )) | ||||||
|  |     pagination = Pagination(request, records, True) | ||||||
|  |     return render(request, "accounting/ledger_summary.html", { | ||||||
|  |         "records": pagination.records, | ||||||
|  |         "pagination": pagination, | ||||||
|  |         "current_subject": current_subject, | ||||||
|  |         "reports": ReportUrl(cash=current_subject), | ||||||
|  |         "subjects": subjects, | ||||||
|  |     }) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user