526 lines
17 KiB
TypeScript
526 lines
17 KiB
TypeScript
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 visible: boolean;
|
|
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[]) {
|
|
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(subAccounts) !== 'undefined') {
|
|
this.subAccounts = subAccounts;
|
|
} else {
|
|
this.subAccounts = undefined;
|
|
}
|
|
}
|
|
|
|
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 {
|
|
return !this.visible;
|
|
}
|
|
|
|
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, subAccounts?: Account[], parentAccount?: Account): AccountCreateRequest {
|
|
let subAccountCreateRequests: AccountCreateRequest[] | undefined = undefined;
|
|
|
|
if (this.type === AccountType.MultiSubAccounts.type) {
|
|
subAccountCreateRequests = [];
|
|
|
|
if (!subAccounts) {
|
|
subAccounts = this.subAccounts;
|
|
}
|
|
|
|
if (subAccounts) {
|
|
for (const subAccount of subAccounts) {
|
|
subAccountCreateRequests.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 ? subAccountCreateRequests : undefined,
|
|
clientSessionId: !parentAccount ? clientSessionId : undefined
|
|
};
|
|
}
|
|
|
|
public toModifyRequest(subAccounts?: Account[], parentAccount?: Account): AccountModifyRequest {
|
|
let subAccountModifyRequests: AccountModifyRequest[] | undefined = undefined;
|
|
|
|
if (this.type === AccountType.MultiSubAccounts.type) {
|
|
subAccountModifyRequests = [];
|
|
|
|
if (!subAccounts) {
|
|
subAccounts = this.subAccounts;
|
|
}
|
|
|
|
if (subAccounts) {
|
|
for (const subAccount of subAccounts) {
|
|
subAccountModifyRequests.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 ? subAccountModifyRequests : undefined,
|
|
};
|
|
}
|
|
|
|
public getAccountOrSubAccountId(subAccountId: string): string | null {
|
|
if (this.type === AccountType.SingleAccount.type) {
|
|
return this.id;
|
|
} else if (this.type === AccountType.MultiSubAccounts.type && !subAccountId) {
|
|
return this.id;
|
|
} else if (this.type === AccountType.MultiSubAccounts.type && subAccountId) {
|
|
if (!this.subAccounts || !this.subAccounts.length) {
|
|
return null;
|
|
}
|
|
|
|
for (let i = 0; i < this.subAccounts.length; i++) {
|
|
const subAccount = this.subAccounts[i];
|
|
|
|
if (subAccountId && subAccountId === subAccount.id) {
|
|
return subAccount.id;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public getAccountOrSubAccountComment(subAccountId: string): string | null {
|
|
if (this.type === AccountType.SingleAccount.type) {
|
|
return this.comment;
|
|
} else if (this.type === AccountType.MultiSubAccounts.type && !subAccountId) {
|
|
return this.comment;
|
|
} else if (this.type === AccountType.MultiSubAccounts.type && subAccountId) {
|
|
if (!this.subAccounts || !this.subAccounts.length) {
|
|
return null;
|
|
}
|
|
|
|
for (let i = 0; i < this.subAccounts.length; i++) {
|
|
const subAccount = this.subAccounts[i];
|
|
|
|
if (subAccountId && subAccountId === subAccount.id) {
|
|
return subAccount.comment;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public getSubAccountCurrencies(showHidden: boolean, subAccountId: string): string[] {
|
|
if (!this.subAccounts || !this.subAccounts.length) {
|
|
return [];
|
|
}
|
|
|
|
const subAccountCurrenciesMap: Record<string, boolean> = {};
|
|
const subAccountCurrencies: string[] = [];
|
|
|
|
for (let i = 0; i < this.subAccounts.length; i++) {
|
|
const subAccount = this.subAccounts[i];
|
|
|
|
if (!showHidden && subAccount.hidden) {
|
|
continue;
|
|
}
|
|
|
|
if (subAccountId && subAccountId === subAccount.id) {
|
|
return [subAccount.currency];
|
|
} else {
|
|
if (!subAccountCurrenciesMap[subAccount.currency]) {
|
|
subAccountCurrenciesMap[subAccount.currency] = true;
|
|
subAccountCurrencies.push(subAccount.currency);
|
|
}
|
|
}
|
|
}
|
|
|
|
return subAccountCurrencies;
|
|
}
|
|
|
|
public clone(): Account {
|
|
return new Account(
|
|
this.id,
|
|
this.name,
|
|
this.parentId,
|
|
this.category,
|
|
this.type,
|
|
this.icon,
|
|
this.color,
|
|
this.currency,
|
|
this.balance,
|
|
this.comment,
|
|
this.displayOrder,
|
|
this.visible,
|
|
this.balanceTime,
|
|
this.creditCardStatementDate,
|
|
this.isAsset,
|
|
this.isLiability,
|
|
typeof(this.subAccounts) !== 'undefined' ? Account.cloneAccounts(this.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;
|
|
}
|
|
|
|
public static findAccountNameById(accounts: Account[], accountId: string, defaultName?: string): string | undefined {
|
|
for (const account of accounts) {
|
|
if (account.id === accountId) {
|
|
return account.name;
|
|
}
|
|
}
|
|
|
|
return defaultName;
|
|
}
|
|
|
|
public static cloneAccounts(accounts: Account[]): Account[] {
|
|
const clonedAccounts: Account[] = [];
|
|
|
|
for (const account of accounts) {
|
|
clonedAccounts.push(account.clone());
|
|
}
|
|
|
|
return clonedAccounts;
|
|
}
|
|
|
|
public static sortAccounts(accounts: Account[]): Account[] {
|
|
if (!accounts || !accounts.length) {
|
|
return accounts;
|
|
}
|
|
|
|
return accounts.sort(function (account1, account2) {
|
|
if (account1.category !== account2.category) {
|
|
const account1Category = AccountCategory.valueOf(account1.category);
|
|
const account2Category = AccountCategory.valueOf(account2.category);
|
|
|
|
if (!account1Category) {
|
|
return 1;
|
|
}
|
|
|
|
if (!account2Category) {
|
|
return -1;
|
|
}
|
|
|
|
return account1Category.displayOrder - account2Category.displayOrder;
|
|
}
|
|
|
|
return account1.displayOrder - account2.displayOrder;
|
|
});
|
|
}
|
|
}
|
|
|
|
export class AccountWithDisplayBalance extends Account {
|
|
public displayBalance: string;
|
|
|
|
private constructor(Account: Account, displayBalance: string) {
|
|
super(
|
|
Account.id,
|
|
Account.name,
|
|
Account.parentId,
|
|
Account.category,
|
|
Account.type,
|
|
Account.icon,
|
|
Account.color,
|
|
Account.currency,
|
|
Account.balance,
|
|
Account.comment,
|
|
Account.displayOrder,
|
|
Account.visible,
|
|
Account.balanceTime,
|
|
Account.creditCardStatementDate,
|
|
Account.isAsset,
|
|
Account.isLiability,
|
|
Account.subAccounts
|
|
);
|
|
|
|
this.displayBalance = displayBalance;
|
|
}
|
|
|
|
public static fromAccount(account: Account, displayBalance: string): AccountWithDisplayBalance {
|
|
return new AccountWithDisplayBalance(account, displayBalance);
|
|
}
|
|
}
|
|
|
|
export interface AccountCreateRequest {
|
|
readonly name: string;
|
|
readonly category: number;
|
|
readonly type: number;
|
|
readonly icon: string;
|
|
readonly color: string;
|
|
readonly currency: string;
|
|
readonly balance: number;
|
|
readonly balanceTime: number;
|
|
readonly comment: string;
|
|
readonly creditCardStatementDate?: number;
|
|
readonly subAccounts?: AccountCreateRequest[];
|
|
readonly clientSessionId?: string;
|
|
}
|
|
|
|
export interface AccountModifyRequest {
|
|
readonly id: string;
|
|
readonly name: string;
|
|
readonly category: number;
|
|
readonly icon: string;
|
|
readonly color: string;
|
|
readonly comment: string;
|
|
readonly creditCardStatementDate?: number;
|
|
readonly hidden: boolean;
|
|
readonly subAccounts?: AccountModifyRequest[];
|
|
}
|
|
|
|
export interface AccountInfoResponse {
|
|
readonly id: string;
|
|
readonly name: string;
|
|
readonly parentId: string;
|
|
readonly category: number;
|
|
readonly type: number;
|
|
readonly icon: string;
|
|
readonly color: string;
|
|
readonly currency: string;
|
|
readonly balance: number;
|
|
readonly comment: string;
|
|
readonly creditCardStatementDate?: number;
|
|
readonly displayOrder: number;
|
|
readonly isAsset?: boolean;
|
|
readonly isLiability?: boolean;
|
|
readonly hidden: boolean;
|
|
readonly subAccounts?: AccountInfoResponse[];
|
|
}
|
|
|
|
export interface AccountHideRequest {
|
|
readonly id: string;
|
|
readonly hidden: boolean;
|
|
}
|
|
|
|
export interface AccountMoveRequest {
|
|
readonly newDisplayOrders: AccountNewDisplayOrderRequest[];
|
|
}
|
|
|
|
export interface AccountNewDisplayOrderRequest {
|
|
readonly id: string;
|
|
readonly displayOrder: number;
|
|
}
|
|
|
|
export interface AccountDeleteRequest {
|
|
readonly id: string;
|
|
}
|
|
|
|
export interface AccountBalance {
|
|
readonly balance: number;
|
|
readonly isAsset: boolean;
|
|
readonly isLiability: boolean;
|
|
readonly currency: string;
|
|
}
|
|
|
|
export interface AccountDisplayBalance {
|
|
readonly balance: string;
|
|
readonly currency: string;
|
|
}
|
|
|
|
export interface CategorizedAccount {
|
|
readonly category: number;
|
|
readonly name: string;
|
|
readonly icon: string;
|
|
readonly accounts: Account[];
|
|
}
|
|
|
|
export class CategorizedAccountWithDisplayBalance {
|
|
public category: number;
|
|
public name: string;
|
|
public icon: string;
|
|
public accounts: AccountWithDisplayBalance[];
|
|
public displayBalance: string;
|
|
|
|
private constructor(category: number, name: string, icon: string, accounts: AccountWithDisplayBalance[], displayBalance: string) {
|
|
this.category = category;
|
|
this.name = name;
|
|
this.icon = icon;
|
|
this.accounts = accounts;
|
|
this.displayBalance = displayBalance;
|
|
}
|
|
|
|
public static of(categorizedAccount: CategorizedAccount, accounts: AccountWithDisplayBalance[], displayBalance: string): CategorizedAccountWithDisplayBalance {
|
|
return new CategorizedAccountWithDisplayBalance(categorizedAccount.category, categorizedAccount.name, categorizedAccount.icon, accounts, displayBalance);
|
|
}
|
|
}
|
|
|
|
export interface AccountCategoriesWithVisibleCount {
|
|
readonly category: number;
|
|
readonly name: string;
|
|
readonly icon: string;
|
|
readonly allAccounts: Account[];
|
|
readonly allVisibleAccountCount: number;
|
|
readonly firstVisibleAccountIndex: number;
|
|
readonly allSubAccounts: Record<string, Account[]>;
|
|
readonly allVisibleSubAccountCounts: Record<string, number>;
|
|
readonly allFirstVisibleSubAccountIndexes: Record<string, number>;
|
|
}
|
|
|
|
export interface AccountShowingIds {
|
|
readonly accounts: Record<number, string>;
|
|
readonly subAccounts: Record<string, string>;
|
|
}
|