import { type RouteLocation } from 'vue-router' import { ApiClient } from './base' import type { Currency } from './data' import type { Page, PageRequest } from './pagination' import { getSelectedProfile } from './profile' import type { Attachment } from './attachment' export interface AccountType { id: string name: string debitsPositive: boolean emoji: string } export abstract class AccountTypes { public static readonly CHECKING: AccountType = { id: 'CHECKING', name: 'Checking', debitsPositive: true, emoji: '💵', } public static readonly SAVINGS: AccountType = { id: 'SAVINGS', name: 'Savings', debitsPositive: true, emoji: '💰', } public static readonly CREDIT_CARD: AccountType = { id: 'CREDIT_CARD', name: 'Credit Card', debitsPositive: false, emoji: '💳', } public static readonly BROKERAGE: AccountType = { id: 'BROKERAGE', name: 'Brokerage', debitsPositive: true, emoji: '📈', } public static of(id: string): AccountType { if (id === 'CHECKING') return AccountTypes.CHECKING if (id === 'SAVINGS') return AccountTypes.SAVINGS if (id === 'CREDIT_CARD') return AccountTypes.CREDIT_CARD if (id === 'BROKERAGE') return AccountTypes.BROKERAGE throw new Error('Unknown account type: ' + id) } } export interface Account { id: number createdAt: string archived: boolean type: string numberSuffix: string name: string currency: Currency description: string currentBalance: number | null } export interface SimpleAccountResponse { id: number name: string type: string numberSuffix: string } export interface AccountCreationPayload { type: string numberSuffix: string name: string currency: string description: string } export enum AccountJournalEntryType { CREDIT = 'CREDIT', DEBIT = 'DEBIT', } export interface AccountJournalEntry { id: number timestamp: string accountId: number transactionId: number amount: number type: AccountJournalEntryType currency: Currency } export enum AccountValueRecordType { BALANCE = 'BALANCE', } export interface AccountValueRecord { id: number timestamp: string accountId: number type: AccountValueRecordType value: number currency: Currency attachments: Attachment[] } export interface AccountValueRecordCreationPayload { timestamp: string type: AccountValueRecordType value: number } // History: export enum AccountHistoryItemType { TEXT = 'TEXT', PROPERTY_CHANGE = 'PROPERTY_CHANGE', VALUE_RECORD = 'VALUE_RECORD', JOURNAL_ENTRY = 'JOURNAL_ENTRY', } export function accountHistoryItemTypeToDisplayName(type: AccountHistoryItemType) { if (type === AccountHistoryItemType.TEXT) return 'Text' if (type === AccountHistoryItemType.PROPERTY_CHANGE) return 'Property Change' if (type === AccountHistoryItemType.VALUE_RECORD) return 'Value Record' if (type === AccountHistoryItemType.JOURNAL_ENTRY) return 'Journal Entry' return 'Unknown' } export interface AccountHistoryItem { timestamp: string type: AccountHistoryItemType } export interface AccountHistoryValueRecordItem extends AccountHistoryItem { valueRecordId: number valueRecordType: AccountValueRecordType value: number currency: Currency } export interface AccountHistoryJournalEntryItem extends AccountHistoryItem { journalEntryType: AccountJournalEntryType amount: number currency: Currency transactionId: number transactionDescription: string } export interface CurrencyBalance { currency: Currency balance: number } export class AccountApiClient extends ApiClient { readonly path: string readonly profileName: string constructor(route: RouteLocation) { super() this.profileName = getSelectedProfile(route) this.path = `/profiles/${getSelectedProfile(route)}/accounts` } getAccounts(): Promise { return super.getJson(this.path) } getAccount(id: number): Promise { return super.getJson(this.path + '/' + id) } createAccount(data: AccountCreationPayload): Promise { return super.postJson(this.path, data) } updateAccount(id: number, data: AccountCreationPayload): Promise { return super.putJson(this.path + '/' + id, data) } deleteAccount(id: number): Promise { return super.delete(this.path + '/' + id) } async getBalance(id: number, timestamp: Date): Promise { const result: { balance: number | null } = await super.getJson( `${this.path}/${id}/balance?timestamp=${timestamp.toISOString()}`, ) if (result.balance === null) return undefined return result.balance } getHistory(id: number, pageRequest: PageRequest): Promise> { return super.getJsonPage(`${this.path}/${id}/history`, pageRequest) } getTotalBalances(): Promise { return super.getJson(`/profiles/${this.profileName}/account-balances`) } getValueRecords(accountId: number, pageRequest: PageRequest): Promise> { return super.getJsonPage(this.path + '/' + accountId + '/value-records', pageRequest) } getValueRecord(accountId: number, valueRecordId: number): Promise { return super.getJson(this.path + '/' + accountId + '/value-records/' + valueRecordId) } createValueRecord( accountId: number, payload: AccountValueRecordCreationPayload, attachments: File[], ): Promise { const formData = new FormData() formData.append('payload', JSON.stringify(payload)) for (const file of attachments) { formData.append('file', file) } return super.postFormData(`${this.path}/${accountId}/value-records`, formData) } deleteValueRecord(accountId: number, valueRecordId: number): Promise { return super.delete(this.path + '/' + accountId + '/value-records/' + valueRecordId) } downloadAccountsExport(): Promise { return super.getFile(this.path + '/export') } }