finnow/web-app/src/api/transaction.ts

389 lines
10 KiB
TypeScript

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<TransactionVendor[]> {
return super.getJson(this.path + '/vendors')
}
getVendor(id: number): Promise<TransactionVendor> {
return super.getJson(this.path + '/vendors/' + id)
}
createVendor(data: TransactionVendorPayload): Promise<TransactionVendor> {
return super.postJson(this.path + '/vendors', data)
}
updateVendor(id: number, data: TransactionVendorPayload): Promise<TransactionVendor> {
return super.putJson(this.path + '/vendors/' + id, data)
}
deleteVendor(id: number): Promise<void> {
return super.delete(this.path + '/vendors/' + id)
}
getCategories(): Promise<TransactionCategoryTree[]> {
return super.getJson(this.path + '/categories')
}
async getCategoriesFlattened(): Promise<TransactionCategoryTree[]> {
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<TransactionCategory> {
return super.getJson(this.path + '/categories/' + id)
}
getChildCategories(parentId: number): Promise<TransactionCategory[]> {
return super.getJson(this.path + '/categories/' + parentId + '/children')
}
getCategoryBalances(id: number, includeChildren: boolean): Promise<TransactionCategoryBalance[]> {
return super.getJson(
this.path + '/categories/' + id + '/balances?includeChildren=' + includeChildren,
)
}
createCategory(data: CreateCategoryPayload): Promise<TransactionCategory> {
return super.postJson(this.path + '/categories', data)
}
updateCategory(id: number, data: CreateCategoryPayload): Promise<TransactionCategory> {
return super.putJson(this.path + '/categories/' + id, data)
}
deleteCategory(id: number): Promise<void> {
return super.delete(this.path + '/categories/' + id)
}
getTransactions(
paginationOptions: PageRequest | undefined = undefined,
): Promise<Page<TransactionsListItem>> {
return super.getJsonPage(this.path + '/transactions', paginationOptions)
}
searchTransactions(
params: URLSearchParams,
paginationOptions: PageRequest | undefined = undefined,
): Promise<Page<TransactionsListItem>> {
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<AggregateTransactionData> {
return super.getJson(this.path + '/transactions/aggregate-data?' + params.toString())
}
exportTransactions(params: URLSearchParams): Promise<void> {
return super.getFile(this.path + '/transactions/export?' + params.toString())
}
getTransaction(id: number): Promise<TransactionDetail> {
return super.getJson(this.path + '/transactions/' + id)
}
addTransaction(data: AddTransactionPayload, files: File[] = []): Promise<TransactionDetail> {
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<TransactionDetail> {
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<void> {
return super.delete(this.path + '/transactions/' + id)
}
getAllTags(): Promise<string[]> {
return super.getJson(this.path + '/transaction-tags')
}
// Drafts:
getDrafts(
paginationOptions: PageRequest | undefined = undefined,
): Promise<Page<TransactionDraftListItem>> {
return super.getJsonPage(this.path + '/transaction-drafts', paginationOptions)
}
getTemplateDrafts(
paginationOptions: PageRequest | undefined = undefined,
): Promise<Page<TransactionDraftListItem>> {
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<TransactionDraftResponse> {
return super.getJson(this.path + '/transaction-drafts/' + id)
}
addDraft(data: TransactionDraftPayload, files: File[] = []): Promise<TransactionDraftResponse> {
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<TransactionDraftResponse> {
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<void> {
return super.delete(this.path + '/transaction-drafts/' + id)
}
}