From f970974e71bfefc40d84d3dfdef1602c7c3400d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=9D=E7=91=AA=E8=B2=93?= Date: Thu, 6 Aug 2020 23:51:20 +0800 Subject: [PATCH] Added the transaction sorting in the accounting application. --- .../locale/zh_Hant/LC_MESSAGES/django.po | 84 +++++++--- accounting/models.py | 29 ++++ .../accounting/css/transactions-sort.css | 43 ++++++ .../static/accounting/js/transaction-sort.js | 47 ++++++ .../accounting/transactions/sort.html | 144 ++++++++++++++++++ accounting/urls.py | 3 +- accounting/views.py | 60 +++++++- mia_core/locale/zh_Hant/LC_MESSAGES/django.po | 2 +- 8 files changed, 385 insertions(+), 27 deletions(-) create mode 100644 accounting/static/accounting/css/transactions-sort.css create mode 100644 accounting/static/accounting/js/transaction-sort.js create mode 100644 accounting/templates/accounting/transactions/sort.html diff --git a/accounting/locale/zh_Hant/LC_MESSAGES/django.po b/accounting/locale/zh_Hant/LC_MESSAGES/django.po index 32c0cdb..765d321 100644 --- a/accounting/locale/zh_Hant/LC_MESSAGES/django.po +++ b/accounting/locale/zh_Hant/LC_MESSAGES/django.po @@ -6,9 +6,9 @@ msgid "" msgstr "" "Project-Id-Version: mia-js 1.0\n" -"Report-Msgid-Bugs-To: imacat \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 \n" "Language-Team: Traditional Chinese \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 "-----未使用科目-----" diff --git a/accounting/models.py b/accounting/models.py index 2a705be..bde0174 100644 --- a/accounting/models.py +++ b/accounting/models.py @@ -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 diff --git a/accounting/static/accounting/css/transactions-sort.css b/accounting/static/accounting/css/transactions-sort.css new file mode 100644 index 0000000..9228a0b --- /dev/null +++ b/accounting/static/accounting/css/transactions-sort.css @@ -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; +} \ No newline at end of file diff --git a/accounting/static/accounting/js/transaction-sort.js b/accounting/static/accounting/js/transaction-sort.js new file mode 100644 index 0000000..09688df --- /dev/null +++ b/accounting/static/accounting/js/transaction-sort.js @@ -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; + } +} diff --git a/accounting/templates/accounting/transactions/sort.html b/accounting/templates/accounting/transactions/sort.html new file mode 100644 index 0000000..43f5ebc --- /dev/null +++ b/accounting/templates/accounting/transactions/sort.html @@ -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 %} + + + +
+
+ +
+ +
+ {{ date|smart_date }} +
+
+ +{% if item_list|length > 1 %} +
+ {% csrf_token %} + + + + + + + + + + + + {% for item in item_list %} + + + + + + + + {% endfor %} + +
{{ _("Type") }}{{ _("Content") }}{{ _("Amount") }}{{ _("Notes") }}
+
+ + + + +
+
+ {% if item.is_cash_expense %} + {{ _("Cash Expense") }} + {% elif item.is_cash_income %} + {{ _("Cash Income") }} + {% else %} + {{ _("Transfer") }} + {% endif %} + + + {% if item.is_cash_expense %} +
    + {% for summary in item.debit_sumaries %} +
  • {{ summary }}
  • + {% endfor %} +
+ {% elif item.is_cash_income %} +
    + {% for summary in item.credit_summaries %} +
  • {{ summary }}
  • + {% endfor %} +
+ {% else %} +
    + {% for summary in item.debit_sumaries %} +
  • {{ summary }}
  • + {% endfor %} +
+
    + {% for summary in item.credit_summaries %} +
  • {{ summary }}
  • + {% endfor %} +
+ {% endif %} + {% if not item.is_balanced %} + + {{ _("Unbalanced") }} + + {% endif %} +
+ {{ item.amount|accounting_amount }} + {{ item.notes|default:"" }}
+ +
+
+ +
+
+
+{% endif %} + +{% endblock %} diff --git a/accounting/urls.py b/accounting/urls.py index dd22e09..8618f70 100644 --- a/accounting/urls.py +++ b/accounting/urls.py @@ -87,9 +87,8 @@ urlpatterns = [ views.txn_store, name="transactions.update"), path("transactions//delete", views.txn_delete, name="transactions.delete"), - # TODO: To be done path("transactions/sort/", - 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"), diff --git a/accounting/views.py b/accounting/views.py index a256529..a9c6929 100644 --- a/accounting/views.py +++ b/accounting/views.py @@ -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): diff --git a/mia_core/locale/zh_Hant/LC_MESSAGES/django.po b/mia_core/locale/zh_Hant/LC_MESSAGES/django.po index 1e9cdc5..6c7aa71 100644 --- a/mia_core/locale/zh_Hant/LC_MESSAGES/django.po +++ b/mia_core/locale/zh_Hant/LC_MESSAGES/django.po @@ -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 \n" "Language-Team: Traditional Chinese \n"