Replaced the function-based txn_sort view with the class-based TransactionSortView in the accounting application.
This commit is contained in:
parent
b829002c61
commit
8f6c8f3497
@ -18,8 +18,9 @@
|
||||
"""The forms of the Mia core application.
|
||||
|
||||
"""
|
||||
import datetime
|
||||
import re
|
||||
from typing import Optional
|
||||
from typing import Optional, List, Dict
|
||||
|
||||
from django import forms
|
||||
from django.core.validators import RegexValidator
|
||||
@ -27,7 +28,7 @@ from django.db.models import Q, Max
|
||||
from django.db.models.functions import Length
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from .models import Account, Record
|
||||
from .models import Account, Record, Transaction
|
||||
from .validators import validate_record_account_code, validate_record_id
|
||||
|
||||
|
||||
@ -342,6 +343,41 @@ class TransactionForm(forms.Form):
|
||||
if "amount" in x.data and "amount" not in x.errors])
|
||||
|
||||
|
||||
class TransactionSortForm(forms.Form):
|
||||
"""A form to sort the transactions in a same day."""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.date = None
|
||||
self.txn_list: Optional[List[Transaction]] = None
|
||||
self.txn_orders: List[TransactionSortForm.Order] = []
|
||||
|
||||
@staticmethod
|
||||
def from_post(date: datetime.date, post: Dict[str, str]):
|
||||
form = TransactionSortForm({})
|
||||
form.date = date
|
||||
post_orders: List[TransactionSortForm.Order] = []
|
||||
for txn in Transaction.objects.filter(date=date).all():
|
||||
key = F"transaction-{txn.pk}-ord"
|
||||
if key not in post:
|
||||
post_orders.append(form.Order(txn, 9999))
|
||||
elif not re.match("^[0-9]+$", post[key]):
|
||||
post_orders.append(form.Order(txn, 9999))
|
||||
else:
|
||||
post_orders.append(form.Order(txn, int(post[key])))
|
||||
post_orders.sort(key=lambda x: (x.order, x.txn.ord))
|
||||
form.txn_orders = []
|
||||
for i in range(len(post_orders)):
|
||||
form.txn_orders.append(form.Order(post_orders[i].txn, i + 1))
|
||||
form.txn_list = [x.txn for x in form.txn_orders]
|
||||
return form
|
||||
|
||||
class Order:
|
||||
"""A transaction order"""
|
||||
def __init__(self, txn: Transaction, order: int):
|
||||
self.txn = txn
|
||||
self.order = order
|
||||
|
||||
|
||||
class AccountForm(forms.Form):
|
||||
"""An account form."""
|
||||
code = forms.CharField(
|
||||
|
@ -27,7 +27,7 @@ First written: 2020/8/6
|
||||
{% load accounting %}
|
||||
|
||||
{% block settings %}
|
||||
{% blocktrans asvar title with date=date|smart_date %}Reorder the Transactions in {{ date }}{% endblocktrans %}
|
||||
{% blocktrans asvar title with date=form.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 %}
|
||||
@ -50,12 +50,12 @@ First written: 2020/8/6
|
||||
</div>
|
||||
|
||||
<div id="txn-date" class="col-sm-10">
|
||||
{{ date|smart_date }}
|
||||
{{ form.date|smart_date }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if txn_list|length > 1 %}
|
||||
<form action="{% url "accounting:transactions.sort" date as url %}{% url_keep_return url %}" method="post">
|
||||
{% if form.txn_list|length > 1 %}
|
||||
<form action="{% url "accounting:transactions.sort" form.date as url %}{% url_keep_return url %}" method="post">
|
||||
{% csrf_token %}
|
||||
<table class="table general-journal-table">
|
||||
<thead>
|
||||
@ -68,7 +68,7 @@ First written: 2020/8/6
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="transactions">
|
||||
{% for txn in txn_list %}
|
||||
{% for txn in form.txn_list %}
|
||||
<tr id="transaction-{{ txn.pk }}" class="transaction {% if not txn.is_balanced %} table-danger {% endif %}">
|
||||
<td class="actions">
|
||||
<div class="btn-group">
|
||||
|
@ -84,7 +84,7 @@ urlpatterns = [
|
||||
path("transactions/<txn:txn>/delete",
|
||||
views.TransactionDeleteView.as_view(), name="transactions.delete"),
|
||||
path("transactions/sort/<date:date>",
|
||||
views.txn_sort, name="transactions.sort"),
|
||||
views.TransactionSortFormView.as_view(), name="transactions.sort"),
|
||||
path("accounts",
|
||||
views.AccountListView.as_view(), name="accounts"),
|
||||
path("accounts/create",
|
||||
|
@ -18,7 +18,6 @@
|
||||
"""The view controllers of the accounting application.
|
||||
|
||||
"""
|
||||
import datetime
|
||||
import json
|
||||
import re
|
||||
from typing import Dict, Optional
|
||||
@ -39,14 +38,13 @@ from django.utils.translation import gettext as _, gettext_noop
|
||||
from django.views.decorators.http import require_GET, require_POST
|
||||
from django.views.generic import RedirectView, ListView, DetailView
|
||||
|
||||
from mia_core import stored_post
|
||||
from mia_core.digest_auth import login_required
|
||||
from mia_core.period import Period
|
||||
from mia_core.utils import Pagination, get_multi_lingual_search, UrlBuilder, \
|
||||
strip_post, PaginationException
|
||||
from mia_core.utils import Pagination, get_multi_lingual_search, \
|
||||
PaginationException
|
||||
from mia_core.views import DeleteView, FormView
|
||||
from . import utils
|
||||
from .forms import AccountForm, TransactionForm
|
||||
from .forms import AccountForm, TransactionForm, TransactionSortForm
|
||||
from .models import Record, Transaction, Account
|
||||
|
||||
|
||||
@ -882,59 +880,44 @@ class TransactionDeleteView(DeleteView):
|
||||
return self.request.GET.get("r") or reverse("accounting:home")
|
||||
|
||||
|
||||
@login_required
|
||||
def txn_sort(request: HttpRequest, date: datetime.date) -> HttpResponse:
|
||||
"""The view for the form to sort the transactions in a same day.
|
||||
@method_decorator(login_required, name="dispatch")
|
||||
class TransactionSortFormView(FormView):
|
||||
"""The form to sort the transactions in a same day."""
|
||||
template_name = "accounting/transaction-sort.html"
|
||||
form_class = TransactionSortForm
|
||||
not_modified_message = gettext_noop(
|
||||
"The transaction orders were not modified.")
|
||||
success_message = gettext_noop(
|
||||
"The transaction orders were saved successfully.")
|
||||
|
||||
Args:
|
||||
request: The request.
|
||||
date: The day.
|
||||
|
||||
Returns:
|
||||
The response.
|
||||
|
||||
Raises:
|
||||
Http404: When there are less than two transactions in this day.
|
||||
"""
|
||||
transactions = Transaction.objects.filter(date=date).order_by("ord")
|
||||
if len(transactions) < 2:
|
||||
def get_form(self, **kwargs):
|
||||
"""Returns the form for the template."""
|
||||
form = super().get_form()
|
||||
if form.txn_list is None:
|
||||
form.date = self.kwargs["date"]
|
||||
form.txn_list = Transaction.objects.filter(date=form.date)\
|
||||
.order_by("ord").all()
|
||||
if len(form.txn_list) < 2:
|
||||
raise Http404
|
||||
if request.method != "POST":
|
||||
return render(request, "accounting/transaction-sort.html", {
|
||||
"txn_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.")
|
||||
return form
|
||||
|
||||
if len(errors) > 0:
|
||||
return stored_post.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
|
||||
modified = [[x, post[F"transaction-{x.pk}-ord"]] for x in transactions
|
||||
if x.ord != post[F"transaction-{x.pk}-ord"]]
|
||||
def make_form_from_post(self, post: Dict[str, str]) -> TransactionSortForm:
|
||||
"""Creates and returns the form from the POST data."""
|
||||
return TransactionSortForm.from_post(self.kwargs["date"], post)
|
||||
|
||||
def form_valid(self, form: TransactionSortForm) -> HttpResponseRedirect:
|
||||
"""Handles the action when the POST form is valid."""
|
||||
modified = [x for x in form.txn_orders if x.txn.ord != x.order]
|
||||
if len(modified) == 0:
|
||||
message = gettext_noop("The transaction orders were not modified.")
|
||||
message = self.get_not_modified_message(form.cleaned_data)
|
||||
else:
|
||||
with transaction.atomic():
|
||||
for x in modified:
|
||||
Transaction.objects.filter(pk=x[0].pk).update(ord=x[1])
|
||||
message = gettext_noop(
|
||||
"The transaction orders were saved successfully.")
|
||||
messages.success(request, message)
|
||||
return redirect(request.GET.get("r") or reverse("accounting:home"))
|
||||
Transaction.objects.filter(pk=x.txn.pk).update(ord=x.order)
|
||||
message = self.get_success_message(form.cleaned_data)
|
||||
messages.success(self.request, message)
|
||||
return redirect(self.request.GET.get("r")
|
||||
or reverse("accounting:home"))
|
||||
|
||||
|
||||
@method_decorator(require_GET, name="dispatch")
|
||||
|
Loading…
Reference in New Issue
Block a user