Compare commits
10 Commits
ca928636fd
...
v0.6.0
Author | SHA1 | Date | |
---|---|---|---|
884e37fe1b | |||
cc6a73211e | |||
2299b86d0f | |||
6d293a1aac | |||
a2311aee24 | |||
5571c0d01f | |||
98e1bad413 | |||
7ff52d99e6 | |||
cc440a4110 | |||
f5149a0c37 |
45
docs/source/accounting.transaction.forms.rst
Normal file
45
docs/source/accounting.transaction.forms.rst
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
accounting.transaction.forms package
|
||||||
|
====================================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
accounting.transaction.forms.currency module
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: accounting.transaction.forms.currency
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
accounting.transaction.forms.journal\_entry module
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: accounting.transaction.forms.journal_entry
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
accounting.transaction.forms.reorder module
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: accounting.transaction.forms.reorder
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
accounting.transaction.forms.transaction module
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: accounting.transaction.forms.transaction
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: accounting.transaction.forms
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
@ -1,6 +1,15 @@
|
|||||||
accounting.transaction package
|
accounting.transaction package
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
|
Subpackages
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 4
|
||||||
|
|
||||||
|
accounting.transaction.forms
|
||||||
|
accounting.transaction.utils
|
||||||
|
|
||||||
Submodules
|
Submodules
|
||||||
----------
|
----------
|
||||||
|
|
||||||
@ -12,30 +21,6 @@ accounting.transaction.converters module
|
|||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
accounting.transaction.forms module
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: accounting.transaction.forms
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
accounting.transaction.operators module
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: accounting.transaction.operators
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
accounting.transaction.summary\_editor module
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: accounting.transaction.summary_editor
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
accounting.transaction.template\_filters module
|
accounting.transaction.template\_filters module
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
|
|
||||||
|
53
docs/source/accounting.transaction.utils.rst
Normal file
53
docs/source/accounting.transaction.utils.rst
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
accounting.transaction.utils package
|
||||||
|
====================================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
accounting.transaction.utils.account\_option module
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: accounting.transaction.utils.account_option
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
accounting.transaction.utils.offset\_alias module
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: accounting.transaction.utils.offset_alias
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
accounting.transaction.utils.operators module
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: accounting.transaction.utils.operators
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
accounting.transaction.utils.original\_entries module
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: accounting.transaction.utils.original_entries
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
accounting.transaction.utils.summary\_editor module
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: accounting.transaction.utils.summary_editor
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: accounting.transaction.utils
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
@ -4,6 +4,14 @@ accounting.utils package
|
|||||||
Submodules
|
Submodules
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
accounting.utils.cast module
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. automodule:: accounting.utils.cast
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
accounting.utils.flash\_errors module
|
accounting.utils.flash\_errors module
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
name = mia-accounting-flask
|
name = mia-accounting-flask
|
||||||
version = 0.5.0
|
version = 0.6.0
|
||||||
author = imacat
|
author = imacat
|
||||||
author_email = imacat@mail.imacat.idv.tw
|
author_email = imacat@mail.imacat.idv.tw
|
||||||
description = The Mia! Accounting Flask project.
|
description = The Mia! Accounting Flask project.
|
||||||
|
@ -29,7 +29,7 @@ from accounting.utils.user import has_user, get_user_pk
|
|||||||
|
|
||||||
AccountData = tuple[int, str, int, str, str, str, bool]
|
AccountData = tuple[int, str, int, str, str, str, bool]
|
||||||
"""The format of the account data, as a list of (ID, base account code, number,
|
"""The format of the account data, as a list of (ID, base account code, number,
|
||||||
English, Traditional Chinese, Simplified Chinese, is-offset-needed) tuples."""
|
English, Traditional Chinese, Simplified Chinese, is-need-offset) tuples."""
|
||||||
|
|
||||||
|
|
||||||
def __validate_username(ctx: click.core.Context, param: click.core.Option,
|
def __validate_username(ctx: click.core.Context, param: click.core.Option,
|
||||||
@ -92,14 +92,14 @@ def init_accounts_command(username: str) -> None:
|
|||||||
data: list[AccountData] = []
|
data: list[AccountData] = []
|
||||||
for base in bases_to_add:
|
for base in bases_to_add:
|
||||||
l10n: dict[str, str] = {x.locale: x.title for x in base.l10n}
|
l10n: dict[str, str] = {x.locale: x.title for x in base.l10n}
|
||||||
is_offset_needed: bool = __is_offset_needed(base.code)
|
is_need_offset: bool = __is_need_offset(base.code)
|
||||||
data.append((get_new_id(), base.code, 1, base.title_l10n,
|
data.append((get_new_id(), base.code, 1, base.title_l10n,
|
||||||
l10n["zh_Hant"], l10n["zh_Hans"], is_offset_needed))
|
l10n["zh_Hant"], l10n["zh_Hans"], is_need_offset))
|
||||||
__add_accounting_accounts(data, creator_pk)
|
__add_accounting_accounts(data, creator_pk)
|
||||||
click.echo(F"{len(data)} added. Accounting accounts initialized.")
|
click.echo(F"{len(data)} added. Accounting accounts initialized.")
|
||||||
|
|
||||||
|
|
||||||
def __is_offset_needed(base_code: str) -> bool:
|
def __is_need_offset(base_code: str) -> bool:
|
||||||
"""Checks that whether entries in the account need offset.
|
"""Checks that whether entries in the account need offset.
|
||||||
|
|
||||||
:param base_code: The code of the base account.
|
:param base_code: The code of the base account.
|
||||||
@ -134,7 +134,7 @@ def __add_accounting_accounts(data: list[AccountData], creator_pk: int)\
|
|||||||
base_code=x[1],
|
base_code=x[1],
|
||||||
no=x[2],
|
no=x[2],
|
||||||
title_l10n=x[3],
|
title_l10n=x[3],
|
||||||
is_offset_needed=x[6],
|
is_need_offset=x[6],
|
||||||
created_by_id=creator_pk,
|
created_by_id=creator_pk,
|
||||||
updated_by_id=creator_pk)
|
updated_by_id=creator_pk)
|
||||||
for x in data]
|
for x in data]
|
||||||
|
@ -80,7 +80,7 @@ class AccountForm(FlaskForm):
|
|||||||
filters=[strip_text],
|
filters=[strip_text],
|
||||||
validators=[DataRequired(lazy_gettext("Please fill in the title"))])
|
validators=[DataRequired(lazy_gettext("Please fill in the title"))])
|
||||||
"""The title."""
|
"""The title."""
|
||||||
is_offset_needed = BooleanField(
|
is_need_offset = BooleanField(
|
||||||
validators=[NoOffsetNominalAccount()])
|
validators=[NoOffsetNominalAccount()])
|
||||||
"""Whether the the entries of this account need offset."""
|
"""Whether the the entries of this account need offset."""
|
||||||
|
|
||||||
@ -103,9 +103,9 @@ class AccountForm(FlaskForm):
|
|||||||
obj.no = count + 1
|
obj.no = count + 1
|
||||||
obj.title = self.title.data
|
obj.title = self.title.data
|
||||||
if self.base_code.data[0] in {"1", "2", "3"}:
|
if self.base_code.data[0] in {"1", "2", "3"}:
|
||||||
obj.is_offset_needed = self.is_offset_needed.data
|
obj.is_need_offset = self.is_need_offset.data
|
||||||
else:
|
else:
|
||||||
obj.is_offset_needed = False
|
obj.is_need_offset = False
|
||||||
if is_new:
|
if is_new:
|
||||||
current_user_pk: int = get_current_user_pk()
|
current_user_pk: int = get_current_user_pk()
|
||||||
obj.created_by_id = current_user_pk
|
obj.created_by_id = current_user_pk
|
||||||
|
@ -48,7 +48,7 @@ def get_account_query() -> list[Account]:
|
|||||||
code.contains(k),
|
code.contains(k),
|
||||||
Account.id.in_(l10n_matches)]
|
Account.id.in_(l10n_matches)]
|
||||||
if k in gettext("Need offset"):
|
if k in gettext("Need offset"):
|
||||||
sub_conditions.append(Account.is_offset_needed)
|
sub_conditions.append(Account.is_need_offset)
|
||||||
conditions.append(sa.or_(*sub_conditions))
|
conditions.append(sa.or_(*sub_conditions))
|
||||||
|
|
||||||
return Account.query.filter(*conditions)\
|
return Account.query.filter(*conditions)\
|
||||||
|
@ -114,7 +114,7 @@ class Account(db.Model):
|
|||||||
"""The account number under the base account."""
|
"""The account number under the base account."""
|
||||||
title_l10n = db.Column("title", db.String, nullable=False)
|
title_l10n = db.Column("title", db.String, nullable=False)
|
||||||
"""The title."""
|
"""The title."""
|
||||||
is_offset_needed = db.Column(db.Boolean, nullable=False, default=False)
|
is_need_offset = db.Column(db.Boolean, nullable=False, default=False)
|
||||||
"""Whether the entries of this account need offset."""
|
"""Whether the entries of this account need offset."""
|
||||||
created_at = db.Column(db.DateTime(timezone=True), nullable=False,
|
created_at = db.Column(db.DateTime(timezone=True), nullable=False,
|
||||||
server_default=db.func.now())
|
server_default=db.func.now())
|
||||||
@ -702,7 +702,7 @@ class JournalEntry(db.Model):
|
|||||||
|
|
||||||
:return: True if the entry needs offset, or False otherwise.
|
:return: True if the entry needs offset, or False otherwise.
|
||||||
"""
|
"""
|
||||||
if not self.account.is_offset_needed:
|
if not self.account.is_need_offset:
|
||||||
return False
|
return False
|
||||||
if self.account.base_code[0] == "1" and not self.is_debit:
|
if self.account.base_code[0] == "1" and not self.is_debit:
|
||||||
return False
|
return False
|
||||||
|
@ -97,7 +97,7 @@ class EntryCollector:
|
|||||||
code.contains(k),
|
code.contains(k),
|
||||||
Account.id.in_(select_l10n)]
|
Account.id.in_(select_l10n)]
|
||||||
if k in gettext("Need offset"):
|
if k in gettext("Need offset"):
|
||||||
conditions.append(Account.is_offset_needed)
|
conditions.append(Account.is_need_offset)
|
||||||
return sa.select(Account.id).filter(sa.or_(*conditions))
|
return sa.select(Account.id).filter(sa.or_(*conditions))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -83,16 +83,16 @@ class AccountForm {
|
|||||||
#titleError;
|
#titleError;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The control of the is-offset-needed option
|
* The control of the is-need-offset option
|
||||||
* @type {HTMLDivElement}
|
* @type {HTMLDivElement}
|
||||||
*/
|
*/
|
||||||
#isOffsetNeededControl;
|
#isNeedOffsetControl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The is-offset-needed option
|
* The is-need-offset option
|
||||||
* @type {HTMLInputElement}
|
* @type {HTMLInputElement}
|
||||||
*/
|
*/
|
||||||
#isOffsetNeeded;
|
#isNeedOffset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the account form.
|
* Constructs the account form.
|
||||||
@ -107,8 +107,8 @@ class AccountForm {
|
|||||||
this.#baseError = document.getElementById("accounting-base-error");
|
this.#baseError = document.getElementById("accounting-base-error");
|
||||||
this.#title = document.getElementById("accounting-title");
|
this.#title = document.getElementById("accounting-title");
|
||||||
this.#titleError = document.getElementById("accounting-title-error");
|
this.#titleError = document.getElementById("accounting-title-error");
|
||||||
this.#isOffsetNeededControl = document.getElementById("accounting-is-offset-needed-control");
|
this.#isNeedOffsetControl = document.getElementById("accounting-is-need-offset-control");
|
||||||
this.#isOffsetNeeded = document.getElementById("accounting-is-offset-needed");
|
this.#isNeedOffset = document.getElementById("accounting-is-need-offset");
|
||||||
this.#formElement.onsubmit = () => {
|
this.#formElement.onsubmit = () => {
|
||||||
return this.#validateForm();
|
return this.#validateForm();
|
||||||
};
|
};
|
||||||
@ -138,12 +138,12 @@ class AccountForm {
|
|||||||
this.#baseCode.value = code;
|
this.#baseCode.value = code;
|
||||||
this.#base.innerText = text;
|
this.#base.innerText = text;
|
||||||
if (["1", "2", "3"].includes(code.substring(0, 1))) {
|
if (["1", "2", "3"].includes(code.substring(0, 1))) {
|
||||||
this.#isOffsetNeededControl.classList.remove("d-none");
|
this.#isNeedOffsetControl.classList.remove("d-none");
|
||||||
this.#isOffsetNeeded.disabled = false;
|
this.#isNeedOffset.disabled = false;
|
||||||
} else {
|
} else {
|
||||||
this.#isOffsetNeededControl.classList.add("d-none");
|
this.#isNeedOffsetControl.classList.add("d-none");
|
||||||
this.#isOffsetNeeded.disabled = true;
|
this.#isNeedOffset.disabled = true;
|
||||||
this.#isOffsetNeeded.checked = false;
|
this.#isNeedOffset.checked = false;
|
||||||
}
|
}
|
||||||
this.#validateBase();
|
this.#validateBase();
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ class AccountSelector {
|
|||||||
};
|
};
|
||||||
this.#clearButton.onclick = () => this.#entryEditor.clearAccount();
|
this.#clearButton.onclick = () => this.#entryEditor.clearAccount();
|
||||||
for (const option of this.#options) {
|
for (const option of this.#options) {
|
||||||
option.onclick = () => this.#entryEditor.saveAccount(option.dataset.code, option.dataset.content, option.classList.contains("accounting-account-is-offset-needed"));
|
option.onclick = () => this.#entryEditor.saveAccount(option.dataset.code, option.dataset.content, option.classList.contains("accounting-account-is-need-offset"));
|
||||||
}
|
}
|
||||||
this.#query.addEventListener("input", () => {
|
this.#query.addEventListener("input", () => {
|
||||||
this.#filterOptions();
|
this.#filterOptions();
|
||||||
@ -206,4 +206,19 @@ class AccountSelector {
|
|||||||
this.#clearButton.disabled = false;
|
this.#clearButton.disabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the account selector instances.
|
||||||
|
*
|
||||||
|
* @param entryEditor {JournalEntryEditor} the journal entry editor
|
||||||
|
* @return {{debit: AccountSelector, credit: AccountSelector}}
|
||||||
|
*/
|
||||||
|
static getInstances(entryEditor) {
|
||||||
|
const selectors = {}
|
||||||
|
const modals = Array.from(document.getElementsByClassName("accounting-account-selector"));
|
||||||
|
for (const modal of modals) {
|
||||||
|
selectors[modal.dataset.entryType] = new AccountSelector(entryEditor, modal.dataset.entryType);
|
||||||
|
}
|
||||||
|
return selectors;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,13 +200,13 @@ class JournalEntryEditor {
|
|||||||
* The summary editors
|
* The summary editors
|
||||||
* @type {{debit: SummaryEditor, credit: SummaryEditor}}
|
* @type {{debit: SummaryEditor, credit: SummaryEditor}}
|
||||||
*/
|
*/
|
||||||
#summaryEditors = {};
|
#summaryEditors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The account selectors
|
* The account selectors
|
||||||
* @type {{debit: AccountSelector, credit: AccountSelector}}
|
* @type {{debit: AccountSelector, credit: AccountSelector}}
|
||||||
*/
|
*/
|
||||||
#accountSelectors = {};
|
#accountSelectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The original entry selector
|
* The original entry selector
|
||||||
@ -236,12 +236,8 @@ class JournalEntryEditor {
|
|||||||
this.#accountError = document.getElementById(this.#prefix + "-account-error")
|
this.#accountError = document.getElementById(this.#prefix + "-account-error")
|
||||||
this.#amount = document.getElementById(this.#prefix + "-amount");
|
this.#amount = document.getElementById(this.#prefix + "-amount");
|
||||||
this.#amountError = document.getElementById(this.#prefix + "-amount-error");
|
this.#amountError = document.getElementById(this.#prefix + "-amount-error");
|
||||||
for (const entryType of ["debit", "credit"]) {
|
this.#summaryEditors = SummaryEditor.getInstances(this);
|
||||||
this.#summaryEditors[entryType] = new SummaryEditor(this, entryType);
|
this.#accountSelectors = AccountSelector.getInstances(this);
|
||||||
}
|
|
||||||
for (const entryType of ["debit", "credit"]) {
|
|
||||||
this.#accountSelectors[entryType] = new AccountSelector(this, entryType);
|
|
||||||
}
|
|
||||||
this.originalEntrySelector = new OriginalEntrySelector();
|
this.originalEntrySelector = new OriginalEntrySelector();
|
||||||
this.#originalEntryControl.onclick = () => this.originalEntrySelector.onOpen(this, this.originalEntryId)
|
this.#originalEntryControl.onclick = () => this.originalEntrySelector.onOpen(this, this.originalEntryId)
|
||||||
this.#originalEntryDelete.onclick = () => this.clearOriginalEntry();
|
this.#originalEntryDelete.onclick = () => this.clearOriginalEntry();
|
||||||
@ -374,10 +370,10 @@ class JournalEntryEditor {
|
|||||||
*
|
*
|
||||||
* @param code {string} the account code
|
* @param code {string} the account code
|
||||||
* @param text {string} the account text
|
* @param text {string} the account text
|
||||||
* @param isOffsetNeeded {boolean} true if the journal entries in the account need offset or false otherwise
|
* @param isNeedOffset {boolean} true if the journal entries in the account need offset or false otherwise
|
||||||
*/
|
*/
|
||||||
saveAccount(code, text, isOffsetNeeded) {
|
saveAccount(code, text, isNeedOffset) {
|
||||||
this.isNeedOffset = isOffsetNeeded;
|
this.isNeedOffset = isNeedOffset;
|
||||||
this.#accountControl.classList.add("accounting-not-empty");
|
this.#accountControl.classList.add("accounting-not-empty");
|
||||||
this.accountCode = code;
|
this.accountCode = code;
|
||||||
this.accountText = text;
|
this.accountText = text;
|
||||||
@ -519,51 +515,43 @@ class JournalEntryEditor {
|
|||||||
* The callback when editing a journal entry.
|
* The callback when editing a journal entry.
|
||||||
*
|
*
|
||||||
* @param entry {JournalEntrySubForm} the journal entry sub-form
|
* @param entry {JournalEntrySubForm} the journal entry sub-form
|
||||||
* @param originalEntryId {string} the ID of the original entry
|
|
||||||
* @param originalEntryDate {string} the date of the original entry
|
|
||||||
* @param originalEntryText {string} the text of the original entry
|
|
||||||
* @param summary {string} the summary
|
|
||||||
* @param accountCode {string} the account code
|
|
||||||
* @param accountText {string} the account text
|
|
||||||
* @param amount {string} the amount
|
|
||||||
* @param amountMin {string} the minimal amount
|
|
||||||
*/
|
*/
|
||||||
onEdit(entry, originalEntryId, originalEntryDate, originalEntryText, summary, accountCode, accountText, amount, amountMin) {
|
onEdit(entry) {
|
||||||
this.entry = entry;
|
this.entry = entry;
|
||||||
this.#side = entry.side;
|
this.#side = entry.side;
|
||||||
this.entryType = this.#side.entryType;
|
this.entryType = this.#side.entryType;
|
||||||
this.isNeedOffset = entry.isNeedOffset();
|
this.isNeedOffset = entry.isNeedOffset();
|
||||||
if (originalEntryId === "") {
|
this.originalEntryId = entry.getOriginalEntryId();
|
||||||
|
this.originalEntryDate = entry.getOriginalEntryDate();
|
||||||
|
this.originalEntryText = entry.getOriginalEntryText();
|
||||||
|
this.#originalEntry.innerText = this.originalEntryText;
|
||||||
|
if (this.originalEntryId === null) {
|
||||||
this.#originalEntryContainer.classList.add("d-none");
|
this.#originalEntryContainer.classList.add("d-none");
|
||||||
this.#originalEntryControl.classList.remove("accounting-not-empty");
|
this.#originalEntryControl.classList.remove("accounting-not-empty");
|
||||||
} else {
|
} else {
|
||||||
this.#originalEntryContainer.classList.remove("d-none");
|
this.#originalEntryContainer.classList.remove("d-none");
|
||||||
this.#originalEntryControl.classList.add("accounting-not-empty");
|
this.#originalEntryControl.classList.add("accounting-not-empty");
|
||||||
}
|
}
|
||||||
this.originalEntryId = originalEntryId === ""? null: originalEntryId;
|
this.#setEnableSummaryAccount(!entry.isMatched && this.originalEntryId === null);
|
||||||
this.originalEntryDate = originalEntryDate === ""? null: originalEntryDate;
|
this.summary = entry.getSummary();
|
||||||
this.originalEntryText = originalEntryText === ""? null: originalEntryText;
|
if (this.summary === null) {
|
||||||
this.#originalEntry.innerText = originalEntryText;
|
|
||||||
this.#setEnableSummaryAccount(!entry.isMatched && originalEntryId === "");
|
|
||||||
if (summary === "") {
|
|
||||||
this.#summaryControl.classList.remove("accounting-not-empty");
|
this.#summaryControl.classList.remove("accounting-not-empty");
|
||||||
} else {
|
} else {
|
||||||
this.#summaryControl.classList.add("accounting-not-empty");
|
this.#summaryControl.classList.add("accounting-not-empty");
|
||||||
}
|
}
|
||||||
this.summary = summary === ""? null: summary;
|
this.#summary.innerText = this.summary === null? "": this.summary;
|
||||||
this.#summary.innerText = summary;
|
if (entry.getAccountCode() === null) {
|
||||||
if (accountCode === "") {
|
|
||||||
this.#accountControl.classList.remove("accounting-not-empty");
|
this.#accountControl.classList.remove("accounting-not-empty");
|
||||||
} else {
|
} else {
|
||||||
this.#accountControl.classList.add("accounting-not-empty");
|
this.#accountControl.classList.add("accounting-not-empty");
|
||||||
}
|
}
|
||||||
this.accountCode = accountCode;
|
this.accountCode = entry.getAccountCode();
|
||||||
this.accountText = accountText;
|
this.accountText = entry.getAccountText();
|
||||||
this.#account.innerText = accountText;
|
this.#account.innerText = this.accountText;
|
||||||
this.#amount.value = amount;
|
this.#amount.value = entry.getAmount() === null? "": String(entry.getAmount());
|
||||||
const maxAmount = this.#getMaxAmount();
|
const maxAmount = this.#getMaxAmount();
|
||||||
this.#amount.max = maxAmount === null? "": maxAmount;
|
this.#amount.max = maxAmount === null? "": maxAmount;
|
||||||
this.#amount.min = amountMin;
|
this.#amount.min = entry.getAmountMin() === null? "": String(entry.getAmountMin());
|
||||||
this.#validate();
|
this.#validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ class SummaryEditor {
|
|||||||
#submit() {
|
#submit() {
|
||||||
bootstrap.Modal.getOrCreateInstance(this.#modal).hide();
|
bootstrap.Modal.getOrCreateInstance(this.#modal).hide();
|
||||||
if (this.#selectedAccount !== null) {
|
if (this.#selectedAccount !== null) {
|
||||||
this.#entryEditor.saveSummaryWithAccount(this.summary.value, this.#selectedAccount.dataset.code, this.#selectedAccount.dataset.text, this.#selectedAccount.classList.contains("accounting-account-is-offset-needed"));
|
this.#entryEditor.saveSummaryWithAccount(this.summary.value, this.#selectedAccount.dataset.code, this.#selectedAccount.dataset.text, this.#selectedAccount.classList.contains("accounting-account-is-need-offset"));
|
||||||
} else {
|
} else {
|
||||||
this.#entryEditor.saveSummary(this.summary.value);
|
this.#entryEditor.saveSummary(this.summary.value);
|
||||||
}
|
}
|
||||||
@ -242,6 +242,21 @@ class SummaryEditor {
|
|||||||
}
|
}
|
||||||
this.tabPlanes.general.switchToMe();
|
this.tabPlanes.general.switchToMe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the summary editor instances.
|
||||||
|
*
|
||||||
|
* @param entryEditor {JournalEntryEditor} the journal entry editor
|
||||||
|
* @return {{debit: SummaryEditor, credit: SummaryEditor}}
|
||||||
|
*/
|
||||||
|
static getInstances(entryEditor) {
|
||||||
|
const editors = {}
|
||||||
|
const forms = Array.from(document.getElementsByClassName("accounting-summary-editor"));
|
||||||
|
for (const form of forms) {
|
||||||
|
editors[form.dataset.entryType] = new SummaryEditor(entryEditor, form.dataset.entryType);
|
||||||
|
}
|
||||||
|
return editors;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -881,7 +881,7 @@ class JournalEntrySubForm {
|
|||||||
this.#amount = document.getElementById(this.#prefix + "-amount");
|
this.#amount = document.getElementById(this.#prefix + "-amount");
|
||||||
this.#amountText = document.getElementById(this.#prefix + "-amount-text");
|
this.#amountText = document.getElementById(this.#prefix + "-amount-text");
|
||||||
this.deleteButton = document.getElementById(this.#prefix + "-delete");
|
this.deleteButton = document.getElementById(this.#prefix + "-delete");
|
||||||
this.#control.onclick = () => this.side.currency.form.entryEditor.onEdit(this, this.#originalEntryId.value, this.#originalEntryId.dataset.date, this.#originalEntryId.dataset.text, this.#summary.value, this.#accountCode.value, this.#accountCode.dataset.text, this.#amount.value, this.#amount.dataset.min);
|
this.#control.onclick = () => this.side.currency.form.entryEditor.onEdit(this);
|
||||||
this.deleteButton.onclick = () => {
|
this.deleteButton.onclick = () => {
|
||||||
this.element.parentElement.removeChild(this.element);
|
this.element.parentElement.removeChild(this.element);
|
||||||
this.side.deleteJournalEntry(this);
|
this.side.deleteJournalEntry(this);
|
||||||
@ -915,6 +915,24 @@ class JournalEntrySubForm {
|
|||||||
return this.#originalEntryId.dataset.date === ""? null: this.#originalEntryId.dataset.date;
|
return this.#originalEntryId.dataset.date === ""? null: this.#originalEntryId.dataset.date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text of the original entry.
|
||||||
|
*
|
||||||
|
* @return {string|null} the text of the original entry
|
||||||
|
*/
|
||||||
|
getOriginalEntryText() {
|
||||||
|
return this.#originalEntryId.dataset.text === ""? null: this.#originalEntryId.dataset.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the summary.
|
||||||
|
*
|
||||||
|
* @return {string|null} the summary
|
||||||
|
*/
|
||||||
|
getSummary() {
|
||||||
|
return this.#summary.value === ""? null: this.#summary.value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the account code.
|
* Returns the account code.
|
||||||
*
|
*
|
||||||
@ -924,6 +942,15 @@ class JournalEntrySubForm {
|
|||||||
return this.#accountCode.value === ""? null: this.#accountCode.value;
|
return this.#accountCode.value === ""? null: this.#accountCode.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the account text.
|
||||||
|
*
|
||||||
|
* @return {string|null} the account text
|
||||||
|
*/
|
||||||
|
getAccountText() {
|
||||||
|
return this.#accountCode.dataset.text === ""? null: this.#accountCode.dataset.text;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the amount.
|
* Returns the amount.
|
||||||
*
|
*
|
||||||
@ -933,6 +960,15 @@ class JournalEntrySubForm {
|
|||||||
return this.#amount.value === ""? null: new Decimal(this.#amount.value);
|
return this.#amount.value === ""? null: new Decimal(this.#amount.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimal amount.
|
||||||
|
*
|
||||||
|
* @return {Decimal|null} the minimal amount
|
||||||
|
*/
|
||||||
|
getAmountMin() {
|
||||||
|
return this.#amount.dataset.min === ""? null: new Decimal(this.#amount.dataset.min);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the form.
|
* Validates the form.
|
||||||
*
|
*
|
||||||
|
@ -85,7 +85,7 @@ First written: 2023/1/31
|
|||||||
<div class="accounting-card col-sm-6">
|
<div class="accounting-card col-sm-6">
|
||||||
<div class="accounting-card-title">{{ obj.title }}</div>
|
<div class="accounting-card-title">{{ obj.title }}</div>
|
||||||
<div class="accounting-card-code">{{ obj.code }}</div>
|
<div class="accounting-card-code">{{ obj.code }}</div>
|
||||||
{% if obj.is_offset_needed %}
|
{% if obj.is_need_offset %}
|
||||||
<div>
|
<div>
|
||||||
<span class="badge rounded-pill bg-info">{{ A_("Need offset") }}</span>
|
<span class="badge rounded-pill bg-info">{{ A_("Need offset") }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -62,9 +62,9 @@ First written: 2023/2/1
|
|||||||
<div id="accounting-title-error" class="invalid-feedback">{% if form.title.errors %}{{ form.title.errors[0] }}{% endif %}</div>
|
<div id="accounting-title-error" class="invalid-feedback">{% if form.title.errors %}{{ form.title.errors[0] }}{% endif %}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="accounting-is-offset-needed-control" class="form-check form-switch mb-3 {% if form.base_code.data[0] not in ["1", "2", "3"] %} d-none {% endif %}">
|
<div id="accounting-is-need-offset-control" class="form-check form-switch mb-3 {% if form.base_code.data[0] not in ["1", "2", "3"] %} d-none {% endif %}">
|
||||||
<input id="accounting-is-offset-needed" class="form-check-input" type="checkbox" name="is_offset_needed" value="1" {% if form.is_offset_needed.data %} checked="checked" {% endif %}>
|
<input id="accounting-is-need-offset" class="form-check-input" type="checkbox" name="is_need_offset" value="1" {% if form.is_need_offset.data %} checked="checked" {% endif %}>
|
||||||
<label class="form-check-label" for="accounting-is-offset-needed">
|
<label class="form-check-label" for="accounting-is-need-offset">
|
||||||
{{ A_("The entries in the account need offset.") }}
|
{{ A_("The entries in the account need offset.") }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,7 +58,7 @@ First written: 2023/1/30
|
|||||||
{% for item in list %}
|
{% for item in list %}
|
||||||
<a class="list-group-item list-group-item-action" href="{{ url_for("accounting.account.detail", account=item)|accounting_append_next }}">
|
<a class="list-group-item list-group-item-action" href="{{ url_for("accounting.account.detail", account=item)|accounting_append_next }}">
|
||||||
{{ item }}
|
{{ item }}
|
||||||
{% if item.is_offset_needed %}
|
{% if item.is_need_offset %}
|
||||||
<span class="badge rounded-pill bg-info">{{ A_("Need offset") }}</span>
|
<span class="badge rounded-pill bg-info">{{ A_("Need offset") }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
|
@ -19,7 +19,7 @@ account-selector-modal.html: The modal for the account selector
|
|||||||
Author: imacat@mail.imacat.idv.tw (imacat)
|
Author: imacat@mail.imacat.idv.tw (imacat)
|
||||||
First written: 2023/2/25
|
First written: 2023/2/25
|
||||||
#}
|
#}
|
||||||
<div id="accounting-account-selector-{{ entry_type }}-modal" class="modal fade" data-entry-type="{{ entry_type }}" tabindex="-1" aria-labelledby="accounting-account-selector-{{ entry_type }}-modal-label" aria-hidden="true">
|
<div id="accounting-account-selector-{{ entry_type }}-modal" class="modal fade accounting-account-selector" data-entry-type="{{ entry_type }}" tabindex="-1" aria-labelledby="accounting-account-selector-{{ entry_type }}-modal-label" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
@ -37,7 +37,7 @@ First written: 2023/2/25
|
|||||||
|
|
||||||
<ul id="accounting-account-selector-{{ entry_type }}-option-list" class="list-group accounting-selector-list">
|
<ul id="accounting-account-selector-{{ entry_type }}-option-list" class="list-group accounting-selector-list">
|
||||||
{% for account in account_options %}
|
{% for account in account_options %}
|
||||||
<li id="accounting-account-selector-{{ entry_type }}-option-{{ account.code }}" class="list-group-item accounting-clickable accounting-account-selector-{{ entry_type }}-option {% if account.is_in_use %} accounting-account-in-use {% endif %} {% if account.is_offset_needed %} accounting-account-is-offset-needed {% endif %}" data-code="{{ account.code }}" data-content="{{ account }}" data-query-values="{{ account.query_values|tojson|forceescape }}" data-bs-toggle="modal" data-bs-target="#accounting-entry-editor-modal">
|
<li id="accounting-account-selector-{{ entry_type }}-option-{{ account.code }}" class="list-group-item accounting-clickable accounting-account-selector-{{ entry_type }}-option {% if account.is_in_use %} accounting-account-in-use {% endif %} {% if account.is_need_offset %} accounting-account-is-need-offset {% endif %}" data-code="{{ account.code }}" data-content="{{ account }}" data-query-values="{{ account.query_values|tojson|forceescape }}" data-bs-toggle="modal" data-bs-target="#accounting-entry-editor-modal">
|
||||||
{{ account }}
|
{{ account }}
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -19,7 +19,7 @@ summary-editor-modal.html: The modal of the summary editor
|
|||||||
Author: imacat@mail.imacat.idv.tw (imacat)
|
Author: imacat@mail.imacat.idv.tw (imacat)
|
||||||
First written: 2023/2/28
|
First written: 2023/2/28
|
||||||
#}
|
#}
|
||||||
<form id="accounting-summary-editor-{{ summary_editor.type }}">
|
<form id="accounting-summary-editor-{{ summary_editor.type }}" class="accounting-summary-editor" data-entry-type="{{ summary_editor.type }}">
|
||||||
<div id="accounting-summary-editor-{{ summary_editor.type }}-modal" class="modal fade" tabindex="-1" aria-labelledby="accounting-summary-editor-{{ summary_editor.type }}-modal-label" aria-hidden="true">
|
<div id="accounting-summary-editor-{{ summary_editor.type }}-modal" class="modal fade" tabindex="-1" aria-labelledby="accounting-summary-editor-{{ summary_editor.type }}-modal-label" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -32,7 +32,7 @@ First written: 2023/2/28
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="d-flex justify-content-between mb-3">
|
<div class="d-flex justify-content-between mb-3">
|
||||||
<input id="accounting-summary-editor-{{ summary_editor.type }}-summary" class="form-control" type="text" aria-labelledby="accounting-summary-editor-{{ summary_editor.type }}-modal-label">
|
<input id="accounting-summary-editor-{{ summary_editor.type }}-summary" class="form-control" type="text" aria-labelledby="accounting-summary-editor-{{ summary_editor.type }}-modal-label">
|
||||||
<button id="accounting-summary-editor-{{ summary_editor.type }}-offset" class="btn btn-primary ms-2" type="button" data-bs-toggle="modal" data-bs-target="#accounting-original-entry-selector-modal">
|
<button id="accounting-summary-editor-{{ summary_editor.type }}-offset" class="btn btn-primary text-nowrap ms-2" type="button" data-bs-toggle="modal" data-bs-target="#accounting-original-entry-selector-modal">
|
||||||
{{ A_("Offset...") }}
|
{{ A_("Offset...") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -177,7 +177,7 @@ First written: 2023/2/28
|
|||||||
{# The suggested accounts #}
|
{# The suggested accounts #}
|
||||||
<div class="mt-3">
|
<div class="mt-3">
|
||||||
{% for account in summary_editor.accounts %}
|
{% for account in summary_editor.accounts %}
|
||||||
<button class="btn btn-outline-primary d-none accounting-summary-editor-{{ summary_editor.type }}-account {% if account.is_offset_needed %} accounting-account-is-offset-needed {% endif %}" type="button" data-code="{{ account.code }}" data-text="{{ account }}">
|
<button class="btn btn-outline-primary d-none accounting-summary-editor-{{ summary_editor.type }}-account {% if account.is_need_offset %} accounting-account-is-need-offset {% endif %}" type="button" data-code="{{ account.code }}" data-text="{{ account }}">
|
||||||
{{ account }}
|
{{ account }}
|
||||||
</button>
|
</button>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -81,7 +81,7 @@ class OriginalEntryNeedOffset:
|
|||||||
= db.session.get(JournalEntry, field.data)
|
= db.session.get(JournalEntry, field.data)
|
||||||
if original_entry is None:
|
if original_entry is None:
|
||||||
return
|
return
|
||||||
if not original_entry.account.is_offset_needed:
|
if not original_entry.account.is_need_offset:
|
||||||
raise ValidationError(lazy_gettext(
|
raise ValidationError(lazy_gettext(
|
||||||
"The original entry does not need offset."))
|
"The original entry does not need offset."))
|
||||||
|
|
||||||
@ -186,7 +186,7 @@ class NotStartPayableFromDebit:
|
|||||||
or form.original_entry_id.data is not None:
|
or form.original_entry_id.data is not None:
|
||||||
return
|
return
|
||||||
account: Account | None = Account.find_by_code(field.data)
|
account: Account | None = Account.find_by_code(field.data)
|
||||||
if account is not None and account.is_offset_needed:
|
if account is not None and account.is_need_offset:
|
||||||
raise ValidationError(lazy_gettext(
|
raise ValidationError(lazy_gettext(
|
||||||
"A payable entry cannot start from the debit side."))
|
"A payable entry cannot start from the debit side."))
|
||||||
|
|
||||||
@ -202,7 +202,7 @@ class NotStartReceivableFromCredit:
|
|||||||
or form.original_entry_id.data is not None:
|
or form.original_entry_id.data is not None:
|
||||||
return
|
return
|
||||||
account: Account | None = Account.find_by_code(field.data)
|
account: Account | None = Account.find_by_code(field.data)
|
||||||
if account is not None and account.is_offset_needed:
|
if account is not None and account.is_need_offset:
|
||||||
raise ValidationError(lazy_gettext(
|
raise ValidationError(lazy_gettext(
|
||||||
"A receivable entry cannot start from the credit side."))
|
"A receivable entry cannot start from the credit side."))
|
||||||
|
|
||||||
@ -361,7 +361,7 @@ class JournalEntryForm(FlaskForm):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
account: Account | None = Account.find_by_code(self.account_code.data)
|
account: Account | None = Account.find_by_code(self.account_code.data)
|
||||||
return account is not None and account.is_offset_needed
|
return account is not None and account.is_need_offset
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def offsets(self) -> list[JournalEntry]:
|
def offsets(self) -> list[JournalEntry]:
|
||||||
|
@ -129,9 +129,9 @@ class TransactionForm(FlaskForm):
|
|||||||
provide their own collectors."""
|
provide their own collectors."""
|
||||||
self.obj: Transaction | None = kwargs.get("obj")
|
self.obj: Transaction | None = kwargs.get("obj")
|
||||||
"""The transaction, when editing an existing one."""
|
"""The transaction, when editing an existing one."""
|
||||||
self._is_payable_needed: bool = False
|
self._is_need_payable: bool = False
|
||||||
"""Whether we need the payable original entries."""
|
"""Whether we need the payable original entries."""
|
||||||
self._is_receivable_needed: bool = False
|
self._is_need_receivable: bool = False
|
||||||
"""Whether we need the receivable original entries."""
|
"""Whether we need the receivable original entries."""
|
||||||
self.__original_entry_options: list[JournalEntry] | None = None
|
self.__original_entry_options: list[JournalEntry] | None = None
|
||||||
"""The options of the original entries."""
|
"""The options of the original entries."""
|
||||||
@ -219,7 +219,7 @@ class TransactionForm(FlaskForm):
|
|||||||
"""
|
"""
|
||||||
accounts: list[AccountOption] \
|
accounts: list[AccountOption] \
|
||||||
= [AccountOption(x) for x in Account.debit()
|
= [AccountOption(x) for x in Account.debit()
|
||||||
if not (x.code[0] == "2" and x.is_offset_needed)]
|
if not (x.code[0] == "2" and x.is_need_offset)]
|
||||||
in_use: set[int] = set(db.session.scalars(
|
in_use: set[int] = set(db.session.scalars(
|
||||||
sa.select(JournalEntry.account_id)
|
sa.select(JournalEntry.account_id)
|
||||||
.filter(JournalEntry.is_debit)
|
.filter(JournalEntry.is_debit)
|
||||||
@ -236,7 +236,7 @@ class TransactionForm(FlaskForm):
|
|||||||
"""
|
"""
|
||||||
accounts: list[AccountOption] \
|
accounts: list[AccountOption] \
|
||||||
= [AccountOption(x) for x in Account.credit()
|
= [AccountOption(x) for x in Account.credit()
|
||||||
if not (x.code[0] == "1" and x.is_offset_needed)]
|
if not (x.code[0] == "1" and x.is_need_offset)]
|
||||||
in_use: set[int] = set(db.session.scalars(
|
in_use: set[int] = set(db.session.scalars(
|
||||||
sa.select(JournalEntry.account_id)
|
sa.select(JournalEntry.account_id)
|
||||||
.filter(sa.not_(JournalEntry.is_debit))
|
.filter(sa.not_(JournalEntry.is_debit))
|
||||||
@ -271,7 +271,7 @@ class TransactionForm(FlaskForm):
|
|||||||
if self.__original_entry_options is None:
|
if self.__original_entry_options is None:
|
||||||
self.__original_entry_options = get_selectable_original_entries(
|
self.__original_entry_options = get_selectable_original_entries(
|
||||||
{x.eid.data for x in self.entries if x.eid.data is not None},
|
{x.eid.data for x in self.entries if x.eid.data is not None},
|
||||||
self._is_payable_needed, self._is_receivable_needed)
|
self._is_need_payable, self._is_need_receivable)
|
||||||
return self.__original_entry_options
|
return self.__original_entry_options
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -459,7 +459,7 @@ class IncomeTransactionForm(TransactionForm):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self._is_receivable_needed = True
|
self._is_need_receivable = True
|
||||||
|
|
||||||
class Collector(JournalEntryCollector[IncomeTransactionForm]):
|
class Collector(JournalEntryCollector[IncomeTransactionForm]):
|
||||||
"""The journal entry collector for the cash income transactions."""
|
"""The journal entry collector for the cash income transactions."""
|
||||||
@ -504,7 +504,7 @@ class ExpenseTransactionForm(TransactionForm):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self._is_payable_needed = True
|
self._is_need_payable = True
|
||||||
|
|
||||||
class Collector(JournalEntryCollector[ExpenseTransactionForm]):
|
class Collector(JournalEntryCollector[ExpenseTransactionForm]):
|
||||||
"""The journal entry collector for the cash expense
|
"""The journal entry collector for the cash expense
|
||||||
@ -550,8 +550,8 @@ class TransferTransactionForm(TransactionForm):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self._is_payable_needed = True
|
self._is_need_payable = True
|
||||||
self._is_receivable_needed = True
|
self._is_need_receivable = True
|
||||||
|
|
||||||
class Collector(JournalEntryCollector[TransferTransactionForm]):
|
class Collector(JournalEntryCollector[TransferTransactionForm]):
|
||||||
"""The journal entry collector for the transfer transactions."""
|
"""The journal entry collector for the transfer transactions."""
|
||||||
|
@ -38,10 +38,8 @@ class AccountOption:
|
|||||||
"""The string representation of the account option."""
|
"""The string representation of the account option."""
|
||||||
self.is_in_use: bool = False
|
self.is_in_use: bool = False
|
||||||
"""True if this account is in use, or False otherwise."""
|
"""True if this account is in use, or False otherwise."""
|
||||||
self.is_offset_needed: bool = account.is_offset_needed
|
self.is_need_offset: bool = account.is_need_offset
|
||||||
"""True if this account needs offset, or False otherwise."""
|
"""True if this account needs offset, or False otherwise."""
|
||||||
self.is_offset_chooser_needed: bool = False
|
|
||||||
"""True if this account needs an offset chooser, or False otherwise."""
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
"""Returns the string representation of the account option.
|
"""Returns the string representation of the account option.
|
||||||
|
@ -50,7 +50,7 @@ def get_selectable_original_entries(
|
|||||||
(offset.c.id.in_(entry_id_on_form), 0),
|
(offset.c.id.in_(entry_id_on_form), 0),
|
||||||
(be(offset.c.is_debit == JournalEntry.is_debit), offset.c.amount),
|
(be(offset.c.is_debit == JournalEntry.is_debit), offset.c.amount),
|
||||||
else_=-offset.c.amount))).label("net_balance")
|
else_=-offset.c.amount))).label("net_balance")
|
||||||
conditions: list[sa.BinaryExpression] = [Account.is_offset_needed]
|
conditions: list[sa.BinaryExpression] = [Account.is_need_offset]
|
||||||
sub_conditions: list[sa.BinaryExpression] = []
|
sub_conditions: list[sa.BinaryExpression] = []
|
||||||
if is_payable:
|
if is_payable:
|
||||||
sub_conditions.append(sa.and_(Account.base_code.startswith("2"),
|
sub_conditions.append(sa.and_(Account.base_code.startswith("2"),
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -377,7 +377,7 @@ class AccountTestCase(unittest.TestCase):
|
|||||||
data={"csrf_token": self.csrf_token,
|
data={"csrf_token": self.csrf_token,
|
||||||
"base_code": "6172",
|
"base_code": "6172",
|
||||||
"title": stock.title,
|
"title": stock.title,
|
||||||
"is_offset_needed": "yes"})
|
"is_need_offset": "yes"})
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
self.assertEqual(response.headers["Location"], create_uri)
|
self.assertEqual(response.headers["Location"], create_uri)
|
||||||
|
|
||||||
@ -484,7 +484,7 @@ class AccountTestCase(unittest.TestCase):
|
|||||||
data={"csrf_token": self.csrf_token,
|
data={"csrf_token": self.csrf_token,
|
||||||
"base_code": "6172",
|
"base_code": "6172",
|
||||||
"title": stock.title,
|
"title": stock.title,
|
||||||
"is_offset_needed": "yes"})
|
"is_need_offset": "yes"})
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
self.assertEqual(response.headers["Location"], edit_uri)
|
self.assertEqual(response.headers["Location"], edit_uri)
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ class OffsetTestCase(unittest.TestCase):
|
|||||||
# The original entry does not need offset
|
# The original entry does not need offset
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
account = Account.find_by_code(Accounts.RECEIVABLE)
|
account = Account.find_by_code(Accounts.RECEIVABLE)
|
||||||
account.is_offset_needed = False
|
account.is_need_offset = False
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
response = self.client.post(store_uri,
|
response = self.client.post(store_uri,
|
||||||
data=txn_data.new_form(self.csrf_token))
|
data=txn_data.new_form(self.csrf_token))
|
||||||
@ -121,7 +121,7 @@ class OffsetTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(response.headers["Location"], create_uri)
|
self.assertEqual(response.headers["Location"], create_uri)
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
account = Account.find_by_code(Accounts.RECEIVABLE)
|
account = Account.find_by_code(Accounts.RECEIVABLE)
|
||||||
account.is_offset_needed = True
|
account.is_need_offset = True
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
# The original entry is also an offset
|
# The original entry is also an offset
|
||||||
@ -219,7 +219,7 @@ class OffsetTestCase(unittest.TestCase):
|
|||||||
# The original entry does not need offset
|
# The original entry does not need offset
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
account = Account.find_by_code(Accounts.RECEIVABLE)
|
account = Account.find_by_code(Accounts.RECEIVABLE)
|
||||||
account.is_offset_needed = False
|
account.is_need_offset = False
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
response = self.client.post(update_uri,
|
response = self.client.post(update_uri,
|
||||||
data=txn_data.update_form(self.csrf_token))
|
data=txn_data.update_form(self.csrf_token))
|
||||||
@ -227,7 +227,7 @@ class OffsetTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(response.headers["Location"], edit_uri)
|
self.assertEqual(response.headers["Location"], edit_uri)
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
account = Account.find_by_code(Accounts.RECEIVABLE)
|
account = Account.find_by_code(Accounts.RECEIVABLE)
|
||||||
account.is_offset_needed = True
|
account.is_need_offset = True
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
# The original entry is also an offset
|
# The original entry is also an offset
|
||||||
@ -419,7 +419,7 @@ class OffsetTestCase(unittest.TestCase):
|
|||||||
# The original entry does not need offset
|
# The original entry does not need offset
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
account = Account.find_by_code(Accounts.PAYABLE)
|
account = Account.find_by_code(Accounts.PAYABLE)
|
||||||
account.is_offset_needed = False
|
account.is_need_offset = False
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
response = self.client.post(store_uri,
|
response = self.client.post(store_uri,
|
||||||
data=txn_data.new_form(self.csrf_token))
|
data=txn_data.new_form(self.csrf_token))
|
||||||
@ -427,7 +427,7 @@ class OffsetTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(response.headers["Location"], create_uri)
|
self.assertEqual(response.headers["Location"], create_uri)
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
account = Account.find_by_code(Accounts.PAYABLE)
|
account = Account.find_by_code(Accounts.PAYABLE)
|
||||||
account.is_offset_needed = True
|
account.is_need_offset = True
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
# The original entry is also an offset
|
# The original entry is also an offset
|
||||||
@ -525,7 +525,7 @@ class OffsetTestCase(unittest.TestCase):
|
|||||||
# The original entry does not need offset
|
# The original entry does not need offset
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
account = Account.find_by_code(Accounts.PAYABLE)
|
account = Account.find_by_code(Accounts.PAYABLE)
|
||||||
account.is_offset_needed = False
|
account.is_need_offset = False
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
response = self.client.post(update_uri,
|
response = self.client.post(update_uri,
|
||||||
data=txn_data.update_form(self.csrf_token))
|
data=txn_data.update_form(self.csrf_token))
|
||||||
@ -533,7 +533,7 @@ class OffsetTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(response.headers["Location"], edit_uri)
|
self.assertEqual(response.headers["Location"], edit_uri)
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
account = Account.find_by_code(Accounts.PAYABLE)
|
account = Account.find_by_code(Accounts.PAYABLE)
|
||||||
account.is_offset_needed = True
|
account.is_need_offset = True
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
# The original entry is also an offset
|
# The original entry is also an offset
|
||||||
|
@ -152,7 +152,7 @@ class PaginationTestCase(unittest.TestCase):
|
|||||||
:param items: All the items in the list.
|
:param items: All the items in the list.
|
||||||
:param is_reversed: Whether the default page is the last page.
|
:param is_reversed: Whether the default page is the last page.
|
||||||
:param result: The expected items on the page.
|
:param result: The expected items on the page.
|
||||||
:param is_paged: Whether the pagination is needed.
|
:param is_paged: Whether we need pagination.
|
||||||
"""
|
"""
|
||||||
self.items: list[int] = items
|
self.items: list[int] = items
|
||||||
self.is_reversed: bool | None = is_reversed
|
self.is_reversed: bool | None = is_reversed
|
||||||
@ -192,7 +192,7 @@ class PaginationTestCase(unittest.TestCase):
|
|||||||
:param query: The query string.
|
:param query: The query string.
|
||||||
:param items: The original items.
|
:param items: The original items.
|
||||||
:param result: The expected page content.
|
:param result: The expected page content.
|
||||||
:param is_paged: Whether the pagination is needed.
|
:param is_paged: Whether we need pagination.
|
||||||
:param is_reversed: Whether the list is reversed.
|
:param is_reversed: Whether the list is reversed.
|
||||||
:return: None.
|
:return: None.
|
||||||
"""
|
"""
|
||||||
@ -247,8 +247,8 @@ class PaginationTestCase(unittest.TestCase):
|
|||||||
self.__test_success("page-no=46&page-size=15", range(1, 687),
|
self.__test_success("page-no=46&page-size=15", range(1, 687),
|
||||||
range(676, 687))
|
range(676, 687))
|
||||||
|
|
||||||
def test_not_needed(self) -> None:
|
def test_not_need(self) -> None:
|
||||||
"""Tests the pagination that is not needed.
|
"""Tests that the data does not need pagination.
|
||||||
|
|
||||||
:return: None.
|
:return: None.
|
||||||
"""
|
"""
|
||||||
|
Reference in New Issue
Block a user