Added the transaction sorting in the accounting application.

This commit is contained in:
依瑪貓 2020-08-06 23:51:20 +08:00
parent 9d49815462
commit f970974e71
8 changed files with 385 additions and 27 deletions

View File

@ -6,9 +6,9 @@
msgid ""
msgstr ""
"Project-Id-Version: mia-js 1.0\n"
"Report-Msgid-Bugs-To: imacat <imacat@mail.imacat.idv.tw>\n"
"POT-Creation-Date: 2020-08-06 01:42+0800\n"
"PO-Revision-Date: 2020-08-06 01:46+0800\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-08-06 23:47+0800\n"
"PO-Revision-Date: 2020-08-06 23:48+0800\n"
"Last-Translator: imacat <imacat@mail.imacat.idv.tw>\n"
"Language-Team: Traditional Chinese <imacat@mail.imacat.idv.tw>\n"
"Language: Traditional Chinese\n"
@ -106,6 +106,7 @@ msgstr "記帳"
#: accounting/templates/accounting/ledger-summary.html:45
#: accounting/templates/accounting/ledger.html:46
#: accounting/templates/accounting/search.html:46
#: accounting/templates/accounting/transactions/sort.html:85
#: accounting/templates/accounting/trial-balance.html:46
msgid "Cash Expense"
msgstr "現金支出"
@ -118,6 +119,7 @@ msgstr "現金支出"
#: accounting/templates/accounting/ledger-summary.html:48
#: accounting/templates/accounting/ledger.html:49
#: accounting/templates/accounting/search.html:49
#: accounting/templates/accounting/transactions/sort.html:87
#: accounting/templates/accounting/trial-balance.html:49
msgid "Cash Income"
msgstr "現金收入"
@ -130,6 +132,7 @@ msgstr "現金收入"
#: accounting/templates/accounting/ledger-summary.html:51
#: accounting/templates/accounting/ledger.html:52
#: accounting/templates/accounting/search.html:52
#: accounting/templates/accounting/transactions/sort.html:89
#: accounting/templates/accounting/trial-balance.html:52
msgid "Transfer"
msgstr "轉帳"
@ -182,14 +185,14 @@ msgstr "查閱"
#: accounting/templates/accounting/income-statement.html:122
#: accounting/templates/accounting/income-statement.html:177
#: accounting/templates/accounting/income-statement.html:187
#: accounting/templates/accounting/transactions/expense/form.html:82
#: accounting/templates/accounting/transactions/expense/form.html:80
#: accounting/templates/accounting/transactions/expense/view.html:145
#: accounting/templates/accounting/transactions/expense/view.html:163
#: accounting/templates/accounting/transactions/income/form.html:82
#: accounting/templates/accounting/transactions/income/form.html:80
#: accounting/templates/accounting/transactions/income/view.html:145
#: accounting/templates/accounting/transactions/income/view.html:163
#: accounting/templates/accounting/transactions/transfer/form.html:84
#: accounting/templates/accounting/transactions/transfer/form.html:110
#: accounting/templates/accounting/transactions/transfer/form.html:82
#: accounting/templates/accounting/transactions/transfer/form.html:108
#: accounting/templates/accounting/transactions/transfer/view.html:141
#: accounting/templates/accounting/transactions/transfer/view.html:159
#: accounting/templates/accounting/transactions/transfer/view.html:188
@ -312,6 +315,7 @@ msgstr "摘要"
#: accounting/templates/accounting/ledger.html:149
#: accounting/templates/accounting/search.html:93
#: accounting/templates/accounting/search.html:128
#: accounting/templates/accounting/transactions/sort.html:120
msgid "Unbalanced"
msgstr "借貸不平衡"
@ -446,6 +450,7 @@ msgid "Income Statement %(prep_period)s"
msgstr "%(prep_period)s的損益表"
#: accounting/templates/accounting/income-statement.html:80
#: accounting/templates/accounting/transactions/sort.html:66
msgid "Amount"
msgstr "金額"
@ -458,7 +463,7 @@ msgstr "%(prep_period)s的日記簿"
#: accounting/templates/accounting/ledger-summary.html:81
#: accounting/templates/accounting/ledger.html:91
#: accounting/templates/accounting/search.html:80
#: accounting/templates/accounting/transactions/transfer/form.html:67
#: accounting/templates/accounting/transactions/transfer/form.html:65
#: accounting/templates/accounting/transactions/transfer/view.html:120
#: accounting/templates/accounting/trial-balance.html:83
msgid "Debit"
@ -468,7 +473,7 @@ msgstr "借方"
#: accounting/templates/accounting/ledger-summary.html:82
#: accounting/templates/accounting/ledger.html:92
#: accounting/templates/accounting/search.html:81
#: accounting/templates/accounting/transactions/transfer/form.html:93
#: accounting/templates/accounting/transactions/transfer/form.html:91
#: accounting/templates/accounting/transactions/transfer/view.html:167
#: accounting/templates/accounting/trial-balance.html:84
msgid "Credit"
@ -476,6 +481,7 @@ msgstr "貸方"
#: accounting/templates/accounting/journal.html:80
#: accounting/templates/accounting/search.html:82
#: accounting/templates/accounting/transactions/sort.html:67
msgid "Notes"
msgstr "註記"
@ -513,33 +519,36 @@ msgstr "現金支出傳票"
#: accounting/templates/accounting/transactions/expense/view.html:72
#: accounting/templates/accounting/transactions/income/form.html:44
#: accounting/templates/accounting/transactions/income/view.html:72
#: accounting/templates/accounting/transactions/sort.html:43
#: accounting/templates/accounting/transactions/transfer/form.html:44
#: accounting/templates/accounting/transactions/transfer/view.html:72
msgctxt "Navigation|"
msgid "Back"
msgstr "回上頁"
#: accounting/templates/accounting/transactions/expense/form.html:57
#: accounting/templates/accounting/transactions/expense/form.html:55
#: accounting/templates/accounting/transactions/expense/view.html:122
#: accounting/templates/accounting/transactions/income/form.html:57
#: accounting/templates/accounting/transactions/income/form.html:55
#: accounting/templates/accounting/transactions/income/view.html:122
#: accounting/templates/accounting/transactions/transfer/form.html:57
#: accounting/templates/accounting/transactions/sort.html:49
#: accounting/templates/accounting/transactions/transfer/form.html:55
#: accounting/templates/accounting/transactions/transfer/view.html:114
msgid "Date:"
msgstr "日期:"
#: accounting/templates/accounting/transactions/expense/form.html:92
#: accounting/templates/accounting/transactions/expense/form.html:90
#: accounting/templates/accounting/transactions/expense/view.html:171
#: accounting/templates/accounting/transactions/income/form.html:92
#: accounting/templates/accounting/transactions/income/form.html:90
#: accounting/templates/accounting/transactions/income/view.html:171
#: accounting/templates/accounting/transactions/transfer/form.html:121
#: accounting/templates/accounting/transactions/transfer/form.html:119
#: accounting/templates/accounting/transactions/transfer/view.html:217
msgid "Notes:"
msgstr "註記:"
#: accounting/templates/accounting/transactions/expense/form.html:104
#: accounting/templates/accounting/transactions/income/form.html:104
#: accounting/templates/accounting/transactions/transfer/form.html:133
#: accounting/templates/accounting/transactions/expense/form.html:102
#: accounting/templates/accounting/transactions/income/form.html:102
#: accounting/templates/accounting/transactions/sort.html:137
#: accounting/templates/accounting/transactions/transfer/form.html:131
msgid "Save"
msgstr "儲存"
@ -655,6 +664,19 @@ msgstr "現金收入傳票刪除確認"
msgid "Do you really want to delete this cash income transaction?"
msgstr "您真的要刪掉這張現金收入傳票嗎?"
#: accounting/templates/accounting/transactions/sort.html:30
#, python-format
msgid "Reorder the Transactions in %(date)s"
msgstr "%(date)s的傳票排序"
#: accounting/templates/accounting/transactions/sort.html:64
msgid "Type"
msgstr "類型"
#: accounting/templates/accounting/transactions/sort.html:65
msgid "Content"
msgstr "內容"
#: accounting/templates/accounting/transactions/transfer/form.html:28
#: accounting/templates/accounting/transactions/transfer/view.html:29
msgid "Transfer Transaction"
@ -705,22 +727,38 @@ msgstr "稅前淨利"
msgid "After Tax Income"
msgstr "稅後淨利"
#: accounting/views.py:909
#: accounting/views.py:912
msgid "This transaction was not modified."
msgstr "會計傳票未異動。"
#: accounting/views.py:955
#: accounting/views.py:958
msgid "This transaction was saved successfully."
msgstr "會計傳票已存檔。"
#: accounting/views.py:987
#: accounting/views.py:990
msgid "This transaction was deleted successfully."
msgstr "會計傳票已刪除。"
#: accounting/views.py:1014
#: accounting/views.py:1022
msgid "Invalid arguments."
msgstr "參數無效。"
#: accounting/views.py:1024
msgid "Invalid order."
msgstr "次序格式錯誤。"
#: accounting/views.py:1040
msgid "The transaction orders were not modified."
msgstr "會計傳票次序未異動。"
#: accounting/views.py:1048
msgid "The transaction orders were saved successfully."
msgstr "會計傳票次序已儲存。"
#: accounting/views.py:1075
msgid "---Accounts In Use---"
msgstr "-----使用中科目-----"
#: accounting/views.py:1019
#: accounting/views.py:1080
msgid "---Accounts Not In Use---"
msgstr "-----未使用科目-----"

