Replaced the function-based account_form and account_store views with the class-based AccountFormView in the accounting application.

This commit is contained in:
依瑪貓 2020-08-14 00:36:29 +08:00
parent 95b6a6a4ea
commit f82c4afbfe
3 changed files with 48 additions and 71 deletions

View File

@ -63,21 +63,22 @@ class Account(DirtyFieldsMixin, models.Model):
self.is_for_credit = None self.is_for_credit = None
self._is_in_use = None self._is_in_use = None
self._is_parent_and_in_use = None self._is_parent_and_in_use = None
self.current_user = None
def __str__(self): def __str__(self):
"""Returns the string representation of this account.""" """Returns the string representation of this account."""
return self.code.__str__() + " " + self.title return self.code.__str__() + " " + self.title
def save(self, current_user=None, force_insert=False, force_update=False, def save(self, force_insert=False, force_update=False, using=None,
using=None, update_fields=None): update_fields=None):
self.parent = None if len(self.code) == 1\ self.parent = None if len(self.code) == 1\
else Account.objects.get(code=self.code[:-1]) else Account.objects.get(code=self.code[:-1])
if self.pk is None: if self.pk is None:
self.pk = new_pk(Account) self.pk = new_pk(Account)
if current_user is not None: if self.current_user is not None:
self.created_by = current_user self.created_by = self.current_user
if current_user is not None: if self.current_user is not None:
self.updated_by = current_user self.updated_by = self.current_user
with transaction.atomic(): with transaction.atomic():
super().save(force_insert=force_insert, force_update=force_update, super().save(force_insert=force_insert, force_update=force_update,
using=using, update_fields=update_fields) using=using, update_fields=update_fields)

View File

