Compare commits

..

No commits in common. "8e5377a41655ec229452193c853b87d4df37f9dc" and "bb2993b0c0fc7f70f4b5be398d3585b3f84d28e2" have entirely different histories.

6 changed files with 24 additions and 72 deletions

View File

@ -53,21 +53,6 @@ class BaseAccountAvailable:
"The base account is not available.")) "The base account is not available."))
class NoOffsetNominalAccount:
"""The validator to check nominal account is not to be offset."""
def __call__(self, form: FlaskForm, field: BooleanField) -> None:
if not field.data:
return
if not isinstance(form, AccountForm):
return
if form.base_code.data is None:
return
if form.base_code.data[0] not in {"1", "2"}:
raise ValidationError(lazy_gettext(
"A nominal account does not need offset."))
class AccountForm(FlaskForm): class AccountForm(FlaskForm):
"""The form to create or edit an account.""" """The form to create or edit an account."""
base_code = StringField( base_code = StringField(
@ -81,8 +66,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_offset_needed = BooleanField()
validators=[NoOffsetNominalAccount()])
"""Whether the the entries of this account need offset.""" """Whether the the entries of this account need offset."""
def populate_obj(self, obj: Account) -> None: def populate_obj(self, obj: Account) -> None:
@ -103,10 +87,7 @@ class AccountForm(FlaskForm):
obj.base_code = self.base_code.data obj.base_code = self.base_code.data
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"}:
obj.is_offset_needed = self.is_offset_needed.data obj.is_offset_needed = self.is_offset_needed.data
else:
obj.is_offset_needed = 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

View File

@ -43,11 +43,9 @@ function initializeBaseAccountSelector() {
const base = document.getElementById("accounting-base"); const base = document.getElementById("accounting-base");
const baseCode = document.getElementById("accounting-base-code"); const baseCode = document.getElementById("accounting-base-code");
const baseContent = document.getElementById("accounting-base-content"); const baseContent = document.getElementById("accounting-base-content");
const isOffsetNeededControl = document.getElementById("accounting-is-offset-needed-control");
const isOffsetNeeded = document.getElementById("accounting-is-offset-needed");
const options = Array.from(document.getElementsByClassName("accounting-base-option")); const options = Array.from(document.getElementsByClassName("accounting-base-option"));
const btnClear = document.getElementById("accounting-btn-clear-base"); const btnClear = document.getElementById("accounting-btn-clear-base");
base.onclick = () => { selector.addEventListener("show.bs.modal", () => {
base.classList.add("accounting-not-empty"); base.classList.add("accounting-not-empty");
for (const option of options) { for (const option of options) {
option.classList.remove("active"); option.classList.remove("active");
@ -56,7 +54,7 @@ function initializeBaseAccountSelector() {
if (selected !== null) { if (selected !== null) {
selected.classList.add("active"); selected.classList.add("active");
} }
}; });
selector.addEventListener("hidden.bs.modal", () => { selector.addEventListener("hidden.bs.modal", () => {
if (baseCode.value === "") { if (baseCode.value === "") {
base.classList.remove("accounting-not-empty"); base.classList.remove("accounting-not-empty");
@ -66,14 +64,6 @@ function initializeBaseAccountSelector() {
option.onclick = () => { option.onclick = () => {
baseCode.value = option.dataset.code; baseCode.value = option.dataset.code;
baseContent.innerText = option.dataset.content; baseContent.innerText = option.dataset.content;
if (["1", "2"].includes(option.dataset.content.substring(0, 1))) {
isOffsetNeededControl.classList.remove("d-none");
isOffsetNeeded.disabled = false;
} else {
isOffsetNeededControl.classList.add("d-none");
isOffsetNeeded.disabled = true;
isOffsetNeeded.checked = false;
}
btnClear.classList.add("btn-danger"); btnClear.classList.add("btn-danger");
btnClear.classList.remove("btn-secondary") btnClear.classList.remove("btn-secondary")
btnClear.disabled = false; btnClear.disabled = false;

View File

@ -62,7 +62,7 @@ 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"] %} d-none {% endif %}"> <div class="form-check form-switch mb-3">
<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-offset-needed" class="form-check-input" type="checkbox" name="is_offset_needed" value="1" {% if form.is_offset_needed.data %} checked="checked" {% endif %}>
<label class="form-check-label" for="accounting-is-offset-needed"> <label class="form-check-label" for="accounting-is-offset-needed">
{{ A_("The entries in the account need offset.") }} {{ A_("The entries in the account need offset.") }}

View File

@ -372,15 +372,6 @@ class AccountTestCase(unittest.TestCase):
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)
# A nominal account that needs offset
response = self.client.post(store_uri,
data={"csrf_token": self.csrf_token,
"base_code": "6172",
"title": stock.title,
"is_offset_needed": "yes"})
self.assertEqual(response.status_code, 302)
self.assertEqual(response.headers["Location"], create_uri)
# Success, with spaces to be stripped # Success, with spaces to be stripped
response = self.client.post(store_uri, response = self.client.post(store_uri,
data={"csrf_token": self.csrf_token, data={"csrf_token": self.csrf_token,
@ -479,15 +470,6 @@ class AccountTestCase(unittest.TestCase):
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)
# A nominal account that needs offset
response = self.client.post(update_uri,
data={"csrf_token": self.csrf_token,
"base_code": "6172",
"title": stock.title,
"is_offset_needed": "yes"})
self.assertEqual(response.status_code, 302)
self.assertEqual(response.headers["Location"], edit_uri)
# Change the base account # Change the base account
response = self.client.post(update_uri, response = self.client.post(update_uri,
data={"csrf_token": self.csrf_token, data={"csrf_token": self.csrf_token,

View File

@ -79,13 +79,13 @@ class SummeryEditorTestCase(unittest.TestCase):
self.assertEqual(editor.debit.general.tags[0].accounts[0].code, self.assertEqual(editor.debit.general.tags[0].accounts[0].code,
Accounts.MEAL) Accounts.MEAL)
self.assertEqual(editor.debit.general.tags[0].accounts[1].code, self.assertEqual(editor.debit.general.tags[0].accounts[1].code,
Accounts.PETTY_CASH) Accounts.PAYABLE)
self.assertEqual(editor.debit.general.tags[1].name, "Dinner") self.assertEqual(editor.debit.general.tags[1].name, "Dinner")
self.assertEqual(len(editor.debit.general.tags[1].accounts), 2) self.assertEqual(len(editor.debit.general.tags[1].accounts), 2)
self.assertEqual(editor.debit.general.tags[1].accounts[0].code, self.assertEqual(editor.debit.general.tags[1].accounts[0].code,
Accounts.MEAL) Accounts.MEAL)
self.assertEqual(editor.debit.general.tags[1].accounts[1].code, self.assertEqual(editor.debit.general.tags[1].accounts[1].code,
Accounts.PETTY_CASH) Accounts.PAYABLE)
# Debit-Travel # Debit-Travel
self.assertEqual(len(editor.debit.travel.tags), 3) self.assertEqual(len(editor.debit.travel.tags), 3)
@ -118,7 +118,7 @@ class SummeryEditorTestCase(unittest.TestCase):
self.assertEqual(editor.credit.general.tags[0].name, "Lunch") self.assertEqual(editor.credit.general.tags[0].name, "Lunch")
self.assertEqual(len(editor.credit.general.tags[0].accounts), 3) self.assertEqual(len(editor.credit.general.tags[0].accounts), 3)
self.assertEqual(editor.credit.general.tags[0].accounts[0].code, self.assertEqual(editor.credit.general.tags[0].accounts[0].code,
Accounts.PETTY_CASH) Accounts.PAYABLE)
self.assertEqual(editor.credit.general.tags[0].accounts[1].code, self.assertEqual(editor.credit.general.tags[0].accounts[1].code,
Accounts.BANK) Accounts.BANK)
self.assertEqual(editor.credit.general.tags[0].accounts[2].code, self.assertEqual(editor.credit.general.tags[0].accounts[2].code,
@ -128,20 +128,20 @@ class SummeryEditorTestCase(unittest.TestCase):
self.assertEqual(editor.credit.general.tags[1].accounts[0].code, self.assertEqual(editor.credit.general.tags[1].accounts[0].code,
Accounts.BANK) Accounts.BANK)
self.assertEqual(editor.credit.general.tags[1].accounts[1].code, self.assertEqual(editor.credit.general.tags[1].accounts[1].code,
Accounts.PETTY_CASH) Accounts.PAYABLE)
# Credit-Travel # Credit-Travel
self.assertEqual(len(editor.credit.travel.tags), 2) self.assertEqual(len(editor.credit.travel.tags), 2)
self.assertEqual(editor.credit.travel.tags[0].name, "Bike") self.assertEqual(editor.credit.travel.tags[0].name, "Bike")
self.assertEqual(len(editor.credit.travel.tags[0].accounts), 2) self.assertEqual(len(editor.credit.travel.tags[0].accounts), 2)
self.assertEqual(editor.credit.travel.tags[0].accounts[0].code, self.assertEqual(editor.credit.travel.tags[0].accounts[0].code,
Accounts.PETTY_CASH) Accounts.PAYABLE)
self.assertEqual(editor.credit.travel.tags[0].accounts[1].code, self.assertEqual(editor.credit.travel.tags[0].accounts[1].code,
Accounts.PREPAID) Accounts.PREPAID)
self.assertEqual(editor.credit.travel.tags[1].name, "Taxi") self.assertEqual(editor.credit.travel.tags[1].name, "Taxi")
self.assertEqual(len(editor.credit.travel.tags[1].accounts), 2) self.assertEqual(len(editor.credit.travel.tags[1].accounts), 2)
self.assertEqual(editor.credit.travel.tags[1].accounts[0].code, self.assertEqual(editor.credit.travel.tags[1].accounts[0].code,
Accounts.PETTY_CASH) Accounts.PAYABLE)
self.assertEqual(editor.credit.travel.tags[1].accounts[1].code, self.assertEqual(editor.credit.travel.tags[1].accounts[1].code,
Accounts.CASH) Accounts.CASH)
@ -152,7 +152,7 @@ class SummeryEditorTestCase(unittest.TestCase):
self.assertEqual(editor.credit.bus.tags[0].accounts[0].code, self.assertEqual(editor.credit.bus.tags[0].accounts[0].code,
Accounts.PREPAID) Accounts.PREPAID)
self.assertEqual(editor.credit.bus.tags[0].accounts[1].code, self.assertEqual(editor.credit.bus.tags[0].accounts[1].code,
Accounts.PETTY_CASH) Accounts.PAYABLE)
self.assertEqual(editor.credit.bus.tags[1].name, "Bus") self.assertEqual(editor.credit.bus.tags[1].name, "Bus")
self.assertEqual(len(editor.credit.bus.tags[1].accounts), 1) self.assertEqual(len(editor.credit.bus.tags[1].accounts), 1)
self.assertEqual(editor.credit.bus.tags[1].accounts[0].code, self.assertEqual(editor.credit.bus.tags[1].accounts[0].code,
@ -186,7 +186,7 @@ def get_form_data(csrf_token: str) -> list[dict[str, str]]:
"currency-0-debit-1-account_code": Accounts.MEAL, "currency-0-debit-1-account_code": Accounts.MEAL,
"currency-0-debit-1-summary": " Lunch—Fries ", "currency-0-debit-1-summary": " Lunch—Fries ",
"currency-0-debit-1-amount": "2.15", "currency-0-debit-1-amount": "2.15",
"currency-0-credit-1-account_code": Accounts.PETTY_CASH, "currency-0-credit-1-account_code": Accounts.PAYABLE,
"currency-0-credit-1-summary": " Lunch—Fries ", "currency-0-credit-1-summary": " Lunch—Fries ",
"currency-0-credit-1-amount": "2.15", "currency-0-credit-1-amount": "2.15",
"currency-0-debit-2-account_code": Accounts.MEAL, "currency-0-debit-2-account_code": Accounts.MEAL,
@ -208,7 +208,7 @@ def get_form_data(csrf_token: str) -> list[dict[str, str]]:
"currency-0-debit-1-account_code": Accounts.MEAL, "currency-0-debit-1-account_code": Accounts.MEAL,
"currency-0-debit-1-summary": " Dinner—Steak ", "currency-0-debit-1-summary": " Dinner—Steak ",
"currency-0-debit-1-amount": "8.28", "currency-0-debit-1-amount": "8.28",
"currency-0-credit-1-account_code": Accounts.PETTY_CASH, "currency-0-credit-1-account_code": Accounts.PAYABLE,
"currency-0-credit-1-summary": " Dinner—Steak ", "currency-0-credit-1-summary": " Dinner—Steak ",
"currency-0-credit-1-amount": "8.28"}, "currency-0-credit-1-amount": "8.28"},
{"csrf_token": csrf_token, {"csrf_token": csrf_token,
@ -218,13 +218,13 @@ def get_form_data(csrf_token: str) -> list[dict[str, str]]:
"currency-0-debit-0-account_code": Accounts.MEAL, "currency-0-debit-0-account_code": Accounts.MEAL,
"currency-0-debit-0-summary": " Lunch—Pizza ", "currency-0-debit-0-summary": " Lunch—Pizza ",
"currency-0-debit-0-amount": "5.49", "currency-0-debit-0-amount": "5.49",
"currency-0-credit-0-account_code": Accounts.PETTY_CASH, "currency-0-credit-0-account_code": Accounts.PAYABLE,
"currency-0-credit-0-summary": " Lunch—Pizza ", "currency-0-credit-0-summary": " Lunch—Pizza ",
"currency-0-credit-0-amount": "5.49", "currency-0-credit-0-amount": "5.49",
"currency-0-debit-1-account_code": Accounts.MEAL, "currency-0-debit-1-account_code": Accounts.MEAL,
"currency-0-debit-1-summary": " Lunch—Noodles ", "currency-0-debit-1-summary": " Lunch—Noodles ",
"currency-0-debit-1-amount": "7.47", "currency-0-debit-1-amount": "7.47",
"currency-0-credit-1-account_code": Accounts.PETTY_CASH, "currency-0-credit-1-account_code": Accounts.PAYABLE,
"currency-0-credit-1-summary": " Lunch—Noodles ", "currency-0-credit-1-summary": " Lunch—Noodles ",
"currency-0-credit-1-amount": "7.47"}, "currency-0-credit-1-amount": "7.47"},
{"csrf_token": csrf_token, {"csrf_token": csrf_token,
@ -259,7 +259,7 @@ def get_form_data(csrf_token: str) -> list[dict[str, str]]:
"currency-0-debit-3-account_code": Accounts.TRAVEL, "currency-0-debit-3-account_code": Accounts.TRAVEL,
"currency-0-debit-3-summary": " Train—Red—Mall→Museum ", "currency-0-debit-3-summary": " Train—Red—Mall→Museum ",
"currency-0-debit-3-amount": "4.4", "currency-0-debit-3-amount": "4.4",
"currency-0-credit-3-account_code": Accounts.PETTY_CASH, "currency-0-credit-3-account_code": Accounts.PAYABLE,
"currency-0-credit-3-summary": " Train—Red—Mall→Museum ", "currency-0-credit-3-summary": " Train—Red—Mall→Museum ",
"currency-0-credit-3-amount": "4.4"}, "currency-0-credit-3-amount": "4.4"},
{"csrf_token": csrf_token, {"csrf_token": csrf_token,
@ -275,31 +275,31 @@ def get_form_data(csrf_token: str) -> list[dict[str, str]]:
"currency-0-debit-1-account_code": Accounts.TRAVEL, "currency-0-debit-1-account_code": Accounts.TRAVEL,
"currency-0-debit-1-summary": " Taxi—Office→Restaurant ", "currency-0-debit-1-summary": " Taxi—Office→Restaurant ",
"currency-0-debit-1-amount": "12", "currency-0-debit-1-amount": "12",
"currency-0-credit-1-account_code": Accounts.PETTY_CASH, "currency-0-credit-1-account_code": Accounts.PAYABLE,
"currency-0-credit-1-summary": " Taxi—Office→Restaurant ", "currency-0-credit-1-summary": " Taxi—Office→Restaurant ",
"currency-0-credit-1-amount": "12", "currency-0-credit-1-amount": "12",
"currency-0-debit-2-account_code": Accounts.TRAVEL, "currency-0-debit-2-account_code": Accounts.TRAVEL,
"currency-0-debit-2-summary": " Taxi—Restaurant→City Hall ", "currency-0-debit-2-summary": " Taxi—Restaurant→City Hall ",
"currency-0-debit-2-amount": "8", "currency-0-debit-2-amount": "8",
"currency-0-credit-2-account_code": Accounts.PETTY_CASH, "currency-0-credit-2-account_code": Accounts.PAYABLE,
"currency-0-credit-2-summary": " Taxi—Restaurant→City Hall ", "currency-0-credit-2-summary": " Taxi—Restaurant→City Hall ",
"currency-0-credit-2-amount": "8", "currency-0-credit-2-amount": "8",
"currency-0-debit-3-account_code": Accounts.TRAVEL, "currency-0-debit-3-account_code": Accounts.TRAVEL,
"currency-0-debit-3-summary": " Bike—City Hall→Office ", "currency-0-debit-3-summary": " Bike—City Hall→Office ",
"currency-0-debit-3-amount": "3.5", "currency-0-debit-3-amount": "3.5",
"currency-0-credit-3-account_code": Accounts.PETTY_CASH, "currency-0-credit-3-account_code": Accounts.PAYABLE,
"currency-0-credit-3-summary": " Bike—City Hall→Office ", "currency-0-credit-3-summary": " Bike—City Hall→Office ",
"currency-0-credit-3-amount": "3.5", "currency-0-credit-3-amount": "3.5",
"currency-0-debit-4-account_code": Accounts.TRAVEL, "currency-0-debit-4-account_code": Accounts.TRAVEL,
"currency-0-debit-4-summary": " Bike—Restaurant→Office ", "currency-0-debit-4-summary": " Bike—Restaurant→Office ",
"currency-0-debit-4-amount": "4", "currency-0-debit-4-amount": "4",
"currency-0-credit-4-account_code": Accounts.PETTY_CASH, "currency-0-credit-4-account_code": Accounts.PAYABLE,
"currency-0-credit-4-summary": " Bike—Restaurant→Office ", "currency-0-credit-4-summary": " Bike—Restaurant→Office ",
"currency-0-credit-4-amount": "4", "currency-0-credit-4-amount": "4",
"currency-0-debit-5-account_code": Accounts.TRAVEL, "currency-0-debit-5-account_code": Accounts.TRAVEL,
"currency-0-debit-5-summary": " Bike—Office→Theatre ", "currency-0-debit-5-summary": " Bike—Office→Theatre ",
"currency-0-debit-5-amount": "1.5", "currency-0-debit-5-amount": "1.5",
"currency-0-credit-5-account_code": Accounts.PETTY_CASH, "currency-0-credit-5-account_code": Accounts.PAYABLE,
"currency-0-credit-5-summary": " Bike—Office→Theatre ", "currency-0-credit-5-summary": " Bike—Office→Theatre ",
"currency-0-credit-5-amount": "1.5", "currency-0-credit-5-amount": "1.5",
"currency-0-debit-6-account_code": Accounts.TRAVEL, "currency-0-debit-6-account_code": Accounts.TRAVEL,
@ -312,13 +312,13 @@ def get_form_data(csrf_token: str) -> list[dict[str, str]]:
"next": NEXT_URI, "next": NEXT_URI,
"date": txn_date, "date": txn_date,
"currency-0-code": "USD", "currency-0-code": "USD",
"currency-0-debit-0-account_code": Accounts.PETTY_CASH, "currency-0-debit-0-account_code": Accounts.PAYABLE,
"currency-0-debit-0-summary": " Dinner—Steak ", "currency-0-debit-0-summary": " Dinner—Steak ",
"currency-0-debit-0-amount": "8.28", "currency-0-debit-0-amount": "8.28",
"currency-0-credit-0-account_code": Accounts.BANK, "currency-0-credit-0-account_code": Accounts.BANK,
"currency-0-credit-0-summary": " Dinner—Steak ", "currency-0-credit-0-summary": " Dinner—Steak ",
"currency-0-credit-0-amount": "8.28", "currency-0-credit-0-amount": "8.28",
"currency-0-debit-1-account_code": Accounts.PETTY_CASH, "currency-0-debit-1-account_code": Accounts.PAYABLE,
"currency-0-debit-1-summary": " Lunch—Pizza ", "currency-0-debit-1-summary": " Lunch—Pizza ",
"currency-0-debit-1-amount": "5.49", "currency-0-debit-1-amount": "5.49",
"currency-0-credit-1-account_code": Accounts.BANK, "currency-0-credit-1-account_code": Accounts.BANK,

View File

@ -38,7 +38,6 @@ EMPTY_NOTE: str = " \n\n "
class Accounts: class Accounts:
"""The shortcuts to the common accounts.""" """The shortcuts to the common accounts."""
CASH: str = "1111-001" CASH: str = "1111-001"
PETTY_CASH: str = "1112-001"
BANK: str = "1113-001" BANK: str = "1113-001"
PREPAID: str = "1258-001" PREPAID: str = "1258-001"
PAYABLE: str = "2141-001" PAYABLE: str = "2141-001"