View File

@ -179,6 +179,16 @@ class Transaction(DirtyFieldsMixin, models.Model):
return sum([x.amount for x in self.debit_records
if isinstance(x.amount, int)])
@property
def debit_summaries(self):
"""The summaries of the debit records.
Returns:
list[str]: The summaries of the debit records.
"""
return [x.account.title if x.summary is None else x.summary
for x in self.debit_records]
@property
def credit_records(self):
"""The credit records of this transaction.
@ -193,6 +203,25 @@ class Transaction(DirtyFieldsMixin, models.Model):
return sum([x.amount for x in self.credit_records
if isinstance(x.amount, int)])
@property
def credit_summaries(self):
"""The summaries of the credit records.
Returns:
list[str]: The summaries of the credit records.
"""
return [x.account.title if x.summary is None else x.summary
for x in self.credit_records]
@property
def amount(self):
"""The amount of this transaction.
Returns:
int: The amount of this transaction.
"""
return self.debit_total()
@property
def is_balanced(self):
"""Whether the sum of the amounts of the debit records is the

View File

@ -0,0 +1,43 @@
/* The Mia Website
* sort.css: The style sheet to reorder the transaction
*/
/* 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/10/12
*/
ul.txn-content-expense {
margin: 0;
padding: 0 0 0 0;
}
ul.txn-content-expense li {
list-style-type: none;
}
.txn-content-income {
margin: 0 0 0 1em;
}
ul.txn-content-income {
margin: 0 0 0 1em;
padding: 0 0 0 0;
}
ul.txn-content-income li {
list-style-type: none;
}
.amount {
text-align: right;
}

