Replace the is_in_use pseudo property of the Account data model with the AccountOption class, and revised the #getAccountCodeUsedInForm method of the SummaryHelper, to solve the issue that the list of used accounts should be different for debit and credit entries.

This commit is contained in:
依瑪貓 2023-03-01 01:28:25 +08:00
parent da4cc6489f
commit 63ae3f0746
4 changed files with 45 additions and 38 deletions

View File

@ -203,25 +203,6 @@ class Account(db.Model):
return return
self.l10n.append(AccountL10n(locale=current_locale, title=value)) self.l10n.append(AccountL10n(locale=current_locale, title=value))
@property
def is_in_use(self) -> bool:
"""Returns whether the account is in use.
:return: True if the account is in use, or False otherwise.
"""
if not hasattr(self, "__is_in_use"):
setattr(self, "__is_in_use", len(self.entries) > 0)
return getattr(self, "__is_in_use")
@is_in_use.setter
def is_in_use(self, is_in_use: bool) -> None:
"""Sets whether the account is in use.
:param is_in_use: True if the account is in use, or False otherwise.
:return: None.
"""
setattr(self, "__is_in_use", is_in_use)
@classmethod @classmethod
def find_by_code(cls, code: str) -> t.Self | None: def find_by_code(cls, code: str) -> t.Self | None:
"""Finds an account by its code. """Finds an account by its code.

View File

@ -140,7 +140,7 @@ class AccountSelector {
* @return {string[]} the account codes that are used in the form * @return {string[]} the account codes that are used in the form
*/ */
#getAccountCodeUsedInForm() { #getAccountCodeUsedInForm() {
const accountCodes = Array.from(document.getElementsByClassName("accounting-account-code")); const accountCodes = Array.from(document.getElementsByClassName("accounting-" + this.#prefix + "-account-code"));
const formAccount = document.getElementById("accounting-entry-form-account"); const formAccount = document.getElementById("accounting-entry-form-account");
const inUse = [formAccount.dataset.code]; const inUse = [formAccount.dataset.code];
for (const accountCode of accountCodes) { for (const accountCode of accountCodes) {

View File

@ -25,7 +25,7 @@ First written: 2023/2/25
<input type="hidden" name="currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-eid" value="{{ entry_id }}"> <input type="hidden" name="currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-eid" value="{{ entry_id }}">
{% endif %} {% endif %}
<input id="accounting-currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-no" type="hidden" name="currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-no" value="{{ entry_index }}"> <input id="accounting-currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-no" type="hidden" name="currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-no" value="{{ entry_index }}">
<input id="accounting-currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-account-code" class="accounting-account-code" type="hidden" name="currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-account_code" value="{{ account_code_data }}" data-text="{{ account_text }}"> <input id="accounting-currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-account-code" class="accounting-{{ entry_type }}-account-code" type="hidden" name="currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-account_code" value="{{ account_code_data }}" data-text="{{ account_text }}">
<input id="accounting-currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-summary" type="hidden" name="currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-summary" value="{{ summary_data }}"> <input id="accounting-currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-summary" type="hidden" name="currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-summary" value="{{ summary_data }}">
<input id="accounting-currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-amount" class="accounting-currency-{{ currency_index }}-{{ entry_type }}-amount" type="hidden" name="currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-amount" value="{{ amount_data }}"> <input id="accounting-currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-amount" class="accounting-currency-{{ currency_index }}-{{ entry_type }}-amount" type="hidden" name="currency-{{ currency_index }}-{{ entry_type }}-{{ entry_index }}-amount" value="{{ amount_data }}">
<div class="accounting-entry-content"> <div class="accounting-entry-content">

View File

@ -115,6 +115,35 @@ class IsDebitAccount:
"This account is not for debit entries.")) "This account is not for debit entries."))
class AccountOption:
"""An account option."""
def __init__(self, account: Account):
"""Constructs an account option.
:param account: The account.
"""
self.__account: Account = account
self.id: str = account.id
self.code: str = account.code
self.is_in_use: bool = False
def __str__(self) -> str:
"""Returns the string representation of the account option.
:return: The string representation of the account option.
"""
return str(self.__account)
@property
def query_values(self) -> list[str]:
"""Returns the values to be queried.
:return: The values to be queried.
"""
return self.__account.query_values
class JournalEntryForm(FlaskForm): class JournalEntryForm(FlaskForm):
"""The base form to create or edit a journal entry.""" """The base form to create or edit a journal entry."""
eid = IntegerField() eid = IntegerField()
@ -321,40 +350,37 @@ class TransactionForm(FlaskForm):
obj.no = count + 1 obj.no = count + 1
@property @property
def debit_account_options(self) -> list[Account]: def debit_account_options(self) -> list[AccountOption]:
"""The selectable debit accounts. """The selectable debit accounts.
:return: The selectable debit accounts. :return: The selectable debit accounts.
""" """
accounts: list[Account] = Account.debit() accounts: list[AccountOption] \
in_use: set[int] = self.__get_in_use_account_id() = [AccountOption(x) for x in Account.debit()]
in_use: set[int] = set(db.session.scalars(
sa.select(JournalEntry.account_id)
.filter(JournalEntry.is_debit)
.group_by(JournalEntry.account_id)).all())
for account in accounts: for account in accounts:
account.is_in_use = account.id in in_use account.is_in_use = account.id in in_use
return accounts return accounts
@property @property
def credit_account_options(self) -> list[Account]: def credit_account_options(self) -> list[AccountOption]:
"""The selectable credit accounts. """The selectable credit accounts.
:return: The selectable credit accounts. :return: The selectable credit accounts.
""" """
accounts: list[Account] = Account.credit() accounts: list[AccountOption] \
in_use: set[int] = self.__get_in_use_account_id() = [AccountOption(x) for x in Account.credit()]
in_use: set[int] = set(db.session.scalars(
sa.select(JournalEntry.account_id)
.filter(sa.not_(JournalEntry.is_debit))
.group_by(JournalEntry.account_id)).all())
for account in accounts: for account in accounts:
account.is_in_use = account.id in in_use account.is_in_use = account.id in in_use
return accounts return accounts
def __get_in_use_account_id(self) -> set[int]:
"""Returns the ID of the accounts that are in use.
:return: The ID of the accounts that are in use.
"""
if self.__in_use_account_id is None:
self.__in_use_account_id = set(db.session.scalars(
sa.select(JournalEntry.account_id)
.group_by(JournalEntry.account_id)).all())
return self.__in_use_account_id
@property @property
def currencies_errors(self) -> list[str | LazyString]: def currencies_errors(self) -> list[str | LazyString]:
"""Returns the currency errors, without the errors in their sub-forms. """Returns the currency errors, without the errors in their sub-forms.