account edit page displays the debt amount instead of the balance for credit card and debt accounts

This commit is contained in:
MaysWind
2025-02-11 00:45:23 +08:00
parent 18a6d25ed6
commit ab58109e5e
12 changed files with 133 additions and 28 deletions
+30 -3
View File
@@ -53,6 +53,7 @@ const props = defineProps<{
readonly?: boolean; readonly?: boolean;
hide?: boolean; hide?: boolean;
enableRules?: boolean; enableRules?: boolean;
flipNegative?: boolean;
modelValue: number; modelValue: number;
}>(); }>();
@@ -90,7 +91,7 @@ const rules = [
} }
]; ];
const currentValue = ref<string>(getFormattedValue(props.modelValue)); const currentValue = ref<string>(getInitedFormattedValue(props.modelValue, props.flipNegative));
const prependText = computed<string | undefined>(() => { const prependText = computed<string | undefined>(() => {
if (!props.currency || !props.showCurrency) { if (!props.currency || !props.showCurrency) {
@@ -292,6 +293,14 @@ function getValidFormattedValue(value: number, textualValue: string, hasDecimalS
return textualValue; return textualValue;
} }
function getInitedFormattedValue(value: number, flipNegative?: boolean): string {
if (flipNegative) {
value = -value;
}
return getFormattedValue(value);
}
function getFormattedValue(value: number): string { function getFormattedValue(value: number): string {
if (!Number.isNaN(value) && Number.isFinite(value)) { if (!Number.isNaN(value) && Number.isFinite(value)) {
const digitGroupingSymbol = getCurrentDigitGroupingSymbol(); const digitGroupingSymbol = getCurrentDigitGroupingSymbol();
@@ -309,7 +318,15 @@ function getDisplayCurrencyPrependAndAppendText(): CurrencyPrependAndAppendText
} }
watch(() => props.currency, () => { watch(() => props.currency, () => {
const newStringValue = getFormattedValue(props.modelValue); const newStringValue = getInitedFormattedValue(props.modelValue, props.flipNegative);
if (!(newStringValue === '0' && currentValue.value === '')) {
currentValue.value = newStringValue;
}
});
watch(() => props.flipNegative, (newValue) => {
const newStringValue = getInitedFormattedValue(props.modelValue, newValue);
if (!(newStringValue === '0' && currentValue.value === '')) { if (!(newStringValue === '0' && currentValue.value === '')) {
currentValue.value = newStringValue; currentValue.value = newStringValue;
@@ -317,6 +334,10 @@ watch(() => props.currency, () => {
}); });
watch(() => props.modelValue, (newValue) => { watch(() => props.modelValue, (newValue) => {
if (props.flipNegative) {
newValue = -newValue;
}
const numericCurrentValue = parseAmount(currentValue.value); const numericCurrentValue = parseAmount(currentValue.value);
if (newValue !== numericCurrentValue) { if (newValue !== numericCurrentValue) {
@@ -346,7 +367,13 @@ watch(currentValue, (newValue) => {
if (finalValue !== newValue) { if (finalValue !== newValue) {
currentValue.value = finalValue; currentValue.value = finalValue;
} else { } else {
emit('update:modelValue', parseAmount(finalValue)); let value: number = parseAmount(finalValue);
if (props.flipNegative) {
value = -value;
}
emit('update:modelValue', value);
} }
}); });
</script> </script>
+22 -5
View File
@@ -66,7 +66,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue'; import { ref, computed, watch } from 'vue';
import { useI18n } from '@/locales/helpers.ts'; import { useI18n } from '@/locales/helpers.ts';
import { useI18nUIComponents } from '@/lib/ui/mobile.ts'; import { useI18nUIComponents } from '@/lib/ui/mobile.ts';
@@ -75,10 +75,11 @@ import { ALL_CURRENCIES } from '@/consts/currency.ts';
import { isString, isNumber, removeAll } from '@/lib/common.ts'; import { isString, isNumber, removeAll } from '@/lib/common.ts';
const props = defineProps<{ const props = defineProps<{
modelValue: number | string; modelValue: number;
minValue?: number; minValue?: number;
maxValue?: number; maxValue?: number;
currency?: string; currency?: string;
flipNegative?: boolean;
show: boolean; show: boolean;
}>(); }>();
@@ -99,7 +100,7 @@ const { showToast } = useI18nUIComponents();
const previousValue = ref<string>(''); const previousValue = ref<string>('');
const currentSymbol = ref<string>(''); const currentSymbol = ref<string>('');
const currentValue = ref<string>(getStringValue(props.modelValue)); const currentValue = ref<string>(getInitedStringValue(props.modelValue, props.flipNegative));
const decimalSeparator = computed<string>(() => getCurrentDecimalSeparator()); const decimalSeparator = computed<string>(() => getCurrentDecimalSeparator());
@@ -140,6 +141,14 @@ const confirmText = computed<string>(() => {
} }
}); });
function getInitedStringValue(value: number, flipNegative?: boolean): string {
if (flipNegative) {
value = -value;
}
return getStringValue(value);
}
function getStringValue(value: number | string): string { function getStringValue(value: number | string): string {
if (!isNumber(value) && !isString(value)) { if (!isNumber(value) && !isString(value)) {
return ''; return '';
@@ -333,7 +342,11 @@ function confirm(): boolean {
return true; return true;
} else { } else {
const value = parseAmount(currentValue.value); let value: number = parseAmount(currentValue.value);
if (props.flipNegative) {
value = -value;
}
emit('update:modelValue', value); emit('update:modelValue', value);
close(); close();
@@ -347,12 +360,16 @@ function close(): void {
} }
function onSheetOpen(): void { function onSheetOpen(): void {
currentValue.value = getStringValue(props.modelValue); currentValue.value = getInitedStringValue(props.modelValue, props.flipNegative);
} }
function onSheetClosed(): void { function onSheetClosed(): void {
close(); close();
} }
watch(() => props.flipNegative, (newValue) => {
currentValue.value = getInitedStringValue(props.modelValue, newValue);
});
</script> </script>
<style> <style>
+14 -10
View File
@@ -25,27 +25,31 @@ export class AccountCategory implements TypeAndName {
private static readonly allInstances: AccountCategory[] = []; private static readonly allInstances: AccountCategory[] = [];
private static readonly allInstancesByType: Record<number, AccountCategory> = {}; private static readonly allInstancesByType: Record<number, AccountCategory> = {};
public static readonly Cash = new AccountCategory(1, 1, 'Cash', '1'); public static readonly Cash = new AccountCategory(1, 1, 'Cash', true, false, '1');
public static readonly CheckingAccount = new AccountCategory(2, 2, 'Checking Account', '100'); public static readonly CheckingAccount = new AccountCategory(2, 2, 'Checking Account', true, false, '100');
public static readonly SavingsAccount = new AccountCategory(8, 3, 'Savings Account', '100'); public static readonly SavingsAccount = new AccountCategory(8, 3, 'Savings Account', true, false, '100');
public static readonly CreditCard = new AccountCategory(3, 4, 'Credit Card', '100'); public static readonly CreditCard = new AccountCategory(3, 4, 'Credit Card', false, true, '100');
public static readonly VirtualAccount = new AccountCategory(4, 5, 'Virtual Account', '500'); public static readonly VirtualAccount = new AccountCategory(4, 5, 'Virtual Account', true, false, '500');
public static readonly DebtAccount = new AccountCategory(5, 6, 'Debt Account', '600'); public static readonly DebtAccount = new AccountCategory(5, 6, 'Debt Account', false, true, '600');
public static readonly Receivables = new AccountCategory(6, 7, 'Receivables', '700'); public static readonly Receivables = new AccountCategory(6, 7, 'Receivables', true, false, '700');
public static readonly CertificateOfDeposit = new AccountCategory(9, 8, 'Certificate of Deposit', '110'); public static readonly CertificateOfDeposit = new AccountCategory(9, 8, 'Certificate of Deposit', true, false, '110');
public static readonly InvestmentAccount = new AccountCategory(7, 9, 'Investment Account', '800'); public static readonly InvestmentAccount = new AccountCategory(7, 9, 'Investment Account', true, false, '800');
public static readonly Default = AccountCategory.Cash; public static readonly Default = AccountCategory.Cash;
public readonly type: number; public readonly type: number;
public readonly displayOrder: number; public readonly displayOrder: number;
public readonly name: string; public readonly name: string;
public readonly isAsset: boolean;
public readonly isLiability: boolean
public readonly defaultAccountIconId: string; public readonly defaultAccountIconId: string;
private constructor(type: number, displayOrder: number, name: string, defaultAccountIconId: string) { private constructor(type: number, displayOrder: number, name: string, isAsset: boolean, isLiability: boolean, defaultAccountIconId: string) {
this.type = type; this.type = type;
this.displayOrder = displayOrder; this.displayOrder = displayOrder;
this.name = name; this.name = name;
this.isAsset = isAsset;
this.isLiability = isLiability;
this.defaultAccountIconId = defaultAccountIconId; this.defaultAccountIconId = defaultAccountIconId;
AccountCategory.allInstances.push(this); AccountCategory.allInstances.push(this);
+2
View File
@@ -1475,7 +1475,9 @@
"Sub-account Color": "Teilkontofarbe", "Sub-account Color": "Teilkontofarbe",
"Currency": "Währung", "Currency": "Währung",
"Account Balance": "Kontostand", "Account Balance": "Kontostand",
"Account Outstanding Balance": "Account Outstanding Balance",
"Sub-account Balance": "Teilkontostand", "Sub-account Balance": "Teilkontostand",
"Sub-account Outstanding Balance": "Sub-account Outstanding Balance",
"Balance Time": "Saldozeit", "Balance Time": "Saldozeit",
"Sub-account Balance Time": "Teilkontosaldozeit", "Sub-account Balance Time": "Teilkontosaldozeit",
"Statement Date": "Abrechnungsdatum", "Statement Date": "Abrechnungsdatum",
+2
View File
@@ -1475,7 +1475,9 @@
"Sub-account Color": "Sub-account Color", "Sub-account Color": "Sub-account Color",
"Currency": "Currency", "Currency": "Currency",
"Account Balance": "Account Balance", "Account Balance": "Account Balance",
"Account Outstanding Balance": "Account Outstanding Balance",
"Sub-account Balance": "Sub-account Balance", "Sub-account Balance": "Sub-account Balance",
"Sub-account Outstanding Balance": "Sub-account Outstanding Balance",
"Balance Time": "Balance Time", "Balance Time": "Balance Time",
"Sub-account Balance Time": "Sub-account Balance Time", "Sub-account Balance Time": "Sub-account Balance Time",
"Statement Date": "Statement Date", "Statement Date": "Statement Date",
+2
View File
@@ -1475,7 +1475,9 @@
"Sub-account Color": "Color de subcuenta", "Sub-account Color": "Color de subcuenta",
"Currency": "Divisa", "Currency": "Divisa",
"Account Balance": "Balance de cuenta", "Account Balance": "Balance de cuenta",
"Account Outstanding Balance": "Account Outstanding Balance",
"Sub-account Balance": "Balance de subcuenta", "Sub-account Balance": "Balance de subcuenta",
"Sub-account Outstanding Balance": "Sub-account Outstanding Balance",
"Balance Time": "Fecha del balance", "Balance Time": "Fecha del balance",
"Sub-account Balance Time": "Fecha del balance de la subcuenta", "Sub-account Balance Time": "Fecha del balance de la subcuenta",
"Statement Date": "Fecha de declaración", "Statement Date": "Fecha de declaración",
+2
View File
@@ -1475,7 +1475,9 @@
"Sub-account Color": "Цвет субсчета", "Sub-account Color": "Цвет субсчета",
"Currency": "Валюта", "Currency": "Валюта",
"Account Balance": "Баланс счета", "Account Balance": "Баланс счета",
"Account Outstanding Balance": "Account Outstanding Balance",
"Sub-account Balance": "Баланс субсчета", "Sub-account Balance": "Баланс субсчета",
"Sub-account Outstanding Balance": "Sub-account Outstanding Balance",
"Balance Time": "Время баланса", "Balance Time": "Время баланса",
"Sub-account Balance Time": "Время баланса субсчета", "Sub-account Balance Time": "Время баланса субсчета",
"Statement Date": "Дата выписки", "Statement Date": "Дата выписки",
+2
View File
@@ -1475,7 +1475,9 @@
"Sub-account Color": "Màu sắc tài khoản phụ", "Sub-account Color": "Màu sắc tài khoản phụ",
"Currency": "Tiền tệ", "Currency": "Tiền tệ",
"Account Balance": "Số dư tài khoản", "Account Balance": "Số dư tài khoản",
"Account Outstanding Balance": "Account Outstanding Balance",
"Sub-account Balance": "Số dư tài khoản phụ", "Sub-account Balance": "Số dư tài khoản phụ",
"Sub-account Outstanding Balance": "Sub-account Outstanding Balance",
"Balance Time": "Thời gian số dư", "Balance Time": "Thời gian số dư",
"Sub-account Balance Time": "Thời gian số dư tài khoản phụ", "Sub-account Balance Time": "Thời gian số dư tài khoản phụ",
"Statement Date": "Statement Date", "Statement Date": "Statement Date",
+2
View File
@@ -1475,7 +1475,9 @@
"Sub-account Color": "子账户颜色", "Sub-account Color": "子账户颜色",
"Currency": "货币", "Currency": "货币",
"Account Balance": "账户余额", "Account Balance": "账户余额",
"Account Outstanding Balance": "账户未清余额",
"Sub-account Balance": "子账户余额", "Sub-account Balance": "子账户余额",
"Sub-account Outstanding Balance": "子账户未清余额",
"Balance Time": "余额时间", "Balance Time": "余额时间",
"Sub-account Balance Time": "子账户余额时间", "Sub-account Balance Time": "子账户余额时间",
"Statement Date": "账单日", "Statement Date": "账单日",
+33 -4
View File
@@ -18,11 +18,12 @@ export class Account implements AccountInfoResponse {
public comment: string; public comment: string;
public creditCardStatementDate?: number; public creditCardStatementDate?: number;
public displayOrder: number; public displayOrder: number;
public isAsset?: boolean;
public isLiability?: boolean;
public visible: boolean; public visible: boolean;
public subAccounts?: Account[]; public subAccounts?: Account[];
private readonly _isAsset?: boolean;
private readonly _isLiability?: boolean;
protected constructor(id: string, name: string, parentId: string, category: number, type: number, icon: string, color: string, currency: string, balance: number, comment: string, displayOrder: number, visible: boolean, balanceTime?: number, creditCardStatementDate?: number, isAsset?: boolean, isLiability?: boolean, subAccounts?: Account[]) { protected constructor(id: string, name: string, parentId: string, category: number, type: number, icon: string, color: string, currency: string, balance: number, comment: string, displayOrder: number, visible: boolean, balanceTime?: number, creditCardStatementDate?: number, isAsset?: boolean, isLiability?: boolean, subAccounts?: Account[]) {
this.id = id; this.id = id;
this.name = name; this.name = name;
@@ -38,8 +39,8 @@ export class Account implements AccountInfoResponse {
this.displayOrder = displayOrder; this.displayOrder = displayOrder;
this.visible = visible; this.visible = visible;
this.creditCardStatementDate = creditCardStatementDate; this.creditCardStatementDate = creditCardStatementDate;
this.isAsset = isAsset; this._isAsset = isAsset;
this.isLiability = isLiability; this._isLiability = isLiability;
if (typeof(subAccounts) !== 'undefined') { if (typeof(subAccounts) !== 'undefined') {
this.subAccounts = subAccounts; this.subAccounts = subAccounts;
@@ -48,6 +49,34 @@ export class Account implements AccountInfoResponse {
} }
} }
public get isAsset(): boolean {
if (typeof(this._isAsset) !== 'undefined') {
return this._isAsset;
}
const accountCategory = AccountCategory.valueOf(this.category);
if (accountCategory) {
return accountCategory.isAsset;
}
return false;
}
public get isLiability(): boolean {
if (typeof(this._isLiability) !== 'undefined') {
return this._isLiability;
}
const accountCategory = AccountCategory.valueOf(this.category);
if (accountCategory) {
return accountCategory.isLiability;
}
return false;
}
public get hidden(): boolean { public get hidden(): boolean {
return !this.visible; return !this.visible;
} }
@@ -146,8 +146,9 @@
:persistent-placeholder="true" :persistent-placeholder="true"
:currency="selectedAccount.currency" :currency="selectedAccount.currency"
:show-currency="true" :show-currency="true"
:label="currentAccountIndex < 0 ? tt('Account Balance') : tt('Sub-account Balance')" :flip-negative="account.isLiability"
:placeholder="currentAccountIndex < 0 ? tt('Account Balance') : tt('Sub-account Balance')" :label="accountAmountTitle"
:placeholder="accountAmountTitle"
v-model="selectedAccount.balance"/> v-model="selectedAccount.balance"/>
</v-col> </v-col>
<v-col cols="12" md="6" v-show="selectedAccount.balance" <v-col cols="12" md="6" v-show="selectedAccount.balance"
@@ -274,6 +275,14 @@ const selectedAccount = computed<Account>(() => {
return subAccounts.value[currentAccountIndex.value]; return subAccounts.value[currentAccountIndex.value];
}); });
const accountAmountTitle = computed<string>(() => {
if (currentAccountIndex.value < 0) {
return account.value.isLiability ? tt('Account Outstanding Balance') : tt('Account Balance');
} else {
return account.value.isLiability ? tt('Sub-account Outstanding Balance') : tt('Sub-account Balance');
}
});
let resolveFunc: ((value: AccountEditResponse) => void) | null = null; let resolveFunc: ((value: AccountEditResponse) => void) | null = null;
let rejectFunc: ((reason?: unknown) => void) | null = null; let rejectFunc: ((reason?: unknown) => void) | null = null;
+11 -4
View File
@@ -191,13 +191,14 @@
link="#" no-chevron link="#" no-chevron
class="list-item-with-header-and-title" class="list-item-with-header-and-title"
:class="{ 'disabled': editAccountId }" :class="{ 'disabled': editAccountId }"
:header="tt('Account Balance')" :header="account.isLiability ? tt('Account Outstanding Balance') : tt('Account Balance')"
:title="formatAmountWithCurrency(account.balance, account.currency)" :title="formatAccountDisplayBalance(account)"
@click="accountContext.showBalanceSheet = true" @click="accountContext.showBalanceSheet = true"
> >
<number-pad-sheet :min-value="TRANSACTION_MIN_AMOUNT" <number-pad-sheet :min-value="TRANSACTION_MIN_AMOUNT"
:max-value="TRANSACTION_MAX_AMOUNT" :max-value="TRANSACTION_MAX_AMOUNT"
:currency="account.currency" :currency="account.currency"
:flip-negative="account.isLiability"
v-model:show="accountContext.showBalanceSheet" v-model:show="accountContext.showBalanceSheet"
v-model="account.balance" v-model="account.balance"
></number-pad-sheet> ></number-pad-sheet>
@@ -419,13 +420,14 @@
link="#" no-chevron link="#" no-chevron
class="list-item-with-header-and-title" class="list-item-with-header-and-title"
:class="{ 'disabled': editAccountId }" :class="{ 'disabled': editAccountId }"
:header="tt('Sub-account Balance')" :header="account.isLiability ? tt('Sub-account Outstanding Balance') : tt('Sub-account Balance')"
:title="formatAmountWithCurrency(subAccount.balance, subAccount.currency)" :title="formatAccountDisplayBalance(subAccount)"
@click="subAccountContexts[idx].showBalanceSheet = true" @click="subAccountContexts[idx].showBalanceSheet = true"
> >
<number-pad-sheet :min-value="TRANSACTION_MIN_AMOUNT" <number-pad-sheet :min-value="TRANSACTION_MIN_AMOUNT"
:max-value="TRANSACTION_MAX_AMOUNT" :max-value="TRANSACTION_MAX_AMOUNT"
:currency="subAccount.currency" :currency="subAccount.currency"
:flip-negative="account.isLiability"
v-model:show="subAccountContexts[idx].showBalanceSheet" v-model:show="subAccountContexts[idx].showBalanceSheet"
v-model="subAccount.balance" v-model="subAccount.balance"
></number-pad-sheet> ></number-pad-sheet>
@@ -566,6 +568,11 @@ const showAccountTypeSheet = ref<boolean>(false);
const showMoreActionSheet = ref<boolean>(false); const showMoreActionSheet = ref<boolean>(false);
const showDeleteActionSheet = ref<boolean>(false); const showDeleteActionSheet = ref<boolean>(false);
function formatAccountDisplayBalance(selectedAccount: Account): string {
const balance = account.value.isLiability ? -selectedAccount.balance : selectedAccount.balance;
return formatAmountWithCurrency(balance, selectedAccount.currency);
}
function formatAccountBalanceDate(account: Account): string { function formatAccountBalanceDate(account: Account): string {
if (!isDefined(account.balanceTime)) { if (!isDefined(account.balanceTime)) {
return ''; return '';