From 9d988f17ca34a7fbde2b6c58867fa8021f816732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=9D=E7=91=AA=E8=B2=93?= Date: Sat, 1 Aug 2020 23:56:41 +0800 Subject: [PATCH] Added forms and validators, and applied them to the transaction form in the accounting application. --- accounting/forms.py | 242 ++++++++++++++++++ .../accounting/transactions/expense/form.html | 35 ++- .../accounting/transactions/income/form.html | 35 ++- .../transactions/transfer/form.html | 66 +++-- accounting/utils.py | 159 ++++++++---- accounting/validators.py | 67 +++++ accounting/views.py | 85 ++---- mia_core/status.py | 10 +- 8 files changed, 513 insertions(+), 186 deletions(-) create mode 100644 accounting/forms.py create mode 100644 accounting/validators.py diff --git a/accounting/forms.py b/accounting/forms.py new file mode 100644 index 0000000..4dcb298 --- /dev/null +++ b/accounting/forms.py @@ -0,0 +1,242 @@ +# The core application of the Mia project. +# by imacat , 2020/7/31 + +# 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. + +"""The forms of the Mia core application. + +""" +import re + +from django import forms +from django.utils.translation import pgettext + +from .models import Account, Record +from .validators import validate_record_account_code, validate_record_id + + +class RecordForm(forms.Form): + """An accounting record form. + + Attributes: + transaction (Transaction|None): The current transaction or None. + is_credit (bool): Whether this is a credit record. + """ + id = forms.IntegerField( + required=False, + error_messages={ + "invalid": pgettext("Accounting|", "This record is not valid."), + }, + validators=[validate_record_id]) + account = forms.CharField( + error_messages={ + "required": pgettext("Accounting|", "Please select the account."), + }, + validators=[validate_record_account_code]) + summary = forms.CharField( + required=False, + max_length=128, + error_messages={ + "max_length": pgettext("Accounting|", "This summary is too long."), + }) + amount = forms.IntegerField( + min_value=1, + error_messages={ + "required": pgettext("Accounting|", "Please fill in the amount."), + "invalid": pgettext("Accounting|", "Please fill in a number."), + "min_value": pgettext( + "Accounting|", "The amount must be at least 1."), + }) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.transaction = None + self.is_credit = None + + def account_title(self): + """Returns the title of the specified account, if any. + + Returns: + str: The title of the specified account, or None if the specified + account is not available. + """ + try: + return Account.objects.get(code=self["account"].value()).title + except KeyError: + return None + except Account.DoesNotExist: + return None + + def clean(self): + """Validates the form globally. + + Raises: + ValidationError: When the validation fails. + """ + errors = [] + validators = [self._validate_transaction, self._validate_account_type] + for validator in validators: + try: + validator() + except forms.ValidationError as e: + errors.append(e) + if errors: + print(errors) + raise forms.ValidationError(errors) + + def _validate_transaction(self): + """Validates whether the transaction matches the transaction form. + + Raises: + ValidationError: When the validation fails. + """ + if "id" in self.errors: + return + if self.transaction is None: + if "id" in self.data: + error = forms.ValidationError( + pgettext("Accounting|", + "This record is not for this transaction."), + code="not_belong") + self.add_error("id", error) + raise error + else: + if "id" in self.data: + record = Record.objects.get(pk=self.data["id"]) + if record.transaction.pk != self.transaction.pk: + error = forms.ValidationError( + pgettext("Accounting|", + "This record is not for this transaction."), + code="not_belong") + self.add_error("id", error) + raise error + + def _validate_account_type(self): + """Validates whether the account is a correct debit or credit account. + + Raises: + ValidationError: When the validation fails. + """ + if "account" in self.errors: + return + if self.is_credit: + print(self.data["account"]) + if not re.match("^([123489]|7[1234])", self.data["account"]): + error = forms.ValidationError( + pgettext("Accounting|", + "This account is not for credit records."), + code="not_credit") + self.add_error("account", error) + raise error + else: + if not re.match("^([1235689]|7[5678])", self.data["account"]): + error = forms.ValidationError( + pgettext("Accounting|", + "This account is not for debit records."), + code="not_debit") + self.add_error("account", error) + raise error + + +class TransactionForm(forms.Form): + """A transaction form. + + Attributes: + txn_type (str): The transaction type. + transaction (Transaction|None): The current transaction or None + debit_records (list[RecordForm]): The debit records. + credit_records (list[RecordForm]): The credit records. + """ + date = forms.DateField( + required=True, + error_messages={ + "invalid": pgettext("Accounting|", "This date is not valid.") + }) + notes = forms.CharField( + required=False, + max_length=128, + error_messages={ + "max_length": pgettext("Accounting|", "This notes is too long.") + }) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.txn_type = None + self.transaction = None + self.debit_records = [] + self.credit_records = [] + + def clean(self): + """Validates the form globally. + + Raises: + ValidationError: When the validation fails. + """ + self._validate_balance() + + def _validate_balance(self): + """Validates whether the total amount of debit and credit records are + consistent. + + Raises: + ValidationError: When the validation fails. + """ + if self.txn_type != "transfer": + return + if self.debit_total() == self.credit_total(): + return + raise forms.ValidationError(pgettext( + "Accounting|", + "The total amount of debit and credit records are inconsistent."), + code="balance") + + def is_valid(self): + if not super(TransactionForm, self).is_valid(): + return False + for x in self.debit_records + self.credit_records: + if not x.is_valid(): + return False + return True + + def balance_error(self): + """Returns the error message when the transaction is imbalanced. + + Returns: + str: The error message when the transaction is imbalanced, or + None otherwise. + """ + errors = [x for x in self.non_field_errors().data + if x.code == "balance"] + if errors: + return errors[0].message + return None + + def debit_total(self): + """Returns the total amount of the debit records. + + Returns: + int: The total amount of the credit records. + """ + return sum([int(x.data["amount"]) for x in self.debit_records + if "amount" not in x.errors]) + + def credit_total(self): + """Returns the total amount of the credit records. + + Returns: + int: The total amount of the credit records. + """ + return sum([int(x.data["amount"]) for x in self.credit_records + if "amount" not in x.errors]) diff --git a/accounting/templates/accounting/transactions/expense/form.html b/accounting/templates/accounting/transactions/expense/form.html index cdec1a4..8d09721 100644 --- a/accounting/templates/accounting/transactions/expense/form.html +++ b/accounting/templates/accounting/transactions/expense/form.html @@ -33,13 +33,13 @@ First written: 2020/7/23 {% block content %} -
+ {% csrf_token %} {# TODO: To be done #} @@ -52,8 +52,8 @@ First written: 2020/7/23
- -
{{ errors|dict:"date"|default:"" }}
+ +
{{ item.date.errors.0|default:"" }}
@@ -64,32 +64,29 @@ First written: 2020/7/23
  • - {% if x.pk is not None %} - + {% if x.id.value %} + {% endif %} - - {% str_format "debit-{}-account" forloop.counter as field %} - + -
    {{ errors|dict:field|default:"" }}
    +
    {{ x.account.errors.0|default:"" }}
    - {% str_format "debit-{}-summary" forloop.counter as field %} - -
    {{ errors|dict:field|default:"" }}
    + +
    {{ x.summary.errors.0|default:"" }}
    - {% str_format "debit-{}-amount" forloop.counter as field %} - -
    {{ errors|dict:field|default:"" }}
    + +
    {{ x.amount.errors.0|default:"" }}
    @@ -136,8 +133,8 @@ First written: 2020/7/23
    - -
    {{ errors|dict:"notes"|default:"" }}
    + +
    {{ item.notes.errors.0|default:"" }}
    diff --git a/accounting/templates/accounting/transactions/income/form.html b/accounting/templates/accounting/transactions/income/form.html index 06440be..76dbe7e 100644 --- a/accounting/templates/accounting/transactions/income/form.html +++ b/accounting/templates/accounting/transactions/income/form.html @@ -33,13 +33,13 @@ First written: 2020/7/23 {% block content %} - + {% csrf_token %} {# TODO: To be done #} @@ -52,8 +52,8 @@ First written: 2020/7/23
    - -
    {{ errors|dict:"date"|default:"" }}
    + +
    {{ item.date.errors.0|default:"" }}
    @@ -64,32 +64,29 @@ First written: 2020/7/23
  • - {% if x.pk is not None %} - + {% if x.id.value %} + {% endif %} - - {% str_format "credit-{}-account" forloop.counter as field %} - + -
    {{ errors|dict:field|default:"" }}
    +
    {{ x.account.errors.0|default:"" }}
    - {% str_format "credit-{}-summary" forloop.counter as field %} - -
    {{ errors|dict:field|default:"" }}
    + +
    {{ x.summary.errors.0|default:"" }}
    - {% str_format "credit-{}-amount" forloop.counter as field %} - -
    {{ errors|dict:field|default:"" }}
    + +
    {{ x.amount.errors.0|default:"" }}
    @@ -136,8 +133,8 @@ First written: 2020/7/23
    - -
    {{ errors|dict:"notes"|default:"" }}
    + +
    {{ item.notes.errors.0|default:"" }}
    diff --git a/accounting/templates/accounting/transactions/transfer/form.html b/accounting/templates/accounting/transactions/transfer/form.html index 23ff1e8..0af36ad 100644 --- a/accounting/templates/accounting/transactions/transfer/form.html +++ b/accounting/templates/accounting/transactions/transfer/form.html @@ -33,13 +33,13 @@ First written: 2020/7/23 {% block content %} - + {% csrf_token %} {# TODO: To be done #} @@ -55,8 +55,8 @@ First written: 2020/7/23
    - -
    {{ errors|dict:"date"|default:"" }}
    + +
    {{ item.date.errors.0|default:"" }}
    @@ -70,32 +70,29 @@ First written: 2020/7/23
    - {% if x.pk is not None %} - + {% if x.id.value %} + {% endif %} - - {% str_format "debit-{}-account" forloop.counter as field %} - + -
    {{ errors|dict:field|default:"" }}
    +
    {{ x.account.errors.0|default:"" }}
    - {% str_format "debit-{}-summary" forloop.counter as field %} - -
    {{ errors|dict:field|default:"" }}
    + +
    {{ x.summary.errors.0|default:"" }}
    - {% str_format "debit-{}-amount" forloop.counter as field %} - -
    {{ errors|dict:field|default:"" }}
    + +
    {{ x.amount.errors.0|default:"" }}
    @@ -119,11 +116,11 @@ First written: 2020/7/23
  • -
    +
    {% trans "Total" context "Accounting|" as text %}{{ text|force_escape }} {{ item.debit_total }}
    -
    {{ errors|dict:"balance"|default:"" }}
    +
    {{ item.balance_error|default:"" }}
  • @@ -137,32 +134,29 @@ First written: 2020/7/23
    - {% if x.pk is not None %} - + {% if x.id.value %} + {% endif %} - - {% str_format "credit-{}-account" forloop.counter as field %} - + -
    {{ errors|dict:field|default:"" }}
    +
    {{ x.account.errors.0|default:"" }}
    - {% str_format "credit-{}-summary" forloop.counter as field %} - -
    {{ errors|dict:field|default:"" }}
    + +
    {{ x.summary.errors.0|default:"" }}
    - {% str_format "credit-{}-amount" forloop.counter as field %} - -
    {{ errors|dict:field|default:"" }}
    + +
    {{ x.amount.errors.0|default:"" }}
    @@ -186,11 +180,11 @@ First written: 2020/7/23
  • -
    +
    {% trans "Total" context "Accounting|" as text %}{{ text|force_escape }} {{ item.credit_total }}
    -
    {{ errors|dict:"balance"|default:"" }}
    +
    {{ item.balance_error|default:"" }}
  • @@ -201,8 +195,8 @@ First written: 2020/7/23
    - -
    {{ errors|dict:"notes"|default:"" }}
    + +
    {{ item.notes.errors.0|default:"" }}
    diff --git a/accounting/utils.py b/accounting/utils.py index 3a9e3e5..2220ef4 100644 --- a/accounting/utils.py +++ b/accounting/utils.py @@ -21,13 +21,13 @@ import re from django.conf import settings -from django.core.exceptions import ValidationError from django.db.models import Q, Sum, Case, When, F, Count, Max, Min from django.urls import reverse from django.utils import timezone -from django.utils.translation import pgettext, gettext_noop +from django.utils.translation import pgettext -from accounting.models import Account, Transaction, Record +from .forms import TransactionForm, RecordForm +from .models import Account, Transaction, Record from mia_core.period import Period from mia_core.status import retrieve_status from mia_core.utils import new_pk @@ -289,7 +289,7 @@ def find_order_holes(records): .filter(~(Q(max=F("count")) & Q(min=1)))] +\ [x["date"] for x in Transaction.objects .values("date", "ord") - .annotate(count=Count("sn")) + .annotate(count=Count("pk")) .filter(~Q(count=1))] for record in records: record.has_order_hole = record.transaction.date in holes @@ -313,7 +313,7 @@ def fill_transaction_from_form(transaction, form): } for key in form.keys(): m = re.match( - "^(debit|credit)-([1-9][0-9]*)-(sn|ord|account|summary|amount)$", + "^(debit|credit)-([1-9][0-9]*)-(id|ord|account|summary|amount)$", key) if m is not None: rec_type = m.group(1) @@ -328,8 +328,8 @@ def fill_transaction_from_form(transaction, form): ord=no, is_credit=(rec_type == "credit"), transaction=transaction) - if F"{rec_type}-{no}-sn" in form: - record.pk = form[F"{rec_type}-{no}-sn"] + if F"{rec_type}-{no}-id" in form: + record.pk = form[F"{rec_type}-{no}-id"] if F"{rec_type}-{no}-account" in form: record.account = Account(code=form[F"{rec_type}-{no}-account"]) if F"{rec_type}-{no}-summary" in form: @@ -340,22 +340,6 @@ def fill_transaction_from_form(transaction, form): transaction.records = records -def fill_transaction_from_previous_form(request, transaction): - """Fills the transaction from the previously-stored form. - - Args: - request (HttpRequest): The request - transaction (Transaction): The transaction. - """ - status = retrieve_status(request) - if status is None: - return - if "form" not in status: - return - form = status["form"] - fill_transaction_from_form(transaction, form) - - def sort_form_transaction_records(form): """Sorts the records in the form by their specified order, so that the form can be used to populate the data to return to the user. @@ -370,7 +354,7 @@ def sort_form_transaction_records(form): } for key in form.keys(): m = re.match( - "^(debit|credit)-([1-9][0-9]*)-(sn|ord|account|summary|amount)", + "^(debit|credit)-([1-9][0-9]*)-(id|ord|account|summary|amount)", key) if m is None: continue @@ -396,41 +380,122 @@ def sort_form_transaction_records(form): old_no = record_no[record_type][i] no = i + 1 new_form[F"{record_type}-{no}-ord"] = no - for attr in ["sn", "account", "summary", "amount"]: + for attr in ["id", "account", "summary", "amount"]: if F"{record_type}-{old_no}-{attr}" in form: new_form[F"{record_type}-{no}-{attr}"]\ = form[F"{record_type}-{old_no}-{attr}"] # Purges the old form and fills it with the new form for x in [x for x in form.keys() if re.match( - "^(debit|credit)-([1-9][0-9]*)-(sn|ord|account|summary|amount)", + "^(debit|credit)-([1-9][0-9]*)-(id|ord|account|summary|amount)", x)]: del form[x] for key in new_form.keys(): form[key] = new_form[key] -def validate_account_code(record): - """Validates the account code. +def make_transaction_form_from_model(transaction, exists): + """Converts a transaction data model to a transaction form. Args: - record (Record): The accounting record. + transaction (Transaction): The transaction data model. + exists (bool): Whether the current transaction exists. - Exceptions: - ValidationError: Thrown when validation fails. + Returns: + TransactionForm: The transaction form. """ - if record.account.code is None: - raise ValidationError(gettext_noop( - "Please select the account.")) - if record.account.code == "": - raise ValidationError(gettext_noop( - "Please select the account.")) - try: - record.account = Account.objects.get(code=record.account.code) - except Account.DoesNotExist: - raise ValidationError(gettext_noop( - "This account does not exist.")) - child_account = Account.objects.filter( - code__startswith=record.account.code).first() - if child_account is not None: - raise ValidationError(gettext_noop( - "You cannot choose a parent account.")) + transaction_form = TransactionForm( + {x: str(getattr(transaction, x)) for x in ["date", "notes"] + if getattr(transaction, x) is not None}) + transaction_form.transaction = transaction if exists else None + for record in transaction.records: + data = {x: getattr(record, x) + for x in ["summary", "amount"] + if getattr(record, x) is not None} + data["id"] = record.pk + try: + data["account"] = record.account.code + except AttributeError: + pass + record_form = RecordForm(data) + record_form.transaction = transaction_form.transaction + record_form.is_credit = record.is_credit + if record.is_credit: + transaction_form.credit_records.append(record_form) + else: + transaction_form.debit_records.append(record_form) + return transaction_form + + +def make_transaction_form_from_post(post, txn_type, transaction): + """Converts the POSTed data to a transaction form. + + Args: + post (dict[str]): The POSTed data. + txn_type (str): The transaction type. + transaction (Transaction|None): The current transaction, or None + if there is no current transaction. + + Returns: + TransactionForm: The transaction form. + """ + transaction_form = TransactionForm( + {x: post[x] for x in ("date", "notes") if x in post}) + transaction_form.transaction = transaction + transaction_form.txn_type = txn_type + # The records + max_no = { + "debit": 0, + "credit": 0, + } + for key in post.keys(): + m = re.match( + "^(debit|credit)-([1-9][0-9]*)-(id|ord|account|summary|amount)$", + key) + if m is not None: + rec_type = m.group(1) + no = int(m.group(2)) + if max_no[rec_type] < no: + max_no[rec_type] = no + if max_no["debit"] == 0: + max_no["debit"] = 1 + if max_no["credit"] == 0: + max_no["credit"] = 1 + for rec_type in max_no.keys(): + records = [] + is_credit = (rec_type == "credit") + for i in range(max_no[rec_type]): + no = i + 1 + record = RecordForm( + {x: post[F"{rec_type}-{no}-{x}"] + for x in ["id", "account", "summary", "amount"] + if F"{rec_type}-{no}-{x}" in post}) + record.transaction = transaction_form.transaction + record.is_credit = is_credit + records.append(record) + if rec_type == "debit": + transaction_form.debit_records = records + else: + transaction_form.credit_records = records + return transaction_form + + +def make_transaction_form_from_status(request, txn_type, transaction): + """Converts the previously-stored status to a transaction form. + + Args: + request (HttpRequest): The request. + txn_type (str): The transaction type. + transaction (Transaction|None): The current transaction, or None + if there is no current transaction. + + Returns: + TransactionForm: The transaction form, or None if there is no + previously-stored status. + """ + status = retrieve_status(request) + if status is None: + return None + if "form" not in status: + return + return make_transaction_form_from_post( + status["form"], txn_type, transaction) diff --git a/accounting/validators.py b/accounting/validators.py new file mode 100644 index 0000000..8dcde95 --- /dev/null +++ b/accounting/validators.py @@ -0,0 +1,67 @@ +# The core application of the Mia project. +# by imacat , 2020/8/1 + +# 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. + +"""The validators of the Mia core application. + +""" +from django.core.exceptions import ValidationError +from django.db.models import Q +from django.utils.translation import pgettext + +from .models import Account, Record + + +def validate_record_id(value): + """Validates the record ID. + + Args: + value (str): The record ID. + + Raises: + ValidationError: When the validation fails. + """ + try: + Record.objects.get(pk=value) + except Record.DoesNotExist: + raise ValidationError( + pgettext("Accounting|", "This record does not exists."), + code="not_exist") + + +def validate_record_account_code(value): + """Validates an account code. + + Args: + value (str): The account code. + + Raises: + ValidationError: When the validation fails. + """ + try: + Account.objects.get(code=value) + except Account.DoesNotExist: + raise ValidationError( + pgettext("Accounting|", "This account does not exist."), + code="not_exist") + child = Account.objects.filter( + Q(code__startswith=value), + ~Q(code=value), + ).first() + if child is not None: + raise ValidationError( + pgettext("Accounting|", "You cannot select a parent account."), + code="parent_account") diff --git a/accounting/views.py b/accounting/views.py index 49999a1..4e6a9d2 100644 --- a/accounting/views.py +++ b/accounting/views.py @@ -21,7 +21,6 @@ import re from django.conf import settings -from django.core.exceptions import ValidationError from django.db.models import Sum, Case, When, F, Q from django.db.models.functions import TruncMonth, Coalesce from django.shortcuts import render @@ -40,8 +39,8 @@ from mia_core.utils import Pagination, get_multi_lingual_search, UrlBuilder, \ from .models import Record, Transaction, Account, RecordSummary from .utils import ReportUrl, get_cash_accounts, get_ledger_accounts, \ find_imbalanced, find_order_holes, fill_transaction_from_form, \ - sort_form_transaction_records, fill_transaction_from_previous_form, \ - validate_account_code + sort_form_transaction_records, make_transaction_form_from_status, \ + make_transaction_form_from_model, make_transaction_form_from_post @method_decorator(require_GET, name="dispatch") @@ -823,15 +822,18 @@ def transaction_edit(request, txn_type, transaction=None): Returns: HttpResponse: The response. """ - if transaction is None: - transaction = Transaction() - fill_transaction_from_previous_form(request, transaction) - if len(transaction.debit_records) == 0: - transaction.records.append(Record(ord=1, is_credit=False)) - if len(transaction.credit_records) == 0: - transaction.records.append(Record(ord=1, is_credit=True)) + form = make_transaction_form_from_status(request, txn_type, transaction) + if form is None: + exists = transaction is not None + if transaction is None: + transaction = Transaction(date=timezone.localdate()) + if len(transaction.debit_records) == 0: + transaction.records.append(Record(ord=1, is_credit=False)) + if len(transaction.credit_records) == 0: + transaction.records.append(Record(ord=1, is_credit=True)) + form = make_transaction_form_from_model(transaction, exists) return render(request, F"accounting/transactions/{txn_type}/form.html", { - "item": transaction, + "item": form, }) @@ -848,61 +850,24 @@ def transaction_store(request, txn_type, transaction=None): Returns: HttpResponse: The response. """ - if transaction is None: - transaction = Transaction() - form = request.POST.dict() - strip_form(form) - sort_form_transaction_records(form) - fill_transaction_from_form(transaction, form) - errors = {} - try: - transaction.full_clean(exclude=["sn", "created_by", "updated_by"]) - except ValidationError as e: - errors = e.message_dict - records = { - "debit": transaction.debit_records, - "credit": transaction.credit_records, - } - for record_type in records.keys(): - no = 0 - for x in records[record_type]: - no = no + 1 - try: - x.full_clean(exclude=[ - "sn", "transaction", "account", "created_by", "updated_by", - ]) - except ValidationError as e: - for key in e.message_dict: - errors[F"{record_type}-{no}-{key}"] = e.message_dict[key] - # Validates the account - try: - validate_account_code(x) - except ValidationError as e: - errors[F"{record_type}-{no}-account"] = e.message - # Validates the transaction - if x.transaction is None: - x.transaction = transaction - if transaction.pk is None: - if x.transaction.pk is not None: - errors[F"{record_type}-{no}-transaction"] = gettext_noop( - "This record is not of the same transaction.") - else: - if x.transaction.pk is None: - pass - elif x.transaction.pk != transaction.pk: - errors[F"{record_type}-{no}-transaction"] = gettext_noop( - "This record is not of the same transaction.") - if len(errors) > 0: - if transaction.pk is None: + post = request.POST.dict() + strip_form(post) + sort_form_transaction_records(post) + form = make_transaction_form_from_post(post, txn_type, transaction) + if not form.is_valid(): + if transaction is None: url = reverse("accounting:transactions.create", args=(txn_type,)) else: url = reverse( "accounting:transactions.edit", args=(txn_type, transaction)) return error_redirect( request, - str(UrlBuilder(url).add("r", request.GET.get("r"))), - form, - errors) + str(UrlBuilder(url).set("r", request.GET.get("r"))), + post) + if transaction is None: + transaction = Transaction() + fill_transaction_from_form(transaction, post) + # TODO: Stores the data return success_redirect( request, str(UrlBuilder(reverse("accounting:transactions.show", diff --git a/mia_core/status.py b/mia_core/status.py index fca9274..247a8e3 100644 --- a/mia_core/status.py +++ b/mia_core/status.py @@ -22,7 +22,7 @@ import random from django.http import HttpResponseRedirect -from mia_core.utils import UrlBuilder +from .utils import UrlBuilder def success_redirect(request, url, success): @@ -39,10 +39,10 @@ def success_redirect(request, url, success): HttpResponseRedirect: The redirect response. """ id = _store(request, {"success": success}) - return HttpResponseRedirect(str(UrlBuilder(url).add("s", id))) + return HttpResponseRedirect(str(UrlBuilder(url).set("s", id))) -def error_redirect(request, url, form, errors_by_field): +def error_redirect(request, url, form): """Redirects to a specific URL on error, with the status ID appended as the query parameter "s". The status will be loaded with the retrieve_status template tag. @@ -57,8 +57,8 @@ def error_redirect(request, url, form, errors_by_field): Returns: HttpResponseRedirect: The redirect response. """ - id = _store(request, {"form": form, "errors_by_field": errors_by_field}) - return HttpResponseRedirect(str(UrlBuilder(url).add("s", id))) + id = _store(request, {"form": form}) + return HttpResponseRedirect(str(UrlBuilder(url).set("s", id))) def retrieve_status(request):