mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-16 07:57:33 +08:00
migrate transaction store to composition API and typescript
This commit is contained in:
@@ -1,4 +1,107 @@
|
||||
import type { TransactionGeoLocationResponse } from './transaction.ts';
|
||||
import { TransactionType } from '@/core/transaction.ts';
|
||||
|
||||
import type { TransactionCreateRequest, TransactionGeoLocationResponse } from './transaction.ts';
|
||||
|
||||
export class ImportTransaction implements ImportTransactionResponse {
|
||||
public type: number;
|
||||
public categoryId: string;
|
||||
public originalCategoryName: string;
|
||||
public time: number;
|
||||
public utcOffset: number;
|
||||
public sourceAccountId: string;
|
||||
public originalSourceAccountName: string;
|
||||
public originalSourceAccountCurrency: string;
|
||||
public destinationAccountId: string;
|
||||
public originalDestinationAccountName?: string;
|
||||
public originalDestinationAccountCurrency?: string;
|
||||
public sourceAmount: number;
|
||||
public destinationAmount: number;
|
||||
public tagIds: string[];
|
||||
public originalTagNames: string[];
|
||||
public comment: string;
|
||||
public geoLocation?: TransactionGeoLocationResponse;
|
||||
|
||||
public actualCategoryName: string;
|
||||
public actualSourceAccountName: string;
|
||||
public actualDestinationAccountName?: string;
|
||||
public index: number;
|
||||
public selected: boolean;
|
||||
public valid: boolean;
|
||||
|
||||
private constructor(response: ImportTransactionResponse, index: number) {
|
||||
this.type = response.type;
|
||||
this.categoryId = response.categoryId;
|
||||
this.originalCategoryName = response.originalCategoryName;
|
||||
this.time = response.time;
|
||||
this.utcOffset = response.utcOffset;
|
||||
this.sourceAccountId = response.sourceAccountId;
|
||||
this.originalSourceAccountName = response.originalSourceAccountName;
|
||||
this.originalSourceAccountCurrency = response.originalSourceAccountCurrency;
|
||||
this.destinationAccountId = response.destinationAccountId || '';
|
||||
this.originalDestinationAccountName = response.originalDestinationAccountName;
|
||||
this.originalDestinationAccountCurrency = response.originalDestinationAccountCurrency;
|
||||
this.sourceAmount = response.sourceAmount;
|
||||
this.destinationAmount = response.destinationAmount || 0;
|
||||
this.tagIds = response.tagIds;
|
||||
this.originalTagNames = response.originalTagNames;
|
||||
this.comment = response.comment;
|
||||
this.geoLocation = response.geoLocation;
|
||||
|
||||
this.actualCategoryName = response.originalCategoryName;
|
||||
this.actualSourceAccountName = response.originalSourceAccountName;
|
||||
this.actualDestinationAccountName = response.originalDestinationAccountName;
|
||||
this.index = index;
|
||||
this.selected = false;
|
||||
this.valid = this.isTransactionValid();
|
||||
}
|
||||
|
||||
public toCreateRequest(): TransactionCreateRequest {
|
||||
return {
|
||||
type: this.type,
|
||||
categoryId: this.categoryId,
|
||||
time: this.time,
|
||||
utcOffset: this.utcOffset,
|
||||
sourceAccountId: this.sourceAccountId,
|
||||
destinationAccountId: this.type === TransactionType.Transfer ? this.destinationAccountId : '0',
|
||||
sourceAmount: this.sourceAmount,
|
||||
destinationAmount: this.type === TransactionType.Transfer ? this.destinationAmount : 0,
|
||||
hideAmount: false,
|
||||
tagIds: this.tagIds,
|
||||
pictureIds: [],
|
||||
comment: this.comment,
|
||||
geoLocation: this.geoLocation,
|
||||
clientSessionId: ''
|
||||
};
|
||||
}
|
||||
|
||||
public isTransactionValid(): boolean {
|
||||
if (this.type !== TransactionType.ModifyBalance && (!this.categoryId || this.categoryId === '0')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.sourceAccountId || this.sourceAccountId === '0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.type === TransactionType.Transfer && (!this.destinationAccountId || this.destinationAccountId === '0')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.tagIds && this.tagIds.length) {
|
||||
for (const tagId of this.tagIds) {
|
||||
if (!tagId || tagId === '0') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static of(response: ImportTransactionResponse, index: number): ImportTransaction {
|
||||
return new ImportTransaction(response, index);
|
||||
}
|
||||
}
|
||||
|
||||
export interface ImportTransactionResponse {
|
||||
readonly type: number;
|
||||
|
||||
+454
-4
@@ -1,10 +1,450 @@
|
||||
import type { PartialRecord } from '@/core/base.ts';
|
||||
import type { YearMonth, StartEndTime } from '@/core/datetime.ts';
|
||||
import { TransactionType } from '@/core/transaction.ts';
|
||||
|
||||
import type { AccountInfoResponse } from './account.ts';
|
||||
import type { TransactionCategoryInfoResponse } from './transaction_category.ts';
|
||||
import { Account, type AccountInfoResponse } from './account.ts';
|
||||
import { TransactionCategory, type TransactionCategoryInfoResponse } from './transaction_category.ts';
|
||||
import { TransactionTag, type TransactionTagInfoResponse } from './transaction_tag.ts';
|
||||
import type { TransactionPictureInfoBasicResponse } from './transaction_picture_info.ts';
|
||||
import type { TransactionTagInfoResponse } from './transaction_tag.ts';
|
||||
|
||||
export class Transaction implements TransactionInfoResponse {
|
||||
public id: string;
|
||||
public timeSequenceId: string;
|
||||
public type: number;
|
||||
public expenseCategoryId: string = '';
|
||||
public incomeCategoryId: string = '';
|
||||
public transferCategoryId: string = '';
|
||||
public time: number;
|
||||
public timeZone?: string; // only in new transaction
|
||||
public utcOffset: number;
|
||||
public sourceAccountId: string;
|
||||
public destinationAccountId: string;
|
||||
public sourceAmount: number;
|
||||
public destinationAmount: number;
|
||||
public hideAmount: boolean;
|
||||
public tagIds: string[];
|
||||
public comment: string;
|
||||
public editable: boolean;
|
||||
|
||||
private _pictures?: TransactionPicture[];
|
||||
private _geoLocation?: TransactionGeoLocation;
|
||||
|
||||
private _category?: TransactionCategory; // only for displaying transaction
|
||||
private _sourceAccount?: Account; // only for displaying transaction
|
||||
private _destinationAccount?: Account; // only for displaying transaction
|
||||
private _tags?: TransactionTag[]; // only for displaying transaction
|
||||
|
||||
private _date?: string = undefined; // only for displaying transaction in transaction list
|
||||
private _day?: number = undefined; // only for displaying transaction in transaction list
|
||||
private _dayOfWeek?: string = undefined; // only for displaying transaction in transaction list
|
||||
|
||||
private constructor(id: string, timeSequenceId: string, type: number, categoryId: string, time: number, timeZone: string | undefined, utcOffset: number, sourceAccountId: string, destinationAccountId: string, sourceAmount: number, destinationAmount: number, hideAmount: boolean, tagIds: string[], comment: string, editable: boolean) {
|
||||
this.id = id;
|
||||
this.timeSequenceId = timeSequenceId;
|
||||
this.type = type;
|
||||
this.time = time;
|
||||
this.timeZone = timeZone;
|
||||
this.utcOffset = utcOffset;
|
||||
this.sourceAccountId = sourceAccountId;
|
||||
this.destinationAccountId = destinationAccountId;
|
||||
this.sourceAmount = sourceAmount;
|
||||
this.destinationAmount = destinationAmount;
|
||||
this.hideAmount = hideAmount;
|
||||
this.tagIds = tagIds;
|
||||
this.comment = comment;
|
||||
this.editable = editable;
|
||||
this.setCategoryId(categoryId);
|
||||
}
|
||||
|
||||
public get pictures(): TransactionPictureInfoBasicResponse[] | undefined {
|
||||
const ret: TransactionPictureInfoBasicResponse[] = [];
|
||||
|
||||
if (this._pictures) {
|
||||
for (const picture of this._pictures) {
|
||||
ret.push(picture);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public get geoLocation(): TransactionGeoLocationResponse | undefined {
|
||||
return this._geoLocation;
|
||||
}
|
||||
|
||||
public get categoryId(): string {
|
||||
return this.getCategoryId();
|
||||
}
|
||||
|
||||
public get category(): TransactionCategoryInfoResponse | undefined {
|
||||
return this._category;
|
||||
}
|
||||
|
||||
public get sourceAccount(): AccountInfoResponse | undefined {
|
||||
return this._sourceAccount;
|
||||
}
|
||||
|
||||
public get destinationAccount(): AccountInfoResponse | undefined {
|
||||
return this._destinationAccount;
|
||||
}
|
||||
|
||||
public get tags(): TransactionTagInfoResponse[] | undefined {
|
||||
const ret: TransactionTagInfoResponse[] = [];
|
||||
|
||||
if (this._tags) {
|
||||
for (const tag of this._tags) {
|
||||
ret.push(tag);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public get date(): string | undefined {
|
||||
return this._date;
|
||||
}
|
||||
|
||||
public get day(): number | undefined {
|
||||
return this._day;
|
||||
}
|
||||
|
||||
public get dayOfWeek(): string | undefined {
|
||||
return this._dayOfWeek;
|
||||
}
|
||||
|
||||
public getCategoryId(): string {
|
||||
if (this.type === TransactionType.Expense) {
|
||||
return this.expenseCategoryId;
|
||||
} else if (this.type === TransactionType.Income) {
|
||||
return this.incomeCategoryId;
|
||||
} else if (this.type === TransactionType.Transfer) {
|
||||
return this.transferCategoryId;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public setCategoryId(categoryId: string): void {
|
||||
if (this.type === TransactionType.Expense) {
|
||||
this.expenseCategoryId = categoryId;
|
||||
} else if (this.type === TransactionType.Income) {
|
||||
this.incomeCategoryId = categoryId;
|
||||
} else if (this.type === TransactionType.Transfer) {
|
||||
this.transferCategoryId = categoryId;
|
||||
}
|
||||
}
|
||||
|
||||
public setCategory(category: TransactionCategory): void {
|
||||
this._category = category;
|
||||
}
|
||||
|
||||
public setSourceAccount(sourceAccount: Account): void {
|
||||
this._sourceAccount = sourceAccount;
|
||||
}
|
||||
|
||||
public setDestinationAccount(destinationAccount: Account): void {
|
||||
this._destinationAccount = destinationAccount;
|
||||
}
|
||||
|
||||
public setTags(tags: TransactionTag[]): void {
|
||||
this._tags = tags;
|
||||
}
|
||||
|
||||
public getPictureIds(): string[] {
|
||||
const pictureIds: string[] = [];
|
||||
|
||||
if (this._pictures) {
|
||||
for (const picture of this._pictures) {
|
||||
pictureIds.push(picture.pictureId);
|
||||
}
|
||||
}
|
||||
|
||||
return pictureIds;
|
||||
}
|
||||
|
||||
public setPictures(pictures: TransactionPicture[]): void {
|
||||
this._pictures = pictures;
|
||||
}
|
||||
|
||||
public addPicture(pictureInfo: TransactionPictureInfoBasicResponse): void {
|
||||
if (!this._pictures) {
|
||||
this._pictures = [];
|
||||
}
|
||||
|
||||
this._pictures.push(TransactionPicture.of(pictureInfo));
|
||||
}
|
||||
|
||||
public removePicture(pictureInfo: TransactionPictureInfoBasicResponse): void {
|
||||
if (!this._pictures) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._pictures.length; i++) {
|
||||
if (this._pictures[i].pictureId === pictureInfo.pictureId) {
|
||||
this._pictures.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public clearPictures(): void {
|
||||
this._pictures = [];
|
||||
}
|
||||
|
||||
public setGeoLocation(geoLocation?: TransactionGeoLocation): void {
|
||||
this._geoLocation = geoLocation;
|
||||
}
|
||||
|
||||
public setLatitudeAndLongitude(latitude: number, longitude: number): void {
|
||||
this._geoLocation = TransactionGeoLocation.createNewGeoLocation(latitude, longitude);
|
||||
}
|
||||
|
||||
public removeGeoLocation(): void {
|
||||
this._geoLocation = undefined;
|
||||
}
|
||||
|
||||
public setDisplayDate(date: string, day: number, dayOfWeek: string): void {
|
||||
this._date = date;
|
||||
this._day = day;
|
||||
this._dayOfWeek = dayOfWeek;
|
||||
}
|
||||
|
||||
public toCreateRequest(clientSessionId: string, actualTime?: number): TransactionCreateRequest {
|
||||
return {
|
||||
type: this.type,
|
||||
categoryId: this.getCategoryId(),
|
||||
time: actualTime ? actualTime : this.time,
|
||||
utcOffset: this.utcOffset,
|
||||
sourceAccountId: this.sourceAccountId,
|
||||
destinationAccountId: this.type === TransactionType.Transfer ? this.destinationAccountId : '0',
|
||||
sourceAmount: this.sourceAmount,
|
||||
destinationAmount: this.type === TransactionType.Transfer ? this.destinationAmount : 0,
|
||||
hideAmount: this.hideAmount,
|
||||
tagIds: this.tagIds,
|
||||
pictureIds: this.getPictureIds(),
|
||||
comment: this.comment,
|
||||
geoLocation: this.geoLocation,
|
||||
clientSessionId: clientSessionId
|
||||
};
|
||||
}
|
||||
|
||||
public toModifyRequest(actualTime?: number): TransactionModifyRequest {
|
||||
return {
|
||||
id: this.id,
|
||||
categoryId: this.getCategoryId(),
|
||||
time: actualTime ? actualTime : this.time,
|
||||
utcOffset: this.utcOffset,
|
||||
sourceAccountId: this.sourceAccountId,
|
||||
destinationAccountId: this.type === TransactionType.Transfer ? this.destinationAccountId : '0',
|
||||
sourceAmount: this.sourceAmount,
|
||||
destinationAmount: this.type === TransactionType.Transfer ? this.destinationAmount : 0,
|
||||
hideAmount: this.hideAmount,
|
||||
tagIds: this.tagIds,
|
||||
pictureIds: this.getPictureIds(),
|
||||
comment: this.comment,
|
||||
geoLocation: this.geoLocation
|
||||
};
|
||||
}
|
||||
|
||||
public toTransactionDraft(): TransactionDraft | null {
|
||||
if (this.type !== TransactionType.Expense &&
|
||||
this.type !== TransactionType.Income &&
|
||||
this.type !== TransactionType.Transfer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
type: this.type,
|
||||
categoryId: this.getCategoryId(),
|
||||
sourceAccountId: this.sourceAccountId,
|
||||
sourceAmount: this.sourceAmount,
|
||||
destinationAccountId: this.type === TransactionType.Transfer ? this.destinationAccountId : '0',
|
||||
destinationAmount: this.type === TransactionType.Transfer ? this.destinationAmount : 0,
|
||||
hideAmount: this.hideAmount,
|
||||
tagIds: this.tagIds,
|
||||
pictures: this.pictures,
|
||||
comment: this.comment,
|
||||
};
|
||||
}
|
||||
|
||||
public static createNewTransaction(type: number, time: number, timeZone: string, utcOffset: number): Transaction {
|
||||
return new Transaction(
|
||||
'', // id
|
||||
'', // timeSequenceId
|
||||
type, // type
|
||||
'', // categoryId
|
||||
time, // time
|
||||
timeZone, // timeZone
|
||||
utcOffset, // utcOffset
|
||||
'', // sourceAccountId
|
||||
'', // destinationAccountId
|
||||
0, // sourceAmount
|
||||
0, // destinationAmount
|
||||
false, // hideAmount
|
||||
[], // tagIds
|
||||
'', // comment
|
||||
true // editable
|
||||
);
|
||||
}
|
||||
|
||||
public static of(transactionResponse: TransactionInfoResponse): Transaction {
|
||||
const transaction: Transaction = new Transaction(
|
||||
transactionResponse.id,
|
||||
transactionResponse.timeSequenceId,
|
||||
transactionResponse.type,
|
||||
transactionResponse.categoryId,
|
||||
transactionResponse.time,
|
||||
undefined, // only in new transaction
|
||||
transactionResponse.utcOffset,
|
||||
transactionResponse.sourceAccountId,
|
||||
transactionResponse.destinationAccountId,
|
||||
transactionResponse.sourceAmount,
|
||||
transactionResponse.destinationAmount,
|
||||
transactionResponse.hideAmount,
|
||||
transactionResponse.tagIds,
|
||||
transactionResponse.comment,
|
||||
transactionResponse.editable
|
||||
);
|
||||
|
||||
if (transactionResponse.category) {
|
||||
transaction.setCategory(TransactionCategory.of(transactionResponse.category));
|
||||
}
|
||||
|
||||
if (transactionResponse.sourceAccount) {
|
||||
transaction.setSourceAccount(Account.of(transactionResponse.sourceAccount));
|
||||
}
|
||||
|
||||
if (transactionResponse.destinationAccount) {
|
||||
transaction.setDestinationAccount(Account.of(transactionResponse.destinationAccount));
|
||||
}
|
||||
|
||||
if (transactionResponse.tags) {
|
||||
transaction.setTags(TransactionTag.ofMany(transactionResponse.tags));
|
||||
}
|
||||
|
||||
if (transactionResponse.pictures) {
|
||||
const pictures: TransactionPicture[] = [];
|
||||
|
||||
for (const picture of transactionResponse.pictures) {
|
||||
pictures.push(TransactionPicture.of(picture));
|
||||
}
|
||||
|
||||
transaction.setPictures(pictures);
|
||||
}
|
||||
|
||||
if (transactionResponse.geoLocation) {
|
||||
transaction.setLatitudeAndLongitude(transactionResponse.geoLocation.latitude, transactionResponse.geoLocation.longitude);
|
||||
}
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public static ofMany(transactionResponses: TransactionInfoResponse[]): Transaction[] {
|
||||
const transactions: Transaction[] = [];
|
||||
|
||||
for (const transactionResponse of transactionResponses) {
|
||||
transactions.push(Transaction.of(transactionResponse));
|
||||
}
|
||||
|
||||
return transactions;
|
||||
}
|
||||
|
||||
public static ofDraft(transactionDraft?: TransactionDraft | null): Transaction | null {
|
||||
if (!transactionDraft) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (transactionDraft.type !== TransactionType.Expense &&
|
||||
transactionDraft.type !== TransactionType.Income &&
|
||||
transactionDraft.type !== TransactionType.Transfer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const transaction: Transaction = new Transaction(
|
||||
'', // id
|
||||
'', // timeSequenceId
|
||||
transactionDraft.type, // type
|
||||
transactionDraft.categoryId ?? '', // categoryId
|
||||
0, // time
|
||||
undefined, // only in new transaction
|
||||
0, // utcOffset
|
||||
transactionDraft.sourceAccountId ?? '', // sourceAccountId
|
||||
transactionDraft.destinationAccountId ?? '', // destinationAccountId
|
||||
transactionDraft.sourceAmount ?? 0, // sourceAmount
|
||||
transactionDraft.destinationAmount ?? 0, // destinationAmount
|
||||
transactionDraft.hideAmount ?? false, // hideAmount
|
||||
transactionDraft.tagIds ?? [], // tagIds
|
||||
transactionDraft.comment ?? '', // comment
|
||||
true // editable
|
||||
);
|
||||
|
||||
if (transactionDraft.pictures) {
|
||||
const pictures: TransactionPicture[] = [];
|
||||
|
||||
for (const picture of transactionDraft.pictures) {
|
||||
pictures.push(TransactionPicture.of(picture));
|
||||
}
|
||||
|
||||
transaction.setPictures(pictures);
|
||||
}
|
||||
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
|
||||
export class TransactionPicture implements TransactionPictureInfoBasicResponse {
|
||||
public pictureId: string;
|
||||
public originalUrl: string;
|
||||
|
||||
private constructor(pictureId: string, originalUrl: string) {
|
||||
this.pictureId = pictureId;
|
||||
this.originalUrl = originalUrl;
|
||||
}
|
||||
|
||||
public static of(picture: TransactionPictureInfoBasicResponse): TransactionPicture {
|
||||
return new TransactionPicture(picture.pictureId, picture.originalUrl);
|
||||
}
|
||||
|
||||
public static ofMany(pictureResponses: TransactionPictureInfoBasicResponse[]): TransactionPicture[] {
|
||||
const pictures: TransactionPicture[] = [];
|
||||
|
||||
for (const pictureResponse of pictureResponses) {
|
||||
pictures.push(TransactionPicture.of(pictureResponse));
|
||||
}
|
||||
|
||||
return pictures;
|
||||
}
|
||||
}
|
||||
|
||||
export class TransactionGeoLocation implements TransactionGeoLocationRequest {
|
||||
public latitude: number;
|
||||
public longitude: number;
|
||||
|
||||
private constructor(latitude: number, longitude: number) {
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
public static createNewGeoLocation(latitude: number, longitude: number): TransactionGeoLocation {
|
||||
return new TransactionGeoLocation(latitude, longitude);
|
||||
}
|
||||
|
||||
public static of(geoLocation: TransactionGeoLocationRequest): TransactionGeoLocation {
|
||||
return new TransactionGeoLocation(geoLocation.latitude, geoLocation.longitude);
|
||||
}
|
||||
}
|
||||
|
||||
export interface TransactionDraft {
|
||||
readonly type?: number;
|
||||
readonly categoryId?: string;
|
||||
readonly sourceAccountId?: string;
|
||||
readonly sourceAmount?: number;
|
||||
readonly destinationAccountId?: string;
|
||||
readonly destinationAmount?: number;
|
||||
readonly hideAmount?: boolean;
|
||||
readonly tagIds?: string[];
|
||||
readonly pictures?: TransactionPictureInfoBasicResponse[];
|
||||
readonly comment?: string;
|
||||
}
|
||||
|
||||
export interface TransactionGeoLocationRequest {
|
||||
readonly latitude: number;
|
||||
@@ -209,7 +649,7 @@ export class TransactionAmountsRequest {
|
||||
|
||||
export interface TransactionInfoPageWrapperResponse {
|
||||
readonly items: TransactionInfoResponse[];
|
||||
readonly nextTimeSequenceId?: string;
|
||||
readonly nextTimeSequenceId?: number;
|
||||
readonly totalCount?: number;
|
||||
}
|
||||
|
||||
@@ -218,6 +658,11 @@ export interface TransactionInfoPageWrapperResponse2 {
|
||||
readonly totalCount: number;
|
||||
}
|
||||
|
||||
export interface TransactionPageWrapper {
|
||||
readonly items: Transaction[];
|
||||
readonly totalCount?: number;
|
||||
}
|
||||
|
||||
export interface TransactionStatisticResponse {
|
||||
readonly startTime: number;
|
||||
readonly endTime: number;
|
||||
@@ -344,3 +789,8 @@ export interface TransactionMonthlyIncomeAndExpenseData {
|
||||
readonly incompleteIncomeAmount: boolean;
|
||||
readonly incompleteExpenseAmount: boolean;
|
||||
}
|
||||
|
||||
export const EMPTY_TRANSACTION_RESULT: TransactionPageWrapper = {
|
||||
items: [],
|
||||
totalCount: 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user