@ -92,9 +92,9 @@ urlpatterns = [
path("accounts", path("accounts",
views.AccountListView.as_view(), name="accounts"), views.AccountListView.as_view(), name="accounts"),
path("accounts/create", path("accounts/create",
views.account_form, name="accounts.create"), views.AccountFormView.as_view(), name="accounts.create"),
path("accounts/store", path("accounts/store",
views.account_store, name="accounts.store"), views.AccountFormView.as_view(), name="accounts.store"),
path("api/accounts", path("api/accounts",
views.api_account_list, name="api.accounts"), views.api_account_list, name="api.accounts"),
path("api/accounts/options", path("api/accounts/options",
@ -102,9 +102,9 @@ urlpatterns = [
path("accounts/<account:account>", path("accounts/<account:account>",
views.AccountView.as_view(), name="accounts.detail"), views.AccountView.as_view(), name="accounts.detail"),
path("accounts/<account:account>/edit", path("accounts/<account:account>/edit",
views.account_form, name="accounts.edit"), views.AccountFormView.as_view(), name="accounts.edit"),
path("accounts/<account:account>/update", path("accounts/<account:account>/update",
views.account_store, name="accounts.update"), views.AccountFormView.as_view(), name="accounts.update"),
path("accounts/<account:account>/delete", path("accounts/<account:account>/delete",
views.account_delete, name="accounts.delete"), views.account_delete, name="accounts.delete"),
] ]

View File

@ -21,11 +21,12 @@
import datetime import datetime
import json import json
import re import re
from typing import Dict, Optional
from django.contrib import messages from django.contrib import messages
from django.db import transaction from django.db import transaction
from django.db.models import Sum, Case, When, F, Q, Count, BooleanField, \ from django.db.models import Sum, Case, When, F, Q, Count, BooleanField, \
ExpressionWrapper ExpressionWrapper, Exists, OuterRef
from django.db.models.functions import TruncMonth, Coalesce from django.db.models.functions import TruncMonth, Coalesce
from django.http import JsonResponse, HttpResponseRedirect, Http404, \ from django.http import JsonResponse, HttpResponseRedirect, Http404, \
HttpRequest, HttpResponse HttpRequest, HttpResponse
@ -43,7 +44,7 @@ from mia_core.digest_auth import login_required
from mia_core.period import Period from mia_core.period import Period
from mia_core.utils import Pagination, get_multi_lingual_search, UrlBuilder, \ from mia_core.utils import Pagination, get_multi_lingual_search, UrlBuilder, \
strip_post, PaginationException strip_post, PaginationException
from mia_core.views import DeleteView from mia_core.views import DeleteView, FormView
from . import utils from . import utils
from .forms import AccountForm, TransactionForm from .forms import AccountForm, TransactionForm
from .models import Record, Transaction, Account from .models import Record, Transaction, Account
@ -965,10 +966,9 @@ def txn_sort(request: HttpRequest, date: datetime.date) -> HttpResponse:
class AccountListView(ListView): class AccountListView(ListView):
"""The view to list the accounts.""" """The view to list the accounts."""
queryset = Account.objects\ queryset = Account.objects\
.annotate(child_count=Count("child_set"),
record_count=Count("record"))\
.annotate(is_parent_and_in_use=ExpressionWrapper( .annotate(is_parent_and_in_use=ExpressionWrapper(
Q(child_count__gt=0) & Q(record_count__gt=0), Exists(Account.objects.filter(parent=OuterRef("pk")))
& Exists(Record.objects.filter(account=OuterRef("pk"))),
output_field=BooleanField()))\ output_field=BooleanField()))\
.order_by("code") .order_by("code")
@ -981,69 +981,45 @@ class AccountView(DetailView):
return self.request.resolver_match.kwargs["account"] return self.request.resolver_match.kwargs["account"]
@require_GET @method_decorator(login_required, name="dispatch")
@login_required class AccountFormView(FormView):
def account_form(request: HttpRequest, model = Account
account: Account = None) -> HttpResponse: form = AccountForm
"""The view to edit an accounting transaction. not_modified_message = gettext_noop("This account was not modified.")
success_message = gettext_noop("This account was saved successfully.")
Args: def make_form_from_post(self, post: Dict[str, str]) -> AccountForm:
request: The request. """Creates and returns the form from the POST data."""
account: The account.
Returns:
The response.
"""
previous_post = stored_post.get_previous_post(request)
if previous_post is not None:
form = AccountForm(previous_post)
elif account is not None:
form = AccountForm({
"code": account.code,
"title": account.title,
})
else:
form = AccountForm()
form.account = account
return render(request, "accounting/account_form.html", {
"form": form,
})
@require_POST
@login_required
def account_store(request: HttpRequest,
account: Account = None) -> HttpResponseRedirect:
"""The view to store an account.
Args:
request: The request.
account: The account.
Returns:
The response.
"""
post = request.POST.dict()
strip_post(post)
form = AccountForm(post) form = AccountForm(post)
form.account = account form.account = self.get_current_object()
if not form.is_valid(): return form
if account is None:
url = reverse("accounting:accounts.create") def make_form_from_model(self, obj: Account) -> AccountForm:
else: """Creates and returns the form from a data model."""
url = reverse("accounting:accounts.edit", args=(account,)) form = AccountForm({
return stored_post.error_redirect(request, url, post) "code": obj.code,
if account is None: "title": obj.title,
account = Account() })
account.code = form["code"].value() form.account = obj
account.title = form["title"].value() return form
if not account.is_dirty():
message = gettext_noop("This account was not modified.") def fill_model_from_form(self, obj: Account, form: AccountForm) -> None:
else: """Fills in the data model from the form."""
account.save(current_user=request.user) obj.code = form["code"].value()
message = gettext_noop("This account was saved successfully.") obj.title = form["title"].value()
messages.success(request, message) obj.current_user = self.request.user
return redirect("accounting:accounts.detail", account)
def get_error_url(self) -> str:
"""Returns the URL on error."""
user = self.get_current_object()
return reverse("accounting:accounts.create") if user is None\
else reverse("accounting:accounts.edit", args=(user,))
def get_current_object(self) -> Optional[Account]:
"""Returns the current object, or None on a create form."""
if "account" in self.kwargs:
return self.kwargs["account"]
return None
@require_POST @require_POST