WIP: Add Drafts, Templates, and Recurring Transactions #45
|
|
@ -59,6 +59,13 @@ export interface Account {
|
||||||
currentBalance: number | null
|
currentBalance: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SimpleAccountResponse {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
type: string
|
||||||
|
numberSuffix: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface AccountCreationPayload {
|
export interface AccountCreationPayload {
|
||||||
type: string
|
type: string
|
||||||
numberSuffix: string
|
numberSuffix: string
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,28 @@
|
||||||
|
import type { SimpleAccountResponse } from './account'
|
||||||
import type { Attachment } from './attachment'
|
import type { Attachment } from './attachment'
|
||||||
import { ApiClient } from './base'
|
import { ApiClient } from './base'
|
||||||
import type { Currency } from './data'
|
import type { Currency } from './data'
|
||||||
import { type Page, type PageRequest } from './pagination'
|
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 {
|
export interface TransactionVendor {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
|
|
@ -47,10 +67,10 @@ export interface TransactionsListItem {
|
||||||
currency: Currency
|
currency: Currency
|
||||||
description: string
|
description: string
|
||||||
internalTransfer: boolean
|
internalTransfer: boolean
|
||||||
vendor: TransactionsListItemVendor | null
|
vendor: SimpleVendorResponse | null
|
||||||
category: TransactionsListItemCategory | null
|
category: SimpleCategoryResponse | null
|
||||||
creditedAccount: TransactionsListItemAccount | null
|
creditedAccount: SimpleAccountResponse | null
|
||||||
debitedAccount: TransactionsListItemAccount | null
|
debitedAccount: SimpleAccountResponse | null
|
||||||
tags: string[]
|
tags: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,28 +102,13 @@ export interface TransactionDetail {
|
||||||
internalTransfer: boolean
|
internalTransfer: boolean
|
||||||
vendor: TransactionVendor | null
|
vendor: TransactionVendor | null
|
||||||
category: TransactionCategory | null
|
category: TransactionCategory | null
|
||||||
creditedAccount: TransactionDetailAccount | null
|
creditedAccount: SimpleAccountResponse | null
|
||||||
debitedAccount: TransactionDetailAccount | null
|
debitedAccount: SimpleAccountResponse | null
|
||||||
tags: string[]
|
tags: string[]
|
||||||
lineItems: TransactionDetailLineItem[]
|
lineItems: TransactionLineItemResponse[]
|
||||||
attachments: Attachment[]
|
attachments: Attachment[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransactionDetailAccount {
|
|
||||||
id: number
|
|
||||||
name: string
|
|
||||||
type: string
|
|
||||||
numberSuffix: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TransactionDetailLineItem {
|
|
||||||
idx: number
|
|
||||||
valuePerItem: number
|
|
||||||
quantity: number
|
|
||||||
description: string
|
|
||||||
category: TransactionCategory | null
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AddTransactionPayload {
|
export interface AddTransactionPayload {
|
||||||
timestamp: string
|
timestamp: string
|
||||||
amount: number
|
amount: number
|
||||||
|
|
@ -144,6 +149,56 @@ export interface AggregateTransactionData {
|
||||||
currencies: AggregateTransactionCurrencyData[]
|
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 {
|
export class TransactionApiClient extends ApiClient {
|
||||||
readonly path: string
|
readonly path: string
|
||||||
|
|
||||||
|
|
@ -277,4 +332,57 @@ export class TransactionApiClient extends ApiClient {
|
||||||
getAllTags(): Promise<string[]> {
|
getAllTags(): Promise<string[]> {
|
||||||
return super.getJson(this.path + '/transaction-tags')
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { TransactionDetailLineItem } from '@/api/transaction'
|
import type { TransactionLineItemResponse } from '@/api/transaction'
|
||||||
import AppButton from './common/AppButton.vue'
|
import AppButton from './common/AppButton.vue'
|
||||||
import { formatMoney, type Currency } from '@/api/data'
|
import { formatMoney, type Currency } from '@/api/data'
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
lineItem: TransactionDetailLineItem
|
lineItem: TransactionLineItemResponse
|
||||||
currency: Currency
|
currency: Currency
|
||||||
totalCount?: number
|
totalCount?: number
|
||||||
editable?: boolean
|
editable?: boolean
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ transaction. This editor shows a table of current line items, and includes a
|
||||||
modal for adding a new one.
|
modal for adding a new one.
|
||||||
-->
|
-->
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type TransactionCategoryTree, type TransactionDetailLineItem } from '@/api/transaction'
|
import { type TransactionCategoryTree, type TransactionLineItemResponse } from '@/api/transaction'
|
||||||
import AppButton from '@/components/common/AppButton.vue'
|
import AppButton from '@/components/common/AppButton.vue'
|
||||||
import FormGroup from '@/components/common/form/FormGroup.vue'
|
import FormGroup from '@/components/common/form/FormGroup.vue'
|
||||||
import { floatMoneyToInteger, formatMoney, type Currency } from '@/api/data'
|
import { floatMoneyToInteger, formatMoney, type Currency } from '@/api/data'
|
||||||
|
|
@ -15,7 +15,7 @@ import CategorySelect from './CategorySelect.vue'
|
||||||
import LineItemCard from './LineItemCard.vue'
|
import LineItemCard from './LineItemCard.vue'
|
||||||
import AppBadge from './common/AppBadge.vue'
|
import AppBadge from './common/AppBadge.vue'
|
||||||
|
|
||||||
const model = defineModel<TransactionDetailLineItem[]>({ required: true })
|
const model = defineModel<TransactionLineItemResponse[]>({ required: true })
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
transactionAmount: number
|
transactionAmount: number
|
||||||
currency: Currency
|
currency: Currency
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import {
|
||||||
TransactionApiClient,
|
TransactionApiClient,
|
||||||
type AddTransactionPayload,
|
type AddTransactionPayload,
|
||||||
type TransactionDetail,
|
type TransactionDetail,
|
||||||
type TransactionDetailLineItem,
|
type TransactionLineItemResponse,
|
||||||
type TransactionVendor,
|
type TransactionVendor,
|
||||||
} from '@/api/transaction'
|
} from '@/api/transaction'
|
||||||
import AppPage from '@/components/common/AppPage.vue'
|
import AppPage from '@/components/common/AppPage.vue'
|
||||||
|
|
@ -144,7 +144,7 @@ const vendor: Ref<TransactionVendor | null> = ref(null)
|
||||||
const categoryId: Ref<number | null> = ref(null)
|
const categoryId: Ref<number | null> = ref(null)
|
||||||
const creditedAccountId: Ref<number | null> = ref(null)
|
const creditedAccountId: Ref<number | null> = ref(null)
|
||||||
const debitedAccountId: Ref<number | null> = ref(null)
|
const debitedAccountId: Ref<number | null> = ref(null)
|
||||||
const lineItems: Ref<TransactionDetailLineItem[]> = ref([])
|
const lineItems: Ref<TransactionLineItemResponse[]> = ref([])
|
||||||
const tags: Ref<string[]> = ref([])
|
const tags: Ref<string[]> = ref([])
|
||||||
const customTagInput = ref('')
|
const customTagInput = ref('')
|
||||||
const customTagInputValid = ref(false)
|
const customTagInputValid = ref(false)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue