Renamed "summary" to "description" in the voucher line item.

This commit is contained in:
依瑪貓 2023-03-20 16:01:25 +08:00
parent 3251660092
commit d18dd7d4d2
38 changed files with 680 additions and 678 deletions

View File

@ -653,8 +653,8 @@ class VoucherLineItem(db.Model):
"""The account ID.""" """The account ID."""
account = db.relationship(Account, back_populates="line_items", lazy=False) account = db.relationship(Account, back_populates="line_items", lazy=False)
"""The account.""" """The account."""
summary = db.Column(db.String, nullable=True) description = db.Column(db.String, nullable=True)
"""The summary.""" """The description."""
amount = db.Column(db.Numeric(14, 2), nullable=False) amount = db.Column(db.Numeric(14, 2), nullable=False)
"""The amount.""" """The amount."""
@ -666,10 +666,10 @@ class VoucherLineItem(db.Model):
if not hasattr(self, "__str"): if not hasattr(self, "__str"):
from accounting.template_filters import format_date, format_amount from accounting.template_filters import format_date, format_amount
setattr(self, "__str", setattr(self, "__str",
gettext("%(date)s %(summary)s %(amount)s", gettext("%(date)s %(description)s %(amount)s",
date=format_date(self.voucher.date), date=format_date(self.voucher.date),
summary="" if self.summary is None description="" if self.description is None
else self.summary, else self.description,
amount=format_amount(self.amount))) amount=format_amount(self.amount)))
return getattr(self, "__str") return getattr(self, "__str")
@ -753,8 +753,8 @@ class VoucherLineItem(db.Model):
return str(whole) + str(abs(frac))[1:] return str(whole) + str(abs(frac))[1:]
voucher_day: date = self.voucher.date voucher_day: date = self.voucher.date
summary: str = "" if self.summary is None else self.summary description: str = "" if self.description is None else self.description
return ([summary], return ([description],
[str(voucher_day.year), [str(voucher_day.year),
"{}/{}".format(voucher_day.year, voucher_day.month), "{}/{}".format(voucher_day.year, voucher_day.month),
"{}/{}".format(voucher_day.month, voucher_day.day), "{}/{}".format(voucher_day.month, voucher_day.day),

View File

@ -57,8 +57,8 @@ class ReportLineItem:
"""The date.""" """The date."""
self.account: Account | None = None self.account: Account | None = None
"""The account.""" """The account."""
self.summary: str | None = None self.description: str | None = None
"""The summary.""" """The description."""
self.income: Decimal | None = None self.income: Decimal | None = None
"""The income amount.""" """The income amount."""
self.expense: Decimal | None = None self.expense: Decimal | None = None
@ -72,7 +72,7 @@ class ReportLineItem:
if line_item is not None: if line_item is not None:
self.date = line_item.voucher.date self.date = line_item.voucher.date
self.account = line_item.account self.account = line_item.account
self.summary = line_item.summary self.description = line_item.description
self.income = None if line_item.is_debit else line_item.amount self.income = None if line_item.is_debit else line_item.amount
self.expense = line_item.amount if line_item.is_debit else None self.expense = line_item.amount if line_item.is_debit else None
self.note = line_item.voucher.note self.note = line_item.voucher.note
@ -131,7 +131,7 @@ class LineItemCollector:
line_item.is_brought_forward = True line_item.is_brought_forward = True
line_item.date = self.__period.start line_item.date = self.__period.start
line_item.account = Account.accumulated_change() line_item.account = Account.accumulated_change()
line_item.summary = gettext("Brought forward") line_item.description = gettext("Brought forward")
if balance > 0: if balance > 0:
line_item.income = balance line_item.income = balance
elif balance < 0: elif balance < 0:
@ -184,7 +184,7 @@ class LineItemCollector:
return None return None
line_item: ReportLineItem = ReportLineItem() line_item: ReportLineItem = ReportLineItem()
line_item.is_total = True line_item.is_total = True
line_item.summary = gettext("Total") line_item.description = gettext("Total")
line_item.income = sum([x.income for x in self.line_items line_item.income = sum([x.income for x in self.line_items
if x.income is not None]) if x.income is not None])
line_item.expense = sum([x.expense for x in self.line_items line_item.expense = sum([x.expense for x in self.line_items
@ -215,7 +215,7 @@ class CSVRow(BaseCSVRow):
def __init__(self, voucher_date: date | str | None, def __init__(self, voucher_date: date | str | None,
account: str | None, account: str | None,
summary: str | None, description: str | None,
income: str | Decimal | None, income: str | Decimal | None,
expense: str | Decimal | None, expense: str | Decimal | None,
balance: str | Decimal | None, balance: str | Decimal | None,
@ -224,7 +224,7 @@ class CSVRow(BaseCSVRow):
:param voucher_date: The voucher date. :param voucher_date: The voucher date.
:param account: The account. :param account: The account.
:param summary: The summary. :param description: The description.
:param income: The income. :param income: The income.
:param expense: The expense. :param expense: The expense.
:param balance: The balance. :param balance: The balance.
@ -234,8 +234,8 @@ class CSVRow(BaseCSVRow):
"""The date.""" """The date."""
self.account: str | None = account self.account: str | None = account
"""The account.""" """The account."""
self.summary: str | None = summary self.description: str | None = description
"""The summary.""" """The description."""
self.income: str | Decimal | None = income self.income: str | Decimal | None = income
"""The income.""" """The income."""
self.expense: str | Decimal | None = expense self.expense: str | Decimal | None = expense
@ -251,7 +251,7 @@ class CSVRow(BaseCSVRow):
:return: The values of the row. :return: The values of the row.
""" """
return [self.date, self.account, self.summary, return [self.date, self.account, self.description,
self.income, self.expense, self.balance, self.note] self.income, self.expense, self.balance, self.note]
@ -405,18 +405,18 @@ class IncomeExpenses(BaseReport):
:return: The CSV rows. :return: The CSV rows.
""" """
rows: list[CSVRow] = [CSVRow(gettext("Date"), gettext("Account"), rows: list[CSVRow] = [CSVRow(gettext("Date"), gettext("Account"),
gettext("Summary"), gettext("Income"), gettext("Description"), gettext("Income"),
gettext("Expense"), gettext("Balance"), gettext("Expense"), gettext("Balance"),
gettext("Note"))] gettext("Note"))]
if self.__brought_forward is not None: if self.__brought_forward is not None:
rows.append(CSVRow(self.__brought_forward.date, rows.append(CSVRow(self.__brought_forward.date,
str(self.__brought_forward.account).title(), str(self.__brought_forward.account).title(),
self.__brought_forward.summary, self.__brought_forward.description,
self.__brought_forward.income, self.__brought_forward.income,
self.__brought_forward.expense, self.__brought_forward.expense,
self.__brought_forward.balance, self.__brought_forward.balance,
None)) None))
rows.extend([CSVRow(x.date, str(x.account).title(), x.summary, rows.extend([CSVRow(x.date, str(x.account).title(), x.description,
x.income, x.expense, x.balance, x.note) x.income, x.expense, x.balance, x.note)
for x in self.__line_items]) for x in self.__line_items])
if self.__total is not None: if self.__total is not None:

View File

@ -53,8 +53,8 @@ class ReportLineItem:
"""The account.""" """The account."""
self.account: Account = line_item.account self.account: Account = line_item.account
"""The account.""" """The account."""
self.summary: str | None = line_item.summary self.description: str | None = line_item.description
"""The summary.""" """The description."""
self.debit: Decimal | None = line_item.debit self.debit: Decimal | None = line_item.debit
"""The debit amount.""" """The debit amount."""
self.credit: Decimal | None = line_item.credit self.credit: Decimal | None = line_item.credit
@ -69,14 +69,14 @@ class CSVRow(BaseCSVRow):
def __init__(self, voucher_date: str | date, def __init__(self, voucher_date: str | date,
currency: str, currency: str,
account: str, account: str,
summary: str | None, description: str | None,
debit: str | Decimal | None, debit: str | Decimal | None,
credit: str | Decimal | None, credit: str | Decimal | None,
note: str | None): note: str | None):
"""Constructs a row in the CSV. """Constructs a row in the CSV.
:param voucher_date: The voucher date. :param voucher_date: The voucher date.
:param summary: The summary. :param description: The description.
:param debit: The debit amount. :param debit: The debit amount.
:param credit: The credit amount. :param credit: The credit amount.
:param note: The note. :param note: The note.
@ -87,8 +87,8 @@ class CSVRow(BaseCSVRow):
"""The currency.""" """The currency."""
self.account: str = account self.account: str = account
"""The account.""" """The account."""
self.summary: str | None = summary self.description: str | None = description
"""The summary.""" """The description."""
self.debit: str | Decimal | None = debit self.debit: str | Decimal | None = debit
"""The debit amount.""" """The debit amount."""
self.credit: str | Decimal | None = credit self.credit: str | Decimal | None = credit
@ -102,7 +102,7 @@ class CSVRow(BaseCSVRow):
:return: The values of the row. :return: The values of the row.
""" """
return [self.date, self.currency, self.account, self.summary, return [self.date, self.currency, self.account, self.description,
self.debit, self.credit, self.note] self.debit, self.credit, self.note]
@ -152,11 +152,11 @@ def get_csv_rows(line_items: list[VoucherLineItem]) -> list[CSVRow]:
:return: The CSV rows. :return: The CSV rows.
""" """
rows: list[CSVRow] = [CSVRow(gettext("Date"), gettext("Currency"), rows: list[CSVRow] = [CSVRow(gettext("Date"), gettext("Currency"),
gettext("Account"), gettext("Summary"), gettext("Account"), gettext("Description"),
gettext("Debit"), gettext("Credit"), gettext("Debit"), gettext("Credit"),
gettext("Note"))] gettext("Note"))]
rows.extend([CSVRow(x.voucher.date, x.currency.code, rows.extend([CSVRow(x.voucher.date, x.currency.code,
str(x.account).title(), x.summary, str(x.account).title(), x.description,
x.debit, x.credit, x.voucher.note) x.debit, x.credit, x.voucher.note)
for x in line_items]) for x in line_items])
return rows return rows

View File

@ -54,8 +54,8 @@ class ReportLineItem:
"""Whether this is the total line item.""" """Whether this is the total line item."""
self.date: date | None = None self.date: date | None = None
"""The date.""" """The date."""
self.summary: str | None = None self.description: str | None = None
"""The summary.""" """The description."""
self.debit: Decimal | None = None self.debit: Decimal | None = None
"""The debit amount.""" """The debit amount."""
self.credit: Decimal | None = None self.credit: Decimal | None = None
@ -68,7 +68,7 @@ class ReportLineItem:
"""The URL to the voucher line item.""" """The URL to the voucher line item."""
if line_item is not None: if line_item is not None:
self.date = line_item.voucher.date self.date = line_item.voucher.date
self.summary = line_item.summary self.description = line_item.description
self.debit = line_item.amount if line_item.is_debit else None self.debit = line_item.amount if line_item.is_debit else None
self.credit = None if line_item.is_debit else line_item.amount self.credit = None if line_item.is_debit else line_item.amount
self.note = line_item.voucher.note self.note = line_item.voucher.note
@ -126,7 +126,7 @@ class LineItemCollector:
line_item: ReportLineItem = ReportLineItem() line_item: ReportLineItem = ReportLineItem()
line_item.is_brought_forward = True line_item.is_brought_forward = True
line_item.date = self.__period.start line_item.date = self.__period.start
line_item.summary = gettext("Brought forward") line_item.description = gettext("Brought forward")
if balance > 0: if balance > 0:
line_item.debit = balance line_item.debit = balance
elif balance < 0: elif balance < 0:
@ -163,7 +163,7 @@ class LineItemCollector:
return None return None
line_item: ReportLineItem = ReportLineItem() line_item: ReportLineItem = ReportLineItem()
line_item.is_total = True line_item.is_total = True
line_item.summary = gettext("Total") line_item.description = gettext("Total")
line_item.debit = sum([x.debit for x in self.line_items line_item.debit = sum([x.debit for x in self.line_items
if x.debit is not None]) if x.debit is not None])
line_item.credit = sum([x.credit for x in self.line_items line_item.credit = sum([x.credit for x in self.line_items
@ -195,7 +195,7 @@ class CSVRow(BaseCSVRow):
"""A row in the CSV.""" """A row in the CSV."""
def __init__(self, voucher_date: date | str | None, def __init__(self, voucher_date: date | str | None,
summary: str | None, description: str | None,
debit: str | Decimal | None, debit: str | Decimal | None,
credit: str | Decimal | None, credit: str | Decimal | None,
balance: str | Decimal | None, balance: str | Decimal | None,
@ -203,7 +203,7 @@ class CSVRow(BaseCSVRow):
"""Constructs a row in the CSV. """Constructs a row in the CSV.
:param voucher_date: The voucher date. :param voucher_date: The voucher date.
:param summary: The summary. :param description: The description.
:param debit: The debit amount. :param debit: The debit amount.
:param credit: The credit amount. :param credit: The credit amount.
:param balance: The balance. :param balance: The balance.
@ -211,8 +211,8 @@ class CSVRow(BaseCSVRow):
""" """
self.date: date | str | None = voucher_date self.date: date | str | None = voucher_date
"""The date.""" """The date."""
self.summary: str | None = summary self.description: str | None = description
"""The summary.""" """The description."""
self.debit: str | Decimal | None = debit self.debit: str | Decimal | None = debit
"""The debit amount.""" """The debit amount."""
self.credit: str | Decimal | None = credit self.credit: str | Decimal | None = credit
@ -228,7 +228,7 @@ class CSVRow(BaseCSVRow):
:return: The values of the row. :return: The values of the row.
""" """
return [self.date, self.summary, return [self.date, self.description,
self.debit, self.credit, self.balance, self.note] self.debit, self.credit, self.balance, self.note]
@ -357,17 +357,17 @@ class Ledger(BaseReport):
:return: The CSV rows. :return: The CSV rows.
""" """
rows: list[CSVRow] = [CSVRow(gettext("Date"), gettext("Summary"), rows: list[CSVRow] = [CSVRow(gettext("Date"), gettext("Description"),
gettext("Debit"), gettext("Credit"), gettext("Debit"), gettext("Credit"),
gettext("Balance"), gettext("Note"))] gettext("Balance"), gettext("Note"))]
if self.__brought_forward is not None: if self.__brought_forward is not None:
rows.append(CSVRow(self.__brought_forward.date, rows.append(CSVRow(self.__brought_forward.date,
self.__brought_forward.summary, self.__brought_forward.description,
self.__brought_forward.debit, self.__brought_forward.debit,
self.__brought_forward.credit, self.__brought_forward.credit,
self.__brought_forward.balance, self.__brought_forward.balance,
None)) None))
rows.extend([CSVRow(x.date, x.summary, rows.extend([CSVRow(x.date, x.description,
x.debit, x.credit, x.balance, x.note) x.debit, x.credit, x.balance, x.note)
for x in self.__line_items]) for x in self.__line_items])
if self.__total is not None: if self.__total is not None:

View File

@ -57,7 +57,7 @@ class LineItemCollector:
conditions: list[sa.BinaryExpression] = [] conditions: list[sa.BinaryExpression] = []
for k in keywords: for k in keywords:
sub_conditions: list[sa.BinaryExpression] \ sub_conditions: list[sa.BinaryExpression] \
= [VoucherLineItem.summary.contains(k), = [VoucherLineItem.description.contains(k),
VoucherLineItem.account_id.in_( VoucherLineItem.account_id.in_(
self.__get_account_condition(k)), self.__get_account_condition(k)),
VoucherLineItem.currency_code.in_( VoucherLineItem.currency_code.in_(

View File

@ -1,5 +1,5 @@
/* The Mia! Accounting Flask Project /* The Mia! Accounting Flask Project
* summary-editor.js: The JavaScript for the summary editor * description-editor.js: The JavaScript for the description editor
*/ */
/* Copyright (c) 2023 imacat. /* Copyright (c) 2023 imacat.
@ -23,10 +23,10 @@
"use strict"; "use strict";
/** /**
* A summary editor. * A description editor.
* *
*/ */
class SummaryEditor { class DescriptionEditor {
/** /**
* The line item editor * The line item editor
@ -35,7 +35,7 @@ class SummaryEditor {
#lineItemEditor; #lineItemEditor;
/** /**
* The summary editor form * The description editor form
* @type {HTMLFormElement} * @type {HTMLFormElement}
*/ */
#form; #form;
@ -47,7 +47,7 @@ class SummaryEditor {
prefix; prefix;
/** /**
* The modal of the summary editor * The modal of the description editor
* @type {HTMLDivElement} * @type {HTMLDivElement}
*/ */
#modal; #modal;
@ -65,10 +65,10 @@ class SummaryEditor {
currentTab; currentTab;
/** /**
* The summary input * The description input
* @type {HTMLInputElement} * @type {HTMLInputElement}
*/ */
summary; description;
/** /**
* The button to the original line item selector * The button to the original line item selector
@ -107,7 +107,7 @@ class SummaryEditor {
tabPlanes = {}; tabPlanes = {};
/** /**
* Constructs a summary editor. * Constructs a description editor.
* *
* @param lineItemEditor {VoucherLineItemEditor} the line item editor * @param lineItemEditor {VoucherLineItemEditor} the line item editor
* @param side {string} the side, either "debit" or "credit" * @param side {string} the side, either "debit" or "credit"
@ -115,10 +115,10 @@ class SummaryEditor {
constructor(lineItemEditor, side) { constructor(lineItemEditor, side) {
this.#lineItemEditor = lineItemEditor; this.#lineItemEditor = lineItemEditor;
this.side = side; this.side = side;
this.prefix = "accounting-summary-editor-" + side; this.prefix = "accounting-description-editor-" + side;
this.#form = document.getElementById(this.prefix); this.#form = document.getElementById(this.prefix);
this.#modal = document.getElementById(this.prefix + "-modal"); this.#modal = document.getElementById(this.prefix + "-modal");
this.summary = document.getElementById(this.prefix + "-summary"); this.description = document.getElementById(this.prefix + "-description");
this.#offsetButton = document.getElementById(this.prefix + "-offset"); this.#offsetButton = document.getElementById(this.prefix + "-offset");
this.number = document.getElementById(this.prefix + "-annotation-number"); this.number = document.getElementById(this.prefix + "-annotation-number");
this.note = document.getElementById(this.prefix + "-annotation-note"); this.note = document.getElementById(this.prefix + "-annotation-note");
@ -131,7 +131,7 @@ class SummaryEditor {
} }
this.currentTab = this.tabPlanes.general; this.currentTab = this.tabPlanes.general;
this.#initializeSuggestedAccounts(); this.#initializeSuggestedAccounts();
this.summary.onchange = () => this.#onSummaryChange(); this.description.onchange = () => this.#onDescriptionChange();
this.#offsetButton.onclick = () => this.#lineItemEditor.originalLineItemSelector.onOpen(); this.#offsetButton.onclick = () => this.#lineItemEditor.originalLineItemSelector.onOpen();
this.#form.onsubmit = () => { this.#form.onsubmit = () => {
if (this.currentTab.validate()) { if (this.currentTab.validate()) {
@ -142,11 +142,11 @@ class SummaryEditor {
} }
/** /**
* The callback when the summary input is changed. * The callback when the description input is changed.
* *
*/ */
#onSummaryChange() { #onDescriptionChange() {
this.summary.value = this.summary.value.trim(); this.description.value = this.description.value.trim();
for (const tabPlane of [this.tabPlanes.bus, this.tabPlanes.travel, this.tabPlanes.general]) { for (const tabPlane of [this.tabPlanes.bus, this.tabPlanes.travel, this.tabPlanes.general]) {
if (tabPlane.populate()) { if (tabPlane.populate()) {
break; break;
@ -209,34 +209,34 @@ class SummaryEditor {
} }
/** /**
* Submits the summary. * Submits the description.
* *
*/ */
#submit() { #submit() {
bootstrap.Modal.getOrCreateInstance(this.#modal).hide(); bootstrap.Modal.getOrCreateInstance(this.#modal).hide();
if (this.#selectedAccount !== null) { if (this.#selectedAccount !== null) {
this.#lineItemEditor.saveSummaryWithAccount(this.summary.value, this.#selectedAccount.dataset.code, this.#selectedAccount.dataset.text, this.#selectedAccount.classList.contains("accounting-account-is-need-offset")); this.#lineItemEditor.saveDescriptionWithAccount(this.description.value, this.#selectedAccount.dataset.code, this.#selectedAccount.dataset.text, this.#selectedAccount.classList.contains("accounting-account-is-need-offset"));
} else { } else {
this.#lineItemEditor.saveSummary(this.summary.value); this.#lineItemEditor.saveDescription(this.description.value);
} }
} }
/** /**
* The callback when the summary editor is shown. * The callback when the description editor is shown.
* *
*/ */
onOpen() { onOpen() {
this.#reset(); this.#reset();
this.summary.value = this.#lineItemEditor.summary === null? "": this.#lineItemEditor.summary; this.description.value = this.#lineItemEditor.description === null? "": this.#lineItemEditor.description;
this.#onSummaryChange(); this.#onDescriptionChange();
} }
/** /**
* Resets the summary editor. * Resets the description editor.
* *
*/ */
#reset() { #reset() {
this.summary.value = ""; this.description.value = "";
for (const tabPlane of Object.values(this.tabPlanes)) { for (const tabPlane of Object.values(this.tabPlanes)) {
tabPlane.reset(); tabPlane.reset();
} }
@ -244,16 +244,16 @@ class SummaryEditor {
} }
/** /**
* Returns the summary editor instances. * Returns the description editor instances.
* *
* @param lineItemEditor {VoucherLineItemEditor} the line item editor * @param lineItemEditor {VoucherLineItemEditor} the line item editor
* @return {{debit: SummaryEditor, credit: SummaryEditor}} * @return {{debit: DescriptionEditor, credit: DescriptionEditor}}
*/ */
static getInstances(lineItemEditor) { static getInstances(lineItemEditor) {
const editors = {} const editors = {}
const forms = Array.from(document.getElementsByClassName("accounting-summary-editor")); const forms = Array.from(document.getElementsByClassName("accounting-description-editor"));
for (const form of forms) { for (const form of forms) {
editors[form.dataset.side] = new SummaryEditor(lineItemEditor, form.dataset.side); editors[form.dataset.side] = new DescriptionEditor(lineItemEditor, form.dataset.side);
} }
return editors; return editors;
} }
@ -268,8 +268,8 @@ class SummaryEditor {
class TabPlane { class TabPlane {
/** /**
* The parent summary editor * The parent description editor
* @type {SummaryEditor} * @type {DescriptionEditor}
*/ */
editor; editor;
@ -294,7 +294,7 @@ class TabPlane {
/** /**
* Constructs a tab plane. * Constructs a tab plane.
* *
* @param editor {SummaryEditor} the parent summary editor * @param editor {DescriptionEditor} the parent description editor
*/ */
constructor(editor) { constructor(editor) {
this.editor = editor; this.editor = editor;
@ -320,9 +320,9 @@ class TabPlane {
reset() { throw new Error("Method not implemented."); } reset() { throw new Error("Method not implemented."); }
/** /**
* Populates the tab plane with the summary input. * Populates the tab plane with the description input.
* *
* @return {boolean} true if the summary input matches this tab, or false otherwise * @return {boolean} true if the description input matches this tab, or false otherwise
* @abstract * @abstract
*/ */
populate() { throw new Error("Method not implemented."); } populate() { throw new Error("Method not implemented."); }
@ -383,7 +383,7 @@ class TagTabPlane extends TabPlane {
/** /**
* Constructs a tab plane. * Constructs a tab plane.
* *
* @param editor {SummaryEditor} the parent summary editor * @param editor {DescriptionEditor} the parent description editor
* @override * @override
*/ */
constructor(editor) { constructor(editor) {
@ -395,7 +395,7 @@ class TagTabPlane extends TabPlane {
this.initializeTagButtons(); this.initializeTagButtons();
this.tag.onchange = () => { this.tag.onchange = () => {
this.onTagChange(); this.onTagChange();
this.updateSummary(); this.updateDescription();
}; };
} }
@ -424,11 +424,11 @@ class TagTabPlane extends TabPlane {
} }
/** /**
* Updates the summary according to the input in the tab plane. * Updates the description according to the input in the tab plane.
* *
* @abstract * @abstract
*/ */
updateSummary() { throw new Error("Method not implemented."); } updateDescription() { throw new Error("Method not implemented."); }
/** /**
* Switches to the tab plane. * Switches to the tab plane.
@ -461,7 +461,7 @@ class TagTabPlane extends TabPlane {
tagButton.classList.add("btn-primary"); tagButton.classList.add("btn-primary");
this.tag.value = tagButton.dataset.value; this.tag.value = tagButton.dataset.value;
this.editor.filterSuggestedAccounts(tagButton); this.editor.filterSuggestedAccounts(tagButton);
this.updateSummary(); this.updateDescription();
}; };
} }
} }
@ -532,28 +532,28 @@ class GeneralTagTab extends TagTabPlane {
}; };
/** /**
* Updates the summary according to the input in the tab plane. * Updates the description according to the input in the tab plane.
* *
* @override * @override
*/ */
updateSummary() { updateDescription() {
const pos = this.editor.summary.value.indexOf("—"); const pos = this.editor.description.value.indexOf("—");
const prefix = this.tag.value === ""? "": this.tag.value + "—"; const prefix = this.tag.value === ""? "": this.tag.value + "—";
if (pos === -1) { if (pos === -1) {
this.editor.summary.value = prefix + this.editor.summary.value; this.editor.description.value = prefix + this.editor.description.value;
} else { } else {
this.editor.summary.value = prefix + this.editor.summary.value.substring(pos + 1); this.editor.description.value = prefix + this.editor.description.value.substring(pos + 1);
} }
} }
/** /**
* Populates the tab plane with the summary input. * Populates the tab plane with the description input.
* *
* @return {boolean} true if the summary input matches this tab, or false otherwise * @return {boolean} true if the description input matches this tab, or false otherwise
* @override * @override
*/ */
populate() { populate() {
const found = this.editor.summary.value.match(/^([^—]+)—/); const found = this.editor.description.value.match(/^([^—]+)—/);
if (found === null) { if (found === null) {
return false; return false;
} }
@ -622,7 +622,7 @@ class GeneralTripTab extends TagTabPlane {
/** /**
* Constructs a tab plane. * Constructs a tab plane.
* *
* @param editor {SummaryEditor} the parent summary editor * @param editor {DescriptionEditor} the parent description editor
* @override * @override
*/ */
constructor(editor) { constructor(editor) {
@ -635,7 +635,7 @@ class GeneralTripTab extends TagTabPlane {
this.#directionButtons = Array.from(document.getElementsByClassName(this.prefix + "-direction")); this.#directionButtons = Array.from(document.getElementsByClassName(this.prefix + "-direction"));
this.#from.onchange = () => { this.#from.onchange = () => {
this.#from.value = this.#from.value.trim(); this.#from.value = this.#from.value.trim();
this.updateSummary(); this.updateDescription();
this.validateFrom(); this.validateFrom();
}; };
for (const directionButton of this.#directionButtons) { for (const directionButton of this.#directionButtons) {
@ -646,12 +646,12 @@ class GeneralTripTab extends TagTabPlane {
} }
directionButton.classList.remove("btn-outline-primary"); directionButton.classList.remove("btn-outline-primary");
directionButton.classList.add("btn-primary"); directionButton.classList.add("btn-primary");
this.updateSummary(); this.updateDescription();
}; };
} }
this.#to.onchange = () => { this.#to.onchange = () => {
this.#to.value = this.#to.value.trim(); this.#to.value = this.#to.value.trim();
this.updateSummary(); this.updateDescription();
this.validateTo(); this.validateTo();
}; };
} }
@ -667,11 +667,11 @@ class GeneralTripTab extends TagTabPlane {
}; };
/** /**
* Updates the summary according to the input in the tab plane. * Updates the description according to the input in the tab plane.
* *
* @override * @override
*/ */
updateSummary() { updateDescription() {
let direction; let direction;
for (const directionButton of this.#directionButtons) { for (const directionButton of this.#directionButtons) {
if (directionButton.classList.contains("btn-primary")) { if (directionButton.classList.contains("btn-primary")) {
@ -679,7 +679,7 @@ class GeneralTripTab extends TagTabPlane {
break; break;
} }
} }
this.editor.summary.value = this.tag.value + "—" + this.#from.value + direction + this.#to.value; this.editor.description.value = this.tag.value + "—" + this.#from.value + direction + this.#to.value;
} }
/** /**
@ -707,13 +707,13 @@ class GeneralTripTab extends TagTabPlane {
} }
/** /**
* Populates the tab plane with the summary input. * Populates the tab plane with the description input.
* *
* @return {boolean} true if the summary input matches this tab, or false otherwise * @return {boolean} true if the description input matches this tab, or false otherwise
* @override * @override
*/ */
populate() { populate() {
const found = this.editor.summary.value.match(/^([^—]+)—([^—→↔]+)([→↔])(.+?)(?:[*×]\d+)?(?:\([^()]+\))?$/); const found = this.editor.description.value.match(/^([^—]+)—([^—→↔]+)([→↔])(.+?)(?:[*×]\d+)?(?:\([^()]+\))?$/);
if (found === null) { if (found === null) {
return false; return false;
} }
@ -834,7 +834,7 @@ class BusTripTab extends TagTabPlane {
/** /**
* Constructs a tab plane. * Constructs a tab plane.
* *
* @param editor {SummaryEditor} the parent summary editor * @param editor {DescriptionEditor} the parent description editor
* @override * @override
*/ */
constructor(editor) { constructor(editor) {
@ -847,17 +847,17 @@ class BusTripTab extends TagTabPlane {
this.#toError = document.getElementById(this.prefix + "-to-error") this.#toError = document.getElementById(this.prefix + "-to-error")
this.#route.onchange = () => { this.#route.onchange = () => {
this.#route.value = this.#route.value.trim(); this.#route.value = this.#route.value.trim();
this.updateSummary(); this.updateDescription();
this.validateRoute(); this.validateRoute();
}; };
this.#from.onchange = () => { this.#from.onchange = () => {
this.#from.value = this.#from.value.trim(); this.#from.value = this.#from.value.trim();
this.updateSummary(); this.updateDescription();
this.validateFrom(); this.validateFrom();
}; };
this.#to.onchange = () => { this.#to.onchange = () => {
this.#to.value = this.#to.value.trim(); this.#to.value = this.#to.value.trim();
this.updateSummary(); this.updateDescription();
this.validateTo(); this.validateTo();
}; };
} }
@ -873,12 +873,12 @@ class BusTripTab extends TagTabPlane {
}; };
/** /**
* Updates the summary according to the input in the tab plane. * Updates the description according to the input in the tab plane.
* *
* @override * @override
*/ */
updateSummary() { updateDescription() {
this.editor.summary.value = this.tag.value + "—" + this.#route.value + "—" + this.#from.value + "→" + this.#to.value; this.editor.description.value = this.tag.value + "—" + this.#route.value + "—" + this.#from.value + "→" + this.#to.value;
} }
/** /**
@ -900,13 +900,13 @@ class BusTripTab extends TagTabPlane {
} }
/** /**
* Populates the tab plane with the summary input. * Populates the tab plane with the description input.
* *
* @return {boolean} true if the summary input matches this tab, or false otherwise * @return {boolean} true if the description input matches this tab, or false otherwise
* @override * @override
*/ */
populate() { populate() {
const found = this.editor.summary.value.match(/^([^—]+)—([^—]+)—([^—→]+)→(.+?)(?:[*×]\d+)?(?:\([^()]+\))?$/); const found = this.editor.description.value.match(/^([^—]+)—([^—]+)—([^—→]+)→(.+?)(?:[*×]\d+)?(?:\([^()]+\))?$/);
if (found === null) { if (found === null) {
return false; return false;
} }
@ -1001,7 +1001,7 @@ class RegularPaymentTab extends TabPlane {
/** /**
* Constructs a tab plane. * Constructs a tab plane.
* *
* @param editor {SummaryEditor} the parent summary editor * @param editor {DescriptionEditor} the parent description editor
* @override * @override
*/ */
constructor(editor) { constructor(editor) {
@ -1033,9 +1033,9 @@ class RegularPaymentTab extends TabPlane {
} }
/** /**
* Populates the tab plane with the summary input. * Populates the tab plane with the description input.
* *
* @return {boolean} true if the summary input matches this tab, or false otherwise * @return {boolean} true if the description input matches this tab, or false otherwise
* @override * @override
*/ */
populate() { populate() {
@ -1063,15 +1063,15 @@ class AnnotationTab extends TabPlane {
/** /**
* Constructs a tab plane. * Constructs a tab plane.
* *
* @param editor {SummaryEditor} the parent summary editor * @param editor {DescriptionEditor} the parent description editor
* @override * @override
*/ */
constructor(editor) { constructor(editor) {
super(editor); super(editor);
this.editor.number.onchange = () => this.updateSummary(); this.editor.number.onchange = () => this.updateDescription();
this.editor.note.onchange = () => { this.editor.note.onchange = () => {
this.editor.note.value = this.editor.note.value.trim(); this.editor.note.value = this.editor.note.value.trim();
this.updateSummary(); this.updateDescription();
}; };
} }
@ -1086,20 +1086,20 @@ class AnnotationTab extends TabPlane {
}; };
/** /**
* Updates the summary according to the input in the tab plane. * Updates the description according to the input in the tab plane.
* *
* @override * @override
*/ */
updateSummary() { updateDescription() {
const found = this.editor.summary.value.match(/^(.*?)(?:[*×]\d+)?(?:\([^()]+\))?$/); const found = this.editor.description.value.match(/^(.*?)(?:[*×]\d+)?(?:\([^()]+\))?$/);
if (found !== null) { if (found !== null) {
this.editor.summary.value = found[1]; this.editor.description.value = found[1];
} }
if (parseInt(this.editor.number.value) > 1) { if (parseInt(this.editor.number.value) > 1) {
this.editor.summary.value = this.editor.summary.value + "×" + this.editor.number.value; this.editor.description.value = this.editor.description.value + "×" + this.editor.number.value;
} }
if (this.editor.note.value !== "") { if (this.editor.note.value !== "") {
this.editor.summary.value = this.editor.summary.value + "(" + this.editor.note.value + ")"; this.editor.description.value = this.editor.description.value + "(" + this.editor.note.value + ")";
} }
} }
@ -1114,25 +1114,25 @@ class AnnotationTab extends TabPlane {
} }
/** /**
* Populates the tab plane with the summary input. * Populates the tab plane with the description input.
* *
* @return {boolean} true if the summary input matches this tab, or false otherwise * @return {boolean} true if the description input matches this tab, or false otherwise
* @override * @override
*/ */
populate() { populate() {
const found = this.editor.summary.value.match(/^(.*?)(?:[*×](\d+))?(?:\(([^()]+)\))?$/); const found = this.editor.description.value.match(/^(.*?)(?:[*×](\d+))?(?:\(([^()]+)\))?$/);
this.editor.summary.value = found[1]; this.editor.description.value = found[1];
if (found[2] === undefined || parseInt(found[2]) === 1) { if (found[2] === undefined || parseInt(found[2]) === 1) {
this.editor.number.value = ""; this.editor.number.value = "";
} else { } else {
this.editor.number.value = found[2]; this.editor.number.value = found[2];
this.editor.summary.value = this.editor.summary.value + "×" + this.editor.number.value; this.editor.description.value = this.editor.description.value + "×" + this.editor.number.value;
} }
if (found[3] === undefined) { if (found[3] === undefined) {
this.editor.note.value = ""; this.editor.note.value = "";
} else { } else {
this.editor.note.value = found[3]; this.editor.note.value = found[3];
this.editor.summary.value = this.editor.summary.value + "(" + this.editor.note.value + ")"; this.editor.description.value = this.editor.description.value + "(" + this.editor.note.value + ")";
} }
return true; return true;
} }

View File

@ -244,10 +244,10 @@ class OriginalLineItem {
accountText; accountText;
/** /**
* The summary * The description
* @type {string} * @type {string}
*/ */
summary; description;
/** /**
* The net balance, without the offset amounts on the form * The net balance, without the offset amounts on the form
@ -294,7 +294,7 @@ class OriginalLineItem {
this.#currencyCode = element.dataset.currencyCode; this.#currencyCode = element.dataset.currencyCode;
this.accountCode = element.dataset.accountCode; this.accountCode = element.dataset.accountCode;
this.accountText = element.dataset.accountText; this.accountText = element.dataset.accountText;
this.summary = element.dataset.summary; this.description = element.dataset.description;
this.bareNetBalance = new Decimal(element.dataset.netBalance); this.bareNetBalance = new Decimal(element.dataset.netBalance);
this.netBalance = this.bareNetBalance; this.netBalance = this.bareNetBalance;
this.netBalanceText = document.getElementById("accounting-original-line-item-selector-option-" + this.id + "-net-balance"); this.netBalanceText = document.getElementById("accounting-original-line-item-selector-option-" + this.id + "-net-balance");

View File

@ -808,16 +808,16 @@ class LineItemSubForm {
#accountText; #accountText;
/** /**
* The summary * The description
* @type {HTMLInputElement} * @type {HTMLInputElement}
*/ */
#summary; #description;
/** /**
* The text display of the summary * The text display of the description
* @type {HTMLDivElement} * @type {HTMLDivElement}
*/ */
#summaryText; #descriptionText;
/** /**
* The ID of the original line item * The ID of the original line item
@ -873,8 +873,8 @@ class LineItemSubForm {
this.no = document.getElementById(this.#prefix + "-no"); this.no = document.getElementById(this.#prefix + "-no");
this.#accountCode = document.getElementById(this.#prefix + "-account-code"); this.#accountCode = document.getElementById(this.#prefix + "-account-code");
this.#accountText = document.getElementById(this.#prefix + "-account-text"); this.#accountText = document.getElementById(this.#prefix + "-account-text");
this.#summary = document.getElementById(this.#prefix + "-summary"); this.#description = document.getElementById(this.#prefix + "-description");
this.#summaryText = document.getElementById(this.#prefix + "-summary-text"); this.#descriptionText = document.getElementById(this.#prefix + "-description-text");
this.#originalLineItemId = document.getElementById(this.#prefix + "-original-line-item-id"); this.#originalLineItemId = document.getElementById(this.#prefix + "-original-line-item-id");
this.#originalLineItemText = document.getElementById(this.#prefix + "-original-line-item-text"); this.#originalLineItemText = document.getElementById(this.#prefix + "-original-line-item-text");
this.#offsets = document.getElementById(this.#prefix + "-offsets"); this.#offsets = document.getElementById(this.#prefix + "-offsets");
@ -925,12 +925,12 @@ class LineItemSubForm {
} }
/** /**
* Returns the summary. * Returns the description.
* *
* @return {string|null} the summary * @return {string|null} the description
*/ */
getSummary() { getDescription() {
return this.#summary.value === ""? null: this.#summary.value; return this.#description.value === ""? null: this.#description.value;
} }
/** /**
@ -1014,8 +1014,8 @@ class LineItemSubForm {
this.#accountCode.value = editor.accountCode === null? "": editor.accountCode; this.#accountCode.value = editor.accountCode === null? "": editor.accountCode;
this.#accountCode.dataset.text = editor.accountText === null? "": editor.accountText; this.#accountCode.dataset.text = editor.accountText === null? "": editor.accountText;
this.#accountText.innerText = editor.accountText === null? "": editor.accountText; this.#accountText.innerText = editor.accountText === null? "": editor.accountText;
this.#summary.value = editor.summary === null? "": editor.summary; this.#description.value = editor.description === null? "": editor.description;
this.#summaryText.innerText = editor.summary === null? "": editor.summary; this.#descriptionText.innerText = editor.description === null? "": editor.description;
this.#amount.value = editor.amount; this.#amount.value = editor.amount;
this.#amountText.innerText = formatDecimal(new Decimal(editor.amount)); this.#amountText.innerText = formatDecimal(new Decimal(editor.amount));
this.validate(); this.validate();

View File

@ -89,22 +89,22 @@ class VoucherLineItemEditor {
#originalLineItemDelete; #originalLineItemDelete;
/** /**
* The control of the summary * The control of the description
* @type {HTMLDivElement} * @type {HTMLDivElement}
*/ */
#summaryControl; #descriptionControl;
/** /**
* The summary * The description
* @type {HTMLDivElement} * @type {HTMLDivElement}
*/ */
#summaryText; #descriptionText;
/** /**
* The error message of the summary * The error message of the description
* @type {HTMLDivElement} * @type {HTMLDivElement}
*/ */
#summaryError; #descriptionError;
/** /**
* The control of the account * The control of the account
@ -185,10 +185,10 @@ class VoucherLineItemEditor {
accountText = null; accountText = null;
/** /**
* The summary * The description
* @type {string|null} * @type {string|null}
*/ */
summary = null; description = null;
/** /**
* The amount * The amount
@ -197,10 +197,10 @@ class VoucherLineItemEditor {
amount = ""; amount = "";
/** /**
* The summary editors * The description editors
* @type {{debit: SummaryEditor, credit: SummaryEditor}} * @type {{debit: DescriptionEditor, credit: DescriptionEditor}}
*/ */
#summaryEditors; #descriptionEditors;
/** /**
* The account selectors * The account selectors
@ -228,20 +228,20 @@ class VoucherLineItemEditor {
this.#originalLineItemText = document.getElementById(this.#prefix + "-original-line-item"); this.#originalLineItemText = document.getElementById(this.#prefix + "-original-line-item");
this.#originalLineItemError = document.getElementById(this.#prefix + "-original-line-item-error"); this.#originalLineItemError = document.getElementById(this.#prefix + "-original-line-item-error");
this.#originalLineItemDelete = document.getElementById(this.#prefix + "-original-line-item-delete"); this.#originalLineItemDelete = document.getElementById(this.#prefix + "-original-line-item-delete");
this.#summaryControl = document.getElementById(this.#prefix + "-summary-control"); this.#descriptionControl = document.getElementById(this.#prefix + "-description-control");
this.#summaryText = document.getElementById(this.#prefix + "-summary"); this.#descriptionText = document.getElementById(this.#prefix + "-description");
this.#summaryError = document.getElementById(this.#prefix + "-summary-error"); this.#descriptionError = document.getElementById(this.#prefix + "-description-error");
this.#accountControl = document.getElementById(this.#prefix + "-account-control"); this.#accountControl = document.getElementById(this.#prefix + "-account-control");
this.#accountText = document.getElementById(this.#prefix + "-account"); this.#accountText = document.getElementById(this.#prefix + "-account");
this.#accountError = document.getElementById(this.#prefix + "-account-error") this.#accountError = document.getElementById(this.#prefix + "-account-error")
this.#amountInput = document.getElementById(this.#prefix + "-amount"); this.#amountInput = document.getElementById(this.#prefix + "-amount");
this.#amountError = document.getElementById(this.#prefix + "-amount-error"); this.#amountError = document.getElementById(this.#prefix + "-amount-error");
this.#summaryEditors = SummaryEditor.getInstances(this); this.#descriptionEditors = DescriptionEditor.getInstances(this);
this.#accountSelectors = AccountSelector.getInstances(this); this.#accountSelectors = AccountSelector.getInstances(this);
this.originalLineItemSelector = new OriginalLineItemSelector(this); this.originalLineItemSelector = new OriginalLineItemSelector(this);
this.#originalLineItemControl.onclick = () => this.originalLineItemSelector.onOpen() this.#originalLineItemControl.onclick = () => this.originalLineItemSelector.onOpen()
this.#originalLineItemDelete.onclick = () => this.clearOriginalLineItem(); this.#originalLineItemDelete.onclick = () => this.clearOriginalLineItem();
this.#summaryControl.onclick = () => this.#summaryEditors[this.side].onOpen(); this.#descriptionControl.onclick = () => this.#descriptionEditors[this.side].onOpen();
this.#accountControl.onclick = () => this.#accountSelectors[this.side].onOpen(); this.#accountControl.onclick = () => this.#accountSelectors[this.side].onOpen();
this.#amountInput.onchange = () => this.#validateAmount(); this.#amountInput.onchange = () => this.#validateAmount();
this.#element.onsubmit = () => { this.#element.onsubmit = () => {
@ -270,14 +270,14 @@ class VoucherLineItemEditor {
this.originalLineItemDate = originalLineItem.date; this.originalLineItemDate = originalLineItem.date;
this.originalLineItemText = originalLineItem.text; this.originalLineItemText = originalLineItem.text;
this.#originalLineItemText.innerText = originalLineItem.text; this.#originalLineItemText.innerText = originalLineItem.text;
this.#setEnableSummaryAccount(false); this.#setEnableDescriptionAccount(false);
if (originalLineItem.summary === "") { if (originalLineItem.description === "") {
this.#summaryControl.classList.remove("accounting-not-empty"); this.#descriptionControl.classList.remove("accounting-not-empty");
} else { } else {
this.#summaryControl.classList.add("accounting-not-empty"); this.#descriptionControl.classList.add("accounting-not-empty");
} }
this.summary = originalLineItem.summary === ""? null: originalLineItem.summary; this.description = originalLineItem.description === ""? null: originalLineItem.description;
this.#summaryText.innerText = originalLineItem.summary; this.#descriptionText.innerText = originalLineItem.description;
this.#accountControl.classList.add("accounting-not-empty"); this.#accountControl.classList.add("accounting-not-empty");
this.accountCode = originalLineItem.accountCode; this.accountCode = originalLineItem.accountCode;
this.accountText = originalLineItem.accountText; this.accountText = originalLineItem.accountText;
@ -300,7 +300,7 @@ class VoucherLineItemEditor {
this.originalLineItemDate = null; this.originalLineItemDate = null;
this.originalLineItemText = null; this.originalLineItemText = null;
this.#originalLineItemText.innerText = ""; this.#originalLineItemText.innerText = "";
this.#setEnableSummaryAccount(true); this.#setEnableDescriptionAccount(true);
this.#accountControl.classList.remove("accounting-not-empty"); this.#accountControl.classList.remove("accounting-not-empty");
this.accountCode = null; this.accountCode = null;
this.accountText = null; this.accountText = null;
@ -318,38 +318,38 @@ class VoucherLineItemEditor {
} }
/** /**
* Saves the summary from the summary editor. * Saves the description from the description editor.
* *
* @param summary {string} the summary * @param description {string} the description
*/ */
saveSummary(summary) { saveDescription(description) {
if (summary === "") { if (description === "") {
this.#summaryControl.classList.remove("accounting-not-empty"); this.#descriptionControl.classList.remove("accounting-not-empty");
} else { } else {
this.#summaryControl.classList.add("accounting-not-empty"); this.#descriptionControl.classList.add("accounting-not-empty");
} }
this.summary = summary === ""? null: summary; this.description = description === ""? null: description;
this.#summaryText.innerText = summary; this.#descriptionText.innerText = description;
this.#validateSummary(); this.#validateDescription();
bootstrap.Modal.getOrCreateInstance(this.#modal).show(); bootstrap.Modal.getOrCreateInstance(this.#modal).show();
} }
/** /**
* Saves the summary with the suggested account from the summary editor. * Saves the description with the suggested account from the description editor.
* *
* @param summary {string} the summary * @param description {string} the description
* @param accountCode {string} the account code * @param accountCode {string} the account code
* @param accountText {string} the account text * @param accountText {string} the account text
* @param isAccountNeedOffset {boolean} true if the line items in the account need offset, or false otherwise * @param isAccountNeedOffset {boolean} true if the line items in the account need offset, or false otherwise
*/ */
saveSummaryWithAccount(summary, accountCode, accountText, isAccountNeedOffset) { saveDescriptionWithAccount(description, accountCode, accountText, isAccountNeedOffset) {
this.isNeedOffset = isAccountNeedOffset; this.isNeedOffset = isAccountNeedOffset;
this.#accountControl.classList.add("accounting-not-empty"); this.#accountControl.classList.add("accounting-not-empty");
this.accountCode = accountCode; this.accountCode = accountCode;
this.accountText = accountText; this.accountText = accountText;
this.#accountText.innerText = accountText; this.#accountText.innerText = accountText;
this.#validateAccount(); this.#validateAccount();
this.saveSummary(summary) this.saveDescription(description)
} }
/** /**
@ -389,7 +389,7 @@ class VoucherLineItemEditor {
#validate() { #validate() {
let isValid = true; let isValid = true;
isValid = this.#validateOriginalLineItem() && isValid; isValid = this.#validateOriginalLineItem() && isValid;
isValid = this.#validateSummary() && isValid; isValid = this.#validateDescription() && isValid;
isValid = this.#validateAccount() && isValid; isValid = this.#validateAccount() && isValid;
isValid = this.#validateAmount() && isValid isValid = this.#validateAmount() && isValid
return isValid; return isValid;
@ -408,14 +408,14 @@ class VoucherLineItemEditor {
} }
/** /**
* Validates the summary. * Validates the description.
* *
* @return {boolean} true if valid, or false otherwise * @return {boolean} true if valid, or false otherwise
* @private * @private
*/ */
#validateSummary() { #validateDescription() {
this.#summaryText.classList.remove("is-invalid"); this.#descriptionText.classList.remove("is-invalid");
this.#summaryError.innerText = ""; this.#descriptionError.innerText = "";
return true; return true;
} }
@ -492,12 +492,12 @@ class VoucherLineItemEditor {
this.originalLineItemDate = null; this.originalLineItemDate = null;
this.originalLineItemText = null; this.originalLineItemText = null;
this.#originalLineItemText.innerText = ""; this.#originalLineItemText.innerText = "";
this.#setEnableSummaryAccount(true); this.#setEnableDescriptionAccount(true);
this.#summaryControl.classList.remove("accounting-not-empty"); this.#descriptionControl.classList.remove("accounting-not-empty");
this.#summaryControl.classList.remove("is-invalid"); this.#descriptionControl.classList.remove("is-invalid");
this.summary = null; this.description = null;
this.#summaryText.innerText = "" this.#descriptionText.innerText = ""
this.#summaryError.innerText = "" this.#descriptionError.innerText = ""
this.#accountControl.classList.remove("accounting-not-empty"); this.#accountControl.classList.remove("accounting-not-empty");
this.#accountControl.classList.remove("is-invalid"); this.#accountControl.classList.remove("is-invalid");
this.accountCode = null; this.accountCode = null;
@ -532,14 +532,14 @@ class VoucherLineItemEditor {
this.#originalLineItemContainer.classList.remove("d-none"); this.#originalLineItemContainer.classList.remove("d-none");
this.#originalLineItemControl.classList.add("accounting-not-empty"); this.#originalLineItemControl.classList.add("accounting-not-empty");
} }
this.#setEnableSummaryAccount(!lineItem.isMatched && this.originalLineItemId === null); this.#setEnableDescriptionAccount(!lineItem.isMatched && this.originalLineItemId === null);
this.summary = lineItem.getSummary(); this.description = lineItem.getDescription();
if (this.summary === null) { if (this.description === null) {
this.#summaryControl.classList.remove("accounting-not-empty"); this.#descriptionControl.classList.remove("accounting-not-empty");
} else { } else {
this.#summaryControl.classList.add("accounting-not-empty"); this.#descriptionControl.classList.add("accounting-not-empty");
} }
this.#summaryText.innerText = this.summary === null? "": this.summary; this.#descriptionText.innerText = this.description === null? "": this.description;
if (lineItem.getAccountCode() === null) { if (lineItem.getAccountCode() === null) {
this.#accountControl.classList.remove("accounting-not-empty"); this.#accountControl.classList.remove("accounting-not-empty");
} else { } else {
@ -568,25 +568,25 @@ class VoucherLineItemEditor {
} }
/** /**
* Sets the enable status of the summary and account. * Sets the enable status of the description and account.
* *
* @param isEnabled {boolean} true to enable, or false otherwise * @param isEnabled {boolean} true to enable, or false otherwise
*/ */
#setEnableSummaryAccount(isEnabled) { #setEnableDescriptionAccount(isEnabled) {
if (isEnabled) { if (isEnabled) {
this.#summaryControl.dataset.bsToggle = "modal"; this.#descriptionControl.dataset.bsToggle = "modal";
this.#summaryControl.dataset.bsTarget = "#accounting-summary-editor-" + this.#sideSubForm.side + "-modal"; this.#descriptionControl.dataset.bsTarget = "#accounting-description-editor-" + this.#sideSubForm.side + "-modal";
this.#summaryControl.classList.remove("accounting-disabled"); this.#descriptionControl.classList.remove("accounting-disabled");
this.#summaryControl.classList.add("accounting-clickable"); this.#descriptionControl.classList.add("accounting-clickable");
this.#accountControl.dataset.bsToggle = "modal"; this.#accountControl.dataset.bsToggle = "modal";
this.#accountControl.dataset.bsTarget = "#accounting-account-selector-" + this.#sideSubForm.side + "-modal"; this.#accountControl.dataset.bsTarget = "#accounting-account-selector-" + this.#sideSubForm.side + "-modal";
this.#accountControl.classList.remove("accounting-disabled"); this.#accountControl.classList.remove("accounting-disabled");
this.#accountControl.classList.add("accounting-clickable"); this.#accountControl.classList.add("accounting-clickable");
} else { } else {
this.#summaryControl.dataset.bsToggle = ""; this.#descriptionControl.dataset.bsToggle = "";
this.#summaryControl.dataset.bsTarget = ""; this.#descriptionControl.dataset.bsTarget = "";
this.#summaryControl.classList.add("accounting-disabled"); this.#descriptionControl.classList.add("accounting-disabled");
this.#summaryControl.classList.remove("accounting-clickable"); this.#descriptionControl.classList.remove("accounting-clickable");
this.#accountControl.dataset.bsToggle = ""; this.#accountControl.dataset.bsToggle = "";
this.#accountControl.dataset.bsTarget = ""; this.#accountControl.dataset.bsTarget = "";
this.#accountControl.classList.add("accounting-disabled"); this.#accountControl.classList.add("accounting-disabled");

View File

@ -21,7 +21,7 @@ First written: 2023/3/8
#} #}
<div>{{ line_item.date|accounting_format_date }}</div> <div>{{ line_item.date|accounting_format_date }}</div>
<div>{{ line_item.account.title|title }}</div> <div>{{ line_item.account.title|title }}</div>
<div>{{ line_item.summary|accounting_default }}</div> <div>{{ line_item.description|accounting_default }}</div>
<div class="accounting-amount">{{ line_item.income|accounting_format_amount|accounting_default }}</div> <div class="accounting-amount">{{ line_item.income|accounting_format_amount|accounting_default }}</div>
<div class="accounting-amount">{{ line_item.expense|accounting_format_amount|accounting_default }}</div> <div class="accounting-amount">{{ line_item.expense|accounting_format_amount|accounting_default }}</div>
<div class="accounting-amount {% if line_item.balance < 0 %} text-danger {% endif %}">{{ line_item.balance|accounting_report_format_amount }}</div> <div class="accounting-amount {% if line_item.balance < 0 %} text-danger {% endif %}">{{ line_item.balance|accounting_report_format_amount }}</div>

View File

@ -30,8 +30,8 @@ First written: 2023/3/5
{% endif %} {% endif %}
</div> </div>
{% endif %} {% endif %}
{% if line_item.summary %} {% if line_item.description %}
<div>{{ line_item.summary }}</div> <div>{{ line_item.description }}</div>
{% endif %} {% endif %}
</div> </div>

View File

@ -20,7 +20,7 @@ Author: imacat@mail.imacat.idv.tw (imacat)
First written: 2023/3/8 First written: 2023/3/8
#} #}
<div>{{ line_item.date|accounting_format_date }}</div> <div>{{ line_item.date|accounting_format_date }}</div>
<div>{{ line_item.summary|accounting_default }}</div> <div>{{ line_item.description|accounting_default }}</div>
<div class="accounting-amount">{{ line_item.debit|accounting_format_amount|accounting_default }}</div> <div class="accounting-amount">{{ line_item.debit|accounting_format_amount|accounting_default }}</div>
<div class="accounting-amount">{{ line_item.credit|accounting_format_amount|accounting_default }}</div> <div class="accounting-amount">{{ line_item.credit|accounting_format_amount|accounting_default }}</div>
{% if report.account.is_real %} {% if report.account.is_real %}

View File

@ -25,8 +25,8 @@ First written: 2023/3/5
{{ line_item.date|accounting_format_date }} {{ line_item.date|accounting_format_date }}
</div> </div>
{% endif %} {% endif %}
{% if line_item.summary %} {% if line_item.description %}
<div>{{ line_item.summary }}</div> <div>{{ line_item.description }}</div>
{% endif %} {% endif %}
</div> </div>

View File

@ -54,7 +54,7 @@ First written: 2023/3/5
<div class="accounting-report-table-row"> <div class="accounting-report-table-row">
<div>{{ A_("Date") }}</div> <div>{{ A_("Date") }}</div>
<div>{{ A_("Account") }}</div> <div>{{ A_("Account") }}</div>
<div>{{ A_("Summary") }}</div> <div>{{ A_("Description") }}</div>
<div class="accounting-amount">{{ A_("Income") }}</div> <div class="accounting-amount">{{ A_("Income") }}</div>
<div class="accounting-amount">{{ A_("Expense") }}</div> <div class="accounting-amount">{{ A_("Expense") }}</div>
<div class="accounting-amount">{{ A_("Balance") }}</div> <div class="accounting-amount">{{ A_("Balance") }}</div>

View File

@ -53,7 +53,7 @@ First written: 2023/3/4
<div>{{ A_("Date") }}</div> <div>{{ A_("Date") }}</div>
<div>{{ A_("Currency") }}</div> <div>{{ A_("Currency") }}</div>
<div>{{ A_("Account") }}</div> <div>{{ A_("Account") }}</div>
<div>{{ A_("Summary") }}</div> <div>{{ A_("Description") }}</div>
<div class="accounting-amount">{{ A_("Debit") }}</div> <div class="accounting-amount">{{ A_("Debit") }}</div>
<div class="accounting-amount">{{ A_("Credit") }}</div> <div class="accounting-amount">{{ A_("Credit") }}</div>
</div> </div>
@ -67,7 +67,7 @@ First written: 2023/3/4
<span class="d-none d-md-inline">{{ line_item.account.code }}</span> <span class="d-none d-md-inline">{{ line_item.account.code }}</span>
{{ line_item.account.title|title }} {{ line_item.account.title|title }}
</div> </div>
<div>{{ line_item.summary|accounting_default }}</div> <div>{{ line_item.description|accounting_default }}</div>
<div class="accounting-amount">{{ line_item.debit|accounting_format_amount|accounting_default }}</div> <div class="accounting-amount">{{ line_item.debit|accounting_format_amount|accounting_default }}</div>
<div class="accounting-amount">{{ line_item.credit|accounting_format_amount|accounting_default }}</div> <div class="accounting-amount">{{ line_item.credit|accounting_format_amount|accounting_default }}</div>
</a> </a>
@ -87,8 +87,8 @@ First written: 2023/3/4
<span class="badge rounded-pill bg-info">{{ line_item.currency.code }}</span> <span class="badge rounded-pill bg-info">{{ line_item.currency.code }}</span>
{% endif %} {% endif %}
</div> </div>
{% if line_item.summary is not none %} {% if line_item.description is not none %}
<div>{{ line_item.summary }}</div> <div>{{ line_item.description }}</div>
{% endif %} {% endif %}
</div> </div>

View File

@ -53,7 +53,7 @@ First written: 2023/3/5
<div class="accounting-report-table-header"> <div class="accounting-report-table-header">
<div class="accounting-report-table-row"> <div class="accounting-report-table-row">
<div>{{ A_("Date") }}</div> <div>{{ A_("Date") }}</div>
<div>{{ A_("Summary") }}</div> <div>{{ A_("Description") }}</div>
<div class="accounting-amount">{{ A_("Debit") }}</div> <div class="accounting-amount">{{ A_("Debit") }}</div>
<div class="accounting-amount">{{ A_("Credit") }}</div> <div class="accounting-amount">{{ A_("Credit") }}</div>
{% if report.account.is_real %} {% if report.account.is_real %}

View File

@ -50,7 +50,7 @@ First written: 2023/3/8
<div>{{ A_("Date") }}</div> <div>{{ A_("Date") }}</div>
<div>{{ A_("Currency") }}</div> <div>{{ A_("Currency") }}</div>
<div>{{ A_("Account") }}</div> <div>{{ A_("Account") }}</div>
<div>{{ A_("Summary") }}</div> <div>{{ A_("Description") }}</div>
<div class="accounting-amount">{{ A_("Debit") }}</div> <div class="accounting-amount">{{ A_("Debit") }}</div>
<div class="accounting-amount">{{ A_("Credit") }}</div> <div class="accounting-amount">{{ A_("Credit") }}</div>
</div> </div>
@ -64,7 +64,7 @@ First written: 2023/3/8
<span class="d-none d-md-inline">{{ line_item.account.code }}</span> <span class="d-none d-md-inline">{{ line_item.account.code }}</span>
{{ line_item.account.title|title }} {{ line_item.account.title|title }}
</div> </div>
<div>{{ line_item.summary|accounting_default }}</div> <div>{{ line_item.description|accounting_default }}</div>
<div class="accounting-amount">{{ line_item.debit|accounting_format_amount|accounting_default }}</div> <div class="accounting-amount">{{ line_item.debit|accounting_format_amount|accounting_default }}</div>
<div class="accounting-amount">{{ line_item.credit|accounting_format_amount|accounting_default }}</div> <div class="accounting-amount">{{ line_item.credit|accounting_format_amount|accounting_default }}</div>
</a> </a>
@ -84,8 +84,8 @@ First written: 2023/3/8
<span class="badge rounded-pill bg-info">{{ line_item.currency.code }}</span> <span class="badge rounded-pill bg-info">{{ line_item.currency.code }}</span>
{% endif %} {% endif %}
</div> </div>
{% if line_item.summary is not none %} {% if line_item.description is not none %}
<div>{{ line_item.summary }}</div> <div>{{ line_item.description }}</div>
{% endif %} {% endif %}
</div> </div>

View File

@ -49,25 +49,25 @@ First written: 2023/2/25
{% with currency_index = currency_index, {% with currency_index = currency_index,
side = "debit", side = "debit",
line_item_index = loop.index, line_item_index = loop.index,
line_item_id = line_item_form.eid.data, line_item_id = line_item_form.form.eid.data,
only_one_line_item_form = debit_forms|length == 1, only_one_line_item_form = debit_forms|length == 1,
account_code_data = line_item_form.account_code.data|accounting_default, account_code_data = line_item_form.form.account_code.data|accounting_default,
account_code_error = line_item_form.account_code.errors, account_code_error = line_item_form.form.account_code.errors,
account_text = line_item_form.account_text, account_text = line_item_form.form.account_text,
summary_data = line_item_form.summary.data|accounting_default, description_data = line_item_form.form.description.data|accounting_default,
summary_errors = line_item_form.summary.errors, description_errors = line_item_form.form.description.errors,
original_line_item_id_data = line_item_form.original_line_item_id.data|accounting_default, original_line_item_id_data = line_item_form.form.original_line_item_id.data|accounting_default,
original_line_item_date = line_item_form.original_line_item_date|accounting_default, original_line_item_date = line_item_form.form.original_line_item_date|accounting_default,
original_line_item_text = line_item_form.original_line_item_text|accounting_default, original_line_item_text = line_item_form.form.original_line_item_text|accounting_default,
is_need_offset = line_item_form.is_need_offset, is_need_offset = line_item_form.form.is_need_offset,
offset_items = line_item_form.offsets, offset_items = line_item_form.form.offsets,
offset_total = line_item_form.offset_total|accounting_default("0"), offset_total = line_item_form.form.offset_total|accounting_default("0"),
net_balance_data = line_item_form.net_balance, net_balance_data = line_item_form.form.net_balance,
net_balance_text = line_item_form.net_balance|accounting_format_amount, net_balance_text = line_item_form.form.net_balance|accounting_format_amount,
amount_data = line_item_form.amount.data|accounting_voucher_format_amount_input, amount_data = line_item_form.form.amount.data|accounting_voucher_format_amount_input,
amount_errors = line_item_form.amount.errors, amount_errors = line_item_form.form.amount.errors,
amount_text = line_item_form.amount.data|accounting_format_amount, amount_text = line_item_form.form.amount.data|accounting_format_amount,
line_item_errors = line_item_form.all_errors %} line_item_errors = line_item_form.form.all_errors %}
{% include "accounting/voucher/include/form-line-item.html" %} {% include "accounting/voucher/include/form-line-item.html" %}
{% endwith %} {% endwith %}
{% endfor %} {% endfor %}

View File

@ -47,8 +47,8 @@ First written: 2023/2/25
{% endblock %} {% endblock %}
{% block form_modals %} {% block form_modals %}
{% with summary_editor = form.summary_editor.debit %} {% with description_editor = form.description_editor.debit %}
{% include "accounting/voucher/include/summary-editor-modal.html" %} {% include "accounting/voucher/include/description-editor-modal.html" %}
{% endwith %} {% endwith %}
{% with side = "debit", {% with side = "debit",
account_options = form.debit_account_options %} account_options = form.debit_account_options %}

View File

@ -0,0 +1,193 @@
{#
The Mia! Accounting Flask Project
description-editor-modal.html: The modal of the description editor
Copyright (c) 2023 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.
Author: imacat@mail.imacat.idv.tw (imacat)
First written: 2023/2/28
#}
<form id="accounting-description-editor-{{ description_editor.side }}" class="accounting-description-editor" data-side="{{ description_editor.side }}">
<div id="accounting-description-editor-{{ description_editor.side }}-modal" class="modal fade" tabindex="-1" aria-labelledby="accounting-description-editor-{{ description_editor.side }}-modal-label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="accounting-description-editor-{{ description_editor.side }}-modal-label">
<label for="accounting-description-editor-{{ description_editor.side }}-description">{{ A_("Description") }}</label>
</h1>
<button class="btn-close" type="button" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal" aria-label="{{ A_("Close") }}"></button>
</div>
<div class="modal-body">
<div class="d-flex justify-content-between mb-3">
<input id="accounting-description-editor-{{ description_editor.side }}-description" class="form-control" type="text" aria-labelledby="accounting-description-editor-{{ description_editor.side }}-modal-label">
<button id="accounting-description-editor-{{ description_editor.side }}-offset" class="btn btn-primary text-nowrap ms-2" type="button" data-bs-toggle="modal" data-bs-target="#accounting-original-line-item-selector-modal">
{{ A_("Offset...") }}
</button>
</div>
{# Tab navigation #}
<ul class="nav nav-tabs mb-2">
<li class="nav-item">
<span id="accounting-description-editor-{{ description_editor.side }}-general-tab" class="nav-link active accounting-clickable" aria-current="page">
{{ A_("General") }}
</span>
</li>
<li class="nav-item">
<span id="accounting-description-editor-{{ description_editor.side }}-travel-tab" class="nav-link accounting-clickable" aria-current="false">
{{ A_("Travel") }}
</span>
</li>
<li class="nav-item">
<span id="accounting-description-editor-{{ description_editor.side }}-bus-tab" class="nav-link accounting-clickable" aria-current="false">
{{ A_("Bus") }}
</span>
</li>
<li class="nav-item">
<span id="accounting-description-editor-{{ description_editor.side }}-regular-tab" class="nav-link accounting-clickable" aria-current="false">
{{ A_("Regular") }}
</span>
</li>
<li class="nav-item">
<span id="accounting-description-editor-{{ description_editor.side }}-annotation-tab" class="nav-link accounting-clickable" aria-current="false">
{{ A_("Annotation") }}
</span>
</li>
</ul>
{# A general description with a tag #}
<div id="accounting-description-editor-{{ description_editor.side }}-general-page" aria-current="page" aria-labelledby="accounting-description-editor-{{ description_editor.side }}-general-tab">
<div class="form-floating mb-2">
<input id="accounting-description-editor-{{ description_editor.side }}-general-tag" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-description-editor-{{ description_editor.side }}-general-tag">{{ A_("Tag") }}</label>
<div id="accounting-description-editor-{{ description_editor.side }}-general-tag-error" class="invalid-feedback"></div>
</div>
<div>
{% for tag in description_editor.general.tags %}
<button class="btn btn-outline-primary accounting-description-editor-{{ description_editor.side }}-general-btn-tag" type="button" tabindex="-1" data-value="{{ tag.name }}" data-accounts="{{ tag.account_codes|tojson|forceescape }}">
{{ tag }}
</button>
{% endfor %}
</div>
</div>
{# A general trip with the origin and distination #}
<div id="accounting-description-editor-{{ description_editor.side }}-travel-page" class="d-none" aria-current="false" aria-labelledby="accounting-description-editor-{{ description_editor.side }}-travel-tab">
<div class="form-floating mb-2">
<input id="accounting-description-editor-{{ description_editor.side }}-travel-tag" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-description-editor-{{ description_editor.side }}-travel-tag">{{ A_("Tag") }}</label>
<div id="accounting-description-editor-{{ description_editor.side }}-travel-tag-error" class="invalid-feedback"></div>
</div>
<div>
{% for tag in description_editor.travel.tags %}
<button class="btn btn-outline-primary accounting-description-editor-{{ description_editor.side }}-travel-btn-tag" type="button" tabindex="-1" data-value="{{ tag.name }}" data-accounts="{{ tag.account_codes|tojson|forceescape }}">
{{ tag }}
</button>
{% endfor %}
</div>
<div class="d-flex justify-content-between mt-2">
<div class="form-floating">
<input id="accounting-description-editor-{{ description_editor.side }}-travel-from" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-description-editor-{{ description_editor.side }}-travel-from">{{ A_("From") }}</label>
<div id="accounting-description-editor-{{ description_editor.side }}-travel-from-error" class="invalid-feedback"></div>
</div>
<div class="btn-group-vertical ms-1 me-1">
<button class="btn btn-primary accounting-description-editor-{{ description_editor.side }}-travel-direction accounting-default" type="button" tabindex="-1" data-arrow="&rarr;">&rarr;</button>
<button class="btn btn-outline-primary accounting-description-editor-{{ description_editor.side }}-travel-direction" type="button" tabindex="-1" data-arrow="&harr;">&harr;</button>
</div>
<div class="form-floating">
<input id="accounting-description-editor-{{ description_editor.side }}-travel-to" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-description-editor-{{ description_editor.side }}-travel-to">{{ A_("To") }}</label>
<div id="accounting-description-editor-{{ description_editor.side }}-travel-to-error" class="invalid-feedback"></div>
</div>
</div>
</div>
{# A bus trip with the route name or route number, the origin and distination #}
<div id="accounting-description-editor-{{ description_editor.side }}-bus-page" class="d-none" aria-current="false" aria-labelledby="accounting-description-editor-{{ description_editor.side }}-bus-tab">
<div class="d-flex justify-content-between mb-2">
<div class="form-floating me-2">
<input id="accounting-description-editor-{{ description_editor.side }}-bus-tag" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-description-editor-{{ description_editor.side }}-bus-tag">{{ A_("Tag") }}</label>
<div id="accounting-description-editor-{{ description_editor.side }}-bus-tag-error" class="invalid-feedback"></div>
</div>
<div class="form-floating">
<input id="accounting-description-editor-{{ description_editor.side }}-bus-route" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-description-editor-{{ description_editor.side }}-bus-route">{{ A_("Route") }}</label>
<div id="accounting-description-editor-{{ description_editor.side }}-bus-route-error" class="invalid-feedback"></div>
</div>
</div>
<div>
{% for tag in description_editor.bus.tags %}
<button class="btn btn-outline-primary accounting-description-editor-{{ description_editor.side }}-bus-btn-tag" type="button" tabindex="-1" data-value="{{ tag.name }}" data-accounts="{{ tag.account_codes|tojson|forceescape }}">
{{ tag }}
</button>
{% endfor %}
</div>
<div class="d-flex justify-content-between mt-2">
<div class="form-floating me-2">
<input id="accounting-description-editor-{{ description_editor.side }}-bus-from" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-description-editor-{{ description_editor.side }}-bus-from">{{ A_("From") }}</label>
<div id="accounting-description-editor-{{ description_editor.side }}-bus-from-error" class="invalid-feedback"></div>
</div>
<div class="form-floating">
<input id="accounting-description-editor-{{ description_editor.side }}-bus-to" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-description-editor-{{ description_editor.side }}-bus-to">{{ A_("To") }}</label>
<div id="accounting-description-editor-{{ description_editor.side }}-bus-to-error" class="invalid-feedback"></div>
</div>
</div>
</div>
{# A regular income or payment #}
<div id="accounting-description-editor-{{ description_editor.side }}-regular-page" class="d-none" aria-current="false" aria-labelledby="accounting-description-editor-{{ description_editor.side }}-regular-tab">
{# TODO: To be done #}
</div>
{# The annotation #}
<div id="accounting-description-editor-{{ description_editor.side }}-annotation-page" class="d-none" aria-current="false" aria-labelledby="accounting-description-editor-{{ description_editor.side }}-annotation-tab">
<div class="form-floating">
<input id="accounting-description-editor-{{ description_editor.side }}-annotation-number" class="form-control" type="number" min="1" value="" placeholder=" ">
<label class="form-label" for="accounting-description-editor-{{ description_editor.side }}-annotation-number">{{ A_("The number of items") }}</label>
<div id="accounting-description-editor-{{ description_editor.side }}-annotation-number-error" class="invalid-feedback"></div>
</div>
<div class="form-floating mt-2">
<input id="accounting-description-editor-{{ description_editor.side }}-annotation-note" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-description-editor-{{ description_editor.side }}-annotation-note">{{ A_("Note") }}</label>
<div id="accounting-description-editor-{{ description_editor.side }}-annotation-note-error" class="invalid-feedback"></div>
</div>
</div>
{# The suggested accounts #}
<div class="mt-3">
{% for account in description_editor.accounts %}
<button class="btn btn-outline-primary d-none accounting-description-editor-{{ description_editor.side }}-account {% if account.is_need_offset %} accounting-account-is-need-offset {% endif %}" type="button" data-code="{{ account.code }}" data-text="{{ account }}">
{{ account }}
</button>
{% endfor %}
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal">{{ A_("Cancel") }}</button>
<button id="accounting-description-editor-{{ description_editor.side }}-btn-save" type="submit" class="btn btn-primary">{{ A_("Save") }}</button>
</div>
</div>
</div>
</div>
</form>

View File

@ -25,8 +25,8 @@ First written: 2023/3/14
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<div> <div>
<div class="small">{{ line_item.account }}</div> <div class="small">{{ line_item.account }}</div>
{% if line_item.summary is not none %} {% if line_item.description is not none %}
<div>{{ line_item.summary }}</div> <div>{{ line_item.description }}</div>
{% endif %} {% endif %}
{% if line_item.original_line_item %} {% if line_item.original_line_item %}
<div class="fst-italic small accounting-original-line-item"> <div class="fst-italic small accounting-original-line-item">

View File

@ -27,13 +27,13 @@ First written: 2023/2/25
<input id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-no" type="hidden" name="currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-no" value="{{ line_item_index }}"> <input id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-no" type="hidden" name="currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-no" value="{{ line_item_index }}">
<input id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-original-line-item-id" class="accounting-original-line-item-id" type="hidden" name="currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-original_line_item_id" value="{{ original_line_item_id_data }}" data-date="{{ original_line_item_date }}" data-text="{{ original_line_item_text }}"> <input id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-original-line-item-id" class="accounting-original-line-item-id" type="hidden" name="currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-original_line_item_id" value="{{ original_line_item_id_data }}" data-date="{{ original_line_item_date }}" data-text="{{ original_line_item_text }}">
<input id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-account-code" type="hidden" name="currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-account_code" value="{{ account_code_data }}" data-text="{{ account_text }}"> <input id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-account-code" type="hidden" name="currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-account_code" value="{{ account_code_data }}" data-text="{{ account_text }}">
<input id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-summary" type="hidden" name="currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-summary" value="{{ summary_data }}"> <input id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-description" type="hidden" name="currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-description" value="{{ description_data }}">
<input id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-amount" type="hidden" name="currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-amount" value="{{ amount_data }}" data-min="{{ offset_total }}"> <input id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-amount" type="hidden" name="currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-amount" value="{{ amount_data }}" data-min="{{ offset_total }}">
<div class="accounting-line-item-content"> <div class="accounting-line-item-content">
<div id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-control" class="form-control clickable d-flex justify-content-between {% if line_item_errors %} is-invalid {% endif %}" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> <div id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-control" class="form-control clickable d-flex justify-content-between {% if line_item_errors %} is-invalid {% endif %}" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal">
<div> <div>
<div id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-account-text" class="small">{{ account_text }}</div> <div id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-account-text" class="small">{{ account_text }}</div>
<div id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-summary-text">{{ summary_data }}</div> <div id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-description-text">{{ description_data }}</div>
<div id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-original-line-item-text" class="fst-italic small accounting-original-line-item {% if not original_line_item_text %} d-none {% endif %}"> <div id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-original-line-item-text" class="fst-italic small accounting-original-line-item {% if not original_line_item_text %} d-none {% endif %}">
{% if original_line_item_text %}{{ A_("Offset %(item)s", item=original_line_item_text) }}{% endif %} {% if original_line_item_text %}{{ A_("Offset %(item)s", item=original_line_item_text) }}{% endif %}
</div> </div>

View File

@ -27,7 +27,7 @@ First written: 2023/2/26
<script src="{{ url_for("accounting.static", filename="js/voucher-line-item-editor.js") }}"></script> <script src="{{ url_for("accounting.static", filename="js/voucher-line-item-editor.js") }}"></script>
<script src="{{ url_for("accounting.static", filename="js/account-selector.js") }}"></script> <script src="{{ url_for("accounting.static", filename="js/account-selector.js") }}"></script>
<script src="{{ url_for("accounting.static", filename="js/original-line-item-selector.js") }}"></script> <script src="{{ url_for("accounting.static", filename="js/original-line-item-selector.js") }}"></script>
<script src="{{ url_for("accounting.static", filename="js/summary-editor.js") }}"></script> <script src="{{ url_for("accounting.static", filename="js/description-editor.js") }}"></script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}

View File

@ -37,8 +37,8 @@ First written: 2023/2/25
<ul id="accounting-original-line-item-selector-option-list" class="list-group accounting-selector-list"> <ul id="accounting-original-line-item-selector-option-list" class="list-group accounting-selector-list">
{% for line_item in form.original_line_item_options %} {% for line_item in form.original_line_item_options %}
<li id="accounting-original-line-item-selector-option-{{ line_item.id }}" class="list-group-item d-flex justify-content-between accounting-clickable accounting-original-line-item-selector-option" data-id="{{ line_item.id }}" data-date="{{ line_item.voucher.date }}" data-side="{{ "debit" if line_item.is_debit else "credit" }}" data-currency-code="{{ line_item.currency.code }}" data-account-code="{{ line_item.account_code }}" data-account-text="{{ line_item.account }}" data-summary="{{ line_item.summary|accounting_default }}" data-net-balance="{{ line_item.net_balance|accounting_voucher_format_amount_input }}" data-text="{{ line_item }}" data-query-values="{{ line_item.query_values|tojson|forceescape }}" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> <li id="accounting-original-line-item-selector-option-{{ line_item.id }}" class="list-group-item d-flex justify-content-between accounting-clickable accounting-original-line-item-selector-option" data-id="{{ line_item.id }}" data-date="{{ line_item.voucher.date }}" data-side="{{ "debit" if line_item.is_debit else "credit" }}" data-currency-code="{{ line_item.currency.code }}" data-account-code="{{ line_item.account_code }}" data-account-text="{{ line_item.account }}" data-description="{{ line_item.description|accounting_default }}" data-net-balance="{{ line_item.net_balance|accounting_voucher_format_amount_input }}" data-text="{{ line_item }}" data-query-values="{{ line_item.query_values|tojson|forceescape }}" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal">
<div>{{ line_item.voucher.date|accounting_format_date }} {{ line_item.summary|accounting_default }}</div> <div>{{ line_item.voucher.date|accounting_format_date }} {{ line_item.description|accounting_default }}</div>
<div> <div>
<span class="badge bg-primary rounded-pill"> <span class="badge bg-primary rounded-pill">
<span id="accounting-original-line-item-selector-option-{{ line_item.id }}-net-balance">{{ line_item.net_balance|accounting_format_amount }}</span> <span id="accounting-original-line-item-selector-option-{{ line_item.id }}-net-balance">{{ line_item.net_balance|accounting_format_amount }}</span>

View File

@ -1,193 +0,0 @@
{#
The Mia! Accounting Flask Project
summary-editor-modal.html: The modal of the summary editor
Copyright (c) 2023 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.
Author: imacat@mail.imacat.idv.tw (imacat)
First written: 2023/2/28
#}
<form id="accounting-summary-editor-{{ summary_editor.side }}" class="accounting-summary-editor" data-side="{{ summary_editor.side }}">
<div id="accounting-summary-editor-{{ summary_editor.side }}-modal" class="modal fade" tabindex="-1" aria-labelledby="accounting-summary-editor-{{ summary_editor.side }}-modal-label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="accounting-summary-editor-{{ summary_editor.side }}-modal-label">
<label for="accounting-summary-editor-{{ summary_editor.side }}-summary">{{ A_("Summary") }}</label>
</h1>
<button class="btn-close" type="button" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal" aria-label="{{ A_("Close") }}"></button>
</div>
<div class="modal-body">
<div class="d-flex justify-content-between mb-3">
<input id="accounting-summary-editor-{{ summary_editor.side }}-summary" class="form-control" type="text" aria-labelledby="accounting-summary-editor-{{ summary_editor.side }}-modal-label">
<button id="accounting-summary-editor-{{ summary_editor.side }}-offset" class="btn btn-primary text-nowrap ms-2" type="button" data-bs-toggle="modal" data-bs-target="#accounting-original-line-item-selector-modal">
{{ A_("Offset...") }}
</button>
</div>
{# Tab navigation #}
<ul class="nav nav-tabs mb-2">
<li class="nav-item">
<span id="accounting-summary-editor-{{ summary_editor.side }}-general-tab" class="nav-link active accounting-clickable" aria-current="page">
{{ A_("General") }}
</span>
</li>
<li class="nav-item">
<span id="accounting-summary-editor-{{ summary_editor.side }}-travel-tab" class="nav-link accounting-clickable" aria-current="false">
{{ A_("Travel") }}
</span>
</li>
<li class="nav-item">
<span id="accounting-summary-editor-{{ summary_editor.side }}-bus-tab" class="nav-link accounting-clickable" aria-current="false">
{{ A_("Bus") }}
</span>
</li>
<li class="nav-item">
<span id="accounting-summary-editor-{{ summary_editor.side }}-regular-tab" class="nav-link accounting-clickable" aria-current="false">
{{ A_("Regular") }}
</span>
</li>
<li class="nav-item">
<span id="accounting-summary-editor-{{ summary_editor.side }}-annotation-tab" class="nav-link accounting-clickable" aria-current="false">
{{ A_("Annotation") }}
</span>
</li>
</ul>
{# A general summary with a tag #}
<div id="accounting-summary-editor-{{ summary_editor.side }}-general-page" aria-current="page" aria-labelledby="accounting-summary-editor-{{ summary_editor.side }}-general-tab">
<div class="form-floating mb-2">
<input id="accounting-summary-editor-{{ summary_editor.side }}-general-tag" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-summary-editor-{{ summary_editor.side }}-general-tag">{{ A_("Tag") }}</label>
<div id="accounting-summary-editor-{{ summary_editor.side }}-general-tag-error" class="invalid-feedback"></div>
</div>
<div>
{% for tag in summary_editor.general.tags %}
<button class="btn btn-outline-primary accounting-summary-editor-{{ summary_editor.side }}-general-btn-tag" type="button" tabindex="-1" data-value="{{ tag.name }}" data-accounts="{{ tag.account_codes|tojson|forceescape }}">
{{ tag }}
</button>
{% endfor %}
</div>
</div>
{# A general trip with the origin and distination #}
<div id="accounting-summary-editor-{{ summary_editor.side }}-travel-page" class="d-none" aria-current="false" aria-labelledby="accounting-summary-editor-{{ summary_editor.side }}-travel-tab">
<div class="form-floating mb-2">
<input id="accounting-summary-editor-{{ summary_editor.side }}-travel-tag" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-summary-editor-{{ summary_editor.side }}-travel-tag">{{ A_("Tag") }}</label>
<div id="accounting-summary-editor-{{ summary_editor.side }}-travel-tag-error" class="invalid-feedback"></div>
</div>
<div>
{% for tag in summary_editor.travel.tags %}
<button class="btn btn-outline-primary accounting-summary-editor-{{ summary_editor.side }}-travel-btn-tag" type="button" tabindex="-1" data-value="{{ tag.name }}" data-accounts="{{ tag.account_codes|tojson|forceescape }}">
{{ tag }}
</button>
{% endfor %}
</div>
<div class="d-flex justify-content-between mt-2">
<div class="form-floating">
<input id="accounting-summary-editor-{{ summary_editor.side }}-travel-from" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-summary-editor-{{ summary_editor.side }}-travel-from">{{ A_("From") }}</label>
<div id="accounting-summary-editor-{{ summary_editor.side }}-travel-from-error" class="invalid-feedback"></div>
</div>
<div class="btn-group-vertical ms-1 me-1">
<button class="btn btn-primary accounting-summary-editor-{{ summary_editor.side }}-travel-direction accounting-default" type="button" tabindex="-1" data-arrow="&rarr;">&rarr;</button>
<button class="btn btn-outline-primary accounting-summary-editor-{{ summary_editor.side }}-travel-direction" type="button" tabindex="-1" data-arrow="&harr;">&harr;</button>
</div>
<div class="form-floating">
<input id="accounting-summary-editor-{{ summary_editor.side }}-travel-to" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-summary-editor-{{ summary_editor.side }}-travel-to">{{ A_("To") }}</label>
<div id="accounting-summary-editor-{{ summary_editor.side }}-travel-to-error" class="invalid-feedback"></div>
</div>
</div>
</div>
{# A bus trip with the route name or route number, the origin and distination #}
<div id="accounting-summary-editor-{{ summary_editor.side }}-bus-page" class="d-none" aria-current="false" aria-labelledby="accounting-summary-editor-{{ summary_editor.side }}-bus-tab">
<div class="d-flex justify-content-between mb-2">
<div class="form-floating me-2">
<input id="accounting-summary-editor-{{ summary_editor.side }}-bus-tag" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-summary-editor-{{ summary_editor.side }}-bus-tag">{{ A_("Tag") }}</label>
<div id="accounting-summary-editor-{{ summary_editor.side }}-bus-tag-error" class="invalid-feedback"></div>
</div>
<div class="form-floating">
<input id="accounting-summary-editor-{{ summary_editor.side }}-bus-route" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-summary-editor-{{ summary_editor.side }}-bus-route">{{ A_("Route") }}</label>
<div id="accounting-summary-editor-{{ summary_editor.side }}-bus-route-error" class="invalid-feedback"></div>
</div>
</div>
<div>
{% for tag in summary_editor.bus.tags %}
<button class="btn btn-outline-primary accounting-summary-editor-{{ summary_editor.side }}-bus-btn-tag" type="button" tabindex="-1" data-value="{{ tag.name }}" data-accounts="{{ tag.account_codes|tojson|forceescape }}">
{{ tag }}
</button>
{% endfor %}
</div>
<div class="d-flex justify-content-between mt-2">
<div class="form-floating me-2">
<input id="accounting-summary-editor-{{ summary_editor.side }}-bus-from" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-summary-editor-{{ summary_editor.side }}-bus-from">{{ A_("From") }}</label>
<div id="accounting-summary-editor-{{ summary_editor.side }}-bus-from-error" class="invalid-feedback"></div>
</div>
<div class="form-floating">
<input id="accounting-summary-editor-{{ summary_editor.side }}-bus-to" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-summary-editor-{{ summary_editor.side }}-bus-to">{{ A_("To") }}</label>
<div id="accounting-summary-editor-{{ summary_editor.side }}-bus-to-error" class="invalid-feedback"></div>
</div>
</div>
</div>
{# A regular income or payment #}
<div id="accounting-summary-editor-{{ summary_editor.side }}-regular-page" class="d-none" aria-current="false" aria-labelledby="accounting-summary-editor-{{ summary_editor.side }}-regular-tab">
{# TODO: To be done #}
</div>
{# The annotation #}
<div id="accounting-summary-editor-{{ summary_editor.side }}-annotation-page" class="d-none" aria-current="false" aria-labelledby="accounting-summary-editor-{{ summary_editor.side }}-annotation-tab">
<div class="form-floating">
<input id="accounting-summary-editor-{{ summary_editor.side }}-annotation-number" class="form-control" type="number" min="1" value="" placeholder=" ">
<label class="form-label" for="accounting-summary-editor-{{ summary_editor.side }}-annotation-number">{{ A_("The number of items") }}</label>
<div id="accounting-summary-editor-{{ summary_editor.side }}-annotation-number-error" class="invalid-feedback"></div>
</div>
<div class="form-floating mt-2">
<input id="accounting-summary-editor-{{ summary_editor.side }}-annotation-note" class="form-control" type="text" value="" placeholder=" ">
<label class="form-label" for="accounting-summary-editor-{{ summary_editor.side }}-annotation-note">{{ A_("Note") }}</label>
<div id="accounting-summary-editor-{{ summary_editor.side }}-annotation-note-error" class="invalid-feedback"></div>
</div>
</div>
{# The suggested accounts #}
<div class="mt-3">
{% for account in summary_editor.accounts %}
<button class="btn btn-outline-primary d-none accounting-summary-editor-{{ summary_editor.side }}-account {% if account.is_need_offset %} accounting-account-is-need-offset {% endif %}" type="button" data-code="{{ account.code }}" data-text="{{ account }}">
{{ account }}
</button>
{% endfor %}
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal">{{ A_("Cancel") }}</button>
<button id="accounting-summary-editor-{{ summary_editor.side }}-btn-save" type="submit" class="btn btn-primary">{{ A_("Save") }}</button>
</div>
</div>
</div>
</div>
</form>

View File

@ -45,11 +45,11 @@ First written: 2023/2/25
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div id="accounting-line-item-editor-summary-control" class="form-control accounting-clickable accounting-material-text-field" data-bs-toggle="modal" data-bs-target=""> <div id="accounting-line-item-editor-description-control" class="form-control accounting-clickable accounting-material-text-field" data-bs-toggle="modal" data-bs-target="">
<label class="form-label" for="accounting-line-item-editor-summary">{{ A_("Summary") }}</label> <label class="form-label" for="accounting-line-item-editor-description">{{ A_("Description") }}</label>
<div id="accounting-line-item-editor-summary"></div> <div id="accounting-line-item-editor-description"></div>
</div> </div>
<div id="accounting-line-item-editor-summary-error" class="invalid-feedback"></div> <div id="accounting-line-item-editor-description-error" class="invalid-feedback"></div>
</div> </div>
<div class="mb-3"> <div class="mb-3">

View File

@ -49,25 +49,25 @@ First written: 2023/2/25
{% with currency_index = currency_index, {% with currency_index = currency_index,
side = "credit", side = "credit",
line_item_index = loop.index, line_item_index = loop.index,
only_one_line_item_form = debit_forms|length == 1, only_one_line_item_form = credit_forms|length == 1,
line_item_id = line_item_form.eid.data, line_item_id = line_item_form.form.eid.data,
account_code_data = line_item_form.account_code.data|accounting_default, account_code_data = line_item_form.form.account_code.data|accounting_default,
account_code_error = line_item_form.account_code.errors, account_code_error = line_item_form.form.account_code.errors,
account_text = line_item_form.account_text, account_text = line_item_form.form.account_text,
summary_data = line_item_form.summary.data|accounting_default, description_data = line_item_form.form.description.data|accounting_default,
summary_errors = line_item_form.summary.errors, description_errors = line_item_form.form.description.errors,
original_line_item_id_data = line_item_form.original_line_item_id.data|accounting_default, original_line_item_id_data = line_item_form.form.original_line_item_id.data|accounting_default,
original_line_item_date = line_item_form.original_line_item_date|accounting_default, original_line_item_date = line_item_form.form.original_line_item_date|accounting_default,
original_line_item_text = line_item_form.original_line_item_text|accounting_default, original_line_item_text = line_item_form.form.original_line_item_text|accounting_default,
is_need_offset = line_item_form.is_need_offset, is_need_offset = line_item_form.form.is_need_offset,
offset_items = line_item_form.offsets, offset_items = line_item_form.form.offsets,
offset_total = line_item_form.offset_total|accounting_default("0"), offset_total = line_item_form.form.offset_total|accounting_default("0"),
net_balance_data = line_item_form.net_balance, net_balance_data = line_item_form.form.net_balance,
net_balance_text = line_item_form.net_balance|accounting_format_amount, net_balance_text = line_item_form.form.net_balance|accounting_format_amount,
amount_data = line_item_form.amount.data|accounting_voucher_format_amount_input, amount_data = line_item_form.form.amount.data|accounting_voucher_format_amount_input,
amount_errors = line_item_form.amount.errors, amount_errors = line_item_form.form.amount.errors,
amount_text = line_item_form.amount.data|accounting_format_amount, amount_text = line_item_form.form.amount.data|accounting_format_amount,
line_item_errors = line_item_form.all_errors %} line_item_errors = line_item_form.form.all_errors %}
{% include "accounting/voucher/include/form-line-item.html" %} {% include "accounting/voucher/include/form-line-item.html" %}
{% endwith %} {% endwith %}
{% endfor %} {% endfor %}

View File

@ -47,8 +47,8 @@ First written: 2023/2/25
{% endblock %} {% endblock %}
{% block form_modals %} {% block form_modals %}
{% with summary_editor = form.summary_editor.credit %} {% with description_editor = form.description_editor.credit %}
{% include "accounting/voucher/include/summary-editor-modal.html" %} {% include "accounting/voucher/include/description-editor-modal.html" %}
{% endwith %} {% endwith %}
{% with side = "credit", {% with side = "credit",
account_options = form.credit_account_options %} account_options = form.credit_account_options %}

View File

@ -52,24 +52,24 @@ First written: 2023/2/25
side = "debit", side = "debit",
line_item_index = loop.index, line_item_index = loop.index,
only_one_line_item_form = debit_forms|length == 1, only_one_line_item_form = debit_forms|length == 1,
line_item_id = line_item_form.eid.data, line_item_id = line_item_form.form.eid.data,
account_code_data = line_item_form.account_code.data|accounting_default, account_code_data = line_item_form.form.account_code.data|accounting_default,
account_code_error = line_item_form.account_code.errors, account_code_error = line_item_form.form.account_code.errors,
account_text = line_item_form.account_text, account_text = line_item_form.form.account_text,
summary_data = line_item_form.summary.data|accounting_default, description_data = line_item_form.form.description.data|accounting_default,
summary_errors = line_item_form.summary.errors, description_errors = line_item_form.form.description.errors,
original_line_item_id_data = line_item_form.original_line_item_id.data|accounting_default, original_line_item_id_data = line_item_form.form.original_line_item_id.data|accounting_default,
original_line_item_date = line_item_form.original_line_item_date|accounting_default, original_line_item_date = line_item_form.form.original_line_item_date|accounting_default,
original_line_item_text = line_item_form.original_line_item_text|accounting_default, original_line_item_text = line_item_form.form.original_line_item_text|accounting_default,
is_need_offset = line_item_form.is_need_offset, is_need_offset = line_item_form.form.is_need_offset,
offset_items = line_item_form.offsets, offset_items = line_item_form.form.offsets,
offset_total = line_item_form.offset_total|accounting_default, offset_total = line_item_form.form.offset_total|accounting_default,
net_balance_data = line_item_form.net_balance, net_balance_data = line_item_form.form.net_balance,
net_balance_text = line_item_form.net_balance|accounting_format_amount, net_balance_text = line_item_form.form.net_balance|accounting_format_amount,
amount_data = line_item_form.amount.data|accounting_voucher_format_amount_input, amount_data = line_item_form.form.amount.data|accounting_voucher_format_amount_input,
amount_errors = line_item_form.amount.errors, amount_errors = line_item_form.form.amount.errors,
amount_text = line_item_form.amount.data|accounting_format_amount, amount_text = line_item_form.form.amount.data|accounting_format_amount,
line_item_errors = line_item_form.all_errors %} line_item_errors = line_item_form.form.all_errors %}
{% include "accounting/voucher/include/form-line-item.html" %} {% include "accounting/voucher/include/form-line-item.html" %}
{% endwith %} {% endwith %}
{% endfor %} {% endfor %}
@ -100,24 +100,24 @@ First written: 2023/2/25
side = "credit", side = "credit",
line_item_index = loop.index, line_item_index = loop.index,
only_one_line_item_form = debit_forms|length == 1, only_one_line_item_form = debit_forms|length == 1,
line_item_id = line_item_form.eid.data, line_item_id = line_item_form.form.eid.data,
account_code_data = line_item_form.account_code.data|accounting_default, account_code_data = line_item_form.form.account_code.data|accounting_default,
account_code_error = line_item_form.account_code.errors, account_code_error = line_item_form.form.account_code.errors,
account_text = line_item_form.account_text, account_text = line_item_form.form.account_text,
summary_data = line_item_form.summary.data|accounting_default, description_data = line_item_form.form.description.data|accounting_default,
summary_errors = line_item_form.summary.errors, description_errors = line_item_form.form.description.errors,
original_line_item_id_data = line_item_form.original_line_item_id.data|accounting_default, original_line_item_id_data = line_item_form.form.original_line_item_id.data|accounting_default,
original_line_item_date = line_item_form.original_line_item_date|accounting_default, original_line_item_date = line_item_form.form.original_line_item_date|accounting_default,
original_line_item_text = line_item_form.original_line_item_text|accounting_default, original_line_item_text = line_item_form.form.original_line_item_text|accounting_default,
is_need_offset = line_item_form.is_need_offset, is_need_offset = line_item_form.form.is_need_offset,
offset_items = line_item_form.offsets, offset_items = line_item_form.form.offsets,
offset_total = line_item_form.offset_total|accounting_default("0"), offset_total = line_item_form.form.offset_total|accounting_default("0"),
net_balance_data = line_item_form.net_balance, net_balance_data = line_item_form.form.net_balance,
net_balance_text = line_item_form.net_balance|accounting_format_amount, net_balance_text = line_item_form.form.net_balance|accounting_format_amount,
amount_data = line_item_form.amount.data|accounting_voucher_format_amount_input, amount_data = line_item_form.form.amount.data|accounting_voucher_format_amount_input,
amount_errors = line_item_form.amount.errors, amount_errors = line_item_form.form.amount.errors,
amount_text = line_item_form.amount.data|accounting_format_amount, amount_text = line_item_form.form.amount.data|accounting_format_amount,
line_item_errors = line_item_form.all_errors %} line_item_errors = line_item_form.form.all_errors %}
{% include "accounting/voucher/include/form-line-item.html" %} {% include "accounting/voucher/include/form-line-item.html" %}
{% endwith %} {% endwith %}
{% endfor %} {% endfor %}

View File

@ -51,11 +51,11 @@ First written: 2023/2/25
{% endblock %} {% endblock %}
{% block form_modals %} {% block form_modals %}
{% with summary_editor = form.summary_editor.debit %} {% with description_editor = form.description_editor.debit %}
{% include "accounting/voucher/include/summary-editor-modal.html" %} {% include "accounting/voucher/include/description-editor-modal.html" %}
{% endwith %} {% endwith %}
{% with summary_editor = form.summary_editor.credit %} {% with description_editor = form.description_editor.credit %}
{% include "accounting/voucher/include/summary-editor-modal.html" %} {% include "accounting/voucher/include/description-editor-modal.html" %}
{% endwith %} {% endwith %}
{% with side = "debit", {% with side = "debit",
account_options = form.debit_account_options %} account_options = form.debit_account_options %}

View File

@ -452,8 +452,8 @@ class DebitLineItemForm(LineItemForm):
"""The account code.""" """The account code."""
offset_original_line_item_id = IntegerField() offset_original_line_item_id = IntegerField()
"""The ID of the original line item.""" """The ID of the original line item."""
summary = StringField(filters=[strip_text]) description = StringField(filters=[strip_text])
"""The summary.""" """The description."""
amount = DecimalField( amount = DecimalField(
validators=[PositiveAmount(), validators=[PositiveAmount(),
NotExceedingOriginalLineItemNetBalance(), NotExceedingOriginalLineItemNetBalance(),
@ -471,7 +471,7 @@ class DebitLineItemForm(LineItemForm):
obj.id = new_id(VoucherLineItem) obj.id = new_id(VoucherLineItem)
obj.original_line_item_id = self.original_line_item_id.data obj.original_line_item_id = self.original_line_item_id.data
obj.account_id = Account.find_by_code(self.account_code.data).id obj.account_id = Account.find_by_code(self.account_code.data).id
obj.summary = self.summary.data obj.description = self.description.data
obj.is_debit = True obj.is_debit = True
obj.amount = self.amount.data obj.amount = self.amount.data
if is_new: if is_new:
@ -502,8 +502,8 @@ class CreditLineItemForm(LineItemForm):
KeepAccountWhenHavingOffset(), KeepAccountWhenHavingOffset(),
NotStartReceivableFromCredit()]) NotStartReceivableFromCredit()])
"""The account code.""" """The account code."""
summary = StringField(filters=[strip_text]) description = StringField(filters=[strip_text])
"""The summary.""" """The description."""
amount = DecimalField( amount = DecimalField(
validators=[PositiveAmount(), validators=[PositiveAmount(),
NotExceedingOriginalLineItemNetBalance(), NotExceedingOriginalLineItemNetBalance(),
@ -521,7 +521,7 @@ class CreditLineItemForm(LineItemForm):
obj.id = new_id(VoucherLineItem) obj.id = new_id(VoucherLineItem)
obj.original_line_item_id = self.original_line_item_id.data obj.original_line_item_id = self.original_line_item_id.data
obj.account_id = Account.find_by_code(self.account_code.data).id obj.account_id = Account.find_by_code(self.account_code.data).id
obj.summary = self.summary.data obj.description = self.description.data
obj.is_debit = False obj.is_debit = False
obj.amount = self.amount.data obj.amount = self.amount.data
if is_new: if is_new:

View File

@ -35,7 +35,7 @@ from accounting.models import Voucher, Account, VoucherLineItem, \
from accounting.voucher.utils.account_option import AccountOption from accounting.voucher.utils.account_option import AccountOption
from accounting.voucher.utils.original_line_items import \ from accounting.voucher.utils.original_line_items import \
get_selectable_original_line_items get_selectable_original_line_items
from accounting.voucher.utils.summary_editor import SummaryEditor from accounting.voucher.utils.description_editor import DescriptionEditor
from accounting.utils.random_id import new_id from accounting.utils.random_id import new_id
from accounting.utils.strip_text import strip_multiline_text from accounting.utils.strip_text import strip_multiline_text
from accounting.utils.user import get_current_user_pk from accounting.utils.user import get_current_user_pk
@ -256,12 +256,12 @@ class VoucherForm(FlaskForm):
if isinstance(x, str) or isinstance(x, LazyString)] if isinstance(x, str) or isinstance(x, LazyString)]
@property @property
def summary_editor(self) -> SummaryEditor: def description_editor(self) -> DescriptionEditor:
"""Returns the summary editor. """Returns the description editor.
:return: The summary editor. :return: The description editor.
""" """
return SummaryEditor() return DescriptionEditor()
@property @property
def original_line_item_options(self) -> list[VoucherLineItem]: def original_line_item_options(self) -> list[VoucherLineItem]:
@ -394,7 +394,7 @@ class LineItemCollector(t.Generic[T], ABC):
candidates.sort(key=lambda x: x.no) candidates.sort(key=lambda x: x.no)
line_item = candidates[0] line_item = candidates[0]
line_item.account_id = Account.cash().id line_item.account_id = Account.cash().id
line_item.summary = None line_item.description = None
line_item.amount = sum([x.amount.data for x in forms]) line_item.amount = sum([x.amount.data for x in forms])
line_item.no = no line_item.no = no
if db.session.is_modified(line_item): if db.session.is_modified(line_item):
@ -405,7 +405,7 @@ class LineItemCollector(t.Generic[T], ABC):
line_item.is_debit = is_debit line_item.is_debit = is_debit
line_item.currency_code = currency_code line_item.currency_code = currency_code
line_item.account_id = Account.cash().id line_item.account_id = Account.cash().id
line_item.summary = None line_item.description = None
line_item.amount = sum([x.amount.data for x in forms]) line_item.amount = sum([x.amount.data for x in forms])
line_item.no = no line_item.no = no
self.__obj.line_items.append(line_item) self.__obj.line_items.append(line_item)

View File

@ -14,7 +14,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
"""The summary editor. """The description editor.
""" """
import typing as t import typing as t
@ -25,11 +25,11 @@ from accounting import db
from accounting.models import Account, VoucherLineItem from accounting.models import Account, VoucherLineItem
class SummaryAccount: class DescriptionAccount:
"""An account for a summary tag.""" """An account for a description tag."""
def __init__(self, account: Account, freq: int): def __init__(self, account: Account, freq: int):
"""Constructs an account for a summary tag. """Constructs an account for a description tag.
:param account: The account. :param account: The account.
:param freq: The frequency of the tag with the account. :param freq: The frequency of the tag with the account.
@ -59,17 +59,17 @@ class SummaryAccount:
self.freq = self.freq + freq self.freq = self.freq + freq
class SummaryTag: class DescriptionTag:
"""A summary tag.""" """A description tag."""
def __init__(self, name: str): def __init__(self, name: str):
"""Constructs a summary tag. """Constructs a description tag.
:param name: The tag name. :param name: The tag name.
""" """
self.name: str = name self.name: str = name
"""The tag name.""" """The tag name."""
self.__account_dict: dict[int, SummaryAccount] = {} self.__account_dict: dict[int, DescriptionAccount] = {}
"""The accounts that come with the tag, in the order of their """The accounts that come with the tag, in the order of their
frequency.""" frequency."""
self.freq: int = 0 self.freq: int = 0
@ -89,11 +89,11 @@ class SummaryTag:
:param freq: The frequency of the tag name with the account. :param freq: The frequency of the tag name with the account.
:return: None. :return: None.
""" """
self.__account_dict[account.id] = SummaryAccount(account, freq) self.__account_dict[account.id] = DescriptionAccount(account, freq)
self.freq = self.freq + freq self.freq = self.freq + freq
@property @property
def accounts(self) -> list[SummaryAccount]: def accounts(self) -> list[DescriptionAccount]:
"""Returns the accounts by the order of their frequencies. """Returns the accounts by the order of their frequencies.
:return: The accounts by the order of their frequencies. :return: The accounts by the order of their frequencies.
@ -109,17 +109,17 @@ class SummaryTag:
return [x.code for x in self.accounts] return [x.code for x in self.accounts]
class SummaryType: class DescriptionType:
"""A summary type""" """A description type"""
def __init__(self, type_id: t.Literal["general", "travel", "bus"]): def __init__(self, type_id: t.Literal["general", "travel", "bus"]):
"""Constructs a summary type. """Constructs a description type.
:param type_id: The type ID, either "general", "travel", or "bus". :param type_id: The type ID, either "general", "travel", or "bus".
""" """
self.id: t.Literal["general", "travel", "bus"] = type_id self.id: t.Literal["general", "travel", "bus"] = type_id
"""The type ID.""" """The type ID."""
self.__tag_dict: dict[str, SummaryTag] = {} self.__tag_dict: dict[str, DescriptionTag] = {}
"""A dictionary from the tag name to their corresponding tag.""" """A dictionary from the tag name to their corresponding tag."""
def add_tag(self, name: str, account: Account, freq: int) -> None: def add_tag(self, name: str, account: Account, freq: int) -> None:
@ -131,11 +131,11 @@ class SummaryType:
:return: None. :return: None.
""" """
if name not in self.__tag_dict: if name not in self.__tag_dict:
self.__tag_dict[name] = SummaryTag(name) self.__tag_dict[name] = DescriptionTag(name)
self.__tag_dict[name].add_account(account, freq) self.__tag_dict[name].add_account(account, freq)
@property @property
def tags(self) -> list[SummaryTag]: def tags(self) -> list[DescriptionTag]:
"""Returns the tags by the order of their frequencies. """Returns the tags by the order of their frequencies.
:return: The tags by the order of their frequencies. :return: The tags by the order of their frequencies.
@ -143,24 +143,24 @@ class SummaryType:
return sorted(self.__tag_dict.values(), key=lambda x: -x.freq) return sorted(self.__tag_dict.values(), key=lambda x: -x.freq)
class SummarySide: class DescriptionSide:
"""A summary side""" """A description side"""
def __init__(self, side_id: t.Literal["debit", "credit"]): def __init__(self, side_id: t.Literal["debit", "credit"]):
"""Constructs a summary side. """Constructs a description side.
:param side_id: The side ID, either "debit" or "credit". :param side_id: The side ID, either "debit" or "credit".
""" """
self.side: t.Literal["debit", "credit"] = side_id self.side: t.Literal["debit", "credit"] = side_id
"""The side.""" """The side."""
self.general: SummaryType = SummaryType("general") self.general: DescriptionType = DescriptionType("general")
"""The general tags.""" """The general tags."""
self.travel: SummaryType = SummaryType("travel") self.travel: DescriptionType = DescriptionType("travel")
"""The travel tags.""" """The travel tags."""
self.bus: SummaryType = SummaryType("bus") self.bus: DescriptionType = DescriptionType("bus")
"""The bus tags.""" """The bus tags."""
self.__type_dict: dict[t.Literal["general", "travel", "bus"], self.__type_dict: dict[t.Literal["general", "travel", "bus"],
SummaryType] \ DescriptionType] \
= {x.id: x for x in {self.general, self.travel, self.bus}} = {x.id: x for x in {self.general, self.travel, self.bus}}
"""A dictionary from the type ID to the corresponding tags.""" """A dictionary from the type ID to the corresponding tags."""
@ -177,13 +177,13 @@ class SummarySide:
self.__type_dict[tag_type].add_tag(name, account, freq) self.__type_dict[tag_type].add_tag(name, account, freq)
@property @property
def accounts(self) -> list[SummaryAccount]: def accounts(self) -> list[DescriptionAccount]:
"""Returns the suggested accounts of all tags in the summary editor in """Returns the suggested accounts of all tags in the description editor
the side, in their frequency order. in the side, in their frequency order.
:return: The suggested accounts of all tags, in their frequency order. :return: The suggested accounts of all tags, in their frequency order.
""" """
accounts: dict[int, SummaryAccount] = {} accounts: dict[int, DescriptionAccount] = {}
freq: dict[int, int] = {} freq: dict[int, int] = {}
for tag_type in self.__type_dict.values(): for tag_type in self.__type_dict.values():
for tag in tag_type.tags: for tag in tag_type.tags:
@ -197,35 +197,36 @@ class SummarySide:
key=lambda x: -freq[x])] key=lambda x: -freq[x])]
class SummaryEditor: class DescriptionEditor:
"""The summary editor.""" """The description editor."""
def __init__(self): def __init__(self):
"""Constructs the summary editor.""" """Constructs the description editor."""
self.debit: SummarySide = SummarySide("debit") self.debit: DescriptionSide = DescriptionSide("debit")
"""The debit tags.""" """The debit tags."""
self.credit: SummarySide = SummarySide("credit") self.credit: DescriptionSide = DescriptionSide("credit")
"""The credit tags.""" """The credit tags."""
side: sa.Label = sa.case((VoucherLineItem.is_debit, "debit"), side: sa.Label = sa.case((VoucherLineItem.is_debit, "debit"),
else_="credit").label("side") else_="credit").label("side")
tag_type: sa.Label = sa.case( tag_type: sa.Label = sa.case(
(VoucherLineItem.summary.like("_%—_%—_%→_%"), "bus"), (VoucherLineItem.description.like("_%—_%—_%→_%"), "bus"),
(sa.or_(VoucherLineItem.summary.like("_%—_%→_%"), (sa.or_(VoucherLineItem.description.like("_%—_%→_%"),
VoucherLineItem.summary.like("_%—_%↔_%")), "travel"), VoucherLineItem.description.like("_%—_%↔_%")), "travel"),
else_="general").label("tag_type") else_="general").label("tag_type")
tag: sa.Label = get_prefix(VoucherLineItem.summary, "").label("tag") tag: sa.Label = get_prefix(VoucherLineItem.description, "")\
.label("tag")
select: sa.Select = sa.Select(side, tag_type, tag, select: sa.Select = sa.Select(side, tag_type, tag,
VoucherLineItem.account_id, VoucherLineItem.account_id,
sa.func.count().label("freq"))\ sa.func.count().label("freq"))\
.filter(VoucherLineItem.summary.is_not(None), .filter(VoucherLineItem.description.is_not(None),
VoucherLineItem.summary.like("_%—_%"), VoucherLineItem.description.like("_%—_%"),
VoucherLineItem.original_line_item_id.is_(None))\ VoucherLineItem.original_line_item_id.is_(None))\
.group_by(side, tag_type, tag, VoucherLineItem.account_id) .group_by(side, tag_type, tag, VoucherLineItem.account_id)
result: list[sa.Row] = db.session.execute(select).all() result: list[sa.Row] = db.session.execute(select).all()
accounts: dict[int, Account] \ accounts: dict[int, Account] \
= {x.id: x for x in Account.query = {x.id: x for x in Account.query
.filter(Account.id.in_({x.account_id for x in result})).all()} .filter(Account.id.in_({x.account_id for x in result})).all()}
side_dict: dict[t.Literal["debit", "credit"], SummarySide] \ side_dict: dict[t.Literal["debit", "credit"], DescriptionSide] \
= {x.side: x for x in {self.debit, self.credit}} = {x.side: x for x in {self.debit, self.credit}}
for row in result: for row in result:
side_dict[row.side].add_tag( side_dict[row.side].add_tag(

View File

@ -14,7 +14,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
"""The test for the summary editor. """The test for the description editor.
""" """
import unittest import unittest
@ -28,8 +28,8 @@ from testlib import create_test_app, get_client
from testlib_voucher import Accounts, NEXT_URI, add_voucher from testlib_voucher import Accounts, NEXT_URI, add_voucher
class SummeryEditorTestCase(unittest.TestCase): class DescriptionEditorTestCase(unittest.TestCase):
"""The summary editor test case.""" """The description editor test case."""
def setUp(self) -> None: def setUp(self) -> None:
"""Sets up the test. """Sets up the test.
@ -60,16 +60,17 @@ class SummeryEditorTestCase(unittest.TestCase):
self.client, self.csrf_token = get_client(self.app, "editor") self.client, self.csrf_token = get_client(self.app, "editor")
def test_summary_editor(self) -> None: def test_description_editor(self) -> None:
"""Test the summary editor. """Test the description editor.
:return: None. :return: None.
""" """
from accounting.voucher.utils.summary_editor import SummaryEditor from accounting.voucher.utils.description_editor import \
DescriptionEditor
for form in get_form_data(self.csrf_token): for form in get_form_data(self.csrf_token):
add_voucher(self.client, form) add_voucher(self.client, form)
with self.app.app_context(): with self.app.app_context():
editor: SummaryEditor = SummaryEditor() editor: DescriptionEditor = DescriptionEditor()
# Debit-General # Debit-General
self.assertEqual(len(editor.debit.general.tags), 2) self.assertEqual(len(editor.debit.general.tags), 2)
@ -170,156 +171,156 @@ def get_form_data(csrf_token: str) -> list[dict[str, str]]:
"date": voucher_date, "date": voucher_date,
"currency-0-code": "USD", "currency-0-code": "USD",
"currency-0-credit-0-account_code": Accounts.SERVICE, "currency-0-credit-0-account_code": Accounts.SERVICE,
"currency-0-credit-0-summary": " Salary ", "currency-0-credit-0-description": " Salary ",
"currency-0-credit-0-amount": "2500"}, "currency-0-credit-0-amount": "2500"},
{"csrf_token": csrf_token, {"csrf_token": csrf_token,
"next": NEXT_URI, "next": NEXT_URI,
"date": voucher_date, "date": voucher_date,
"currency-0-code": "USD", "currency-0-code": "USD",
"currency-0-debit-0-account_code": Accounts.MEAL, "currency-0-debit-0-account_code": Accounts.MEAL,
"currency-0-debit-0-summary": " Lunch—Fish ", "currency-0-debit-0-description": " Lunch—Fish ",
"currency-0-debit-0-amount": "4.7", "currency-0-debit-0-amount": "4.7",
"currency-0-credit-0-account_code": Accounts.BANK, "currency-0-credit-0-account_code": Accounts.BANK,
"currency-0-credit-0-summary": " Lunch—Fish ", "currency-0-credit-0-description": " Lunch—Fish ",
"currency-0-credit-0-amount": "4.7", "currency-0-credit-0-amount": "4.7",
"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-description": " 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.PETTY_CASH,
"currency-0-credit-1-summary": " Lunch—Fries ", "currency-0-credit-1-description": " 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,
"currency-0-debit-2-summary": " Dinner—Hamburger ", "currency-0-debit-2-description": " Dinner—Hamburger ",
"currency-0-debit-2-amount": "4.25", "currency-0-debit-2-amount": "4.25",
"currency-0-credit-2-account_code": Accounts.BANK, "currency-0-credit-2-account_code": Accounts.BANK,
"currency-0-credit-2-summary": " Dinner—Hamburger ", "currency-0-credit-2-description": " Dinner—Hamburger ",
"currency-0-credit-2-amount": "4.25"}, "currency-0-credit-2-amount": "4.25"},
{"csrf_token": csrf_token, {"csrf_token": csrf_token,
"next": NEXT_URI, "next": NEXT_URI,
"date": voucher_date, "date": voucher_date,
"currency-0-code": "USD", "currency-0-code": "USD",
"currency-0-debit-0-account_code": Accounts.MEAL, "currency-0-debit-0-account_code": Accounts.MEAL,
"currency-0-debit-0-summary": " Lunch—Salad ", "currency-0-debit-0-description": " Lunch—Salad ",
"currency-0-debit-0-amount": "4.99", "currency-0-debit-0-amount": "4.99",
"currency-0-credit-0-account_code": Accounts.CASH, "currency-0-credit-0-account_code": Accounts.CASH,
"currency-0-credit-0-summary": " Lunch—Salad ", "currency-0-credit-0-description": " Lunch—Salad ",
"currency-0-credit-0-amount": "4.99", "currency-0-credit-0-amount": "4.99",
"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-description": " 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.PETTY_CASH,
"currency-0-credit-1-summary": " Dinner—Steak ", "currency-0-credit-1-description": " Dinner—Steak ",
"currency-0-credit-1-amount": "8.28"}, "currency-0-credit-1-amount": "8.28"},
{"csrf_token": csrf_token, {"csrf_token": csrf_token,
"next": NEXT_URI, "next": NEXT_URI,
"date": voucher_date, "date": voucher_date,
"currency-0-code": "USD", "currency-0-code": "USD",
"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-description": " 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.PETTY_CASH,
"currency-0-credit-0-summary": " Lunch—Pizza ", "currency-0-credit-0-description": " 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-description": " 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.PETTY_CASH,
"currency-0-credit-1-summary": " Lunch—Noodles ", "currency-0-credit-1-description": " Lunch—Noodles ",
"currency-0-credit-1-amount": "7.47"}, "currency-0-credit-1-amount": "7.47"},
{"csrf_token": csrf_token, {"csrf_token": csrf_token,
"next": NEXT_URI, "next": NEXT_URI,
"date": voucher_date, "date": voucher_date,
"currency-0-code": "USD", "currency-0-code": "USD",
"currency-0-debit-0-account_code": Accounts.TRAVEL, "currency-0-debit-0-account_code": Accounts.TRAVEL,
"currency-0-debit-0-summary": " Airplane—Lake City↔Hill Town ", "currency-0-debit-0-description": " Airplane—Lake City↔Hill Town",
"currency-0-debit-0-amount": "800"}, "currency-0-debit-0-amount": "800"},
{"csrf_token": csrf_token, {"csrf_token": csrf_token,
"next": NEXT_URI, "next": NEXT_URI,
"date": voucher_date, "date": voucher_date,
"currency-0-code": "USD", "currency-0-code": "USD",
"currency-0-debit-0-account_code": Accounts.TRAVEL, "currency-0-debit-0-account_code": Accounts.TRAVEL,
"currency-0-debit-0-summary": " Bus—323—Downtown→Museum ", "currency-0-debit-0-description": " Bus—323—Downtown→Museum ",
"currency-0-debit-0-amount": "2.5", "currency-0-debit-0-amount": "2.5",
"currency-0-credit-0-account_code": Accounts.PREPAID, "currency-0-credit-0-account_code": Accounts.PREPAID,
"currency-0-credit-0-summary": " Bus—323—Downtown→Museum ", "currency-0-credit-0-description": " Bus—323—Downtown→Museum ",
"currency-0-credit-0-amount": "2.5", "currency-0-credit-0-amount": "2.5",
"currency-0-debit-1-account_code": Accounts.TRAVEL, "currency-0-debit-1-account_code": Accounts.TRAVEL,
"currency-0-debit-1-summary": " Train—Blue—Museum→Central ", "currency-0-debit-1-description": " Train—Blue—Museum→Central ",
"currency-0-debit-1-amount": "3.2", "currency-0-debit-1-amount": "3.2",
"currency-0-credit-1-account_code": Accounts.PREPAID, "currency-0-credit-1-account_code": Accounts.PREPAID,
"currency-0-credit-1-summary": " Train—Blue—Museum→Central ", "currency-0-credit-1-description": " Train—Blue—Museum→Central ",
"currency-0-credit-1-amount": "3.2", "currency-0-credit-1-amount": "3.2",
"currency-0-debit-2-account_code": Accounts.TRAVEL, "currency-0-debit-2-account_code": Accounts.TRAVEL,
"currency-0-debit-2-summary": " Train—Green—Central→Mall ", "currency-0-debit-2-description": " Train—Green—Central→Mall ",
"currency-0-debit-2-amount": "3.2", "currency-0-debit-2-amount": "3.2",
"currency-0-credit-2-account_code": Accounts.PREPAID, "currency-0-credit-2-account_code": Accounts.PREPAID,
"currency-0-credit-2-summary": " Train—Green—Central→Mall ", "currency-0-credit-2-description": " Train—Green—Central→Mall ",
"currency-0-credit-2-amount": "3.2", "currency-0-credit-2-amount": "3.2",
"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-description": " 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.PETTY_CASH,
"currency-0-credit-3-summary": " Train—Red—Mall→Museum ", "currency-0-credit-3-description": " 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,
"next": NEXT_URI, "next": NEXT_URI,
"date": voucher_date, "date": voucher_date,
"currency-0-code": "USD", "currency-0-code": "USD",
"currency-0-debit-0-account_code": Accounts.TRAVEL, "currency-0-debit-0-account_code": Accounts.TRAVEL,
"currency-0-debit-0-summary": " Taxi—Museum→Office ", "currency-0-debit-0-description": " Taxi—Museum→Office ",
"currency-0-debit-0-amount": "15.5", "currency-0-debit-0-amount": "15.5",
"currency-0-credit-0-account_code": Accounts.CASH, "currency-0-credit-0-account_code": Accounts.CASH,
"currency-0-credit-0-summary": " Taxi—Museum→Office ", "currency-0-credit-0-description": " Taxi—Museum→Office ",
"currency-0-credit-0-amount": "15.5", "currency-0-credit-0-amount": "15.5",
"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-description": " 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.PETTY_CASH,
"currency-0-credit-1-summary": " Taxi—Office→Restaurant ", "currency-0-credit-1-description": " 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-description": " 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.PETTY_CASH,
"currency-0-credit-2-summary": " Taxi—Restaurant→City Hall ", "currency-0-credit-2-description": " 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-description": " 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.PETTY_CASH,
"currency-0-credit-3-summary": " Bike—City Hall→Office ", "currency-0-credit-3-description": " 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-description": " 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.PETTY_CASH,
"currency-0-credit-4-summary": " Bike—Restaurant→Office ", "currency-0-credit-4-description": " 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-description": " 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.PETTY_CASH,
"currency-0-credit-5-summary": " Bike—Office→Theatre ", "currency-0-credit-5-description": " 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,
"currency-0-debit-6-summary": " Bike—Theatre→Home ", "currency-0-debit-6-description": " Bike—Theatre→Home ",
"currency-0-debit-6-amount": "5.5", "currency-0-debit-6-amount": "5.5",
"currency-0-credit-6-account_code": Accounts.PREPAID, "currency-0-credit-6-account_code": Accounts.PREPAID,
"currency-0-credit-6-summary": " Bike—Theatre→Home ", "currency-0-credit-6-description": " Bike—Theatre→Home ",
"currency-0-credit-6-amount": "5.5"}, "currency-0-credit-6-amount": "5.5"},
{"csrf_token": csrf_token, {"csrf_token": csrf_token,
"next": NEXT_URI, "next": NEXT_URI,
"date": voucher_date, "date": voucher_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.PETTY_CASH,
"currency-0-debit-0-summary": " Dinner—Steak ", "currency-0-debit-0-description": " 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-description": " 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.PETTY_CASH,
"currency-0-debit-1-summary": " Lunch—Pizza ", "currency-0-debit-1-description": " 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,
"currency-0-credit-1-summary": " Lunch—Pizza ", "currency-0-credit-1-description": " Lunch—Pizza ",
"currency-0-credit-1-amount": "5.49"}] "currency-0-credit-1-amount": "5.49"}]

View File

@ -85,13 +85,13 @@ class OffsetTestCase(unittest.TestCase):
"USD", "USD",
[], [],
[VoucherLineItemData(Accounts.RECEIVABLE, [VoucherLineItemData(Accounts.RECEIVABLE,
self.data.e_r_or1d.summary, "300", self.data.e_r_or1d.description, "300",
original_line_item=self.data.e_r_or1d), original_line_item=self.data.e_r_or1d),
VoucherLineItemData(Accounts.RECEIVABLE, VoucherLineItemData(Accounts.RECEIVABLE,
self.data.e_r_or1d.summary, "100", self.data.e_r_or1d.description, "100",
original_line_item=self.data.e_r_or1d), original_line_item=self.data.e_r_or1d),
VoucherLineItemData(Accounts.RECEIVABLE, VoucherLineItemData(Accounts.RECEIVABLE,
self.data.e_r_or3d.summary, "100", self.data.e_r_or3d.description, "100",
original_line_item=self.data.e_r_or3d)])]) original_line_item=self.data.e_r_or3d)])])
# Non-existing original line item ID # Non-existing original line item ID
@ -400,13 +400,13 @@ class OffsetTestCase(unittest.TestCase):
self.data.e_p_or3c.voucher.days, [CurrencyData( self.data.e_p_or3c.voucher.days, [CurrencyData(
"USD", "USD",
[VoucherLineItemData(Accounts.PAYABLE, [VoucherLineItemData(Accounts.PAYABLE,
self.data.e_p_or1c.summary, "500", self.data.e_p_or1c.description, "500",
original_line_item=self.data.e_p_or1c), original_line_item=self.data.e_p_or1c),
VoucherLineItemData(Accounts.PAYABLE, VoucherLineItemData(Accounts.PAYABLE,
self.data.e_p_or1c.summary, "300", self.data.e_p_or1c.description, "300",
original_line_item=self.data.e_p_or1c), original_line_item=self.data.e_p_or1c),
VoucherLineItemData(Accounts.PAYABLE, VoucherLineItemData(Accounts.PAYABLE,
self.data.e_p_or3c.summary, "120", self.data.e_p_or3c.description, "120",
original_line_item=self.data.e_p_or3c)], original_line_item=self.data.e_p_or3c)],
[])]) [])])

View File

@ -264,7 +264,7 @@ class CashReceiptVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies[0].debit[0].no, 1) self.assertEqual(currencies[0].debit[0].no, 1)
self.assertEqual(currencies[0].debit[0].account.code, self.assertEqual(currencies[0].debit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies[0].debit[0].summary) self.assertIsNone(currencies[0].debit[0].description)
self.assertEqual(currencies[0].debit[0].amount, self.assertEqual(currencies[0].debit[0].amount,
sum([x.amount for x in currencies[0].credit])) sum([x.amount for x in currencies[0].credit]))
self.assertEqual(len(currencies[0].credit), 2) self.assertEqual(len(currencies[0].credit), 2)
@ -280,7 +280,7 @@ class CashReceiptVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies[1].debit[0].no, 2) self.assertEqual(currencies[1].debit[0].no, 2)
self.assertEqual(currencies[1].debit[0].account.code, self.assertEqual(currencies[1].debit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies[1].debit[0].summary) self.assertIsNone(currencies[1].debit[0].description)
self.assertEqual(currencies[1].debit[0].amount, self.assertEqual(currencies[1].debit[0].amount,
sum([x.amount for x in currencies[1].credit])) sum([x.amount for x in currencies[1].credit]))
self.assertEqual(len(currencies[1].credit), 3) self.assertEqual(len(currencies[1].credit), 3)
@ -299,7 +299,7 @@ class CashReceiptVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies[2].debit[0].no, 3) self.assertEqual(currencies[2].debit[0].no, 3)
self.assertEqual(currencies[2].debit[0].account.code, self.assertEqual(currencies[2].debit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies[2].debit[0].summary) self.assertIsNone(currencies[2].debit[0].description)
self.assertEqual(currencies[2].debit[0].amount, self.assertEqual(currencies[2].debit[0].amount,
sum([x.amount for x in currencies[2].credit])) sum([x.amount for x in currencies[2].credit]))
self.assertEqual(len(currencies[2].credit), 2) self.assertEqual(len(currencies[2].credit), 2)
@ -424,7 +424,7 @@ class CashReceiptVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[0].debit[0].no, 1) self.assertEqual(currencies1[0].debit[0].no, 1)
self.assertEqual(currencies1[0].debit[0].account.code, self.assertEqual(currencies1[0].debit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[0].debit[0].summary) self.assertIsNone(currencies1[0].debit[0].description)
self.assertEqual(currencies1[0].debit[0].amount, self.assertEqual(currencies1[0].debit[0].amount,
sum([x.amount for x in currencies1[0].credit])) sum([x.amount for x in currencies1[0].credit]))
self.assertEqual(len(currencies1[0].credit), 2) self.assertEqual(len(currencies1[0].credit), 2)
@ -443,7 +443,7 @@ class CashReceiptVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[1].debit[0].no, 2) self.assertEqual(currencies1[1].debit[0].no, 2)
self.assertEqual(currencies1[1].debit[0].account.code, self.assertEqual(currencies1[1].debit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[1].debit[0].summary) self.assertIsNone(currencies1[1].debit[0].description)
self.assertEqual(currencies1[1].debit[0].amount, self.assertEqual(currencies1[1].debit[0].amount,
sum([x.amount for x in currencies1[1].credit])) sum([x.amount for x in currencies1[1].credit]))
self.assertEqual(len(currencies1[1].credit), 2) self.assertEqual(len(currencies1[1].credit), 2)
@ -465,7 +465,7 @@ class CashReceiptVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[2].debit[0].no, 3) self.assertEqual(currencies1[2].debit[0].no, 3)
self.assertEqual(currencies1[2].debit[0].account.code, self.assertEqual(currencies1[2].debit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[2].debit[0].summary) self.assertIsNone(currencies1[2].debit[0].description)
self.assertEqual(currencies1[2].debit[0].amount, self.assertEqual(currencies1[2].debit[0].amount,
sum([x.amount for x in currencies1[2].credit])) sum([x.amount for x in currencies1[2].credit]))
self.assertEqual(len(currencies1[2].credit), 3) self.assertEqual(len(currencies1[2].credit), 3)
@ -843,7 +843,7 @@ class CashDisbursementVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies[0].credit[0].no, 1) self.assertEqual(currencies[0].credit[0].no, 1)
self.assertEqual(currencies[0].credit[0].account.code, self.assertEqual(currencies[0].credit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies[0].credit[0].summary) self.assertIsNone(currencies[0].credit[0].description)
self.assertEqual(currencies[0].credit[0].amount, self.assertEqual(currencies[0].credit[0].amount,
sum([x.amount for x in currencies[0].debit])) sum([x.amount for x in currencies[0].debit]))
@ -852,20 +852,20 @@ class CashDisbursementVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies[1].debit[0].no, 3) self.assertEqual(currencies[1].debit[0].no, 3)
self.assertEqual(currencies[1].debit[0].account.code, self.assertEqual(currencies[1].debit[0].account.code,
Accounts.BANK) Accounts.BANK)
self.assertEqual(currencies[1].debit[0].summary, "Deposit") self.assertEqual(currencies[1].debit[0].description, "Deposit")
self.assertEqual(currencies[1].debit[1].no, 4) self.assertEqual(currencies[1].debit[1].no, 4)
self.assertEqual(currencies[1].debit[1].account.code, self.assertEqual(currencies[1].debit[1].account.code,
Accounts.OFFICE) Accounts.OFFICE)
self.assertEqual(currencies[1].debit[1].summary, "Pens") self.assertEqual(currencies[1].debit[1].description, "Pens")
self.assertEqual(currencies[1].debit[2].no, 5) self.assertEqual(currencies[1].debit[2].no, 5)
self.assertEqual(currencies[1].debit[2].account.code, self.assertEqual(currencies[1].debit[2].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies[1].debit[2].summary) self.assertIsNone(currencies[1].debit[2].description)
self.assertEqual(len(currencies[1].credit), 1) self.assertEqual(len(currencies[1].credit), 1)
self.assertEqual(currencies[1].credit[0].no, 2) self.assertEqual(currencies[1].credit[0].no, 2)
self.assertEqual(currencies[1].credit[0].account.code, self.assertEqual(currencies[1].credit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies[1].credit[0].summary) self.assertIsNone(currencies[1].credit[0].description)
self.assertEqual(currencies[1].credit[0].amount, self.assertEqual(currencies[1].credit[0].amount,
sum([x.amount for x in currencies[1].debit])) sum([x.amount for x in currencies[1].debit]))
@ -881,7 +881,7 @@ class CashDisbursementVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies[2].credit[0].no, 3) self.assertEqual(currencies[2].credit[0].no, 3)
self.assertEqual(currencies[2].credit[0].account.code, self.assertEqual(currencies[2].credit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies[2].credit[0].summary) self.assertIsNone(currencies[2].credit[0].description)
self.assertEqual(currencies[2].credit[0].amount, self.assertEqual(currencies[2].credit[0].amount,
sum([x.amount for x in currencies[2].debit])) sum([x.amount for x in currencies[2].debit]))
@ -1008,7 +1008,7 @@ class CashDisbursementVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[0].credit[0].no, 1) self.assertEqual(currencies1[0].credit[0].no, 1)
self.assertEqual(currencies1[0].credit[0].account.code, self.assertEqual(currencies1[0].credit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[0].credit[0].summary) self.assertIsNone(currencies1[0].credit[0].description)
self.assertEqual(currencies1[0].credit[0].amount, self.assertEqual(currencies1[0].credit[0].amount,
sum([x.amount for x in currencies1[0].debit])) sum([x.amount for x in currencies1[0].debit]))
@ -1019,7 +1019,7 @@ class CashDisbursementVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[1].debit[0].no, 3) self.assertEqual(currencies1[1].debit[0].no, 3)
self.assertEqual(currencies1[1].debit[0].account.code, self.assertEqual(currencies1[1].debit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[1].debit[0].summary) self.assertIsNone(currencies1[1].debit[0].description)
self.assertEqual(currencies1[1].debit[1].id, self.assertEqual(currencies1[1].debit[1].id,
currencies0[2].debit[1].id) currencies0[2].debit[1].id)
self.assertEqual(currencies1[1].debit[1].no, 4) self.assertEqual(currencies1[1].debit[1].no, 4)
@ -1030,7 +1030,7 @@ class CashDisbursementVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[1].credit[0].no, 2) self.assertEqual(currencies1[1].credit[0].no, 2)
self.assertEqual(currencies1[1].credit[0].account.code, self.assertEqual(currencies1[1].credit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[1].credit[0].summary) self.assertIsNone(currencies1[1].credit[0].description)
self.assertEqual(currencies1[1].credit[0].amount, self.assertEqual(currencies1[1].credit[0].amount,
sum([x.amount for x in currencies1[1].debit])) sum([x.amount for x in currencies1[1].debit]))
@ -1040,26 +1040,26 @@ class CashDisbursementVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[2].debit[0].no, 5) self.assertEqual(currencies1[2].debit[0].no, 5)
self.assertEqual(currencies1[2].debit[0].account.code, self.assertEqual(currencies1[2].debit[0].account.code,
Accounts.TRAVEL) Accounts.TRAVEL)
self.assertIsNone(currencies1[2].debit[0].summary) self.assertIsNone(currencies1[2].debit[0].description)
self.assertEqual(currencies1[2].debit[1].id, self.assertEqual(currencies1[2].debit[1].id,
currencies0[1].debit[2].id) currencies0[1].debit[2].id)
self.assertEqual(currencies1[2].debit[1].no, 6) self.assertEqual(currencies1[2].debit[1].no, 6)
self.assertEqual(currencies1[2].debit[1].account.code, self.assertEqual(currencies1[2].debit[1].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[2].debit[1].summary) self.assertIsNone(currencies1[2].debit[1].description)
self.assertEqual(currencies1[2].debit[2].id, self.assertEqual(currencies1[2].debit[2].id,
currencies0[1].debit[0].id) currencies0[1].debit[0].id)
self.assertEqual(currencies1[2].debit[2].no, 7) self.assertEqual(currencies1[2].debit[2].no, 7)
self.assertEqual(currencies1[2].debit[2].account.code, self.assertEqual(currencies1[2].debit[2].account.code,
Accounts.BANK) Accounts.BANK)
self.assertEqual(currencies1[2].debit[2].summary, "Deposit") self.assertEqual(currencies1[2].debit[2].description, "Deposit")
self.assertEqual(len(currencies1[2].credit), 1) self.assertEqual(len(currencies1[2].credit), 1)
self.assertEqual(currencies1[2].credit[0].id, self.assertEqual(currencies1[2].credit[0].id,
currencies0[1].credit[0].id) currencies0[1].credit[0].id)
self.assertEqual(currencies1[2].credit[0].no, 3) self.assertEqual(currencies1[2].credit[0].no, 3)
self.assertEqual(currencies1[2].credit[0].account.code, self.assertEqual(currencies1[2].credit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[2].credit[0].summary) self.assertIsNone(currencies1[2].credit[0].description)
self.assertEqual(currencies1[2].credit[0].amount, self.assertEqual(currencies1[2].credit[0].amount,
sum([x.amount for x in currencies1[2].debit])) sum([x.amount for x in currencies1[2].debit]))
@ -1464,15 +1464,15 @@ class TransferVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies[1].debit[0].no, 3) self.assertEqual(currencies[1].debit[0].no, 3)
self.assertEqual(currencies[1].debit[0].account.code, self.assertEqual(currencies[1].debit[0].account.code,
Accounts.BANK) Accounts.BANK)
self.assertEqual(currencies[1].debit[0].summary, "Deposit") self.assertEqual(currencies[1].debit[0].description, "Deposit")
self.assertEqual(currencies[1].debit[1].no, 4) self.assertEqual(currencies[1].debit[1].no, 4)
self.assertEqual(currencies[1].debit[1].account.code, self.assertEqual(currencies[1].debit[1].account.code,
Accounts.OFFICE) Accounts.OFFICE)
self.assertEqual(currencies[1].debit[1].summary, "Pens") self.assertEqual(currencies[1].debit[1].description, "Pens")
self.assertEqual(currencies[1].debit[2].no, 5) self.assertEqual(currencies[1].debit[2].no, 5)
self.assertEqual(currencies[1].debit[2].account.code, self.assertEqual(currencies[1].debit[2].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies[1].debit[2].summary) self.assertIsNone(currencies[1].debit[2].description)
self.assertEqual(len(currencies[1].credit), 3) self.assertEqual(len(currencies[1].credit), 3)
self.assertEqual(currencies[1].credit[0].no, 3) self.assertEqual(currencies[1].credit[0].no, 3)
self.assertEqual(currencies[1].credit[0].account.code, self.assertEqual(currencies[1].credit[0].account.code,
@ -1668,7 +1668,7 @@ class TransferVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[1].debit[0].no, 3) self.assertEqual(currencies1[1].debit[0].no, 3)
self.assertEqual(currencies1[1].debit[0].account.code, self.assertEqual(currencies1[1].debit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[1].debit[0].summary) self.assertIsNone(currencies1[1].debit[0].description)
self.assertEqual(currencies1[1].debit[1].id, self.assertEqual(currencies1[1].debit[1].id,
currencies0[2].debit[1].id) currencies0[2].debit[1].id)
self.assertEqual(currencies1[1].debit[1].no, 4) self.assertEqual(currencies1[1].debit[1].no, 4)
@ -1692,19 +1692,19 @@ class TransferVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[2].debit[0].no, 5) self.assertEqual(currencies1[2].debit[0].no, 5)
self.assertEqual(currencies1[2].debit[0].account.code, self.assertEqual(currencies1[2].debit[0].account.code,
Accounts.TRAVEL) Accounts.TRAVEL)
self.assertIsNone(currencies1[2].debit[0].summary) self.assertIsNone(currencies1[2].debit[0].description)
self.assertEqual(currencies1[2].debit[1].id, self.assertEqual(currencies1[2].debit[1].id,
currencies0[1].debit[2].id) currencies0[1].debit[2].id)
self.assertEqual(currencies1[2].debit[1].no, 6) self.assertEqual(currencies1[2].debit[1].no, 6)
self.assertEqual(currencies1[2].debit[1].account.code, self.assertEqual(currencies1[2].debit[1].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[2].debit[1].summary) self.assertIsNone(currencies1[2].debit[1].description)
self.assertEqual(currencies1[2].debit[2].id, self.assertEqual(currencies1[2].debit[2].id,
currencies0[1].debit[0].id) currencies0[1].debit[0].id)
self.assertEqual(currencies1[2].debit[2].no, 7) self.assertEqual(currencies1[2].debit[2].no, 7)
self.assertEqual(currencies1[2].debit[2].account.code, self.assertEqual(currencies1[2].debit[2].account.code,
Accounts.BANK) Accounts.BANK)
self.assertEqual(currencies1[2].debit[2].summary, "Deposit") self.assertEqual(currencies1[2].debit[2].description, "Deposit")
self.assertEqual(len(currencies1[2].credit), 3) self.assertEqual(len(currencies1[2].credit), 3)
self.assertNotIn(currencies1[2].credit[0].id, old_id) self.assertNotIn(currencies1[2].credit[0].id, old_id)
self.assertEqual(currencies1[2].credit[0].no, 5) self.assertEqual(currencies1[2].credit[0].no, 5)
@ -1824,7 +1824,7 @@ class TransferVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[0].debit[0].no, 1) self.assertEqual(currencies1[0].debit[0].no, 1)
self.assertEqual(currencies1[0].debit[0].account.code, self.assertEqual(currencies1[0].debit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[0].debit[0].summary) self.assertIsNone(currencies1[0].debit[0].description)
self.assertEqual(currencies1[0].debit[0].amount, self.assertEqual(currencies1[0].debit[0].amount,
sum([x.amount for x in currencies1[0].credit])) sum([x.amount for x in currencies1[0].credit]))
self.assertEqual(len(currencies1[0].credit), 2) self.assertEqual(len(currencies1[0].credit), 2)
@ -1843,7 +1843,7 @@ class TransferVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[1].debit[0].no, 2) self.assertEqual(currencies1[1].debit[0].no, 2)
self.assertEqual(currencies1[1].debit[0].account.code, self.assertEqual(currencies1[1].debit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[1].debit[0].summary) self.assertIsNone(currencies1[1].debit[0].description)
self.assertEqual(currencies1[1].debit[0].amount, self.assertEqual(currencies1[1].debit[0].amount,
sum([x.amount for x in currencies1[1].credit])) sum([x.amount for x in currencies1[1].credit]))
self.assertEqual(len(currencies1[1].credit), 2) self.assertEqual(len(currencies1[1].credit), 2)
@ -1865,7 +1865,7 @@ class TransferVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[2].debit[0].no, 3) self.assertEqual(currencies1[2].debit[0].no, 3)
self.assertEqual(currencies1[2].debit[0].account.code, self.assertEqual(currencies1[2].debit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[2].debit[0].summary) self.assertIsNone(currencies1[2].debit[0].description)
self.assertEqual(currencies1[2].debit[0].amount, self.assertEqual(currencies1[2].debit[0].amount,
sum([x.amount for x in currencies1[2].credit])) sum([x.amount for x in currencies1[2].credit]))
self.assertEqual(len(currencies1[2].credit), 3) self.assertEqual(len(currencies1[2].credit), 3)
@ -1932,7 +1932,7 @@ class TransferVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[0].credit[0].no, 1) self.assertEqual(currencies1[0].credit[0].no, 1)
self.assertEqual(currencies1[0].credit[0].account.code, self.assertEqual(currencies1[0].credit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[0].credit[0].summary) self.assertIsNone(currencies1[0].credit[0].description)
self.assertEqual(currencies1[0].credit[0].amount, self.assertEqual(currencies1[0].credit[0].amount,
sum([x.amount for x in currencies1[0].debit])) sum([x.amount for x in currencies1[0].debit]))
@ -1943,7 +1943,7 @@ class TransferVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[1].debit[0].no, 3) self.assertEqual(currencies1[1].debit[0].no, 3)
self.assertEqual(currencies1[1].debit[0].account.code, self.assertEqual(currencies1[1].debit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[1].debit[0].summary) self.assertIsNone(currencies1[1].debit[0].description)
self.assertEqual(currencies1[1].debit[1].id, self.assertEqual(currencies1[1].debit[1].id,
currencies0[2].debit[1].id) currencies0[2].debit[1].id)
self.assertEqual(currencies1[1].debit[1].no, 4) self.assertEqual(currencies1[1].debit[1].no, 4)
@ -1954,7 +1954,7 @@ class TransferVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[1].credit[0].no, 2) self.assertEqual(currencies1[1].credit[0].no, 2)
self.assertEqual(currencies1[1].credit[0].account.code, self.assertEqual(currencies1[1].credit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[1].credit[0].summary) self.assertIsNone(currencies1[1].credit[0].description)
self.assertEqual(currencies1[1].credit[0].amount, self.assertEqual(currencies1[1].credit[0].amount,
sum([x.amount for x in currencies1[1].debit])) sum([x.amount for x in currencies1[1].debit]))
@ -1964,26 +1964,26 @@ class TransferVoucherTestCase(unittest.TestCase):
self.assertEqual(currencies1[2].debit[0].no, 5) self.assertEqual(currencies1[2].debit[0].no, 5)
self.assertEqual(currencies1[2].debit[0].account.code, self.assertEqual(currencies1[2].debit[0].account.code,
Accounts.TRAVEL) Accounts.TRAVEL)
self.assertIsNone(currencies1[2].debit[0].summary) self.assertIsNone(currencies1[2].debit[0].description)
self.assertEqual(currencies1[2].debit[1].id, self.assertEqual(currencies1[2].debit[1].id,
currencies0[1].debit[2].id) currencies0[1].debit[2].id)
self.assertEqual(currencies1[2].debit[1].no, 6) self.assertEqual(currencies1[2].debit[1].no, 6)
self.assertEqual(currencies1[2].debit[1].account.code, self.assertEqual(currencies1[2].debit[1].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[2].debit[1].summary) self.assertIsNone(currencies1[2].debit[1].description)
self.assertEqual(currencies1[2].debit[2].id, self.assertEqual(currencies1[2].debit[2].id,
currencies0[1].debit[0].id) currencies0[1].debit[0].id)
self.assertEqual(currencies1[2].debit[2].no, 7) self.assertEqual(currencies1[2].debit[2].no, 7)
self.assertEqual(currencies1[2].debit[2].account.code, self.assertEqual(currencies1[2].debit[2].account.code,
Accounts.BANK) Accounts.BANK)
self.assertEqual(currencies1[2].debit[2].summary, "Deposit") self.assertEqual(currencies1[2].debit[2].description, "Deposit")
self.assertEqual(len(currencies1[2].credit), 1) self.assertEqual(len(currencies1[2].credit), 1)
self.assertEqual(currencies1[2].credit[0].id, self.assertEqual(currencies1[2].credit[0].id,
currencies0[1].credit[0].id) currencies0[1].credit[0].id)
self.assertEqual(currencies1[2].credit[0].no, 3) self.assertEqual(currencies1[2].credit[0].no, 3)
self.assertEqual(currencies1[2].credit[0].account.code, self.assertEqual(currencies1[2].credit[0].account.code,
Accounts.CASH) Accounts.CASH)
self.assertIsNone(currencies1[2].credit[0].summary) self.assertIsNone(currencies1[2].credit[0].description)
self.assertEqual(currencies1[2].credit[0].amount, self.assertEqual(currencies1[2].credit[0].amount,
sum([x.amount for x in currencies1[2].debit])) sum([x.amount for x in currencies1[2].debit]))

View File

@ -32,12 +32,12 @@ from testlib_voucher import Accounts, match_voucher_detail, NEXT_URI
class VoucherLineItemData: class VoucherLineItemData:
"""The voucher line item data.""" """The voucher line item data."""
def __init__(self, account: str, summary: str, amount: str, def __init__(self, account: str, description: str, amount: str,
original_line_item: VoucherLineItemData | None = None): original_line_item: VoucherLineItemData | None = None):
"""Constructs the voucher line item data. """Constructs the voucher line item data.
:param account: The account code. :param account: The account code.
:param summary: The summary. :param description: The description.
:param amount: The amount. :param amount: The amount.
:param original_line_item: The original voucher line item. :param original_line_item: The original voucher line item.
""" """
@ -47,7 +47,7 @@ class VoucherLineItemData:
self.original_line_item: VoucherLineItemData | None \ self.original_line_item: VoucherLineItemData | None \
= original_line_item = original_line_item
self.account: str = account self.account: str = account
self.summary: str = summary self.description: str = description
self.amount: Decimal = Decimal(amount) self.amount: Decimal = Decimal(amount)
def form(self, prefix: str, side: str, index: int, is_update: bool) \ def form(self, prefix: str, side: str, index: int, is_update: bool) \
@ -62,7 +62,7 @@ class VoucherLineItemData:
""" """
prefix = f"{prefix}-{side}-{index}" prefix = f"{prefix}-{side}-{index}"
form: dict[str, str] = {f"{prefix}-account_code": self.account, form: dict[str, str] = {f"{prefix}-account_code": self.account,
f"{prefix}-summary": self.summary, f"{prefix}-description": self.description,
f"{prefix}-amount": str(self.amount)} f"{prefix}-amount": str(self.amount)}
if is_update and self.id != -1: if is_update and self.id != -1:
form[f"{prefix}-eid"] = str(self.id) form[f"{prefix}-eid"] = str(self.id)
@ -174,18 +174,18 @@ class TestData:
self.client: httpx.Client = client self.client: httpx.Client = client
self.csrf_token: str = csrf_token self.csrf_token: str = csrf_token
def couple(summary: str, amount: str, debit: str, credit: str) \ def couple(description: str, amount: str, debit: str, credit: str) \
-> tuple[VoucherLineItemData, VoucherLineItemData]: -> tuple[VoucherLineItemData, VoucherLineItemData]:
"""Returns a couple of debit-credit line items. """Returns a couple of debit-credit line items.
:param summary: The summary. :param description: The description.
:param amount: The amount. :param amount: The amount.
:param debit: The debit account code. :param debit: The debit account code.
:param credit: The credit account code. :param credit: The credit account code.
:return: The debit line item and credit line item. :return: The debit line item and credit line item.
""" """
return VoucherLineItemData(debit, summary, amount),\ return VoucherLineItemData(debit, description, amount),\
VoucherLineItemData(credit, summary, amount) VoucherLineItemData(credit, description, amount)
# Receivable original line items # Receivable original line items
self.e_r_or1d, self.e_r_or1c = couple( self.e_r_or1d, self.e_r_or1c = couple(

View File

@ -68,58 +68,58 @@ def get_add_form(csrf_token: str) -> dict[str, str]:
"currency-0-code": "USD", "currency-0-code": "USD",
"currency-0-debit-0-no": "16", "currency-0-debit-0-no": "16",
"currency-0-debit-0-account_code": Accounts.CASH, "currency-0-debit-0-account_code": Accounts.CASH,
"currency-0-debit-0-summary": " ", "currency-0-debit-0-description": " ",
"currency-0-debit-0-amount": " 495.26 ", "currency-0-debit-0-amount": " 495.26 ",
"currency-0-debit-6-no": "2", "currency-0-debit-6-no": "2",
"currency-0-debit-6-account_code": Accounts.BANK, "currency-0-debit-6-account_code": Accounts.BANK,
"currency-0-debit-6-summary": " Deposit ", "currency-0-debit-6-description": " Deposit ",
"currency-0-debit-6-amount": "6000", "currency-0-debit-6-amount": "6000",
"currency-0-debit-12-no": "2", "currency-0-debit-12-no": "2",
"currency-0-debit-12-account_code": Accounts.OFFICE, "currency-0-debit-12-account_code": Accounts.OFFICE,
"currency-0-debit-12-summary": " Pens ", "currency-0-debit-12-description": " Pens ",
"currency-0-debit-12-amount": "4.99", "currency-0-debit-12-amount": "4.99",
"currency-0-credit-2-no": "6", "currency-0-credit-2-no": "6",
"currency-0-credit-2-account_code": Accounts.SERVICE, "currency-0-credit-2-account_code": Accounts.SERVICE,
"currency-0-credit-2-summary": " ", "currency-0-credit-2-description": " ",
"currency-0-credit-2-amount": "5500", "currency-0-credit-2-amount": "5500",
"currency-0-credit-7-account_code": Accounts.SALES, "currency-0-credit-7-account_code": Accounts.SALES,
"currency-0-credit-7-summary": " ", "currency-0-credit-7-description": " ",
"currency-0-credit-7-amount": "950", "currency-0-credit-7-amount": "950",
"currency-0-credit-27-account_code": Accounts.INTEREST, "currency-0-credit-27-account_code": Accounts.INTEREST,
"currency-0-credit-27-summary": " ", "currency-0-credit-27-description": " ",
"currency-0-credit-27-amount": "50.25", "currency-0-credit-27-amount": "50.25",
"currency-3-no": "2", "currency-3-no": "2",
"currency-3-code": "JPY", "currency-3-code": "JPY",
"currency-3-debit-2-no": "2", "currency-3-debit-2-no": "2",
"currency-3-debit-2-account_code": Accounts.CASH, "currency-3-debit-2-account_code": Accounts.CASH,
"currency-3-debit-2-summary": " ", "currency-3-debit-2-description": " ",
"currency-3-debit-2-amount": "15000", "currency-3-debit-2-amount": "15000",
"currency-3-debit-9-no": "5", "currency-3-debit-9-no": "5",
"currency-3-debit-9-account_code": Accounts.BANK, "currency-3-debit-9-account_code": Accounts.BANK,
"currency-3-debit-9-summary": " Deposit ", "currency-3-debit-9-description": " Deposit ",
"currency-3-debit-9-amount": "95000", "currency-3-debit-9-amount": "95000",
"currency-3-credit-3-account_code": Accounts.AGENCY, "currency-3-credit-3-account_code": Accounts.AGENCY,
"currency-3-credit-3-summary": " Realtor ", "currency-3-credit-3-description": " Realtor ",
"currency-3-credit-3-amount": "65000", "currency-3-credit-3-amount": "65000",
"currency-3-credit-5-no": "4", "currency-3-credit-5-no": "4",
"currency-3-credit-5-account_code": Accounts.DONATION, "currency-3-credit-5-account_code": Accounts.DONATION,
"currency-3-credit-5-summary": " Donation ", "currency-3-credit-5-description": " Donation ",
"currency-3-credit-5-amount": "45000", "currency-3-credit-5-amount": "45000",
"currency-16-code": "TWD", "currency-16-code": "TWD",
"currency-16-debit-2-no": "2", "currency-16-debit-2-no": "2",
"currency-16-debit-2-account_code": Accounts.CASH, "currency-16-debit-2-account_code": Accounts.CASH,
"currency-16-debit-2-summary": " ", "currency-16-debit-2-description": " ",
"currency-16-debit-2-amount": "10000", "currency-16-debit-2-amount": "10000",
"currency-16-debit-9-no": "2", "currency-16-debit-9-no": "2",
"currency-16-debit-9-account_code": Accounts.TRAVEL, "currency-16-debit-9-account_code": Accounts.TRAVEL,
"currency-16-debit-9-summary": " Gas ", "currency-16-debit-9-description": " Gas ",
"currency-16-debit-9-amount": "30000", "currency-16-debit-9-amount": "30000",
"currency-16-credit-6-no": "6", "currency-16-credit-6-no": "6",
"currency-16-credit-6-account_code": Accounts.RENT, "currency-16-credit-6-account_code": Accounts.RENT,
"currency-16-credit-6-summary": " Rent ", "currency-16-credit-6-description": " Rent ",
"currency-16-credit-6-amount": "35000", "currency-16-credit-6-amount": "35000",
"currency-16-credit-9-account_code": Accounts.DONATION, "currency-16-credit-9-account_code": Accounts.DONATION,
"currency-16-credit-9-summary": " Donation ", "currency-16-credit-9-description": " Donation ",
"currency-16-credit-9-amount": "5000", "currency-16-credit-9-amount": "5000",
"note": f"\n \n\n \n{NON_EMPTY_NOTE} \n \n\n "} "note": f"\n \n\n \n{NON_EMPTY_NOTE} \n \n\n "}
@ -167,9 +167,9 @@ def get_unchanged_update_form(voucher_id: int, app: Flask, csrf_token: str) \
form[f"{prefix}-eid"] = str(line_item.id) form[f"{prefix}-eid"] = str(line_item.id)
form[f"{prefix}-no"] = str(line_item_no) form[f"{prefix}-no"] = str(line_item_no)
form[f"{prefix}-account_code"] = line_item.account.code form[f"{prefix}-account_code"] = line_item.account.code
form[f"{prefix}-summary"] \ form[f"{prefix}-description"] \
= " " if line_item.summary is None \ = " " if line_item.description is None \
else f" {line_item.summary} " else f" {line_item.description} "
form[f"{prefix}-amount"] = str(line_item.amount) form[f"{prefix}-amount"] = str(line_item.amount)
line_item_indices_used = set() line_item_indices_used = set()
@ -181,8 +181,8 @@ def get_unchanged_update_form(voucher_id: int, app: Flask, csrf_token: str) \
form[f"{prefix}-eid"] = str(line_item.id) form[f"{prefix}-eid"] = str(line_item.id)
form[f"{prefix}-no"] = str(line_item_no) form[f"{prefix}-no"] = str(line_item_no)
form[f"{prefix}-account_code"] = line_item.account.code form[f"{prefix}-account_code"] = line_item.account.code
form[f"{prefix}-summary"] \ form[f"{prefix}-description"] \
= " " if line_item.summary is None else f" {line_item.summary} " = " " if line_item.description is None else f" {line_item.description} "
form[f"{prefix}-amount"] = str(line_item.amount) form[f"{prefix}-amount"] = str(line_item.amount)
return form return form
@ -335,19 +335,19 @@ def __mess_up_currencies(form: dict[str, str]) -> dict[str, str]:
f"{prefix}no": str(1 + randbelow(min_no - 1)), f"{prefix}no": str(1 + randbelow(min_no - 1)),
f"{prefix}debit-0-no": "6", f"{prefix}debit-0-no": "6",
f"{prefix}debit-0-account_code": Accounts.OFFICE, f"{prefix}debit-0-account_code": Accounts.OFFICE,
f"{prefix}debit-0-summary": " Envelop ", f"{prefix}debit-0-description": " Envelop ",
f"{prefix}debit-0-amount": "5.45", f"{prefix}debit-0-amount": "5.45",
f"{prefix}debit-14-no": "6", f"{prefix}debit-14-no": "6",
f"{prefix}debit-14-account_code": Accounts.CASH, f"{prefix}debit-14-account_code": Accounts.CASH,
f"{prefix}debit-14-summary": " ", f"{prefix}debit-14-description": " ",
f"{prefix}debit-14-amount": "14.55", f"{prefix}debit-14-amount": "14.55",
f"{prefix}credit-16-no": "7", f"{prefix}credit-16-no": "7",
f"{prefix}credit-16-account_code": Accounts.RENT, f"{prefix}credit-16-account_code": Accounts.RENT,
f"{prefix}credit-16-summary": " Bike ", f"{prefix}credit-16-description": " Bike ",
f"{prefix}credit-16-amount": "19.5", f"{prefix}credit-16-amount": "19.5",
f"{prefix}credit-22-no": "5", f"{prefix}credit-22-no": "5",
f"{prefix}credit-22-account_code": Accounts.DONATION, f"{prefix}credit-22-account_code": Accounts.DONATION,
f"{prefix}credit-22-summary": " Artist ", f"{prefix}credit-22-description": " Artist ",
f"{prefix}credit-22-amount": "0.5", f"{prefix}credit-22-amount": "0.5",
}) })
# Swap the USD and TWD order # Swap the USD and TWD order