Renamed "side" to "debit-credit".
This commit is contained in:
		| @@ -35,10 +35,10 @@ class AccountSelector { | ||||
|     #lineItemEditor; | ||||
|  | ||||
|     /** | ||||
|      * The side, either "debit" or "credit" | ||||
|      * Either "debit" or "credit" | ||||
|      * @type {string} | ||||
|      */ | ||||
|     #side; | ||||
|     #debitCredit; | ||||
|  | ||||
|     /** | ||||
|      * The prefix of the HTML ID and class | ||||
| @@ -86,12 +86,12 @@ class AccountSelector { | ||||
|      * Constructs an account selector. | ||||
|      * | ||||
|      * @param lineItemEditor {VoucherLineItemEditor} the line item editor | ||||
|      * @param side {string} the side, either "debit" or "credit" | ||||
|      * @param debitCredit {string} either "debit" or "credit" | ||||
|      */ | ||||
|     constructor(lineItemEditor, side) { | ||||
|     constructor(lineItemEditor, debitCredit) { | ||||
|         this.#lineItemEditor = lineItemEditor | ||||
|         this.#side = side; | ||||
|         this.#prefix = "accounting-account-selector-" + side; | ||||
|         this.#debitCredit = debitCredit; | ||||
|         this.#prefix = "accounting-account-selector-" + debitCredit; | ||||
|         this.#query = document.getElementById(this.#prefix + "-query"); | ||||
|         this.#queryNoResult = document.getElementById(this.#prefix + "-option-no-result"); | ||||
|         this.#optionList = document.getElementById(this.#prefix + "-option-list"); | ||||
| @@ -143,7 +143,7 @@ class AccountSelector { | ||||
|      * @return {string[]} the account codes that are used in the form | ||||
|      */ | ||||
|     #getCodesUsedInForm() { | ||||
|         const inUse = this.#lineItemEditor.form.getAccountCodesUsed(this.#side); | ||||
|         const inUse = this.#lineItemEditor.form.getAccountCodesUsed(this.#debitCredit); | ||||
|         if (this.#lineItemEditor.accountCode !== null) { | ||||
|             inUse.push(this.#lineItemEditor.accountCode); | ||||
|         } | ||||
| @@ -217,7 +217,7 @@ class AccountSelector { | ||||
|         const selectors = {} | ||||
|         const modals = Array.from(document.getElementsByClassName("accounting-account-selector")); | ||||
|         for (const modal of modals) { | ||||
|             selectors[modal.dataset.side] = new AccountSelector(lineItemEditor, modal.dataset.side); | ||||
|             selectors[modal.dataset.debitCredit] = new AccountSelector(lineItemEditor, modal.dataset.debitCredit); | ||||
|         } | ||||
|         return selectors; | ||||
|     } | ||||
|   | ||||
| @@ -53,10 +53,10 @@ class DescriptionEditor { | ||||
|     #modal; | ||||
|  | ||||
|     /** | ||||
|      * The side, either "debit" or "credit" | ||||
|      * Either "debit" or "credit" | ||||
|      * @type {string} | ||||
|      */ | ||||
|     side; | ||||
|     debitCredit; | ||||
|  | ||||
|     /** | ||||
|      * The current tab | ||||
| @@ -110,12 +110,12 @@ class DescriptionEditor { | ||||
|      * Constructs a description editor. | ||||
|      * | ||||
|      * @param lineItemEditor {VoucherLineItemEditor} the line item editor | ||||
|      * @param side {string} the side, either "debit" or "credit" | ||||
|      * @param debitCredit {string} either "debit" or "credit" | ||||
|      */ | ||||
|     constructor(lineItemEditor, side) { | ||||
|     constructor(lineItemEditor, debitCredit) { | ||||
|         this.#lineItemEditor = lineItemEditor; | ||||
|         this.side = side; | ||||
|         this.prefix = "accounting-description-editor-" + side; | ||||
|         this.debitCredit = debitCredit; | ||||
|         this.prefix = "accounting-description-editor-" + debitCredit; | ||||
|         this.#form = document.getElementById(this.prefix); | ||||
|         this.#modal = document.getElementById(this.prefix + "-modal"); | ||||
|         this.description = document.getElementById(this.prefix + "-description"); | ||||
| @@ -253,7 +253,7 @@ class DescriptionEditor { | ||||
|         const editors = {} | ||||
|         const forms = Array.from(document.getElementsByClassName("accounting-description-editor")); | ||||
|         for (const form of forms) { | ||||
|             editors[form.dataset.side] = new DescriptionEditor(lineItemEditor, form.dataset.side); | ||||
|             editors[form.dataset.debitCredit] = new DescriptionEditor(lineItemEditor, form.dataset.debitCredit); | ||||
|         } | ||||
|         return editors; | ||||
|     } | ||||
|   | ||||
| @@ -77,9 +77,9 @@ class OriginalLineItemSelector { | ||||
|     #currencyCode; | ||||
|  | ||||
|     /** | ||||
|      * The side, either "credit" or "debit" | ||||
|      * Either "credit" or "debit" | ||||
|      */ | ||||
|     #side; | ||||
|     #debitCredit; | ||||
|  | ||||
|     /** | ||||
|      * Constructs an original line item selector. | ||||
| @@ -157,7 +157,7 @@ class OriginalLineItemSelector { | ||||
|     #filterOptions() { | ||||
|         let hasAnyMatched = false; | ||||
|         for (const option of this.#options) { | ||||
|             if (option.isMatched(this.#side, this.#currencyCode, this.#query.value)) { | ||||
|             if (option.isMatched(this.#debitCredit, this.#currencyCode, this.#query.value)) { | ||||
|                 option.setShown(true); | ||||
|                 hasAnyMatched = true; | ||||
|             } else { | ||||
| @@ -179,7 +179,7 @@ class OriginalLineItemSelector { | ||||
|      */ | ||||
|     onOpen() { | ||||
|         this.#currencyCode = this.lineItemEditor.getCurrencyCode(); | ||||
|         this.#side = this.lineItemEditor.side; | ||||
|         this.#debitCredit = this.lineItemEditor.debitCredit; | ||||
|         for (const option of this.#options) { | ||||
|             option.setActive(option.id === this.lineItemEditor.originalLineItemId); | ||||
|         } | ||||
| @@ -220,10 +220,10 @@ class OriginalLineItem { | ||||
|     date; | ||||
|  | ||||
|     /** | ||||
|      * The side, either "debit" or "credit" | ||||
|      * Either "debit" or "credit" | ||||
|      * @type {string} | ||||
|      */ | ||||
|     #side; | ||||
|     #debitCredit; | ||||
|  | ||||
|     /** | ||||
|      * The currency code | ||||
| @@ -290,7 +290,7 @@ class OriginalLineItem { | ||||
|         this.#element = element; | ||||
|         this.id = element.dataset.id; | ||||
|         this.date = element.dataset.date; | ||||
|         this.#side = element.dataset.side; | ||||
|         this.#debitCredit = element.dataset.debitCredit; | ||||
|         this.#currencyCode = element.dataset.currencyCode; | ||||
|         this.accountCode = element.dataset.accountCode; | ||||
|         this.accountText = element.dataset.accountText; | ||||
| @@ -335,27 +335,27 @@ class OriginalLineItem { | ||||
|     /** | ||||
|      * Returns whether the original matches. | ||||
|      * | ||||
|      * @param side {string} the side, either "debit" or "credit" | ||||
|      * @param debitCredit {string} either "debit" or "credit" | ||||
|      * @param currencyCode {string} the currency code | ||||
|      * @param query {string|null} the query term | ||||
|      */ | ||||
|     isMatched(side, currencyCode, query = null) { | ||||
|     isMatched(debitCredit, currencyCode, query = null) { | ||||
|         return this.netBalance.greaterThan(0) | ||||
|             && this.date <= this.#selector.lineItemEditor.form.getDate() | ||||
|             && this.#isSideMatches(side) | ||||
|             && this.#isDebitCreditMatches(debitCredit) | ||||
|             && this.#currencyCode === currencyCode | ||||
|             && this.#isQueryMatches(query); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns whether the original line item matches the debit or credit side. | ||||
|      * Returns whether the original line item matches the debit or credit. | ||||
|      * | ||||
|      * @param side {string} the side, either "debit" or credit | ||||
|      * @param debitCredit {string} either "debit" or credit | ||||
|      * @return {boolean} true if the option matches, or false otherwise | ||||
|      */ | ||||
|     #isSideMatches(side) { | ||||
|         return (side === "debit" && this.#side === "credit") | ||||
|             || (side === "credit" && this.#side === "debit"); | ||||
|     #isDebitCreditMatches(debitCredit) { | ||||
|         return (debitCredit === "debit" && this.#debitCredit === "credit") | ||||
|             || (debitCredit === "credit" && this.#debitCredit === "debit"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -195,13 +195,13 @@ class VoucherForm { | ||||
|     /** | ||||
|      * Returns all the line items in the form. | ||||
|      * | ||||
|      * @param side {string|null} the side, either "debit" or "credit", or null for both | ||||
|      * @param debitCredit {string|null} Either "debit" or "credit", or null for both | ||||
|      * @return {LineItemSubForm[]} all the line item sub-forms | ||||
|      */ | ||||
|     getLineItems(side = null) { | ||||
|     getLineItems(debitCredit = null) { | ||||
|         const lineItems = []; | ||||
|         for (const currency of this.#currencies) { | ||||
|             lineItems.push(...currency.getLineItems(side)); | ||||
|             lineItems.push(...currency.getLineItems(debitCredit)); | ||||
|         } | ||||
|         return lineItems; | ||||
|     } | ||||
| @@ -209,11 +209,11 @@ class VoucherForm { | ||||
|     /** | ||||
|      * Returns the account codes used in the form. | ||||
|      * | ||||
|      * @param side {string} the side, either "debit" or "credit" | ||||
|      * @param debitCredit {string} either "debit" or "credit" | ||||
|      * @return {string[]} the account codes used in the form | ||||
|      */ | ||||
|     getAccountCodesUsed(side) { | ||||
|         return this.getLineItems(side).map((lineItem) => lineItem.getAccountCode()) | ||||
|     getAccountCodesUsed(debitCredit) { | ||||
|         return this.getLineItems(debitCredit).map((lineItem) => lineItem.getAccountCode()) | ||||
|             .filter((code) => code !== null); | ||||
|     } | ||||
|  | ||||
| @@ -406,14 +406,14 @@ class CurrencySubForm { | ||||
|     deleteButton; | ||||
|  | ||||
|     /** | ||||
|      * The debit side | ||||
|      * @type {SideSubForm|null} | ||||
|      * The debit sub-form | ||||
|      * @type {DebitCreditSubForm|null} | ||||
|      */ | ||||
|     #debit; | ||||
|  | ||||
|     /** | ||||
|      * The credit side | ||||
|      * @type {SideSubForm|null} | ||||
|      * The credit sub-form | ||||
|      * @type {DebitCreditSubForm|null} | ||||
|      */ | ||||
|     #credit; | ||||
|  | ||||
| @@ -435,9 +435,9 @@ class CurrencySubForm { | ||||
|         this.#codeSelect = document.getElementById(this.#prefix + "-code-select"); | ||||
|         this.deleteButton = document.getElementById(this.#prefix + "-delete"); | ||||
|         const debitElement = document.getElementById(this.#prefix + "-debit"); | ||||
|         this.#debit = debitElement === null? null: new SideSubForm(this, debitElement, "debit"); | ||||
|         this.#debit = debitElement === null? null: new DebitCreditSubForm(this, debitElement, "debit"); | ||||
|         const creditElement = document.getElementById(this.#prefix + "-credit"); | ||||
|         this.#credit = creditElement == null? null: new SideSubForm(this, creditElement, "credit"); | ||||
|         this.#credit = creditElement == null? null: new DebitCreditSubForm(this, creditElement, "credit"); | ||||
|         this.#codeSelect.onchange = () => this.#code.value = this.#codeSelect.value; | ||||
|         this.deleteButton.onclick = () => { | ||||
|             this.element.parentElement.removeChild(this.element); | ||||
| @@ -457,15 +457,15 @@ class CurrencySubForm { | ||||
|     /** | ||||
|      * Returns all the line items in the form. | ||||
|      * | ||||
|      * @param side {string|null} the side, either "debit" or "credit", or null for both | ||||
|      * @param debitCredit {string|null} either "debit" or "credit", or null for both | ||||
|      * @return {LineItemSubForm[]} all the line item sub-forms | ||||
|      */ | ||||
|     getLineItems(side = null) { | ||||
|     getLineItems(debitCredit = null) { | ||||
|         const lineItems = [] | ||||
|         for (const sideSubForm of [this.#debit, this.#credit]) { | ||||
|             if (sideSubForm !== null ) { | ||||
|                 if (side === null || sideSubForm.side === side) { | ||||
|                     lineItems.push(...sideSubForm.lineItems); | ||||
|         for (const debitCreditSubForm of [this.#debit, this.#credit]) { | ||||
|             if (debitCreditSubForm !== null ) { | ||||
|                 if (debitCredit === null || debitCreditSubForm.debitCredit === debitCredit) { | ||||
|                     lineItems.push(...debitCreditSubForm.lineItems); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -524,10 +524,10 @@ class CurrencySubForm { | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * The debit or credit side sub-form | ||||
|  * The debit or credit sub-form | ||||
|  * | ||||
|  */ | ||||
| class SideSubForm { | ||||
| class DebitCreditSubForm { | ||||
|  | ||||
|     /** | ||||
|      * The currency sub-form | ||||
| @@ -548,10 +548,10 @@ class SideSubForm { | ||||
|     #currencyIndex; | ||||
|  | ||||
|     /** | ||||
|      * The side, either "debit" or "credit" | ||||
|      * Either "debit" or "credit" | ||||
|      * @type {string} | ||||
|      */ | ||||
|     side; | ||||
|     debitCredit; | ||||
|  | ||||
|     /** | ||||
|      * The prefix of the HTML ID and class | ||||
| @@ -590,18 +590,18 @@ class SideSubForm { | ||||
|     #addLineItemButton; | ||||
|  | ||||
|     /** | ||||
|      * Constructs a debit or credit side sub-form | ||||
|      * Constructs a debit or credit sub-form | ||||
|      * | ||||
|      * @param currency {CurrencySubForm} the currency sub-form | ||||
|      * @param element {HTMLDivElement} the element | ||||
|      * @param side {string} the side, either "debit" or "credit" | ||||
|      * @param debitCredit {string} either "debit" or "credit" | ||||
|      */ | ||||
|     constructor(currency, element, side) { | ||||
|     constructor(currency, element, debitCredit) { | ||||
|         this.currency = currency; | ||||
|         this.#element = element; | ||||
|         this.#currencyIndex = currency.index; | ||||
|         this.side = side; | ||||
|         this.#prefix = "accounting-currency-" + String(this.#currencyIndex) + "-" + side; | ||||
|         this.debitCredit = debitCredit; | ||||
|         this.#prefix = "accounting-currency-" + String(this.#currencyIndex) + "-" + debitCredit; | ||||
|         this.#error = document.getElementById(this.#prefix + "-error"); | ||||
|         this.#lineItemList = document.getElementById(this.#prefix + "-list"); | ||||
|         // noinspection JSValidateTypes | ||||
| @@ -622,7 +622,7 @@ class SideSubForm { | ||||
|         const newIndex = 1 + (this.lineItems.length === 0? 0: Math.max(...this.lineItems.map((lineItem) => lineItem.lineItemIndex))); | ||||
|         const html = this.currency.form.lineItemTemplate | ||||
|             .replaceAll("CURRENCY_INDEX", escapeHtml(String(this.#currencyIndex))) | ||||
|             .replaceAll("SIDE", escapeHtml(this.side)) | ||||
|             .replaceAll("DEBIT_CREDIT", escapeHtml(this.debitCredit)) | ||||
|             .replaceAll("LINE_ITEM_INDEX", escapeHtml(String(newIndex))); | ||||
|         this.#lineItemList.insertAdjacentHTML("beforeend", html); | ||||
|         const lineItem = new LineItemSubForm(this, document.getElementById(this.#prefix + "-" + String(newIndex))); | ||||
| @@ -742,10 +742,10 @@ class SideSubForm { | ||||
| class LineItemSubForm { | ||||
|  | ||||
|     /** | ||||
|      * The debit or credit side sub-form | ||||
|      * @type {SideSubForm} | ||||
|      * The debit or credit sub-form | ||||
|      * @type {DebitCreditSubForm} | ||||
|      */ | ||||
|     sideSubForm; | ||||
|     debitCreditSubForm; | ||||
|  | ||||
|     /** | ||||
|      * The element | ||||
| @@ -754,10 +754,10 @@ class LineItemSubForm { | ||||
|     element; | ||||
|  | ||||
|     /** | ||||
|      * The side, either "debit" or "credit" | ||||
|      * Either "debit" or "credit" | ||||
|      * @type {string} | ||||
|      */ | ||||
|     side; | ||||
|     debitCredit; | ||||
|  | ||||
|     /** | ||||
|      * The line item index | ||||
| @@ -858,16 +858,16 @@ class LineItemSubForm { | ||||
|     /** | ||||
|      * Constructs the line item sub-form. | ||||
|      * | ||||
|      * @param side {SideSubForm} the debit or credit side sub-form | ||||
|      * @param debitCredit {DebitCreditSubForm} the debit or credit sub-form | ||||
|      * @param element {HTMLLIElement} the element | ||||
|      */ | ||||
|     constructor(side, element) { | ||||
|         this.sideSubForm = side; | ||||
|     constructor(debitCredit, element) { | ||||
|         this.debitCreditSubForm = debitCredit; | ||||
|         this.element = element; | ||||
|         this.side = element.dataset.side; | ||||
|         this.debitCredit = element.dataset.debitCredit; | ||||
|         this.lineItemIndex = parseInt(element.dataset.lineItemIndex); | ||||
|         this.isMatched = element.classList.contains("accounting-matched-line-item"); | ||||
|         this.#prefix = "accounting-currency-" + element.dataset.currencyIndex + "-" + this.side + "-" + this.lineItemIndex; | ||||
|         this.#prefix = "accounting-currency-" + element.dataset.currencyIndex + "-" + this.debitCredit + "-" + this.lineItemIndex; | ||||
|         this.#control = document.getElementById(this.#prefix + "-control"); | ||||
|         this.#error = document.getElementById(this.#prefix + "-error"); | ||||
|         this.no = document.getElementById(this.#prefix + "-no"); | ||||
| @@ -881,10 +881,10 @@ class LineItemSubForm { | ||||
|         this.#amount = document.getElementById(this.#prefix + "-amount"); | ||||
|         this.#amountText = document.getElementById(this.#prefix + "-amount-text"); | ||||
|         this.deleteButton = document.getElementById(this.#prefix + "-delete"); | ||||
|         this.#control.onclick = () => this.sideSubForm.currency.form.lineItemEditor.onEdit(this); | ||||
|         this.#control.onclick = () => this.debitCreditSubForm.currency.form.lineItemEditor.onEdit(this); | ||||
|         this.deleteButton.onclick = () => { | ||||
|             this.element.parentElement.removeChild(this.element); | ||||
|             this.sideSubForm.deleteLineItem(this); | ||||
|             this.debitCreditSubForm.deleteLineItem(this); | ||||
|         }; | ||||
|     } | ||||
|  | ||||
| @@ -1019,9 +1019,9 @@ class LineItemSubForm { | ||||
|         this.#amount.value = editor.amount; | ||||
|         this.#amountText.innerText = formatDecimal(new Decimal(editor.amount)); | ||||
|         this.validate(); | ||||
|         this.sideSubForm.updateTotal(); | ||||
|         this.sideSubForm.currency.updateCodeSelectorStatus(); | ||||
|         this.sideSubForm.currency.form.updateMinDate(); | ||||
|         this.debitCreditSubForm.updateTotal(); | ||||
|         this.debitCreditSubForm.currency.updateCodeSelectorStatus(); | ||||
|         this.debitCreditSubForm.currency.form.updateMinDate(); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -47,10 +47,10 @@ class VoucherLineItemEditor { | ||||
|     #modal; | ||||
|  | ||||
|     /** | ||||
|      * The side, either "debit" or "credit" | ||||
|      * Either "debit" or "credit" | ||||
|      * @type {string} | ||||
|      */ | ||||
|     side; | ||||
|     debitCredit; | ||||
|  | ||||
|     /** | ||||
|      * The prefix of the HTML ID and class | ||||
| @@ -143,10 +143,10 @@ class VoucherLineItemEditor { | ||||
|     lineItem; | ||||
|  | ||||
|     /** | ||||
|      * The debit or credit side sub-form | ||||
|      * @type {SideSubForm} | ||||
|      * The debit or credit sub-form | ||||
|      * @type {DebitCreditSubForm} | ||||
|      */ | ||||
|     #sideSubForm; | ||||
|     #debitCreditSubForm; | ||||
|  | ||||
|     /** | ||||
|      * Whether the voucher line item needs offset | ||||
| @@ -241,13 +241,13 @@ class VoucherLineItemEditor { | ||||
|         this.originalLineItemSelector = new OriginalLineItemSelector(this); | ||||
|         this.#originalLineItemControl.onclick = () => this.originalLineItemSelector.onOpen() | ||||
|         this.#originalLineItemDelete.onclick = () => this.clearOriginalLineItem(); | ||||
|         this.#descriptionControl.onclick = () => this.#descriptionEditors[this.side].onOpen(); | ||||
|         this.#accountControl.onclick = () => this.#accountSelectors[this.side].onOpen(); | ||||
|         this.#descriptionControl.onclick = () => this.#descriptionEditors[this.debitCredit].onOpen(); | ||||
|         this.#accountControl.onclick = () => this.#accountSelectors[this.debitCredit].onOpen(); | ||||
|         this.#amountInput.onchange = () => this.#validateAmount(); | ||||
|         this.#element.onsubmit = () => { | ||||
|             if (this.#validate()) { | ||||
|                 if (this.lineItem === null) { | ||||
|                     this.lineItem = this.#sideSubForm.addLineItem(); | ||||
|                     this.lineItem = this.#debitCreditSubForm.addLineItem(); | ||||
|                 } | ||||
|                 this.amount = this.#amountInput.value; | ||||
|                 this.lineItem.save(this); | ||||
| @@ -314,7 +314,7 @@ class VoucherLineItemEditor { | ||||
|      * @return {string} the currency code | ||||
|      */ | ||||
|     getCurrencyCode() { | ||||
|         return this.#sideSubForm.currency.getCurrencyCode(); | ||||
|         return this.#debitCreditSubForm.currency.getCurrencyCode(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -478,12 +478,12 @@ class VoucherLineItemEditor { | ||||
|     /** | ||||
|      * The callback when adding a new voucher line item. | ||||
|      * | ||||
|      * @param side {SideSubForm} the debit or credit side sub-form | ||||
|      * @param debitCredit {DebitCreditSubForm} the debit or credit sub-form | ||||
|      */ | ||||
|     onAddNew(side) { | ||||
|     onAddNew(debitCredit) { | ||||
|         this.lineItem = null; | ||||
|         this.#sideSubForm = side; | ||||
|         this.side = this.#sideSubForm.side; | ||||
|         this.#debitCreditSubForm = debitCredit; | ||||
|         this.debitCredit = this.#debitCreditSubForm.debitCredit; | ||||
|         this.isNeedOffset = false; | ||||
|         this.#originalLineItemContainer.classList.add("d-none"); | ||||
|         this.#originalLineItemControl.classList.remove("accounting-not-empty"); | ||||
| @@ -518,8 +518,8 @@ class VoucherLineItemEditor { | ||||
|      */ | ||||
|     onEdit(lineItem) { | ||||
|         this.lineItem = lineItem; | ||||
|         this.#sideSubForm = lineItem.sideSubForm; | ||||
|         this.side = this.#sideSubForm.side; | ||||
|         this.#debitCreditSubForm = lineItem.debitCreditSubForm; | ||||
|         this.debitCredit = this.#debitCreditSubForm.debitCredit; | ||||
|         this.isNeedOffset = lineItem.isNeedOffset(); | ||||
|         this.originalLineItemId = lineItem.getOriginalLineItemId(); | ||||
|         this.originalLineItemDate = lineItem.getOriginalLineItemDate(); | ||||
| @@ -575,11 +575,11 @@ class VoucherLineItemEditor { | ||||
|     #setEnableDescriptionAccount(isEnabled) { | ||||
|         if (isEnabled) { | ||||
|             this.#descriptionControl.dataset.bsToggle = "modal"; | ||||
|             this.#descriptionControl.dataset.bsTarget = "#accounting-description-editor-" + this.#sideSubForm.side + "-modal"; | ||||
|             this.#descriptionControl.dataset.bsTarget = "#accounting-description-editor-" + this.#debitCreditSubForm.debitCredit + "-modal"; | ||||
|             this.#descriptionControl.classList.remove("accounting-disabled"); | ||||
|             this.#descriptionControl.classList.add("accounting-clickable"); | ||||
|             this.#accountControl.dataset.bsToggle = "modal"; | ||||
|             this.#accountControl.dataset.bsTarget = "#accounting-account-selector-" + this.#sideSubForm.side + "-modal"; | ||||
|             this.#accountControl.dataset.bsTarget = "#accounting-account-selector-" + this.#debitCreditSubForm.debitCredit + "-modal"; | ||||
|             this.#accountControl.classList.remove("accounting-disabled"); | ||||
|             this.#accountControl.classList.add("accounting-clickable"); | ||||
|         } else { | ||||
|   | ||||
| @@ -47,7 +47,7 @@ First written: 2023/2/25 | ||||
|         <ul id="accounting-currency-{{ currency_index }}-debit-list" class="list-group accounting-line-item-list"> | ||||
|           {% for line_item_form in debit_forms %} | ||||
|             {% with currency_index = currency_index, | ||||
|                     side = "debit", | ||||
|                     debit_credit = "debit", | ||||
|                     line_item_index = loop.index, | ||||
|                     only_one_line_item_form = debit_forms|length == 1, | ||||
|                     form = line_item_form.form %} | ||||
| @@ -62,7 +62,7 @@ First written: 2023/2/25 | ||||
|         </div> | ||||
|  | ||||
|         <div> | ||||
|           <button id="accounting-currency-{{ currency_index }}-debit-add-line-item" class="btn btn-primary" type="button" data-currency-index="{{ currency_index }}" data-side="debit" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> | ||||
|           <button id="accounting-currency-{{ currency_index }}-debit-add-line-item" class="btn btn-primary" type="button" data-currency-index="{{ currency_index }}" data-debit-credit="debit" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> | ||||
|             <i class="fas fa-plus"></i> | ||||
|             {{ A_("New") }} | ||||
|           </button> | ||||
|   | ||||
| @@ -50,7 +50,7 @@ First written: 2023/2/25 | ||||
|   {% with description_editor = form.description_editor.debit %} | ||||
|     {% include "accounting/voucher/include/description-editor-modal.html" %} | ||||
|   {% endwith %} | ||||
|   {% with side = "debit", | ||||
|   {% with debit_credit = "debit", | ||||
|           account_options = form.debit_account_options %} | ||||
|     {% include "accounting/voucher/include/account-selector-modal.html" %} | ||||
|   {% endwith %} | ||||
|   | ||||
| @@ -19,35 +19,35 @@ account-selector-modal.html: The modal for the account selector | ||||
| Author: imacat@mail.imacat.idv.tw (imacat) | ||||
| First written: 2023/2/25 | ||||
| #} | ||||
| <div id="accounting-account-selector-{{ side }}-modal" class="modal fade accounting-account-selector" data-side="{{ side }}" tabindex="-1" aria-labelledby="accounting-account-selector-{{ side }}-modal-label" aria-hidden="true"> | ||||
| <div id="accounting-account-selector-{{ debit_credit }}-modal" class="modal fade accounting-account-selector" data-debit-credit="{{ debit_credit }}" tabindex="-1" aria-labelledby="accounting-account-selector-{{ debit_credit }}-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-account-selector-{{ side }}-modal-label">{{ A_("Select Account") }}</h1> | ||||
|         <h1 class="modal-title fs-5" id="accounting-account-selector-{{ debit_credit }}-modal-label">{{ A_("Select Account") }}</h1> | ||||
|         <button type="button" class="btn-close" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal" aria-label="{{ A_("Close") }}"></button> | ||||
|       </div> | ||||
|       <div class="modal-body"> | ||||
|         <div class="input-group mb-2"> | ||||
|           <input id="accounting-account-selector-{{ side }}-query" class="form-control form-control-sm" type="search" placeholder=" " required="required"> | ||||
|           <label class="input-group-text" for="accounting-account-selector-{{ side }}-query"> | ||||
|           <input id="accounting-account-selector-{{ debit_credit }}-query" class="form-control form-control-sm" type="search" placeholder=" " required="required"> | ||||
|           <label class="input-group-text" for="accounting-account-selector-{{ debit_credit }}-query"> | ||||
|             <i class="fa-solid fa-magnifying-glass"></i> | ||||
|             {{ A_("Search") }} | ||||
|           </label> | ||||
|         </div> | ||||
|  | ||||
|         <ul id="accounting-account-selector-{{ side }}-option-list" class="list-group accounting-selector-list"> | ||||
|         <ul id="accounting-account-selector-{{ debit_credit }}-option-list" class="list-group accounting-selector-list"> | ||||
|           {% for account in account_options %} | ||||
|             <li id="accounting-account-selector-{{ side }}-option-{{ account.code }}" class="list-group-item accounting-clickable accounting-account-selector-{{ side }}-option {% if account.is_in_use %} accounting-account-in-use {% endif %} {% if account.is_need_offset %} accounting-account-is-need-offset {% endif %}" data-code="{{ account.code }}" data-content="{{ account }}" data-query-values="{{ account.query_values|tojson|forceescape }}" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> | ||||
|             <li id="accounting-account-selector-{{ debit_credit }}-option-{{ account.code }}" class="list-group-item accounting-clickable accounting-account-selector-{{ debit_credit }}-option {% if account.is_in_use %} accounting-account-in-use {% endif %} {% if account.is_need_offset %} accounting-account-is-need-offset {% endif %}" data-code="{{ account.code }}" data-content="{{ account }}" data-query-values="{{ account.query_values|tojson|forceescape }}" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> | ||||
|               {{ account }} | ||||
|             </li> | ||||
|           {% endfor %} | ||||
|           <li id="accounting-account-selector-{{ side }}-more" class="list-group-item accounting-clickable">{{ A_("More…") }}</li> | ||||
|           <li id="accounting-account-selector-{{ debit_credit }}-more" class="list-group-item accounting-clickable">{{ A_("More…") }}</li> | ||||
|         </ul> | ||||
|         <p id="accounting-account-selector-{{ side }}-option-no-result" class="d-none">{{ A_("There is no data.") }}</p> | ||||
|         <p id="accounting-account-selector-{{ debit_credit }}-option-no-result" class="d-none">{{ A_("There is no data.") }}</p> | ||||
|       </div> | ||||
|       <div class="modal-footer"> | ||||
|         <button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal">{{ A_("Cancel") }}</button> | ||||
|         <button id="accounting-account-selector-{{ side }}-btn-clear" type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal">{{ A_("Clear") }}</button> | ||||
|         <button id="accounting-account-selector-{{ debit_credit }}-btn-clear" type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal">{{ A_("Clear") }}</button> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
|   | ||||
| @@ -19,20 +19,20 @@ description-editor-modal.html: The modal of the description editor | ||||
| 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"> | ||||
| <form id="accounting-description-editor-{{ description_editor.debit_credit }}" class="accounting-description-editor" data-debit-credit="{{ description_editor.debit_credit }}"> | ||||
|   <div id="accounting-description-editor-{{ description_editor.debit_credit }}-modal" class="modal fade" tabindex="-1" aria-labelledby="accounting-description-editor-{{ description_editor.debit_credit }}-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 class="modal-title fs-5" id="accounting-description-editor-{{ description_editor.debit_credit }}-modal-label"> | ||||
|             <label for="accounting-description-editor-{{ description_editor.debit_credit }}-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"> | ||||
|             <input id="accounting-description-editor-{{ description_editor.debit_credit }}-description" class="form-control" type="text" aria-labelledby="accounting-description-editor-{{ description_editor.debit_credit }}-modal-label"> | ||||
|             <button id="accounting-description-editor-{{ description_editor.debit_credit }}-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> | ||||
| @@ -40,43 +40,43 @@ First written: 2023/2/28 | ||||
|           {# 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"> | ||||
|               <span id="accounting-description-editor-{{ description_editor.debit_credit }}-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"> | ||||
|               <span id="accounting-description-editor-{{ description_editor.debit_credit }}-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"> | ||||
|               <span id="accounting-description-editor-{{ description_editor.debit_credit }}-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"> | ||||
|               <span id="accounting-description-editor-{{ description_editor.debit_credit }}-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"> | ||||
|               <span id="accounting-description-editor-{{ description_editor.debit_credit }}-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 id="accounting-description-editor-{{ description_editor.debit_credit }}-general-page" aria-current="page" aria-labelledby="accounting-description-editor-{{ description_editor.debit_credit }}-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> | ||||
|               <input id="accounting-description-editor-{{ description_editor.debit_credit }}-general-tag" class="form-control" type="text" value="" placeholder=" "> | ||||
|               <label class="form-label" for="accounting-description-editor-{{ description_editor.debit_credit }}-general-tag">{{ A_("Tag") }}</label> | ||||
|               <div id="accounting-description-editor-{{ description_editor.debit_credit }}-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 }}"> | ||||
|                 <button class="btn btn-outline-primary accounting-description-editor-{{ description_editor.debit_credit }}-general-btn-tag" type="button" tabindex="-1" data-value="{{ tag.name }}" data-accounts="{{ tag.account_codes|tojson|forceescape }}"> | ||||
|                   {{ tag }} | ||||
|                 </button> | ||||
|               {% endfor %} | ||||
| @@ -84,16 +84,16 @@ First written: 2023/2/28 | ||||
|           </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 id="accounting-description-editor-{{ description_editor.debit_credit }}-travel-page" class="d-none" aria-current="false" aria-labelledby="accounting-description-editor-{{ description_editor.debit_credit }}-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> | ||||
|               <input id="accounting-description-editor-{{ description_editor.debit_credit }}-travel-tag" class="form-control" type="text" value="" placeholder=" "> | ||||
|               <label class="form-label" for="accounting-description-editor-{{ description_editor.debit_credit }}-travel-tag">{{ A_("Tag") }}</label> | ||||
|               <div id="accounting-description-editor-{{ description_editor.debit_credit }}-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 }}"> | ||||
|                 <button class="btn btn-outline-primary accounting-description-editor-{{ description_editor.debit_credit }}-travel-btn-tag" type="button" tabindex="-1" data-value="{{ tag.name }}" data-accounts="{{ tag.account_codes|tojson|forceescape }}"> | ||||
|                   {{ tag }} | ||||
|                 </button> | ||||
|               {% endfor %} | ||||
| @@ -101,40 +101,40 @@ First written: 2023/2/28 | ||||
|  | ||||
|             <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> | ||||
|                 <input id="accounting-description-editor-{{ description_editor.debit_credit }}-travel-from" class="form-control" type="text" value="" placeholder=" "> | ||||
|                 <label class="form-label" for="accounting-description-editor-{{ description_editor.debit_credit }}-travel-from">{{ A_("From") }}</label> | ||||
|                 <div id="accounting-description-editor-{{ description_editor.debit_credit }}-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="→">→</button> | ||||
|                 <button class="btn btn-outline-primary accounting-description-editor-{{ description_editor.side }}-travel-direction" type="button" tabindex="-1" data-arrow="↔">↔</button> | ||||
|                 <button class="btn btn-primary accounting-description-editor-{{ description_editor.debit_credit }}-travel-direction accounting-default" type="button" tabindex="-1" data-arrow="→">→</button> | ||||
|                 <button class="btn btn-outline-primary accounting-description-editor-{{ description_editor.debit_credit }}-travel-direction" type="button" tabindex="-1" data-arrow="↔">↔</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> | ||||
|                 <input id="accounting-description-editor-{{ description_editor.debit_credit }}-travel-to" class="form-control" type="text" value="" placeholder=" "> | ||||
|                 <label class="form-label" for="accounting-description-editor-{{ description_editor.debit_credit }}-travel-to">{{ A_("To") }}</label> | ||||
|                 <div id="accounting-description-editor-{{ description_editor.debit_credit }}-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 id="accounting-description-editor-{{ description_editor.debit_credit }}-bus-page" class="d-none" aria-current="false" aria-labelledby="accounting-description-editor-{{ description_editor.debit_credit }}-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> | ||||
|                 <input id="accounting-description-editor-{{ description_editor.debit_credit }}-bus-tag" class="form-control" type="text" value="" placeholder=" "> | ||||
|                 <label class="form-label" for="accounting-description-editor-{{ description_editor.debit_credit }}-bus-tag">{{ A_("Tag") }}</label> | ||||
|                 <div id="accounting-description-editor-{{ description_editor.debit_credit }}-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> | ||||
|                 <input id="accounting-description-editor-{{ description_editor.debit_credit }}-bus-route" class="form-control" type="text" value="" placeholder=" "> | ||||
|                 <label class="form-label" for="accounting-description-editor-{{ description_editor.debit_credit }}-bus-route">{{ A_("Route") }}</label> | ||||
|                 <div id="accounting-description-editor-{{ description_editor.debit_credit }}-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 }}"> | ||||
|                 <button class="btn btn-outline-primary accounting-description-editor-{{ description_editor.debit_credit }}-bus-btn-tag" type="button" tabindex="-1" data-value="{{ tag.name }}" data-accounts="{{ tag.account_codes|tojson|forceescape }}"> | ||||
|                   {{ tag }} | ||||
|                 </button> | ||||
|               {% endfor %} | ||||
| @@ -142,42 +142,42 @@ First written: 2023/2/28 | ||||
|  | ||||
|             <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> | ||||
|                 <input id="accounting-description-editor-{{ description_editor.debit_credit }}-bus-from" class="form-control" type="text" value="" placeholder=" "> | ||||
|                 <label class="form-label" for="accounting-description-editor-{{ description_editor.debit_credit }}-bus-from">{{ A_("From") }}</label> | ||||
|                 <div id="accounting-description-editor-{{ description_editor.debit_credit }}-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> | ||||
|                 <input id="accounting-description-editor-{{ description_editor.debit_credit }}-bus-to" class="form-control" type="text" value="" placeholder=" "> | ||||
|                 <label class="form-label" for="accounting-description-editor-{{ description_editor.debit_credit }}-bus-to">{{ A_("To") }}</label> | ||||
|                 <div id="accounting-description-editor-{{ description_editor.debit_credit }}-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"> | ||||
|           <div id="accounting-description-editor-{{ description_editor.debit_credit }}-regular-page" class="d-none" aria-current="false" aria-labelledby="accounting-description-editor-{{ description_editor.debit_credit }}-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 id="accounting-description-editor-{{ description_editor.debit_credit }}-annotation-page" class="d-none" aria-current="false" aria-labelledby="accounting-description-editor-{{ description_editor.debit_credit }}-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> | ||||
|               <input id="accounting-description-editor-{{ description_editor.debit_credit }}-annotation-number" class="form-control" type="number" min="1" value="" placeholder=" "> | ||||
|               <label class="form-label" for="accounting-description-editor-{{ description_editor.debit_credit }}-annotation-number">{{ A_("The number of items") }}</label> | ||||
|               <div id="accounting-description-editor-{{ description_editor.debit_credit }}-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> | ||||
|               <input id="accounting-description-editor-{{ description_editor.debit_credit }}-annotation-note" class="form-control" type="text" value="" placeholder=" "> | ||||
|               <label class="form-label" for="accounting-description-editor-{{ description_editor.debit_credit }}-annotation-note">{{ A_("Note") }}</label> | ||||
|               <div id="accounting-description-editor-{{ description_editor.debit_credit }}-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 }}"> | ||||
|               <button class="btn btn-outline-primary d-none accounting-description-editor-{{ description_editor.debit_credit }}-account {% if account.is_need_offset %} accounting-account-is-need-offset {% endif %}" type="button" data-code="{{ account.code }}" data-text="{{ account }}"> | ||||
|                 {{ account }} | ||||
|               </button> | ||||
|             {% endfor %} | ||||
| @@ -185,7 +185,7 @@ First written: 2023/2/28 | ||||
|         </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> | ||||
|           <button id="accounting-description-editor-{{ description_editor.debit_credit }}-btn-save" type="submit" class="btn btn-primary">{{ A_("Save") }}</button> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   | ||||
| @@ -20,24 +20,24 @@ Author: imacat@mail.imacat.idv.tw (imacat) | ||||
| First written: 2023/2/25 | ||||
| #} | ||||
| {# <ul> For SonarQube not to complain about incorrect HTML #} | ||||
| <li id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}" class="list-group-item list-group-item-action d-flex justify-content-between accounting-currency-{{ currency_index }}-{{ side }} {% if form.offsets %} accounting-matched-line-item {% endif %}" data-currency-index="{{ currency_index }}" data-side="{{ side }}" data-line-item-index="{{ line_item_index }}" {% if form.is_need_offset %} data-is-need-offset="true" {% endif %}> | ||||
| <li id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}" class="list-group-item list-group-item-action d-flex justify-content-between accounting-currency-{{ currency_index }}-{{ debit_credit }} {% if form.offsets %} accounting-matched-line-item {% endif %}" data-currency-index="{{ currency_index }}" data-debit-credit="{{ debit_credit }}" data-line-item-index="{{ line_item_index }}" {% if form.is_need_offset %} data-is-need-offset="true" {% endif %}> | ||||
|   {% if form.eid.data %} | ||||
|     <input type="hidden" name="currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-eid" value="{{ form.eid.data }}"> | ||||
|     <input type="hidden" name="currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-eid" value="{{ form.eid.data }}"> | ||||
|   {% endif %} | ||||
|   <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="{{ form.original_line_item_id.data|accounting_default }}" data-date="{{ form.original_line_item_date|accounting_default }}" data-text="{{ form.original_line_item_text|accounting_default }}"> | ||||
|   <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="{{ form.account_code.data|accounting_default }}" data-text="{{ form.account_text }}"> | ||||
|   <input id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-description" type="hidden" name="currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-description" value="{{ form.description.data|accounting_default }}"> | ||||
|   <input id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-amount" type="hidden" name="currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-amount" value="{{ form.amount.data|accounting_voucher_format_amount_input }}" data-min="{{ form.offset_total|accounting_default("0") }}"> | ||||
|   <input id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-no" type="hidden" name="currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-no" value="{{ line_item_index }}"> | ||||
|   <input id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-original-line-item-id" class="accounting-original-line-item-id" type="hidden" name="currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-original_line_item_id" value="{{ form.original_line_item_id.data|accounting_default }}" data-date="{{ form.original_line_item_date|accounting_default }}" data-text="{{ form.original_line_item_text|accounting_default }}"> | ||||
|   <input id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-account-code" type="hidden" name="currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-account_code" value="{{ form.account_code.data|accounting_default }}" data-text="{{ form.account_text }}"> | ||||
|   <input id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-description" type="hidden" name="currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-description" value="{{ form.description.data|accounting_default }}"> | ||||
|   <input id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-amount" type="hidden" name="currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-amount" value="{{ form.amount.data|accounting_voucher_format_amount_input }}" data-min="{{ form.offset_total|accounting_default("0") }}"> | ||||
|   <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 form.all_errors %} is-invalid {% endif %}" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> | ||||
|     <div id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-control" class="form-control clickable d-flex justify-content-between {% if form.all_errors %} is-invalid {% endif %}" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> | ||||
|       <div> | ||||
|         <div id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-account-text" class="small">{{ form.account_text }}</div> | ||||
|         <div id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-description-text">{{ form.description.data|accounting_default }}</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 form.original_line_item_id.data %} d-none {% endif %}"> | ||||
|         <div id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-account-text" class="small">{{ form.account_text }}</div> | ||||
|         <div id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-description-text">{{ form.description.data|accounting_default }}</div> | ||||
|         <div id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-original-line-item-text" class="fst-italic small accounting-original-line-item {% if not form.original_line_item_id.data %} d-none {% endif %}"> | ||||
|           {% if form.original_line_item_id.data %}{{ A_("Offset %(item)s", item=form.original_line_item_text|accounting_default) }}{% endif %} | ||||
|         </div> | ||||
|         <div id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-offsets" class="fst-italic small accounting-offset-line-items {% if not form.is_need_offset %} d-none {% endif %}"> | ||||
|         <div id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-offsets" class="fst-italic small accounting-offset-line-items {% if not form.is_need_offset %} d-none {% endif %}"> | ||||
|           {% if form.offsets %} | ||||
|             <div class="d-flex justify-content-between {% if not form.offsets %} d-none {% endif %}"> | ||||
|               <div>{{ A_("Offsets") }}</div> | ||||
| @@ -60,13 +60,13 @@ First written: 2023/2/25 | ||||
|           {% endif %} | ||||
|         </div> | ||||
|       </div> | ||||
|       <div><span id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-amount-text" class="badge rounded-pill bg-primary">{{ form.amount.data|accounting_format_amount }}</span></div> | ||||
|       <div><span id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-amount-text" class="badge rounded-pill bg-primary">{{ form.amount.data|accounting_format_amount }}</span></div> | ||||
|     </div> | ||||
|     <div id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-error" class="invalid-feedback">{% if form.all_errors %}{{ form.all_errors[0] }}{% endif %}</div> | ||||
|     <div id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-error" class="invalid-feedback">{% if form.all_errors %}{{ form.all_errors[0] }}{% endif %}</div> | ||||
|   </div> | ||||
|  | ||||
|   <div> | ||||
|     <button id="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}-delete" class="btn btn-danger rounded-circle {% if only_one_form or form.offsets %} d-none {% endif %}" type="button" data-target="accounting-currency-{{ currency_index }}-{{ side }}-{{ line_item_index }}"> | ||||
|     <button id="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}-delete" class="btn btn-danger rounded-circle {% if only_one_form or form.offsets %} d-none {% endif %}" type="button" data-target="accounting-currency-{{ currency_index }}-{{ debit_credit }}-{{ line_item_index }}"> | ||||
|       <i class="fas fa-minus"></i> | ||||
|     </button> | ||||
|   </div> | ||||
|   | ||||
| @@ -37,7 +37,7 @@ First written: 2023/2/25 | ||||
|  | ||||
|         <ul id="accounting-original-line-item-selector-option-list" class="list-group accounting-selector-list"> | ||||
|           {% 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-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"> | ||||
|             <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-debit-credit="{{ "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.description|accounting_default }}</div> | ||||
|               <div> | ||||
|                 <span class="badge bg-primary rounded-pill"> | ||||
|   | ||||
| @@ -47,7 +47,7 @@ First written: 2023/2/25 | ||||
|         <ul id="accounting-currency-{{ currency_index }}-credit-list" class="list-group accounting-line-item-list"> | ||||
|           {% for line_item_form in credit_forms %} | ||||
|             {% with currency_index = currency_index, | ||||
|                     side = "credit", | ||||
|                     debit_credit = "credit", | ||||
|                     line_item_index = loop.index, | ||||
|                     only_one_line_item_form = credit_forms|length == 1, | ||||
|                     form = line_item_form.form %} | ||||
| @@ -62,7 +62,7 @@ First written: 2023/2/25 | ||||
|         </div> | ||||
|  | ||||
|         <div> | ||||
|           <button id="accounting-currency-{{ currency_index }}-credit-add-line-item" class="btn btn-primary" type="button" data-currency-index="{{ currency_index }}" data-side="credit" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> | ||||
|           <button id="accounting-currency-{{ currency_index }}-credit-add-line-item" class="btn btn-primary" type="button" data-currency-index="{{ currency_index }}" data-debit-credit="credit" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> | ||||
|             <i class="fas fa-plus"></i> | ||||
|             {{ A_("New") }} | ||||
|           </button> | ||||
|   | ||||
| @@ -50,7 +50,7 @@ First written: 2023/2/25 | ||||
|   {% with description_editor = form.description_editor.credit %} | ||||
|     {% include "accounting/voucher/include/description-editor-modal.html" %} | ||||
|   {% endwith %} | ||||
|   {% with side = "credit", | ||||
|   {% with debit_credit = "credit", | ||||
|           account_options = form.credit_account_options %} | ||||
|     {% include "accounting/voucher/include/account-selector-modal.html" %} | ||||
|   {% endwith %} | ||||
|   | ||||
| @@ -49,7 +49,7 @@ First written: 2023/2/25 | ||||
|           <ul id="accounting-currency-{{ currency_index }}-debit-list" class="list-group accounting-line-item-list"> | ||||
|             {% for line_item_form in debit_forms %} | ||||
|               {% with currency_index = currency_index, | ||||
|                       side = "debit", | ||||
|                       debit_credit = "debit", | ||||
|                       line_item_index = loop.index, | ||||
|                       only_one_line_item_form = debit_forms|length == 1, | ||||
|                       form = line_item_form.form %} | ||||
| @@ -64,7 +64,7 @@ First written: 2023/2/25 | ||||
|           </div> | ||||
|  | ||||
|           <div> | ||||
|             <button id="accounting-currency-{{ currency_index }}-debit-add-line-item" class="btn btn-primary" type="button" data-currency-index="{{ currency_index }}" data-side="debit" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> | ||||
|             <button id="accounting-currency-{{ currency_index }}-debit-add-line-item" class="btn btn-primary" type="button" data-currency-index="{{ currency_index }}" data-debit-credit="debit" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> | ||||
|               <i class="fas fa-plus"></i> | ||||
|               {{ A_("New") }} | ||||
|             </button> | ||||
| @@ -80,7 +80,7 @@ First written: 2023/2/25 | ||||
|           <ul id="accounting-currency-{{ currency_index }}-credit-list" class="list-group accounting-line-item-list"> | ||||
|             {% for line_item_form in credit_forms %} | ||||
|               {% with currency_index = currency_index, | ||||
|                       side = "credit", | ||||
|                       debit_credit = "credit", | ||||
|                       line_item_index = loop.index, | ||||
|                       only_one_line_item_form = credit_forms|length == 1, | ||||
|                       form = line_item_form.form %} | ||||
| @@ -95,7 +95,7 @@ First written: 2023/2/25 | ||||
|           </div> | ||||
|  | ||||
|           <div> | ||||
|             <button id="accounting-currency-{{ currency_index }}-credit-add-line-item" class="btn btn-primary" type="button" data-currency-index="{{ currency_index }}" data-side="credit" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> | ||||
|             <button id="accounting-currency-{{ currency_index }}-credit-add-line-item" class="btn btn-primary" type="button" data-currency-index="{{ currency_index }}" data-debit-credit="credit" data-bs-toggle="modal" data-bs-target="#accounting-line-item-editor-modal"> | ||||
|               <i class="fas fa-plus"></i> | ||||
|               {{ A_("New") }} | ||||
|             </button> | ||||
|   | ||||
| @@ -57,11 +57,11 @@ First written: 2023/2/25 | ||||
|   {% with description_editor = form.description_editor.credit %} | ||||
|     {% include "accounting/voucher/include/description-editor-modal.html" %} | ||||
|   {% endwith %} | ||||
|   {% with side = "debit", | ||||
|   {% with debit_credit = "debit", | ||||
|           account_options = form.debit_account_options %} | ||||
|     {% include "accounting/voucher/include/account-selector-modal.html" %} | ||||
|   {% endwith %} | ||||
|   {% with side = "credit", | ||||
|   {% with debit_credit = "credit", | ||||
|           account_options = form.credit_account_options %} | ||||
|     {% include "accounting/voucher/include/account-selector-modal.html" %} | ||||
|   {% endwith %} | ||||
|   | ||||
| @@ -53,9 +53,9 @@ class OriginalLineItemExists: | ||||
|                 "The original line item does not exist.")) | ||||
|  | ||||
|  | ||||
| class OriginalLineItemOppositeSide: | ||||
| class OriginalLineItemOppositeDebitCredit: | ||||
|     """The validator to check if the original line item is on the opposite | ||||
|     side.""" | ||||
|     debit or credit.""" | ||||
|  | ||||
|     def __call__(self, form: FlaskForm, field: IntegerField) -> None: | ||||
|         if field.data is None: | ||||
| @@ -71,7 +71,7 @@ class OriginalLineItemOppositeSide: | ||||
|                 and not original_line_item.is_debit: | ||||
|             return | ||||
|         raise ValidationError(lazy_gettext( | ||||
|             "The original line item is on the same side.")) | ||||
|             "The original line item is on the same debit or credit.")) | ||||
|  | ||||
|  | ||||
| class OriginalLineItemNeedOffset: | ||||
| @@ -180,7 +180,7 @@ class KeepAccountWhenHavingOffset: | ||||
|  | ||||
| class NotStartPayableFromDebit: | ||||
|     """The validator to check that a payable line item does not start from | ||||
|     the debit side.""" | ||||
|     debit.""" | ||||
|  | ||||
|     def __call__(self, form: FlaskForm, field: StringField) -> None: | ||||
|         assert isinstance(form, DebitLineItemForm) | ||||
| @@ -191,12 +191,12 @@ class NotStartPayableFromDebit: | ||||
|         account: Account | None = Account.find_by_code(field.data) | ||||
|         if account is not None and account.is_need_offset: | ||||
|             raise ValidationError(lazy_gettext( | ||||
|                 "A payable line item cannot start from the debit side.")) | ||||
|                 "A payable line item cannot start from debit.")) | ||||
|  | ||||
|  | ||||
| class NotStartReceivableFromCredit: | ||||
|     """The validator to check that a receivable line item does not start | ||||
|     from the credit side.""" | ||||
|     from credit.""" | ||||
|  | ||||
|     def __call__(self, form: FlaskForm, field: StringField) -> None: | ||||
|         assert isinstance(form, CreditLineItemForm) | ||||
| @@ -207,7 +207,7 @@ class NotStartReceivableFromCredit: | ||||
|         account: Account | None = Account.find_by_code(field.data) | ||||
|         if account is not None and account.is_need_offset: | ||||
|             raise ValidationError(lazy_gettext( | ||||
|                 "A receivable line item cannot start from the credit side.")) | ||||
|                 "A receivable line item cannot start from credit.")) | ||||
|  | ||||
|  | ||||
| class PositiveAmount: | ||||
| @@ -439,7 +439,7 @@ class DebitLineItemForm(LineItemForm): | ||||
|     original_line_item_id = IntegerField( | ||||
|         validators=[Optional(), | ||||
|                     OriginalLineItemExists(), | ||||
|                     OriginalLineItemOppositeSide(), | ||||
|                     OriginalLineItemOppositeDebitCredit(), | ||||
|                     OriginalLineItemNeedOffset(), | ||||
|                     OriginalLineItemNotOffset()]) | ||||
|     """The ID of the original line item.""" | ||||
| @@ -489,7 +489,7 @@ class CreditLineItemForm(LineItemForm): | ||||
|     original_line_item_id = IntegerField( | ||||
|         validators=[Optional(), | ||||
|                     OriginalLineItemExists(), | ||||
|                     OriginalLineItemOppositeSide(), | ||||
|                     OriginalLineItemOppositeDebitCredit(), | ||||
|                     OriginalLineItemNeedOffset(), | ||||
|                     OriginalLineItemNotOffset()]) | ||||
|     """The ID of the original line item.""" | ||||
|   | ||||
| @@ -376,7 +376,7 @@ class LineItemCollector(t.Generic[T], ABC): | ||||
|  | ||||
|     def _make_cash_line_item(self, forms: list[LineItemForm], is_debit: bool, | ||||
|                              currency_code: str, no: int) -> None: | ||||
|         """Composes the cash line item at the other side of the cash | ||||
|         """Composes the cash line item at the other debit or credit of the cash | ||||
|         voucher. | ||||
|  | ||||
|         :param forms: The line item forms in the same currency. | ||||
|   | ||||
| @@ -143,16 +143,16 @@ class DescriptionType: | ||||
|         return sorted(self.__tag_dict.values(), key=lambda x: -x.freq) | ||||
|  | ||||
|  | ||||
| class DescriptionSide: | ||||
|     """A description side""" | ||||
| class DescriptionDebitCredit: | ||||
|     """The description on debit or credit.""" | ||||
|  | ||||
|     def __init__(self, side_id: t.Literal["debit", "credit"]): | ||||
|         """Constructs a description side. | ||||
|     def __init__(self, debit_credit: t.Literal["debit", "credit"]): | ||||
|         """Constructs the description on debit or credit. | ||||
|  | ||||
|         :param side_id: The side ID, either "debit" or "credit". | ||||
|         :param debit_credit: Either "debit" or "credit". | ||||
|         """ | ||||
|         self.side: t.Literal["debit", "credit"] = side_id | ||||
|         """The side.""" | ||||
|         self.debit_credit: t.Literal["debit", "credit"] = debit_credit | ||||
|         """Either debit or credit.""" | ||||
|         self.general: DescriptionType = DescriptionType("general") | ||||
|         """The general tags.""" | ||||
|         self.travel: DescriptionType = DescriptionType("travel") | ||||
| @@ -179,7 +179,7 @@ class DescriptionSide: | ||||
|     @property | ||||
|     def accounts(self) -> list[DescriptionAccount]: | ||||
|         """Returns the suggested accounts of all tags in the description editor | ||||
|         in the side, in their frequency order. | ||||
|         in debit or credit, in their frequency order. | ||||
|  | ||||
|         :return: The suggested accounts of all tags, in their frequency order. | ||||
|         """ | ||||
| @@ -202,12 +202,12 @@ class DescriptionEditor: | ||||
|  | ||||
|     def __init__(self): | ||||
|         """Constructs the description editor.""" | ||||
|         self.debit: DescriptionSide = DescriptionSide("debit") | ||||
|         self.debit: DescriptionDebitCredit = DescriptionDebitCredit("debit") | ||||
|         """The debit tags.""" | ||||
|         self.credit: DescriptionSide = DescriptionSide("credit") | ||||
|         self.credit: DescriptionDebitCredit = DescriptionDebitCredit("credit") | ||||
|         """The credit tags.""" | ||||
|         side: sa.Label = sa.case((VoucherLineItem.is_debit, "debit"), | ||||
|                                  else_="credit").label("side") | ||||
|         debit_credit: sa.Label = sa.case((VoucherLineItem.is_debit, "debit"), | ||||
|                                          else_="credit").label("debit_credit") | ||||
|         tag_type: sa.Label = sa.case( | ||||
|             (VoucherLineItem.description.like("_%—_%—_%→_%"), "bus"), | ||||
|             (sa.or_(VoucherLineItem.description.like("_%—_%→_%"), | ||||
| @@ -215,21 +215,22 @@ class DescriptionEditor: | ||||
|             else_="general").label("tag_type") | ||||
|         tag: sa.Label = get_prefix(VoucherLineItem.description, "—")\ | ||||
|             .label("tag") | ||||
|         select: sa.Select = sa.Select(side, tag_type, tag, | ||||
|         select: sa.Select = sa.Select(debit_credit, tag_type, tag, | ||||
|                                       VoucherLineItem.account_id, | ||||
|                                       sa.func.count().label("freq"))\ | ||||
|             .filter(VoucherLineItem.description.is_not(None), | ||||
|                     VoucherLineItem.description.like("_%—_%"), | ||||
|                     VoucherLineItem.original_line_item_id.is_(None))\ | ||||
|             .group_by(side, tag_type, tag, VoucherLineItem.account_id) | ||||
|             .group_by(debit_credit, tag_type, tag, VoucherLineItem.account_id) | ||||
|         result: list[sa.Row] = db.session.execute(select).all() | ||||
|         accounts: dict[int, Account] \ | ||||
|             = {x.id: x for x in Account.query | ||||
|                .filter(Account.id.in_({x.account_id for x in result})).all()} | ||||
|         side_dict: dict[t.Literal["debit", "credit"], DescriptionSide] \ | ||||
|             = {x.side: x for x in {self.debit, self.credit}} | ||||
|         debit_credit_dict: dict[t.Literal["debit", "credit"], | ||||
|                                 DescriptionDebitCredit] \ | ||||
|             = {x.debit_credit: x for x in {self.debit, self.credit}} | ||||
|         for row in result: | ||||
|             side_dict[row.side].add_tag( | ||||
|             debit_credit_dict[row.debit_credit].add_tag( | ||||
|                 row.tag_type, row.tag, accounts[row.account_id], row.freq) | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -87,7 +87,7 @@ class VoucherOperator(ABC): | ||||
|         return render_template( | ||||
|             "accounting/voucher/include/form-line-item.html", | ||||
|             currency_index="CURRENCY_INDEX", | ||||
|             side="SIDE", | ||||
|             debit_credit="DEBIT_CREDIT", | ||||
|             line_item_index="LINE_ITEM_INDEX", | ||||
|             form=LineItemForm()) | ||||
|  | ||||
|   | ||||
| @@ -101,7 +101,7 @@ class OffsetTestCase(unittest.TestCase): | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.headers["Location"], create_uri) | ||||
|  | ||||
|         # The same side | ||||
|         # The same debit or credit | ||||
|         form = voucher_data.new_form(self.csrf_token) | ||||
|         form["currency-1-credit-1-original_line_item_id"] \ | ||||
|             = self.data.e_p_or1c.id | ||||
| @@ -210,7 +210,7 @@ class OffsetTestCase(unittest.TestCase): | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.headers["Location"], edit_uri) | ||||
|  | ||||
|         # The same side | ||||
|         # The same debit or credit | ||||
|         form = voucher_data.update_form(self.csrf_token) | ||||
|         form["currency-1-credit-1-original_line_item_id"] \ | ||||
|             = self.data.e_p_or1c.id | ||||
| @@ -417,7 +417,7 @@ class OffsetTestCase(unittest.TestCase): | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.headers["Location"], create_uri) | ||||
|  | ||||
|         # The same side | ||||
|         # The same debit or credit | ||||
|         form = voucher_data.new_form(self.csrf_token) | ||||
|         form["currency-1-debit-1-original_line_item_id"] \ | ||||
|             = self.data.e_r_or1d.id | ||||
| @@ -524,7 +524,7 @@ class OffsetTestCase(unittest.TestCase): | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.headers["Location"], edit_uri) | ||||
|  | ||||
|         # The same side | ||||
|         # The same debit or credit | ||||
|         form = voucher_data.update_form(self.csrf_token) | ||||
|         form["currency-1-debit-1-original_line_item_id"] \ | ||||
|             = self.data.e_r_or1d.id | ||||
|   | ||||
| @@ -231,7 +231,7 @@ class CashReceiptVoucherTestCase(unittest.TestCase): | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.headers["Location"], create_uri) | ||||
|  | ||||
|         # A receivable line item cannot start from the credit side | ||||
|         # A receivable line item cannot start from credit | ||||
|         form = self.__get_add_form() | ||||
|         key: str = [x for x in form.keys() | ||||
|                     if x.endswith("-account_code") and "-credit-" in x][0] | ||||
| @@ -391,7 +391,7 @@ class CashReceiptVoucherTestCase(unittest.TestCase): | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.headers["Location"], edit_uri) | ||||
|  | ||||
|         # A receivable line item cannot start from the credit side | ||||
|         # A receivable line item cannot start from credit | ||||
|         form = self.__get_add_form() | ||||
|         key: str = [x for x in form.keys() | ||||
|                     if x.endswith("-account_code") and "-credit-" in x][0] | ||||
| @@ -803,7 +803,7 @@ class CashDisbursementVoucherTestCase(unittest.TestCase): | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.headers["Location"], create_uri) | ||||
|  | ||||
|         # A payable line item cannot start from the debit side | ||||
|         # A payable line item cannot start from debit | ||||
|         form = self.__get_add_form() | ||||
|         key: str = [x for x in form.keys() | ||||
|                     if x.endswith("-account_code") and "-debit-" in x][0] | ||||
| @@ -966,7 +966,7 @@ class CashDisbursementVoucherTestCase(unittest.TestCase): | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.headers["Location"], edit_uri) | ||||
|  | ||||
|         # A payable line item cannot start from the debit side | ||||
|         # A payable line item cannot start from debit | ||||
|         form = self.__get_add_form() | ||||
|         key: str = [x for x in form.keys() | ||||
|                     if x.endswith("-account_code") and "-debit-" in x][0] | ||||
| @@ -1398,7 +1398,7 @@ class TransferVoucherTestCase(unittest.TestCase): | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.headers["Location"], create_uri) | ||||
|  | ||||
|         # A receivable line item cannot start from the credit side | ||||
|         # A receivable line item cannot start from credit | ||||
|         form = self.__get_add_form() | ||||
|         key: str = [x for x in form.keys() | ||||
|                     if x.endswith("-account_code") and "-credit-" in x][0] | ||||
| @@ -1407,7 +1407,7 @@ class TransferVoucherTestCase(unittest.TestCase): | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.headers["Location"], create_uri) | ||||
|  | ||||
|         # A payable line item cannot start from the debit side | ||||
|         # A payable line item cannot start from debit | ||||
|         form = self.__get_add_form() | ||||
|         key: str = [x for x in form.keys() | ||||
|                     if x.endswith("-account_code") and "-debit-" in x][0] | ||||
| @@ -1597,7 +1597,7 @@ class TransferVoucherTestCase(unittest.TestCase): | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.headers["Location"], edit_uri) | ||||
|  | ||||
|         # A receivable line item cannot start from the credit side | ||||
|         # A receivable line item cannot start from credit | ||||
|         form = self.__get_add_form() | ||||
|         key: str = [x for x in form.keys() | ||||
|                     if x.endswith("-account_code") and "-credit-" in x][0] | ||||
| @@ -1606,7 +1606,7 @@ class TransferVoucherTestCase(unittest.TestCase): | ||||
|         self.assertEqual(response.status_code, 302) | ||||
|         self.assertEqual(response.headers["Location"], edit_uri) | ||||
|  | ||||
|         # A payable line item cannot start from the debit side | ||||
|         # A payable line item cannot start from debit | ||||
|         form = self.__get_add_form() | ||||
|         key: str = [x for x in form.keys() | ||||
|                     if x.endswith("-account_code") and "-debit-" in x][0] | ||||
|   | ||||
| @@ -50,17 +50,17 @@ class VoucherLineItemData: | ||||
|         self.description: str = description | ||||
|         self.amount: Decimal = Decimal(amount) | ||||
|  | ||||
|     def form(self, prefix: str, side: str, index: int, is_update: bool) \ | ||||
|             -> dict[str, str]: | ||||
|     def form(self, prefix: str, debit_credit: str, index: int, | ||||
|              is_update: bool) -> dict[str, str]: | ||||
|         """Returns the line item as form data. | ||||
|  | ||||
|         :param prefix: The prefix of the form fields. | ||||
|         :param side: The side, either "debit" or "credit". | ||||
|         :param debit_credit: Either "debit" or "credit". | ||||
|         :param index: The line item index. | ||||
|         :param is_update: True for an update operation, or False otherwise | ||||
|         :return: The form data. | ||||
|         """ | ||||
|         prefix = f"{prefix}-{side}-{index}" | ||||
|         prefix = f"{prefix}-{debit_credit}-{index}" | ||||
|         form: dict[str, str] = {f"{prefix}-account_code": self.account, | ||||
|                                 f"{prefix}-description": self.description, | ||||
|                                 f"{prefix}-amount": str(self.amount)} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user