update closing balance in reconciliation statement page / dialog
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<v-dialog persistent min-width="320" width="auto" v-model="showState">
|
||||
<v-card>
|
||||
<v-toolbar :color="finalColor">
|
||||
<v-toolbar-title>{{ titleContent }}</v-toolbar-title>
|
||||
</v-toolbar>
|
||||
<v-card-text v-if="textContent" class="pa-4 pb-6">{{ textContent }}</v-card-text>
|
||||
<v-card-text>
|
||||
<v-form>
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<amount-input :persistent-placeholder="true"
|
||||
:currency="dialogOptions?.currency"
|
||||
:show-currency="!!dialogOptions?.currency"
|
||||
:label="inputLabelContent"
|
||||
:placeholder="inputPlaceholderContent"
|
||||
v-model="amount" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
<v-card-actions class="px-4 pb-4">
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="gray" @click="cancel">{{ tt('Cancel') }}</v-btn>
|
||||
<v-btn :color="finalColor" @click="confirm">{{ tt('OK') }}</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
interface AmountInputDialogOptions {
|
||||
title?: string;
|
||||
text?: string;
|
||||
textI18nOptions?: Record<string, unknown>;
|
||||
inputLabel?: string;
|
||||
inputPlaceholder?: string;
|
||||
color?: string;
|
||||
currency?: string;
|
||||
initAmount?: number;
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:show', value: boolean): void;
|
||||
}>();
|
||||
|
||||
const { tt } = useI18n();
|
||||
|
||||
const showState = ref<boolean>(false);
|
||||
const dialogOptions = ref<AmountInputDialogOptions | undefined>(undefined);
|
||||
const amount = ref<number>(0);
|
||||
|
||||
let resolveFunc: ((value: number) => void) | null = null;
|
||||
let rejectFunc: ((reason?: unknown) => void) | null = null;
|
||||
|
||||
const titleContent = computed<string>(() => dialogOptions.value?.title ? tt(dialogOptions.value.title) : tt('global.app.title'));
|
||||
const textContent = computed<string>(() => dialogOptions.value?.text ? tt(dialogOptions.value.text, dialogOptions.value.textI18nOptions ?? {}) : '');
|
||||
const inputLabelContent = computed<string | undefined>(() => dialogOptions.value?.inputLabel ? tt(dialogOptions.value.inputLabel) : undefined);
|
||||
const inputPlaceholderContent = computed<string | undefined>(() => dialogOptions.value?.inputPlaceholder ? tt(dialogOptions.value.inputPlaceholder) : undefined);
|
||||
const finalColor = computed<string>(() => dialogOptions.value?.color || 'primary');
|
||||
|
||||
function open(options: AmountInputDialogOptions): Promise<number> {
|
||||
showState.value = true;
|
||||
dialogOptions.value = options;
|
||||
amount.value = options.initAmount ?? 0;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
resolveFunc = resolve;
|
||||
rejectFunc = reject;
|
||||
});
|
||||
}
|
||||
|
||||
function confirm(): void {
|
||||
if (resolveFunc) {
|
||||
resolveFunc(amount.value);
|
||||
}
|
||||
|
||||
showState.value = false;
|
||||
emit('update:show', false);
|
||||
}
|
||||
|
||||
function cancel(): void {
|
||||
if (rejectFunc) {
|
||||
rejectFunc();
|
||||
}
|
||||
|
||||
showState.value = false;
|
||||
emit('update:show', false);
|
||||
}
|
||||
|
||||
watch(showState, newValue => {
|
||||
emit('update:show', newValue);
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
});
|
||||
</script>
|
||||
@@ -79,6 +79,7 @@ import ItemIcon from '@/components/desktop/ItemIcon.vue';
|
||||
import BtnVerticalGroup from '@/components/desktop/BtnVerticalGroup.vue';
|
||||
import NumberInput from '@/components/desktop/NumberInput.vue';
|
||||
import AmountInput from '@/components/desktop/AmountInput.vue';
|
||||
import AmountInputDialog from '@/components/desktop/AmountInputDialog.vue';
|
||||
import LanguageSelect from '@/components/desktop/LanguageSelect.vue';
|
||||
import LanguageSelectButton from '@/components/desktop/LanguageSelectButton.vue';
|
||||
import CurrencySelect from '@/components/desktop/CurrencySelect.vue';
|
||||
@@ -457,6 +458,7 @@ app.component('ItemIcon', ItemIcon);
|
||||
app.component('BtnVerticalGroup', BtnVerticalGroup);
|
||||
app.component('NumberInput', NumberInput);
|
||||
app.component('AmountInput', AmountInput);
|
||||
app.component('AmountInputDialog', AmountInputDialog);
|
||||
app.component('LanguageSelect', LanguageSelect);
|
||||
app.component('LanguageSelectButton', LanguageSelectButton);
|
||||
app.component('CurrencySelect', CurrencySelect);
|
||||
|
||||
@@ -1634,6 +1634,8 @@
|
||||
"Unable to delete this account": "Konto kann nicht gelöscht werden",
|
||||
"Unable to delete this sub-account": "Unable to delete this sub-account",
|
||||
"Reconciliation Statement": "Reconciliation Statement",
|
||||
"Update Closing Balance": "Update Closing Balance",
|
||||
"Please enter the new closing balance for the account": "Please enter the new closing balance for the account",
|
||||
"Transaction": "Transaktion",
|
||||
"Transactions": "Transaktionen",
|
||||
"Transaction Pictures": "Transaktionsbilder",
|
||||
|
||||
@@ -1634,6 +1634,8 @@
|
||||
"Unable to delete this account": "Unable to delete this account",
|
||||
"Unable to delete this sub-account": "Unable to delete this sub-account",
|
||||
"Reconciliation Statement": "Reconciliation Statement",
|
||||
"Update Closing Balance": "Update Closing Balance",
|
||||
"Please enter the new closing balance for the account": "Please enter the new closing balance for the account",
|
||||
"Transaction": "Transaction",
|
||||
"Transactions": "Transactions",
|
||||
"Transaction Pictures": "Transaction Pictures",
|
||||
|
||||
@@ -1634,6 +1634,8 @@
|
||||
"Unable to delete this account": "No se puede eliminar esta cuenta",
|
||||
"Unable to delete this sub-account": "Unable to delete this sub-account",
|
||||
"Reconciliation Statement": "Reconciliation Statement",
|
||||
"Update Closing Balance": "Update Closing Balance",
|
||||
"Please enter the new closing balance for the account": "Please enter the new closing balance for the account",
|
||||
"Transaction": "Transacción",
|
||||
"Transactions": "Transacciones",
|
||||
"Transaction Pictures": "Imágenes de transacciones",
|
||||
|
||||
@@ -1634,6 +1634,8 @@
|
||||
"Unable to delete this account": "Impossibile eliminare questo account",
|
||||
"Unable to delete this sub-account": "Impossibile eliminare questo sotto-account",
|
||||
"Reconciliation Statement": "Reconciliation Statement",
|
||||
"Update Closing Balance": "Update Closing Balance",
|
||||
"Please enter the new closing balance for the account": "Please enter the new closing balance for the account",
|
||||
"Transaction": "Transazione",
|
||||
"Transactions": "Transazioni",
|
||||
"Transaction Pictures": "Immagini transazione",
|
||||
|
||||
@@ -1634,6 +1634,8 @@
|
||||
"Unable to delete this account": "この口座を削除できません",
|
||||
"Unable to delete this sub-account": "Unable to delete this sub-account",
|
||||
"Reconciliation Statement": "Reconciliation Statement",
|
||||
"Update Closing Balance": "Update Closing Balance",
|
||||
"Please enter the new closing balance for the account": "Please enter the new closing balance for the account",
|
||||
"Transaction": "取引",
|
||||
"Transactions": "取引",
|
||||
"Transaction Pictures": "取引の写真",
|
||||
|
||||
@@ -1634,6 +1634,8 @@
|
||||
"Unable to delete this account": "Não foi possível deletar esta conta",
|
||||
"Unable to delete this sub-account": "Não foi possível deletar esta subconta",
|
||||
"Reconciliation Statement": "Reconciliation Statement",
|
||||
"Update Closing Balance": "Update Closing Balance",
|
||||
"Please enter the new closing balance for the account": "Please enter the new closing balance for the account",
|
||||
"Transaction": "Transação",
|
||||
"Transactions": "Transações",
|
||||
"Transaction Pictures": "Imagens das Transações",
|
||||
|
||||
@@ -1634,6 +1634,8 @@
|
||||
"Unable to delete this account": "Не удалось удалить этот счет",
|
||||
"Unable to delete this sub-account": "Unable to delete this sub-account",
|
||||
"Reconciliation Statement": "Reconciliation Statement",
|
||||
"Update Closing Balance": "Update Closing Balance",
|
||||
"Please enter the new closing balance for the account": "Please enter the new closing balance for the account",
|
||||
"Transaction": "Транзакция",
|
||||
"Transactions": "Транзакции",
|
||||
"Transaction Pictures": "Изображения транзакций",
|
||||
|
||||
@@ -1634,6 +1634,8 @@
|
||||
"Unable to delete this account": "Не вдалося видалити цей рахунок",
|
||||
"Unable to delete this sub-account": "Не вдалося видалити цей субрахунок",
|
||||
"Reconciliation Statement": "Reconciliation Statement",
|
||||
"Update Closing Balance": "Update Closing Balance",
|
||||
"Please enter the new closing balance for the account": "Please enter the new closing balance for the account",
|
||||
"Transaction": "Транзакція",
|
||||
"Transactions": "Транзакції",
|
||||
"Transaction Pictures": "Зображення транзакцій",
|
||||
|
||||
@@ -1634,6 +1634,8 @@
|
||||
"Unable to delete this account": "Không thể xóa tài khoản này",
|
||||
"Unable to delete this sub-account": "Unable to delete this sub-account",
|
||||
"Reconciliation Statement": "Reconciliation Statement",
|
||||
"Update Closing Balance": "Update Closing Balance",
|
||||
"Please enter the new closing balance for the account": "Please enter the new closing balance for the account",
|
||||
"Transaction": "Giao dịch",
|
||||
"Transactions": "Giao dịch",
|
||||
"Transaction Pictures": "Ảnh giao dịch",
|
||||
|
||||
@@ -1634,6 +1634,8 @@
|
||||
"Unable to delete this account": "无法删除该账户",
|
||||
"Unable to delete this sub-account": "无法删除该子账户",
|
||||
"Reconciliation Statement": "对账单",
|
||||
"Update Closing Balance": "更新期末余额",
|
||||
"Please enter the new closing balance for the account": "请输入账户的新期末余额",
|
||||
"Transaction": "交易",
|
||||
"Transactions": "交易",
|
||||
"Transaction Pictures": "交易图片",
|
||||
|
||||
@@ -1634,6 +1634,8 @@
|
||||
"Unable to delete this account": "無法刪除此帳戶",
|
||||
"Unable to delete this sub-account": "無法刪除此子帳戶",
|
||||
"Reconciliation Statement": "對帳單",
|
||||
"Update Closing Balance": "更新期末餘額",
|
||||
"Please enter the new closing balance for the account": "請輸入帳戶的新期末餘額",
|
||||
"Transaction": "交易",
|
||||
"Transactions": "交易",
|
||||
"Transaction Pictures": "交易圖片",
|
||||
|
||||
@@ -12,10 +12,14 @@
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent">
|
||||
<v-list>
|
||||
<v-list-item :prepend-icon="mdiReceiptTextPlusOutline"
|
||||
<v-list-item :prepend-icon="mdiInvoiceTextPlusOutline"
|
||||
:title="tt('Add Transaction')"
|
||||
@click="addTransaction()"></v-list-item>
|
||||
<v-divider class="my-2"/>
|
||||
<v-list-item :prepend-icon="mdiInvoiceTextEditOutline"
|
||||
:title="tt('Update Closing Balance')"
|
||||
@click="updateClosingBalance()"></v-list-item>
|
||||
<v-divider class="my-2"/>
|
||||
<v-list-item :prepend-icon="mdiComma"
|
||||
:disabled="!reconciliationStatements || !reconciliationStatements.transactions || reconciliationStatements.transactions.length < 1"
|
||||
@click="exportReconciliationStatements(KnownFileType.CSV)">
|
||||
@@ -189,6 +193,7 @@
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<amount-input-dialog ref="amountInputDialog" />
|
||||
<edit-dialog ref="editDialog" :type="TransactionEditPageType.Transaction" />
|
||||
|
||||
<snack-bar ref="snackbar" />
|
||||
@@ -197,6 +202,7 @@
|
||||
<script setup lang="ts">
|
||||
import PaginationButtons from '@/components/desktop/PaginationButtons.vue';
|
||||
import SnackBar from '@/components/desktop/SnackBar.vue';
|
||||
import AmountInputDialog from '@/components/desktop/AmountInputDialog.vue';
|
||||
import EditDialog from '@/views/desktop/transactions/list/dialogs/EditDialog.vue';
|
||||
import { TransactionEditPageType } from '@/views/base/transactions/TransactionEditPageBase.ts';
|
||||
|
||||
@@ -213,18 +219,21 @@ import { TransactionType } from '@/core/transaction.ts';
|
||||
import { KnownFileType } from '@/core/file.ts';
|
||||
import { Transaction, type TransactionReconciliationStatementResponseItem } from '@/models/transaction.ts';
|
||||
|
||||
import { getCurrentUnixTime } from '@/lib/datetime.ts';
|
||||
import { startDownloadFile } from '@/lib/ui/common.ts';
|
||||
|
||||
import {
|
||||
mdiArrowRight,
|
||||
mdiDotsVertical,
|
||||
mdiReceiptTextPlusOutline,
|
||||
mdiInvoiceTextPlusOutline,
|
||||
mdiInvoiceTextEditOutline,
|
||||
mdiComma,
|
||||
mdiKeyboardTab,
|
||||
mdiPencilBoxOutline
|
||||
} from '@mdi/js';
|
||||
|
||||
type SnackBarType = InstanceType<typeof SnackBar>;
|
||||
type AmountInputDialogType = InstanceType<typeof AmountInputDialog>;
|
||||
type EditDialogType = InstanceType<typeof EditDialog>;
|
||||
|
||||
interface ReconciliationStatementDialogTablePageOption {
|
||||
@@ -246,6 +255,7 @@ const {
|
||||
currentTimezoneOffsetMinutes,
|
||||
allAccountsMap,
|
||||
allCategoriesMap,
|
||||
currentAccountCurrency,
|
||||
isCurrentLiabilityAccount,
|
||||
exportFileName,
|
||||
displayStartDateTime,
|
||||
@@ -267,6 +277,7 @@ const accountsStore = useAccountsStore();
|
||||
const transactionCategoriesStore = useTransactionCategoriesStore();
|
||||
const transactionsStore = useTransactionsStore();
|
||||
|
||||
const amountInputDialog = useTemplateRef<AmountInputDialogType>('amountInputDialog');
|
||||
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
||||
const editDialog = useTemplateRef<EditDialogType>('editDialog');
|
||||
|
||||
@@ -404,6 +415,65 @@ function addTransaction(): void {
|
||||
});
|
||||
}
|
||||
|
||||
function updateClosingBalance(): void {
|
||||
let currentClosingBalance = reconciliationStatements.value?.closingBalance ?? 0;
|
||||
|
||||
if (isCurrentLiabilityAccount.value) {
|
||||
currentClosingBalance = -currentClosingBalance;
|
||||
}
|
||||
|
||||
amountInputDialog.value?.open({
|
||||
text: tt('Please enter the new closing balance for the account'),
|
||||
inputLabel: tt('Closing Balance'),
|
||||
inputPlaceholder: tt('Closing Balance'),
|
||||
currency: currentAccountCurrency.value,
|
||||
initAmount: currentClosingBalance
|
||||
}).then(newClosingBalance => {
|
||||
if (!newClosingBalance) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentUnixTime = getCurrentUnixTime();
|
||||
let setTransactionTime = false;
|
||||
let newTransactionTime: number | undefined = undefined;
|
||||
|
||||
if (endTime.value < currentUnixTime) {
|
||||
setTransactionTime = true;
|
||||
newTransactionTime = endTime.value;
|
||||
} else if (currentUnixTime < startTime.value) {
|
||||
setTransactionTime = true;
|
||||
newTransactionTime = startTime.value;
|
||||
}
|
||||
|
||||
let newTransactionType: TransactionType = isCurrentLiabilityAccount.value ? TransactionType.Expense : TransactionType.Income;
|
||||
let newTransactionAmount: number = newClosingBalance - currentClosingBalance;
|
||||
|
||||
if (newTransactionAmount < 0) {
|
||||
newTransactionType = isCurrentLiabilityAccount.value ? TransactionType.Income : TransactionType.Expense;
|
||||
newTransactionAmount = -newTransactionAmount;
|
||||
}
|
||||
|
||||
editDialog.value?.open({
|
||||
time: newTransactionTime,
|
||||
type: newTransactionType,
|
||||
amount: newTransactionAmount,
|
||||
accountId: accountId.value,
|
||||
setAmount: true,
|
||||
setTransactionTime: setTransactionTime
|
||||
}).then(result => {
|
||||
if (result && result.message) {
|
||||
snackbar.value?.showMessage(result.message);
|
||||
}
|
||||
|
||||
reload();
|
||||
}).catch(error => {
|
||||
if (error) {
|
||||
snackbar.value?.showError(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function exportReconciliationStatements(fileType: KnownFileType): void {
|
||||
if (!reconciliationStatements.value || !reconciliationStatements.value.transactions || reconciliationStatements.value.transactions.length < 1) {
|
||||
return;
|
||||
|
||||
@@ -497,6 +497,7 @@ import { TransactionTemplate } from '@/models/transaction_template.ts';
|
||||
import type { TransactionPictureInfoBasicResponse } from '@/models/transaction_picture_info.ts';
|
||||
import { Transaction } from '@/models/transaction.ts';
|
||||
|
||||
import { isDefined } from '@/lib/common.ts';
|
||||
import {
|
||||
getTimezoneOffsetMinutes,
|
||||
getCurrentUnixTime
|
||||
@@ -537,6 +538,9 @@ export interface TransactionEditOptions extends SetTransactionOptions {
|
||||
template?: TransactionTemplate;
|
||||
currentTransaction?: Transaction;
|
||||
currentTemplate?: TransactionTemplate;
|
||||
time?: number;
|
||||
setAmount?: boolean;
|
||||
setTransactionTime?: boolean;
|
||||
}
|
||||
|
||||
interface TransactionEditResponse {
|
||||
@@ -816,6 +820,14 @@ function open(options: TransactionEditOptions): Promise<TransactionEditResponse
|
||||
(transaction.value as TransactionTemplate).fillFrom(template);
|
||||
} else {
|
||||
setTransaction(null, options, true, true);
|
||||
|
||||
if (options.setAmount && isDefined(options.amount)) {
|
||||
transaction.value.sourceAmount = options.amount;
|
||||
}
|
||||
|
||||
if (options.setTransactionTime && isDefined(options.time)) {
|
||||
transaction.value.time = options.time;
|
||||
}
|
||||
}
|
||||
|
||||
loading.value = false;
|
||||
|
||||
Reference in New Issue
Block a user