From 6f019d23c04fa8962aac5349881d52d541ca88fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=9D=E7=91=AA=E8=B2=93?= Date: Wed, 19 Aug 2020 13:38:05 +0800 Subject: [PATCH] Moved the sort_post_txn_records utility and the logic to create the form to TransactionForm in the accounting application. --- accounting/forms.py | 63 ++++++++++++++++++++++++++++++++++++++++++++- accounting/tests.py | 4 +-- accounting/utils.py | 53 -------------------------------------- accounting/views.py | 6 +---- 4 files changed, 65 insertions(+), 61 deletions(-) diff --git a/accounting/forms.py b/accounting/forms.py index a431506..6470e7e 100644 --- a/accounting/forms.py +++ b/accounting/forms.py @@ -24,7 +24,7 @@ from typing import Optional, List, Dict from django import forms from django.core.validators import RegexValidator -from django.db.models import Q, Max +from django.db.models import Q, Max, Model from django.db.models.functions import Length from django.utils.translation import gettext as _ @@ -234,6 +234,67 @@ class TransactionForm(forms.Form): self.txn_type = None self.transaction = None + @staticmethod + def from_post(post: Dict[str, str], txn_type: str, txn: Model): + TransactionForm._sort_post_txn_records(post) + form = TransactionForm(post) + form.txn_type = txn_type + form.transaction = txn + return form + + @staticmethod + def _sort_post_txn_records(post: Dict[str, str]) -> None: + """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. + + Args: + post: The POSTed form. + """ + # Collects the available record numbers + record_no = { + "debit": [], + "credit": [], + } + for key in post.keys(): + m = re.match( + "^(debit|credit)-([1-9][0-9]*)-(id|ord|account|summary|amount)", + key) + if m is None: + continue + record_type = m.group(1) + no = int(m.group(2)) + if no not in record_no[record_type]: + record_no[record_type].append(no) + # Sorts these record numbers by their specified orders + for record_type in record_no.keys(): + orders = {} + for no in record_no[record_type]: + try: + orders[no] = int(post[F"{record_type}-{no}-ord"]) + except KeyError: + orders[no] = 9999 + except ValueError: + orders[no] = 9999 + record_no[record_type].sort(key=lambda n: orders[n]) + # Constructs the sorted new form + new_post = {} + for record_type in record_no.keys(): + for i in range(len(record_no[record_type])): + old_no = record_no[record_type][i] + no = i + 1 + new_post[F"{record_type}-{no}-ord"] = str(no) + for attr in ["id", "account", "summary", "amount"]: + if F"{record_type}-{old_no}-{attr}" in post: + new_post[F"{record_type}-{no}-{attr}"] \ + = post[F"{record_type}-{old_no}-{attr}"] + # Purges the old form and fills it with the new form + for x in [x for x in post.keys() if re.match( + "^(debit|credit)-([1-9][0-9]*)-(id|ord|account|summary|amount)", + x)]: + del post[x] + for key in new_post.keys(): + post[key] = new_post[key] + def clean(self): """Validates the form globally. diff --git a/accounting/tests.py b/accounting/tests.py index 2ad7a07..d03b8d7 100644 --- a/accounting/tests.py +++ b/accounting/tests.py @@ -20,7 +20,7 @@ """ from django.test import TestCase -from .utils import sort_post_txn_records +from .forms import TransactionForm class SortTransactionPostTestCase(TestCase): @@ -51,7 +51,7 @@ class SortTransactionPostTestCase(TestCase): "credit-7-summary": "", "credit-7-amount": "667", } - sort_post_txn_records(post) + TransactionForm._sort_post_txn_records(post) self.assertEqual(post.get("date"), "2020-07-15") self.assertEqual(post.get("notes"), "") self.assertEqual(post.get("debit-1-ord"), "1") diff --git a/accounting/utils.py b/accounting/utils.py index 8546355..e0d25e7 100644 --- a/accounting/utils.py +++ b/accounting/utils.py @@ -580,59 +580,6 @@ def fill_txn_from_post(txn_type: str, txn: Transaction, txn.records = records -def sort_post_txn_records(post: Dict[str, str]) -> None: - """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. - - Args: - post: The POSTed form. - """ - # Collects the available record numbers - record_no = { - "debit": [], - "credit": [], - } - for key in post.keys(): - m = re.match( - "^(debit|credit)-([1-9][0-9]*)-(id|ord|account|summary|amount)", - key) - if m is None: - continue - record_type = m.group(1) - no = int(m.group(2)) - if no not in record_no[record_type]: - record_no[record_type].append(no) - # Sorts these record numbers by their specified orders - for record_type in record_no.keys(): - orders = {} - for no in record_no[record_type]: - try: - orders[no] = int(post[F"{record_type}-{no}-ord"]) - except KeyError: - orders[no] = 9999 - except ValueError: - orders[no] = 9999 - record_no[record_type].sort(key=lambda n: orders[n]) - # Constructs the sorted new form - new_post = {} - for record_type in record_no.keys(): - for i in range(len(record_no[record_type])): - old_no = record_no[record_type][i] - no = i + 1 - new_post[F"{record_type}-{no}-ord"] = str(no) - for attr in ["id", "account", "summary", "amount"]: - if F"{record_type}-{old_no}-{attr}" in post: - new_post[F"{record_type}-{no}-{attr}"]\ - = post[F"{record_type}-{old_no}-{attr}"] - # Purges the old form and fills it with the new form - for x in [x for x in post.keys() if re.match( - "^(debit|credit)-([1-9][0-9]*)-(id|ord|account|summary|amount)", - x)]: - del post[x] - for key in new_post.keys(): - post[key] = new_post[key] - - def make_txn_form_from_model(txn_type: str, txn: Transaction) -> TransactionForm: """Converts a transaction data model to a transaction form. diff --git a/accounting/views.py b/accounting/views.py index aea5fce..a3bd491 100644 --- a/accounting/views.py +++ b/accounting/views.py @@ -823,11 +823,7 @@ class TransactionFormView(FormView): def make_form_from_post(self, post: Dict[str, str]) -> TransactionForm: """Creates and returns the form from the POST data.""" - utils.sort_post_txn_records(post) - form = TransactionForm(post) - form.txn_type = self.txn_type - form.transaction = self.object - return form + return TransactionForm.from_post(post, self.txn_type, self.object) def make_form_from_model(self, obj: Transaction) -> TransactionForm: """Creates and returns the form from a data model."""