View File

@ -0,0 +1,47 @@
/* The Mia Website
* sort.js: The JavaScript to reorder the transactions
*/
/* 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/10/13
*/
// Initializes the page JavaScript.
$(function () {
$("#transactions").sortable({
classes: {
"ui-sortable-helper": "table-active",
},
cursor: "move",
stop: function () {
resetTransactionOrders();
},
});
});
/**
* Resets the order of the transactions according to their appearance.
*
* @private
*/
function resetTransactionOrders() {
const sorted = $("#transactions").sortable("toArray");
for (let i = 0; i < sorted.length; i++) {
$("#" + sorted[i] + "-ord")[0].value = i + 1;
}
}

View File

@ -0,0 +1,144 @@
{% extends "base.html" %}
{% comment %}
The Mia Accounting Application
sort.html: The template to sort transactions in a same day
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/8/6
{% endcomment %}
{% load static %}
{% load i18n %}
{% load humanize %}
{% load mia_core %}
{% load accounting %}
{% block settings %}
{% blocktrans asvar title with date=date|smart_date %}Reorder the Transactions in {{ date }}{% endblocktrans %}
{% setvar "title" title %}
{% setvar "use_jqueryui" True %}
{% static "accounting/css/report.css" as file %}{% add_css file %}
{% static "accounting/css/transactions-sort.css" as file %}{% add_css file %}
{% static "accounting/js/transaction-sort.js" as file %}{% add_js file %}
{% endblock %}
{% block content %}
<div class="btn-group btn-actions">
<a class="btn btn-primary" role="button" href="{% if "r" in request.GET %}{{ request.GET.r }}{% else %}{% url "accounting:home" %}{% endif %}">
<i class="fas fa-chevron-circle-left"></i>
{% trans "Back" context "Navigation|" as text %}{{ text|force_escape }}
</a>
</div>
<div class="form-group row">
<div class="col-sm-2">
<label for="txn-date">{{ _("Date:") }}</label>
</div>
<div id="txn-date" class="col-sm-10">
{{ date|smart_date }}
</div>
</div>
{% if item_list|length > 1 %}
<form action="{% url_keep_return "accounting:transactions.sort" date %}" method="post">
{% csrf_token %}
<table class="table general-journal-table">
<thead>
<tr>
<th class="actions" scope="col"></th>
<th scope="col">{{ _("Type") }}</th>
<th scope="col">{{ _("Content") }}</th>
<th class="amount" scope="col">{{ _("Amount") }}</th>
<th scope="col">{{ _("Notes") }}</th>
</tr>
</thead>
<tbody id="transactions">
{% for item in item_list %}
<tr id="transaction-{{ item.pk }}" class="transaction {% if not item.is_balanced %} table-danger {% endif %}">
<td class="actions">
<div class="btn-group">
<button class="btn btn-outline-secondary" type="button">
<i class="fas fa-sort"></i>
</button>
<a class="btn btn-primary" role="button" href="{% url_with_return "accounting:transactions.show" item.type item %}">
<i class="fas fa-eye"></i>
</a>
</div>
</td>
<td>
{% if item.is_cash_expense %}
{{ _("Cash Expense") }}
{% elif item.is_cash_income %}
{{ _("Cash Income") }}
{% else %}
{{ _("Transfer") }}
{% endif %}
</td>
<td>
<input id="transaction-{{ item.pk }}-ord" type="hidden" name="transaction-{{ item.pk }}-ord" value="{{ forloop.counter }}" />
{% if item.is_cash_expense %}
<ul class="txn-content-expense">
{% for summary in item.debit_sumaries %}
<li>{{ summary }}</li>
{% endfor %}
</ul>
{% elif item.is_cash_income %}
<ul class="txn-content-income">
{% for summary in item.credit_summaries %}
<li>{{ summary }}</li>
{% endfor %}
</ul>
{% else %}
<ul class="txn-content-expense">
{% for summary in item.debit_sumaries %}
<li>{{ summary }}</li>
{% endfor %}
</ul>
<ul class="txn-content-income">
{% for summary in item.credit_summaries %}
<li>{{ summary }}</li>
{% endfor %}
</ul>
{% endif %}
{% if not item.is_balanced %}
<span class="badge badge-danger badge-pill">
{{ _("Unbalanced") }}
</span>
{% endif %}
</td>
<td class="amount">
{{ item.amount|accounting_amount }}
</td>
<td>{{ item.notes|default:"" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-group row">
<div class="col-sm-12">
<button class="btn btn-primary" type="submit">
<i class="fas fa-save"></i>
{{ _("Save") }}
</button>
</div>
</div>
</form>
{% endif %}
{% endblock %}

View File

@ -87,9 +87,8 @@ urlpatterns = [
views.txn_store, name="transactions.update"),
path("transactions/<txn:txn>/delete",
views.txn_delete, name="transactions.delete"),
# TODO: To be done
path("transactions/sort/<date:date>",
mia_core_views.todo, name="transactions.sort"),
views.txn_sort, name="transactions.sort"),
# TODO: To be done
path("accounts",
mia_core_views.todo, name="accounts"),

View File

@ -25,7 +25,7 @@ from django.conf import settings
from django.db import transaction
from django.db.models import Sum, Case, When, F, Q, Max, Count, BooleanField
from django.db.models.functions import TruncMonth, Coalesce, Now
from django.http import JsonResponse, HttpResponseRedirect
from django.http import JsonResponse, HttpResponseRedirect, Http404
from django.shortcuts import render
from django.template.loader import render_to_string
from django.urls import reverse
@ -991,6 +991,64 @@ def txn_delete(request, txn):
return success_redirect(request, url, message)
@login_required
def txn_sort(request, date):
"""The view for the form to sort the transactions in a same day.
Args:
request (HttpRequest): The request.
date (datetime.date): The day.
Returns:
HttpResponse: The response.
Raises:
Http404: When ther are less than two transactions in this day.
"""
transactions = Transaction.objects.filter(date=date).order_by("ord")
if len(transactions) < 2:
raise Http404
if request.method != "POST":
return render(request, "accounting/transactions/sort.html", {
"item_list": transactions,
"date": date,
})
else:
post = request.POST.dict()
errors = {}
for txn in transactions:
key = F"transaction-{txn.pk}-ord"
if key not in post:
errors[key] = gettext_noop("Invalid arguments.")
elif not re.match("^[1-9][0-9]*", post[key]):
errors[key] = gettext_noop("Invalid order.")
if len(errors) > 0:
return error_redirect(
request, reverse("accounting:transactions.sort"), post)
keys = [F"transaction-{x.pk}-ord" for x in transactions]
keys.sort(key=lambda x: int(post[x]))
for i in range(len(keys)):
post[keys[i]] = i + 1
for txn in transactions:
txn.ord = post[F"transaction-{txn.pk}-ord"]
modified = [x for x in transactions if x.is_dirty()]
if len(modified) == 0:
url = request.GET.get("r") or reverse("accounting:home")
message = gettext_noop("The transaction orders were not modified.")
return success_redirect(request, url, message)
with transaction.atomic():
for txn in modified:
txn.save()
url = request.GET.get("r") or reverse("accounting:home")
message = gettext_noop(
"The transaction orders were saved successfully.")
return success_redirect(request, url, message)
@require_GET
@login_required
def account_options(request):

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: mia 1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-08-06 01:42+0800\n"
"POT-Creation-Date: 2020-08-06 23:47+0800\n"
"PO-Revision-Date: 2020-08-06 01:46+0800\n"
"Last-Translator: imacat <imacat@mail.imacat.idv.tw>\n"
"Language-Team: Traditional Chinese <imacat@mail.imacat.idv.tw>\n"