diff --git a/src/lib/account.js b/src/lib/account.ts similarity index 68% rename from src/lib/account.js rename to src/lib/account.ts index 0f36f726..4735ea8b 100644 --- a/src/lib/account.js +++ b/src/lib/account.ts @@ -1,33 +1,19 @@ import { AccountType, AccountCategory } from '@/core/account.ts'; import { PARENT_ACCOUNT_CURRENCY_PLACEHOLDER } from '@/consts/currency.ts'; +import { type AccountBalance, type CategorizedAccount, type AccountCategoriesWithVisibleCount, Account } from '@/models/account.ts'; -export function setAccountModelByAnotherAccount(account, account2) { - account.id = account2.id; - account.category = account2.category; - account.type = account2.type; - account.name = account2.name; - account.icon = account2.icon; - account.color = account2.color; - account.currency = account2.currency; - account.balance = account2.balance; - account.balanceTime = account2.balanceTime; - account.comment = account2.comment; - account.creditCardStatementDate = account2.creditCardStatementDate; - account.visible = !account2.hidden; -} - -export function getAccountOrSubAccountId(account, subAccountId) { +export function getAccountOrSubAccountId(account: Account, subAccountId: string): string | null { if (account.type === AccountType.SingleAccount.type) { return account.id; } else if (account.type === AccountType.MultiSubAccounts.type && !subAccountId) { return account.id; } else if (account.type === AccountType.MultiSubAccounts.type && subAccountId) { - if (!account.subAccounts || !account.subAccounts.length) { + if (!account.childrenAccounts || !account.childrenAccounts.length) { return null; } - for (let i = 0; i < account.subAccounts.length; i++) { - const subAccount = account.subAccounts[i]; + for (let i = 0; i < account.childrenAccounts.length; i++) { + const subAccount = account.childrenAccounts[i]; if (subAccountId && subAccountId === subAccount.id) { return subAccount.id; @@ -40,18 +26,18 @@ export function getAccountOrSubAccountId(account, subAccountId) { } } -export function getAccountOrSubAccountComment(account, subAccountId) { +export function getAccountOrSubAccountComment(account: Account, subAccountId: string): string | null { if (account.type === AccountType.SingleAccount.type) { return account.comment; } else if (account.type === AccountType.MultiSubAccounts.type && !subAccountId) { return account.comment; } else if (account.type === AccountType.MultiSubAccounts.type && subAccountId) { - if (!account.subAccounts || !account.subAccounts.length) { + if (!account.childrenAccounts || !account.childrenAccounts.length) { return null; } - for (let i = 0; i < account.subAccounts.length; i++) { - const subAccount = account.subAccounts[i]; + for (let i = 0; i < account.childrenAccounts.length; i++) { + const subAccount = account.childrenAccounts[i]; if (subAccountId && subAccountId === subAccount.id) { return subAccount.comment; @@ -64,16 +50,16 @@ export function getAccountOrSubAccountComment(account, subAccountId) { } } -export function getSubAccountCurrencies(account, showHidden, subAccountId) { - if (!account.subAccounts || !account.subAccounts.length) { +export function getSubAccountCurrencies(account: Account, showHidden: boolean, subAccountId: string): string[] { + if (!account.childrenAccounts || !account.childrenAccounts.length) { return []; } - const subAccountCurrenciesMap = {}; - const subAccountCurrencies = []; + const subAccountCurrenciesMap: Record = {}; + const subAccountCurrencies: string[] = []; - for (let i = 0; i < account.subAccounts.length; i++) { - const subAccount = account.subAccounts[i]; + for (let i = 0; i < account.childrenAccounts.length; i++) { + const subAccount = account.childrenAccounts[i]; if (!showHidden && subAccount.hidden) { continue; @@ -92,8 +78,8 @@ export function getSubAccountCurrencies(account, showHidden, subAccountId) { return subAccountCurrencies; } -export function getCategorizedAccountsMap(allAccounts) { - const ret = {}; +export function getCategorizedAccountsMap(allAccounts: Account[]): Record { + const ret: Record = {}; for (let i = 0; i < allAccounts.length; i++) { const account = allAccounts[i]; @@ -120,8 +106,8 @@ export function getCategorizedAccountsMap(allAccounts) { return ret; } -export function getCategorizedAccounts(allAccounts) { - const ret = []; +export function getCategorizedAccounts(allAccounts: Account[]): CategorizedAccount[] { + const ret: CategorizedAccount[] = []; const allCategories = AccountCategory.values(); const categorizedAccounts = getCategorizedAccountsMap(allAccounts); @@ -139,8 +125,8 @@ export function getCategorizedAccounts(allAccounts) { return ret; } -export function getCategorizedAccountsWithVisibleCount(categorizedAccountsMap) { - const ret = []; +export function getCategorizedAccountsWithVisibleCount(categorizedAccountsMap: Record): AccountCategoriesWithVisibleCount[] { + const ret: AccountCategoriesWithVisibleCount[] = []; const allCategories = AccountCategory.values(); for (let i = 0; i < allCategories.length; i++) { @@ -151,9 +137,9 @@ export function getCategorizedAccountsWithVisibleCount(categorizedAccountsMap) { } const allAccounts = categorizedAccountsMap[accountCategory.type].accounts; - const allSubAccounts = {}; - const allVisibleSubAccountCounts = {}; - const allFirstVisibleSubAccountIndexes = {}; + const allSubAccounts: Record = {}; + const allVisibleSubAccountCounts: Record = {}; + const allFirstVisibleSubAccountIndexes: Record = {}; let allVisibleAccountCount = 0; let firstVisibleAccountIndex = -1; @@ -168,12 +154,12 @@ export function getCategorizedAccountsWithVisibleCount(categorizedAccountsMap) { } } - if (account.type === AccountType.MultiSubAccounts.type && account.subAccounts) { + if (account.type === AccountType.MultiSubAccounts.type && account.childrenAccounts) { let visibleSubAccountCount = 0; let firstVisibleSubAccountIndex = -1; - for (let k = 0; k < account.subAccounts.length; k++) { - const subAccount = account.subAccounts[k]; + for (let k = 0; k < account.childrenAccounts.length; k++) { + const subAccount = account.childrenAccounts[k]; if (!subAccount.hidden) { visibleSubAccountCount++; @@ -184,8 +170,8 @@ export function getCategorizedAccountsWithVisibleCount(categorizedAccountsMap) { } } - if (account.subAccounts.length > 0) { - allSubAccounts[account.id] = account.subAccounts; + if (account.childrenAccounts.length > 0) { + allSubAccounts[account.id] = account.childrenAccounts; allVisibleSubAccountCounts[account.id] = visibleSubAccountCount; allFirstVisibleSubAccountIndexes[account.id] = firstVisibleSubAccountIndex; } @@ -210,9 +196,9 @@ export function getCategorizedAccountsWithVisibleCount(categorizedAccountsMap) { return ret; } -export function getAllFilteredAccountsBalance(categorizedAccounts, accountFilter) { +export function getAllFilteredAccountsBalance(categorizedAccounts: CategorizedAccount[], accountFilter: (account: Account) => boolean): AccountBalance[] { const allAccountCategories = AccountCategory.values(); - const ret = []; + const ret: AccountBalance[] = []; for (let categoryIdx = 0; categoryIdx < allAccountCategories.length; categoryIdx++) { const accountCategory = allAccountCategories[categoryIdx]; @@ -231,13 +217,13 @@ export function getAllFilteredAccountsBalance(categorizedAccounts, accountFilter if (account.type === AccountType.SingleAccount.type) { ret.push({ balance: account.balance, - isAsset: account.isAsset, - isLiability: account.isLiability, + isAsset: !!account.isAsset, + isLiability: !!account.isLiability, currency: account.currency }); - } else if (account.type === AccountType.MultiSubAccounts.type && account.subAccounts) { - for (let subAccountIdx = 0; subAccountIdx < account.subAccounts.length; subAccountIdx++) { - const subAccount = account.subAccounts[subAccountIdx]; + } else if (account.type === AccountType.MultiSubAccounts.type && account.childrenAccounts) { + for (let subAccountIdx = 0; subAccountIdx < account.childrenAccounts.length; subAccountIdx++) { + const subAccount = account.childrenAccounts[subAccountIdx]; if (subAccount.hidden || !accountFilter(subAccount)) { continue; @@ -245,8 +231,8 @@ export function getAllFilteredAccountsBalance(categorizedAccounts, accountFilter ret.push({ balance: subAccount.balance, - isAsset: subAccount.isAsset, - isLiability: subAccount.isLiability, + isAsset: !!subAccount.isAsset, + isLiability: !!subAccount.isLiability, currency: subAccount.currency }); } @@ -257,14 +243,14 @@ export function getAllFilteredAccountsBalance(categorizedAccounts, accountFilter return ret; } -export function getFinalAccountIdsByFilteredAccountIds(allAccountsMap, filteredAccountIds) { +export function getFinalAccountIdsByFilteredAccountIds(allAccountsMap: Record, filteredAccountIds: Record): string { let finalAccountIds = ''; if (!allAccountsMap) { return finalAccountIds; } - for (let accountId in allAccountsMap) { + for (const accountId in allAccountsMap) { if (!Object.prototype.hasOwnProperty.call(allAccountsMap, accountId)) { continue; } @@ -285,19 +271,19 @@ export function getFinalAccountIdsByFilteredAccountIds(allAccountsMap, filteredA return finalAccountIds; } -export function getUnifiedSelectedAccountsCurrencyOrDefaultCurrency(allAccounts, selectedAccountIds, defaultCurrency) { +export function getUnifiedSelectedAccountsCurrencyOrDefaultCurrency(allAccountsMap: Record, selectedAccountIds: Record, defaultCurrency: string): string { if (!selectedAccountIds) { return defaultCurrency; } let accountCurrency = ''; - for (let accountId in selectedAccountIds) { + for (const accountId in selectedAccountIds) { if (!Object.prototype.hasOwnProperty.call(selectedAccountIds, accountId)) { continue; } - const account = allAccounts[accountId]; + const account = allAccountsMap[accountId]; if (account.currency === PARENT_ACCOUNT_CURRENCY_PLACEHOLDER) { continue; @@ -317,23 +303,23 @@ export function getUnifiedSelectedAccountsCurrencyOrDefaultCurrency(allAccounts, return defaultCurrency; } -export function selectAccountOrSubAccounts(filterAccountIds, account, value) { +export function selectAccountOrSubAccounts(filterAccountIds: Record, account: Account, value: boolean): void { if (account.type === AccountType.SingleAccount.type) { filterAccountIds[account.id] = value; } else if (account.type === AccountType.MultiSubAccounts.type) { - if (!account.subAccounts || !account.subAccounts.length) { + if (!account.childrenAccounts || !account.childrenAccounts.length) { return; } - for (let i = 0; i < account.subAccounts.length; i++) { - const subAccount = account.subAccounts[i]; + for (let i = 0; i < account.childrenAccounts.length; i++) { + const subAccount = account.childrenAccounts[i]; filterAccountIds[subAccount.id] = value; } } } -export function selectAll(filterAccountIds, allAccountsMap) { - for (let accountId in filterAccountIds) { +export function selectAll(filterAccountIds: Record, allAccountsMap: Record): void { + for (const accountId in filterAccountIds) { if (!Object.prototype.hasOwnProperty.call(filterAccountIds, accountId)) { continue; } @@ -346,8 +332,8 @@ export function selectAll(filterAccountIds, allAccountsMap) { } } -export function selectNone(filterAccountIds, allAccountsMap) { - for (let accountId in filterAccountIds) { +export function selectNone(filterAccountIds: Record, allAccountsMap: Record): void { + for (const accountId in filterAccountIds) { if (!Object.prototype.hasOwnProperty.call(filterAccountIds, accountId)) { continue; } @@ -360,8 +346,8 @@ export function selectNone(filterAccountIds, allAccountsMap) { } } -export function selectInvert(filterAccountIds, allAccountsMap) { - for (let accountId in filterAccountIds) { +export function selectInvert(filterAccountIds: Record, allAccountsMap: Record): void { + for (const accountId in filterAccountIds) { if (!Object.prototype.hasOwnProperty.call(filterAccountIds, accountId)) { continue; } @@ -374,13 +360,13 @@ export function selectInvert(filterAccountIds, allAccountsMap) { } } -export function isAccountOrSubAccountsAllChecked(account, filterAccountIds) { - if (!account.subAccounts) { +export function isAccountOrSubAccountsAllChecked(account: Account, filterAccountIds: Record): boolean { + if (!account.childrenAccounts) { return !filterAccountIds[account.id]; } - for (let i = 0; i < account.subAccounts.length; i++) { - const subAccount = account.subAccounts[i]; + for (let i = 0; i < account.childrenAccounts.length; i++) { + const subAccount = account.childrenAccounts[i]; if (filterAccountIds[subAccount.id]) { return false; } @@ -389,24 +375,24 @@ export function isAccountOrSubAccountsAllChecked(account, filterAccountIds) { return true; } -export function isAccountOrSubAccountsHasButNotAllChecked(account, filterAccountIds) { - if (!account.subAccounts) { +export function isAccountOrSubAccountsHasButNotAllChecked(account: Account, filterAccountIds: Record): boolean { + if (!account.childrenAccounts) { return false; } let checkedCount = 0; - for (let i = 0; i < account.subAccounts.length; i++) { - const subAccount = account.subAccounts[i]; + for (let i = 0; i < account.childrenAccounts.length; i++) { + const subAccount = account.childrenAccounts[i]; if (!filterAccountIds[subAccount.id]) { checkedCount++; } } - return checkedCount > 0 && checkedCount < account.subAccounts.length; + return checkedCount > 0 && checkedCount < account.childrenAccounts.length; } -export function setAccountSuitableIcon(account, oldCategory, newCategory) { +export function setAccountSuitableIcon(account: Account, oldCategory: number, newCategory: number): void { const allCategories = AccountCategory.values(); for (let i = 0; i < allCategories.length; i++) { diff --git a/src/locales/helper.js b/src/locales/helper.js index 743decc6..6586eaad 100644 --- a/src/locales/helper.js +++ b/src/locales/helper.js @@ -58,7 +58,7 @@ import { import { getCategorizedAccountsMap, getAllFilteredAccountsBalance -} from '@/lib/account.js'; +} from '@/lib/account.ts'; import logger from '@/lib/logger.ts'; import services from '@/lib/services.ts'; diff --git a/src/models/account.ts b/src/models/account.ts index bafb1502..7a558a42 100644 --- a/src/models/account.ts +++ b/src/models/account.ts @@ -1,3 +1,222 @@ +import type { ColorValue } from '@/core/color.ts'; +import { AccountType, AccountCategory } from '@/core/account.ts'; +import { PARENT_ACCOUNT_CURRENCY_PLACEHOLDER } from '@/consts/currency.ts'; +import { DEFAULT_ACCOUNT_ICON_ID } from '@/consts/icon.ts'; +import { DEFAULT_ACCOUNT_COLOR } from '@/consts/color.ts'; + +export class Account implements AccountInfoResponse { + public id: string; + public name: string; + public parentId: string; + public category: number; + public type: number; + public icon: string; + public color: ColorValue; + public currency: string; + public balance: number; + public balanceTime?: number; + public comment: string; + public creditCardStatementDate?: number; + public displayOrder: number; + public isAsset?: boolean; + public isLiability?: boolean; + public visible: boolean; + public childrenAccounts?: Account[]; + + private 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, childrenAccounts?: Account[]) { + this.id = id; + this.name = name; + this.parentId = parentId; + this.category = category; + this.type = type; + this.icon = icon; + this.color = color; + this.currency = currency; + this.balance = balance; + this.balanceTime = balanceTime; + this.comment = comment; + this.displayOrder = displayOrder; + this.visible = visible; + this.creditCardStatementDate = creditCardStatementDate; + this.isAsset = isAsset; + this.isLiability = isLiability; + + if (typeof(childrenAccounts) !== 'undefined') { + this.childrenAccounts = childrenAccounts; + } else { + this.childrenAccounts = undefined; + } + } + + get hidden(): boolean { + return !this.visible; + } + + get subAccounts(): AccountInfoResponse[] | undefined { + if (typeof(this.childrenAccounts) === 'undefined') { + return undefined; + } + + const ret: AccountInfoResponse[] = []; + + if (this.childrenAccounts) { + for (const subCategory of this.childrenAccounts) { + ret.push(subCategory); + } + } + + return ret; + } + + public from(other: Account): void { + this.id = other.id; + this.category = other.category; + this.type = other.type; + this.name = other.name; + this.icon = other.icon; + this.color = other.color; + this.currency = other.currency; + this.balance = other.balance; + this.balanceTime = other.balanceTime; + this.comment = other.comment; + this.creditCardStatementDate = other.creditCardStatementDate; + this.visible = other.visible; + } + + public toCreateRequest(clientSessionId: string, childrenAccounts?: Account[], parentAccount?: Account): AccountCreateRequest { + let subAccounts: AccountCreateRequest[] | undefined = undefined; + + if (this.type === AccountType.MultiSubAccounts.type) { + subAccounts = []; + + if (!childrenAccounts) { + childrenAccounts = this.childrenAccounts; + } + + if (childrenAccounts) { + for (const subAccount of childrenAccounts) { + subAccounts.push(subAccount.toCreateRequest(clientSessionId, undefined, this)); + } + } + } + + return { + name: this.name, + category: parentAccount ? parentAccount.category : this.category, + type: parentAccount ? AccountType.SingleAccount.type : this.type, + icon: this.icon, + color: this.color, + currency: parentAccount || this.type === AccountType.SingleAccount.type ? this.currency : PARENT_ACCOUNT_CURRENCY_PLACEHOLDER, + balance: parentAccount || this.type === AccountType.SingleAccount.type ? this.balance : 0, + balanceTime: (parentAccount || this.type === AccountType.SingleAccount.type) && this.balanceTime ? this.balanceTime : 0, + comment: this.comment, + creditCardStatementDate: !parentAccount && this.category === AccountCategory.CreditCard.type ? this.creditCardStatementDate : undefined, + subAccounts: !parentAccount ? subAccounts : undefined, + clientSessionId: !parentAccount ? clientSessionId : undefined + }; + } + + public toModifyRequest(childrenAccounts?: Account[], parentAccount?: Account): AccountModifyRequest { + let subAccounts: AccountModifyRequest[] | undefined = undefined; + + if (this.type === AccountType.MultiSubAccounts.type) { + subAccounts = []; + + if (!childrenAccounts) { + childrenAccounts = this.childrenAccounts; + } + + if (childrenAccounts) { + for (const subAccount of childrenAccounts) { + subAccounts.push(subAccount.toModifyRequest(undefined, this)); + } + } + } + + return { + id: this.id, + name: this.name, + category: parentAccount ? parentAccount.category : this.category, + icon: this.icon, + color: this.color, + comment: this.comment, + creditCardStatementDate: !parentAccount && this.category === AccountCategory.CreditCard.type ? this.creditCardStatementDate : undefined, + hidden: !this.visible, + subAccounts: !parentAccount ? subAccounts : undefined, + }; + } + + public createNewSubAccount(currency: string, balanceTime: number): Account { + return new Account( + '', // id + '', // name + '', // parentId + 0, // category + 0, // type + this.icon, // icon + this.color, // color + currency, // currency + 0, // balance + '', // comment + 0, // displayOrder + true, // visible + balanceTime, // balanceTime + 0 // creditCardStatementDate + ); + } + + public static createNewAccount(currency: string, balanceTime: number): Account { + return new Account( + '', // id + '', // name + '', // parentId + AccountCategory.Cash.type, // category + AccountType.SingleAccount.type, // type + DEFAULT_ACCOUNT_ICON_ID, // icon + DEFAULT_ACCOUNT_COLOR, // color + currency, // currency + 0, // balance + '', // comment + 0, // displayOrder + true, // visible + balanceTime, // balanceTime + 0 // creditCardStatementDate + ); + } + + public static of(accountResponse: AccountInfoResponse): Account { + return new Account( + accountResponse.id, + accountResponse.name, + accountResponse.parentId, + accountResponse.category, + accountResponse.type, + accountResponse.icon, + accountResponse.color, + accountResponse.currency, + accountResponse.balance, + accountResponse.comment, + accountResponse.displayOrder, + !accountResponse.hidden, + undefined, + accountResponse.creditCardStatementDate, + accountResponse.isAsset, + accountResponse.isLiability, + accountResponse.subAccounts ? Account.ofMany(accountResponse.subAccounts) : undefined + ); + } + + public static ofMany(accountResponses: AccountInfoResponse[]): Account[] { + const accounts: Account[] = []; + + for (const accountResponse of accountResponses) { + accounts.push(Account.of(accountResponse)); + } + + return accounts; + } +} + export interface AccountCreateRequest { readonly name: string; readonly category: number; @@ -8,9 +227,9 @@ export interface AccountCreateRequest { readonly balance: number; readonly balanceTime: number; readonly comment: string; - readonly creditCardStatementDate: number; + readonly creditCardStatementDate?: number; readonly subAccounts?: AccountCreateRequest[]; - readonly clientSessionId: string; + readonly clientSessionId?: string; } export interface AccountModifyRequest { @@ -61,3 +280,29 @@ export interface AccountNewDisplayOrderRequest { export interface AccountDeleteRequest { readonly id: string; } + +export interface AccountBalance { + readonly balance: number; + readonly isAsset: boolean; + readonly isLiability: boolean; + readonly currency: string; +} + +export interface CategorizedAccount { + readonly category: number; + readonly name: string; + readonly icon: string; + readonly accounts: Account[]; +} + +export interface AccountCategoriesWithVisibleCount { + readonly category: number; + readonly name: string; + readonly icon: string; + readonly allAccounts: Account[]; + readonly allVisibleAccountCount: number; + readonly firstVisibleAccountIndex: number; + readonly allSubAccounts: Record; + readonly allVisibleSubAccountCounts: Record; + readonly allFirstVisibleSubAccountIndexes: Record; +} diff --git a/src/stores/account.js b/src/stores/account.js index 2c0f832b..ddda0cff 100644 --- a/src/stores/account.js +++ b/src/stores/account.js @@ -5,13 +5,13 @@ import { useExchangeRatesStore } from './exchangeRates.ts'; import { AccountType, AccountCategory } from '@/core/account.ts'; import { PARENT_ACCOUNT_CURRENCY_PLACEHOLDER } from '@/consts/currency.ts'; -import { DEFAULT_ACCOUNT_ICON_ID } from '@/consts/icon.ts'; -import { DEFAULT_ACCOUNT_COLOR } from '@/consts/color.ts'; +import { Account } from '@/models/account.ts'; + import services from '@/lib/services.ts'; import logger from '@/lib/logger.ts'; import { isNumber, isEquals } from '@/lib/common.ts'; import { getCurrentUnixTime } from '@/lib/datetime.ts'; -import { getCategorizedAccountsMap, getAllFilteredAccountsBalance } from '@/lib/account.js'; +import { getCategorizedAccountsMap, getAllFilteredAccountsBalance } from '@/lib/account.ts'; function loadAccountList(state, accounts) { state.allAccounts = accounts; @@ -132,7 +132,7 @@ function updateAccountDisplayOrderInAccountList(state, { account, from, to, upda function updateAccountVisibilityInAccountList(state, { account, hidden }) { if (state.allAccountsMap[account.id]) { - state.allAccountsMap[account.id].hidden = hidden; + state.allAccountsMap[account.id].visible = !hidden; } } @@ -260,37 +260,12 @@ export const useAccountsStore = defineStore('accounts', { generateNewAccountModel() { const userStore = useUserStore(); const now = getCurrentUnixTime(); - - return { - category: AccountCategory.Cash.type, - type: AccountType.SingleAccount.type, - name: '', - icon: DEFAULT_ACCOUNT_ICON_ID, - color: DEFAULT_ACCOUNT_COLOR, - currency: userStore.currentUserDefaultCurrency, - balance: 0, - balanceTime: now, - comment: '', - creditCardStatementDate: 0, - visible: true - }; + return Account.createNewAccount(userStore.currentUserDefaultCurrency, now); }, generateNewSubAccountModel(parentAccount) { const userStore = useUserStore(); const now = getCurrentUnixTime(); - - return { - category: null, - type: null, - name: '', - icon: parentAccount.icon, - color: parentAccount.color, - currency: userStore.currentUserDefaultCurrency, - balance: 0, - balanceTime: now, - comment: '', - visible: true - }; + return parentAccount.createNewSubAccount(userStore.currentUserDefaultCurrency, now); }, updateAccountListInvalidState(invalidState) { this.accountListStateInvalid = invalidState; @@ -736,14 +711,16 @@ export const useAccountsStore = defineStore('accounts', { self.updateAccountListInvalidState(false); } - if (force && data.result && isEquals(self.allAccounts, data.result)) { + const accounts = Account.ofMany(data.result); + + if (force && data.result && isEquals(self.allAccounts, accounts)) { reject({ message: 'Account list is up to date' }); return; } - loadAccountList(self, data.result); + loadAccountList(self, accounts); - resolve(data.result); + resolve(accounts); }).catch(error => { if (force) { logger.error('failed to force load account list', error); @@ -773,7 +750,9 @@ export const useAccountsStore = defineStore('accounts', { return; } - resolve(data.result); + const account = Account.of(data.result); + + resolve(account); }).catch(error => { logger.error('failed to load account info', error); @@ -790,78 +769,21 @@ export const useAccountsStore = defineStore('accounts', { saveAccount({ account, subAccounts, isEdit, clientSessionId }) { const self = this; - const submitSubAccounts = []; - - if (account.type === AccountType.MultiSubAccounts.type) { - for (let i = 0; i < subAccounts.length; i++) { - const subAccount = subAccounts[i]; - const submitAccount = { - category: account.category, - type: AccountType.SingleAccount.type, - name: subAccount.name, - icon: subAccount.icon, - color: subAccount.color, - currency: subAccount.currency, - balance: subAccount.balance, - comment: subAccount.comment - }; - - if (isEdit) { - submitAccount.id = subAccount.id; - submitAccount.hidden = !subAccount.visible; - } else { - submitAccount.balanceTime = subAccount.balanceTime; - } - - submitSubAccounts.push(submitAccount); - } - } - - const submitAccount = { - category: account.category, - type: account.type, - name: account.name, - icon: account.icon, - color: account.color, - currency: account.type === AccountType.SingleAccount.type ? account.currency : PARENT_ACCOUNT_CURRENCY_PLACEHOLDER, - balance: account.type === AccountType.SingleAccount.type ? account.balance : 0, - comment: account.comment, - subAccounts: account.type === AccountType.SingleAccount.type ? null : submitSubAccounts, - }; - - if (account.category === AccountCategory.CreditCard.type) { - submitAccount.creditCardStatementDate = account.creditCardStatementDate; - } - - if (clientSessionId) { - submitAccount.clientSessionId = clientSessionId; - } - - if (isEdit) { - submitAccount.id = account.id; - submitAccount.hidden = !account.visible; - } else { - if (account.type === AccountType.SingleAccount.type) { - submitAccount.balanceTime = account.balanceTime; - } - } - - const oldAccount = submitAccount.id ? self.allAccountsMap[submitAccount.id] : null; - return new Promise((resolve, reject) => { + const oldAccount = isEdit ? self.allAccountsMap[account.id] : null; let promise = null; - if (!submitAccount.id) { - promise = services.addAccount(submitAccount); + if (!isEdit) { + promise = services.addAccount(account.toCreateRequest(clientSessionId, subAccounts)); } else { - promise = services.modifyAccount(submitAccount); + promise = services.modifyAccount(account.toModifyRequest(subAccounts)); } promise.then(response => { const data = response.data; if (!data || !data.success || !data.result) { - if (!submitAccount.id) { + if (!isEdit) { reject({ message: 'Unable to add account' }); } else { reject({ message: 'Unable to save account' }); @@ -869,24 +791,26 @@ export const useAccountsStore = defineStore('accounts', { return; } - if (!submitAccount.id) { - addAccountToAccountList(self, data.result); + const newAccount = Account.of(data.result); + + if (!isEdit) { + addAccountToAccountList(self, newAccount); } else { - if (oldAccount && oldAccount.category === data.result.category) { - updateAccountToAccountList(self, data.result); + if (oldAccount && oldAccount.category === newAccount.category) { + updateAccountToAccountList(self, newAccount); } else { self.updateAccountListInvalidState(true); } } - resolve(data.result); + resolve(newAccount); }).catch(error => { logger.error('failed to save account', error); if (error.response && error.response.data && error.response.data.errorMessage) { reject({ error: error.response.data }); } else if (!error.processed) { - if (!submitAccount.id) { + if (!isEdit) { reject({ message: 'Unable to add account' }); } else { reject({ message: 'Unable to save account' }); diff --git a/src/stores/statistics.js b/src/stores/statistics.js index aaf3f591..28a4ee7a 100644 --- a/src/stores/statistics.js +++ b/src/stores/statistics.js @@ -40,7 +40,7 @@ import { } from '@/lib/datetime.ts'; import { getFinalAccountIdsByFilteredAccountIds -} from '@/lib/account.js'; +} from '@/lib/account.ts'; import { getFinalCategoryIdsByFilteredCategoryIds } from '@/lib/category.ts'; diff --git a/src/views/desktop/accounts/ListPage.vue b/src/views/desktop/accounts/ListPage.vue index 6f974ac9..00ae1a1e 100644 --- a/src/views/desktop/accounts/ListPage.vue +++ b/src/views/desktop/accounts/ListPage.vue @@ -271,7 +271,7 @@ import { getSubAccountCurrencies, getAccountOrSubAccountId, getAccountOrSubAccountComment -} from '@/lib/account.js'; +} from '@/lib/account.ts'; import { mdiEyeOutline, diff --git a/src/views/desktop/accounts/list/dialogs/EditDialog.vue b/src/views/desktop/accounts/list/dialogs/EditDialog.vue index 2dc2dd1e..7e8abea2 100644 --- a/src/views/desktop/accounts/list/dialogs/EditDialog.vue +++ b/src/views/desktop/accounts/list/dialogs/EditDialog.vue @@ -203,12 +203,10 @@ import { useAccountsStore } from '@/stores/account.js'; import { AccountType, AccountCategory } from '@/core/account.ts'; import { ALL_ACCOUNT_ICONS } from '@/consts/icon.ts'; import { ALL_ACCOUNT_COLORS } from '@/consts/color.ts'; + import { isNumber } from '@/lib/common.ts'; import { generateRandomUUID } from '@/lib/misc.ts'; -import { - setAccountModelByAnotherAccount, - setAccountSuitableIcon -} from '@/lib/account.js'; +import { setAccountSuitableIcon } from '@/lib/account.ts'; import { mdiDotsVertical, @@ -324,7 +322,7 @@ export default { self.submitting = false; const newAccount = self.accountsStore.generateNewAccountModel(); - setAccountModelByAnotherAccount(self.account, newAccount); + self.account.from(newAccount); self.subAccounts = []; self.currentAccountIndex = -1; @@ -485,13 +483,13 @@ export default { } }, setAccount(account) { - setAccountModelByAnotherAccount(this.account, account); + this.account.from(account); this.subAccounts = []; - if (account.subAccounts && account.subAccounts.length > 0) { - for (let i = 0; i < account.subAccounts.length; i++) { + if (account.childrenAccounts && account.childrenAccounts.length > 0) { + for (let i = 0; i < account.childrenAccounts.length; i++) { const subAccount = this.accountsStore.generateNewSubAccountModel(this.account); - setAccountModelByAnotherAccount(subAccount, account.subAccounts[i]); + subAccount.from(account.childrenAccounts[i]); this.subAccounts.push(subAccount); } diff --git a/src/views/desktop/common/cards/AccountFilterSettingsCard.vue b/src/views/desktop/common/cards/AccountFilterSettingsCard.vue index ebf6cd03..1f1fe501 100644 --- a/src/views/desktop/common/cards/AccountFilterSettingsCard.vue +++ b/src/views/desktop/common/cards/AccountFilterSettingsCard.vue @@ -162,7 +162,7 @@ import { selectInvert, isAccountOrSubAccountsAllChecked, isAccountOrSubAccountsHasButNotAllChecked -} from '@/lib/account.js'; +} from '@/lib/account.ts'; import { mdiSelectAll, diff --git a/src/views/desktop/transactions/ListPage.vue b/src/views/desktop/transactions/ListPage.vue index 3a6cfd33..6f514fc4 100644 --- a/src/views/desktop/transactions/ListPage.vue +++ b/src/views/desktop/transactions/ListPage.vue @@ -628,7 +628,7 @@ import { categoryTypeToTransactionType, transactionTypeToCategoryType } from '@/lib/category.ts'; -import { getUnifiedSelectedAccountsCurrencyOrDefaultCurrency } from '@/lib/account.js'; +import { getUnifiedSelectedAccountsCurrencyOrDefaultCurrency } from '@/lib/account.ts'; import { getTransactionDisplayAmount } from '@/lib/transaction.js'; import { isDataImportingEnabled } from '@/lib/server_settings.ts'; import { scrollToSelectedItem } from '@/lib/ui/desktop.ts'; diff --git a/src/views/desktop/user/settings/tabs/UserBasicSettingTab.vue b/src/views/desktop/user/settings/tabs/UserBasicSettingTab.vue index 109191f3..a995b180 100644 --- a/src/views/desktop/user/settings/tabs/UserBasicSettingTab.vue +++ b/src/views/desktop/user/settings/tabs/UserBasicSettingTab.vue @@ -341,7 +341,7 @@ import { WeekDay } from '@/core/datetime.ts'; import { SUPPORTED_IMAGE_EXTENSIONS } from '@/consts/file.ts'; import { getNameByKeyValue } from '@/lib/common.ts'; import { generateRandomUUID } from '@/lib/misc.ts'; -import { getCategorizedAccounts } from '@/lib/account.js'; +import { getCategorizedAccounts } from '@/lib/account.ts'; import { isUserVerifyEmailEnabled } from '@/lib/server_settings.ts'; import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts'; diff --git a/src/views/mobile/accounts/EditPage.vue b/src/views/mobile/accounts/EditPage.vue index 6d7d69d6..5652420c 100644 --- a/src/views/mobile/accounts/EditPage.vue +++ b/src/views/mobile/accounts/EditPage.vue @@ -497,12 +497,10 @@ import { AccountType, AccountCategory } from '@/core/account.ts'; import { ALL_ACCOUNT_ICONS } from '@/consts/icon.ts'; import { ALL_ACCOUNT_COLORS } from '@/consts/color.ts'; import { TRANSACTION_MIN_AMOUNT, TRANSACTION_MAX_AMOUNT } from '@/consts/transaction.ts'; + import { getNameByKeyValue } from '@/lib/common.ts'; import { generateRandomUUID } from '@/lib/misc.ts'; -import { - setAccountModelByAnotherAccount, - setAccountSuitableIcon -} from '@/lib/account.js'; +import { setAccountSuitableIcon } from '@/lib/account.ts'; import { getTimezoneOffsetMinutes, getBrowserTimezoneOffsetMinutes, @@ -618,13 +616,13 @@ export default { self.accountsStore.getAccount({ accountId: self.editAccountId }).then(account => { - setAccountModelByAnotherAccount(self.account, account); + self.account.from(account); self.subAccounts = []; - if (account.subAccounts && account.subAccounts.length > 0) { - for (let i = 0; i < account.subAccounts.length; i++) { + if (account.childrenAccounts && account.childrenAccounts.length > 0) { + for (let i = 0; i < account.childrenAccounts.length; i++) { const subAccount = self.accountsStore.generateNewSubAccountModel(self.account); - setAccountModelByAnotherAccount(subAccount, account.subAccounts[i]); + subAccount.from(account.childrenAccounts[i]); subAccount.showIconSelectionSheet = false; subAccount.showColorSelectionSheet = false; subAccount.showBalanceSheet = false; diff --git a/src/views/mobile/settings/AccountFilterSettingsPage.vue b/src/views/mobile/settings/AccountFilterSettingsPage.vue index 45cb0f90..9e5d324b 100644 --- a/src/views/mobile/settings/AccountFilterSettingsPage.vue +++ b/src/views/mobile/settings/AccountFilterSettingsPage.vue @@ -148,7 +148,7 @@ import { selectInvert, isAccountOrSubAccountsAllChecked, isAccountOrSubAccountsHasButNotAllChecked -} from '@/lib/account.js'; +} from '@/lib/account.ts'; export default { props: [ diff --git a/src/views/mobile/transactions/ListPage.vue b/src/views/mobile/transactions/ListPage.vue index 7bbb86a6..a93be539 100644 --- a/src/views/mobile/transactions/ListPage.vue +++ b/src/views/mobile/transactions/ListPage.vue @@ -549,7 +549,7 @@ import { getDateRangeByBillingCycleDateType } from '@/lib/datetime.ts'; import { categoryTypeToTransactionType, transactionTypeToCategoryType } from '@/lib/category.ts'; -import { getUnifiedSelectedAccountsCurrencyOrDefaultCurrency } from '@/lib/account.js'; +import { getUnifiedSelectedAccountsCurrencyOrDefaultCurrency } from '@/lib/account.ts'; import { getTransactionDisplayAmount } from '@/lib/transaction.js'; import { onSwipeoutDeleted, scrollToSelectedItem } from '@/lib/ui/mobile.ts'; diff --git a/src/views/mobile/users/UserProfilePage.vue b/src/views/mobile/users/UserProfilePage.vue index fdf25c69..4cce8131 100644 --- a/src/views/mobile/users/UserProfilePage.vue +++ b/src/views/mobile/users/UserProfilePage.vue @@ -340,7 +340,7 @@ import { useAccountsStore } from '@/stores/account.js'; import { useOverviewStore } from '@/stores/overview.ts'; import { getNameByKeyValue } from '@/lib/common.ts'; -import { getCategorizedAccounts } from '@/lib/account.js'; +import { getCategorizedAccounts } from '@/lib/account.ts'; import { isUserVerifyEmailEnabled } from '@/lib/server_settings.ts'; import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';