import type { SimpleAccountResponse } from './account' import type { Attachment } from './attachment' import { ApiClient } from './base' import type { Currency } from './data' import { type Page, type PageRequest } from './pagination' export interface SimpleVendorResponse { id: number name: string } export interface SimpleCategoryResponse { id: number name: string color: string } export interface TransactionLineItemResponse { idx: number valuePerItem: number quantity: number description: string category: TransactionCategory | null } export interface TransactionVendor { id: number name: string description: string | null } export interface TransactionVendorPayload { name: string description: string | null } export interface TransactionCategory { id: number parentId: number | null name: string description: string | null color: string } export interface TransactionCategoryTree { id: number parentId: number | null name: string description: string color: string children: TransactionCategoryTree[] depth: number } export interface TransactionCategoryBalance { credits: number debits: number balance: number currency: Currency } export interface TransactionsListItem { id: number timestamp: string addedAt: string amount: number currency: Currency description: string internalTransfer: boolean vendor: SimpleVendorResponse | null category: SimpleCategoryResponse | null creditedAccount: SimpleAccountResponse | null debitedAccount: SimpleAccountResponse | null tags: string[] } export interface TransactionsListItemVendor { id: number name: string } export interface TransactionsListItemCategory { id: number name: string color: string } export interface TransactionsListItemAccount { id: number name: string type: string numberSuffix: string } export interface TransactionDetail { id: number timestamp: string addedAt: string amount: number currency: Currency description: string internalTransfer: boolean vendor: TransactionVendor | null category: TransactionCategory | null creditedAccount: SimpleAccountResponse | null debitedAccount: SimpleAccountResponse | null tags: string[] lineItems: TransactionLineItemResponse[] attachments: Attachment[] } export interface AddTransactionPayload { timestamp: string amount: number currencyCode: string description: string internalTransfer: boolean vendorId: number | null categoryId: number | null creditedAccountId: number | null debitedAccountId: number | null tags: string[] lineItems: AddTransactionPayloadLineItem[] attachmentIdsToRemove: number[] } export interface AddTransactionPayloadLineItem { valuePerItem: number quantity: number description: string categoryId: number | null } export interface CreateCategoryPayload { name: string description: string | null color: string parentId: number | null } export interface AggregateTransactionCurrencyData { credits: number debits: number balance: number currency: Currency } export interface AggregateTransactionData { currencies: AggregateTransactionCurrencyData[] } export interface TransactionDraftListItem { id: number addedAt: string templateName: string | null timestamp: string | null amount: number | null currency: Currency | null description: string | null internalTransfer: boolean | null vendor: SimpleVendorResponse | null category: SimpleCategoryResponse | null creditedAccount: SimpleAccountResponse | null debitedAccount: SimpleAccountResponse | null tags: string[] } export interface TransactionDraftResponse { id: number addedAt: string templateName: string | null timestamp: string | null amount: number | null currency: Currency | null description: string | null internalTransfer: boolean | null vendor: SimpleVendorResponse | null category: SimpleCategoryResponse | null creditedAccount: SimpleAccountResponse | null debitedAccount: SimpleAccountResponse | null tags: string[] lineItems: TransactionLineItemResponse[] attachments: Attachment[] } export interface TransactionDraftPayload { templateName: string | null timestamp: string | null amount: number | null currencyCode: string | null description: string | null internalTransfer: boolean | null vendorId: number | null categoryId: number | null creditedAccountId: number | null debitedAccountId: number | null tags: string[] lineItems: AddTransactionPayloadLineItem[] attachmentIdsToRemove: number[] } export class TransactionApiClient extends ApiClient { readonly path: string constructor(profileName: string) { super() this.path = `/profiles/${profileName}` } getVendors(): Promise { return super.getJson(this.path + '/vendors') } getVendor(id: number): Promise { return super.getJson(this.path + '/vendors/' + id) } createVendor(data: TransactionVendorPayload): Promise { return super.postJson(this.path + '/vendors', data) } updateVendor(id: number, data: TransactionVendorPayload): Promise { return super.putJson(this.path + '/vendors/' + id, data) } deleteVendor(id: number): Promise { return super.delete(this.path + '/vendors/' + id) } getCategories(): Promise { return super.getJson(this.path + '/categories') } async getCategoriesFlattened(): Promise { const categories = await this.getCategories() const flat: TransactionCategoryTree[] = [] await this.flattenCategories(flat, categories) return flat } private flattenCategories(arr: TransactionCategoryTree[], tree: TransactionCategoryTree[]) { for (const category of tree) { arr.push(category) this.flattenCategories(arr, category.children) } } getCategory(id: number): Promise { return super.getJson(this.path + '/categories/' + id) } getChildCategories(parentId: number): Promise { return super.getJson(this.path + '/categories/' + parentId + '/children') } getCategoryBalances(id: number, includeChildren: boolean): Promise { return super.getJson( this.path + '/categories/' + id + '/balances?includeChildren=' + includeChildren, ) } createCategory(data: CreateCategoryPayload): Promise { return super.postJson(this.path + '/categories', data) } updateCategory(id: number, data: CreateCategoryPayload): Promise { return super.putJson(this.path + '/categories/' + id, data) } deleteCategory(id: number): Promise { return super.delete(this.path + '/categories/' + id) } getTransactions( paginationOptions: PageRequest | undefined = undefined, ): Promise> { return super.getJsonPage(this.path + '/transactions', paginationOptions) } searchTransactions( params: URLSearchParams, paginationOptions: PageRequest | undefined = undefined, ): Promise> { if (paginationOptions !== undefined) { params.append('page', paginationOptions.page + '') params.append('size', paginationOptions.size + '') for (const sort of paginationOptions.sorts) { params.append('sort', sort.attribute + ',' + sort.dir) } } return super.getJson(this.path + '/transactions/search?' + params.toString()) } getAggregateTransactionData(params: URLSearchParams): Promise { return super.getJson(this.path + '/transactions/aggregate-data?' + params.toString()) } exportTransactions(params: URLSearchParams): Promise { return super.getFile(this.path + '/transactions/export?' + params.toString()) } getTransaction(id: number): Promise { return super.getJson(this.path + '/transactions/' + id) } addTransaction(data: AddTransactionPayload, files: File[] = []): Promise { const formData = new FormData() formData.append('payload', JSON.stringify(data)) for (const file of files) { formData.append('file', file) } return super.postFormData(this.path + '/transactions', formData) } updateTransaction( id: number, data: AddTransactionPayload, files: File[] = [], ): Promise { const formData = new FormData() formData.append('payload', JSON.stringify(data)) for (const file of files) { formData.append('file', file) } return super.putFormData(this.path + '/transactions/' + id, formData) } deleteTransaction(id: number): Promise { return super.delete(this.path + '/transactions/' + id) } getAllTags(): Promise { return super.getJson(this.path + '/transaction-tags') } // Drafts: getDrafts( paginationOptions: PageRequest | undefined = undefined, ): Promise> { return super.getJsonPage(this.path + '/transaction-drafts', paginationOptions) } getTemplateDrafts( paginationOptions: PageRequest | undefined = undefined, ): Promise> { const params = new URLSearchParams() params.append('template', 'true') if (paginationOptions !== undefined) { params.append('page', paginationOptions.page + '') params.append('size', paginationOptions.size + '') for (const sort of paginationOptions.sorts) { params.append('sort', sort.attribute + ',' + sort.dir) } } return super.getJson(this.path + '/transaction-drafts?' + params.toString()) } getDraft(id: number): Promise { return super.getJson(this.path + '/transaction-drafts/' + id) } addDraft(data: TransactionDraftPayload, files: File[] = []): Promise { const formData = new FormData() formData.append('payload', JSON.stringify(data)) for (const file of files) { formData.append('file', file) } return super.postFormData(this.path + '/transaction-drafts', formData) } updateDraft( id: number, data: TransactionDraftPayload, files: File[] = [], ): Promise { const formData = new FormData() formData.append('payload', JSON.stringify(data)) for (const file of files) { formData.append('file', file) } return super.putFormData(this.path + '/transaction-drafts/' + id, formData) } deleteDraft(id: number): Promise { return super.delete(this.path + '/transaction-drafts/' + id) } }