mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-20 01:34:24 +08:00
migrate transaction store to composition API and typescript
This commit is contained in:
@@ -489,6 +489,41 @@ export function arrayItemToObjectField<T>(array: string[], value: T): Record<str
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function splitItemsToMap(str: string | undefined | null, separator: string): Record<string, boolean> {
|
||||||
|
const ret: Record<string, boolean> = {};
|
||||||
|
|
||||||
|
if (!str) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = str.split(separator);
|
||||||
|
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
if (items[i]) {
|
||||||
|
ret[items[i]] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function countSplitItems(str: string | undefined | null, separator: string): number {
|
||||||
|
if (!str) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = str.split(separator);
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
if (items[i]) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
export function categorizedArrayToPlainArray<T>(object: Record<string, T[]>): T[] {
|
export function categorizedArrayToPlainArray<T>(object: Record<string, T[]>): T[] {
|
||||||
const ret: T[] = [];
|
const ret: T[] = [];
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import { CategoryType } from '@/core/category.ts';
|
import { CategoryType } from '@/core/category.ts';
|
||||||
import { TransactionType } from '@/core/transaction.ts';
|
import { TransactionType } from '@/core/transaction.ts';
|
||||||
|
import { Account } from '@/models/account.ts';
|
||||||
|
import { TransactionCategory } from '@/models/transaction_category.ts';
|
||||||
|
import { TransactionTag } from '@/models/transaction_tag.ts';
|
||||||
|
import {Transaction, TransactionPicture} from '@/models/transaction.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
isNumber
|
isNumber
|
||||||
} from './common.ts';
|
} from './common.ts';
|
||||||
@@ -14,7 +19,18 @@ import {
|
|||||||
getFirstAvailableSubCategoryId
|
getFirstAvailableSubCategoryId
|
||||||
} from './category.ts';
|
} from './category.ts';
|
||||||
|
|
||||||
function getDisplayAmount(amount, currency, hideAmount, formatAmountWithCurrencyFunc) {
|
export interface SetTransactionOptions {
|
||||||
|
type: number;
|
||||||
|
categoryId: string;
|
||||||
|
accountId: string;
|
||||||
|
destinationAccountId: string;
|
||||||
|
amount: number;
|
||||||
|
destinationAmount: number;
|
||||||
|
tagIds: string;
|
||||||
|
comment: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDisplayAmount(amount: number, currency: string, hideAmount: boolean, formatAmountWithCurrencyFunc: (value: number | string, currencyCode?: string) => string): string {
|
||||||
if (hideAmount) {
|
if (hideAmount) {
|
||||||
return formatAmountWithCurrencyFunc('***', currency);
|
return formatAmountWithCurrencyFunc('***', currency);
|
||||||
}
|
}
|
||||||
@@ -22,8 +38,8 @@ function getDisplayAmount(amount, currency, hideAmount, formatAmountWithCurrency
|
|||||||
return formatAmountWithCurrencyFunc(amount, currency);
|
return formatAmountWithCurrencyFunc(amount, currency);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setTransactionModelByTransaction(transaction, transaction2, allCategories, allCategoriesMap, allVisibleAccounts, allAccountsMap, allTagsMap, defaultAccountId, options, setContextData, convertContextTime) {
|
export function setTransactionModelByTransaction(transaction: Transaction, transaction2: Transaction | null | undefined, allCategories: Record<number, TransactionCategory[]>, allCategoriesMap: Record<string, TransactionCategory>, allVisibleAccounts: Account[], allAccountsMap: Record<string, Account>, allTagsMap: Record<string, TransactionTag>, defaultAccountId: string, options: SetTransactionOptions, setContextData: boolean, convertContextTime: boolean): void {
|
||||||
if ((!options.type || options.type === '0') && options.categoryId && options.categoryId !== '0' && allCategoriesMap[options.categoryId]) {
|
if (!options.type && options.categoryId && options.categoryId !== '0' && allCategoriesMap[options.categoryId]) {
|
||||||
const category = allCategoriesMap[options.categoryId];
|
const category = allCategoriesMap[options.categoryId];
|
||||||
const type = categoryTypeToTransactionType(category.type);
|
const type = categoryTypeToTransactionType(category.type);
|
||||||
|
|
||||||
@@ -36,14 +52,14 @@ export function setTransactionModelByTransaction(transaction, transaction2, allC
|
|||||||
allCategories[CategoryType.Expense].length) {
|
allCategories[CategoryType.Expense].length) {
|
||||||
if (options.categoryId && options.categoryId !== '0') {
|
if (options.categoryId && options.categoryId !== '0') {
|
||||||
if (isSubCategoryIdAvailable(allCategories[CategoryType.Expense], options.categoryId)) {
|
if (isSubCategoryIdAvailable(allCategories[CategoryType.Expense], options.categoryId)) {
|
||||||
transaction.expenseCategory = options.categoryId;
|
transaction.expenseCategoryId = options.categoryId;
|
||||||
} else {
|
} else {
|
||||||
transaction.expenseCategory = getFirstAvailableSubCategoryId(allCategories[CategoryType.Expense], options.categoryId);
|
transaction.expenseCategoryId = getFirstAvailableSubCategoryId(allCategories[CategoryType.Expense], options.categoryId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!transaction.expenseCategory) {
|
if (!transaction.expenseCategoryId) {
|
||||||
transaction.expenseCategory = getFirstAvailableCategoryId(allCategories[CategoryType.Expense]);
|
transaction.expenseCategoryId = getFirstAvailableCategoryId(allCategories[CategoryType.Expense]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,14 +67,14 @@ export function setTransactionModelByTransaction(transaction, transaction2, allC
|
|||||||
allCategories[CategoryType.Income].length) {
|
allCategories[CategoryType.Income].length) {
|
||||||
if (options.categoryId && options.categoryId !== '0') {
|
if (options.categoryId && options.categoryId !== '0') {
|
||||||
if (isSubCategoryIdAvailable(allCategories[CategoryType.Income], options.categoryId)) {
|
if (isSubCategoryIdAvailable(allCategories[CategoryType.Income], options.categoryId)) {
|
||||||
transaction.incomeCategory = options.categoryId;
|
transaction.incomeCategoryId = options.categoryId;
|
||||||
} else {
|
} else {
|
||||||
transaction.incomeCategory = getFirstAvailableSubCategoryId(allCategories[CategoryType.Income], options.categoryId);
|
transaction.incomeCategoryId = getFirstAvailableSubCategoryId(allCategories[CategoryType.Income], options.categoryId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!transaction.incomeCategory) {
|
if (!transaction.incomeCategoryId) {
|
||||||
transaction.incomeCategory = getFirstAvailableCategoryId(allCategories[CategoryType.Income]);
|
transaction.incomeCategoryId = getFirstAvailableCategoryId(allCategories[CategoryType.Income]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,14 +82,14 @@ export function setTransactionModelByTransaction(transaction, transaction2, allC
|
|||||||
allCategories[CategoryType.Transfer].length) {
|
allCategories[CategoryType.Transfer].length) {
|
||||||
if (options.categoryId && options.categoryId !== '0') {
|
if (options.categoryId && options.categoryId !== '0') {
|
||||||
if (isSubCategoryIdAvailable(allCategories[CategoryType.Transfer], options.categoryId)) {
|
if (isSubCategoryIdAvailable(allCategories[CategoryType.Transfer], options.categoryId)) {
|
||||||
transaction.transferCategory = options.categoryId;
|
transaction.transferCategoryId = options.categoryId;
|
||||||
} else {
|
} else {
|
||||||
transaction.transferCategory = getFirstAvailableSubCategoryId(allCategories[CategoryType.Transfer], options.categoryId);
|
transaction.transferCategoryId = getFirstAvailableSubCategoryId(allCategories[CategoryType.Transfer], options.categoryId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!transaction.transferCategory) {
|
if (!transaction.transferCategoryId) {
|
||||||
transaction.transferCategory = getFirstAvailableCategoryId(allCategories[CategoryType.Transfer]);
|
transaction.transferCategoryId = getFirstAvailableCategoryId(allCategories[CategoryType.Transfer]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,11 +145,11 @@ export function setTransactionModelByTransaction(transaction, transaction2, allC
|
|||||||
transaction.type = transaction2.type;
|
transaction.type = transaction2.type;
|
||||||
|
|
||||||
if (transaction.type === TransactionType.Expense) {
|
if (transaction.type === TransactionType.Expense) {
|
||||||
transaction.expenseCategory = transaction2.categoryId || '';
|
transaction.expenseCategoryId = transaction2.categoryId || '';
|
||||||
} else if (transaction.type === TransactionType.Income) {
|
} else if (transaction.type === TransactionType.Income) {
|
||||||
transaction.incomeCategory = transaction2.categoryId || '';
|
transaction.incomeCategoryId = transaction2.categoryId || '';
|
||||||
} else if (transaction.type === TransactionType.Transfer) {
|
} else if (transaction.type === TransactionType.Transfer) {
|
||||||
transaction.transferCategory = transaction2.categoryId || '';
|
transaction.transferCategoryId = transaction2.categoryId || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setContextData) {
|
if (setContextData) {
|
||||||
@@ -165,17 +181,17 @@ export function setTransactionModelByTransaction(transaction, transaction2, allC
|
|||||||
|
|
||||||
transaction.hideAmount = transaction2.hideAmount;
|
transaction.hideAmount = transaction2.hideAmount;
|
||||||
transaction.tagIds = transaction2.tagIds || [];
|
transaction.tagIds = transaction2.tagIds || [];
|
||||||
transaction.pictures = transaction2.pictures || [];
|
transaction.setPictures(TransactionPicture.ofMany(transaction2.pictures || []));
|
||||||
|
|
||||||
transaction.comment = transaction2.comment;
|
transaction.comment = transaction2.comment;
|
||||||
|
|
||||||
if (setContextData) {
|
if (setContextData) {
|
||||||
transaction.geoLocation = transaction2.geoLocation;
|
transaction.setGeoLocation(transaction2.geoLocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTransactionDisplayAmount(transaction, allFilterAccountIdsCount, allFilterAccountIds, formatAmountWithCurrencyFunc) {
|
export function getTransactionDisplayAmount(transaction: Transaction, allFilterAccountIdsCount: number, allFilterAccountIds: Record<string, boolean>, formatAmountWithCurrencyFunc: (value: number | string, currencyCode?: string) => string): string {
|
||||||
if (allFilterAccountIdsCount < 1) {
|
if (allFilterAccountIdsCount < 1) {
|
||||||
if (transaction.sourceAccount) {
|
if (transaction.sourceAccount) {
|
||||||
return getDisplayAmount(transaction.sourceAmount, transaction.sourceAccount.currency, transaction.hideAmount, formatAmountWithCurrencyFunc);
|
return getDisplayAmount(transaction.sourceAmount, transaction.sourceAccount.currency, transaction.hideAmount, formatAmountWithCurrencyFunc);
|
||||||
@@ -2,6 +2,7 @@ import CryptoJS from 'crypto-js';
|
|||||||
|
|
||||||
import type { ApplicationLockState, WebAuthnConfig } from '@/core/setting.ts';
|
import type { ApplicationLockState, WebAuthnConfig } from '@/core/setting.ts';
|
||||||
import type { UserBasicInfo } from '@/models/user.ts';
|
import type { UserBasicInfo } from '@/models/user.ts';
|
||||||
|
import type { TransactionDraft } from '@/models/transaction.ts';
|
||||||
|
|
||||||
import { isString, isObject } from './common.ts';
|
import { isString, isObject } from './common.ts';
|
||||||
import { isEnableApplicationLock } from './settings.ts';
|
import { isEnableApplicationLock } from './settings.ts';
|
||||||
@@ -257,7 +258,7 @@ export function clearCurrentUserInfo(): void {
|
|||||||
localStorage.removeItem(userInfoLocalStorageKey);
|
localStorage.removeItem(userInfoLocalStorageKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUserTransactionDraft(): unknown | null {
|
export function getUserTransactionDraft(): TransactionDraft | null {
|
||||||
let data = localStorage.getItem(transactionDraftLocalStorageKey);
|
let data = localStorage.getItem(transactionDraftLocalStorageKey);
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
@@ -274,10 +275,10 @@ export function getUserTransactionDraft(): unknown | null {
|
|||||||
data = getDecryptedToken(data, appLockState);
|
data = getDecryptedToken(data, appLockState);
|
||||||
}
|
}
|
||||||
|
|
||||||
return JSON.parse(data);
|
return JSON.parse(data) as TransactionDraft;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateUserTransactionDraft(transaction: unknown): void {
|
export function updateUserTransactionDraft(transaction?: TransactionDraft | null): void {
|
||||||
if (!isObject(transaction)) {
|
if (!isObject(transaction)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
export interface ImportTransactionResponse {
|
||||||
readonly type: number;
|
readonly type: number;
|
||||||
|
|||||||
+454
-4
@@ -1,10 +1,450 @@
|
|||||||
import type { PartialRecord } from '@/core/base.ts';
|
import type { PartialRecord } from '@/core/base.ts';
|
||||||
import type { YearMonth, StartEndTime } from '@/core/datetime.ts';
|
import type { YearMonth, StartEndTime } from '@/core/datetime.ts';
|
||||||
|
import { TransactionType } from '@/core/transaction.ts';
|
||||||
|
|
||||||
import type { AccountInfoResponse } from './account.ts';
|
import { Account, type AccountInfoResponse } from './account.ts';
|
||||||
import type { TransactionCategoryInfoResponse } from './transaction_category.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 { 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 {
|
export interface TransactionGeoLocationRequest {
|
||||||
readonly latitude: number;
|
readonly latitude: number;
|
||||||
@@ -209,7 +649,7 @@ export class TransactionAmountsRequest {
|
|||||||
|
|
||||||
export interface TransactionInfoPageWrapperResponse {
|
export interface TransactionInfoPageWrapperResponse {
|
||||||
readonly items: TransactionInfoResponse[];
|
readonly items: TransactionInfoResponse[];
|
||||||
readonly nextTimeSequenceId?: string;
|
readonly nextTimeSequenceId?: number;
|
||||||
readonly totalCount?: number;
|
readonly totalCount?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,6 +658,11 @@ export interface TransactionInfoPageWrapperResponse2 {
|
|||||||
readonly totalCount: number;
|
readonly totalCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TransactionPageWrapper {
|
||||||
|
readonly items: Transaction[];
|
||||||
|
readonly totalCount?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TransactionStatisticResponse {
|
export interface TransactionStatisticResponse {
|
||||||
readonly startTime: number;
|
readonly startTime: number;
|
||||||
readonly endTime: number;
|
readonly endTime: number;
|
||||||
@@ -344,3 +789,8 @@ export interface TransactionMonthlyIncomeAndExpenseData {
|
|||||||
readonly incompleteIncomeAmount: boolean;
|
readonly incompleteIncomeAmount: boolean;
|
||||||
readonly incompleteExpenseAmount: boolean;
|
readonly incompleteExpenseAmount: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const EMPTY_TRANSACTION_RESULT: TransactionPageWrapper = {
|
||||||
|
items: [],
|
||||||
|
totalCount: 0
|
||||||
|
}
|
||||||
|
|||||||
+1
-2
@@ -8,8 +8,7 @@ import { useTransactionCategoriesStore } from './transactionCategory.ts';
|
|||||||
import { useTransactionTagsStore } from './transactionTag.ts';
|
import { useTransactionTagsStore } from './transactionTag.ts';
|
||||||
// @ts-expect-error the above file is migrating to ts
|
// @ts-expect-error the above file is migrating to ts
|
||||||
import { useTransactionTemplatesStore } from './transactionTemplate.js';
|
import { useTransactionTemplatesStore } from './transactionTemplate.js';
|
||||||
// @ts-expect-error the above file is migrating to ts
|
import { useTransactionsStore } from './transaction.ts';
|
||||||
import { useTransactionsStore } from './transaction.js';
|
|
||||||
import { useOverviewStore } from './overview.ts';
|
import { useOverviewStore } from './overview.ts';
|
||||||
import { useStatisticsStore } from './statistics.ts';
|
import { useStatisticsStore } from './statistics.ts';
|
||||||
import { useExchangeRatesStore } from './exchangeRates.ts';
|
import { useExchangeRatesStore } from './exchangeRates.ts';
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -238,11 +238,11 @@ export const useTransactionTemplatesStore = defineStore('transactionTemplates',
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (template.type === TransactionType.Expense) {
|
if (template.type === TransactionType.Expense) {
|
||||||
submitTemplate.categoryId = template.expenseCategory;
|
submitTemplate.categoryId = template.expenseCategoryId;
|
||||||
} else if (template.type === TransactionType.Income) {
|
} else if (template.type === TransactionType.Income) {
|
||||||
submitTemplate.categoryId = template.incomeCategory;
|
submitTemplate.categoryId = template.incomeCategoryId;
|
||||||
} else if (template.type === TransactionType.Transfer) {
|
} else if (template.type === TransactionType.Transfer) {
|
||||||
submitTemplate.categoryId = template.transferCategory;
|
submitTemplate.categoryId = template.transferCategoryId;
|
||||||
submitTemplate.destinationAccountId = template.destinationAccountId;
|
submitTemplate.destinationAccountId = template.destinationAccountId;
|
||||||
submitTemplate.destinationAmount = template.destinationAmount;
|
submitTemplate.destinationAmount = template.destinationAmount;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ import { useRootStore } from '@/stores/index.ts';
|
|||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useTokensStore } from '@/stores/token.ts';
|
import { useTokensStore } from '@/stores/token.ts';
|
||||||
// @ts-expect-error the above file is migrating to ts
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
|
||||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||||
|
|
||||||
import { isWebAuthnSupported } from '@/lib/webauthn.ts';
|
import { isWebAuthnSupported } from '@/lib/webauthn.ts';
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import { computed } from 'vue';
|
|||||||
import { useI18n } from '@/locales/helpers.ts';
|
import { useI18n } from '@/locales/helpers.ts';
|
||||||
|
|
||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
// @ts-expect-error the above file is migrating to ts
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
|
||||||
import { useOverviewStore } from '@/stores/overview.ts';
|
import { useOverviewStore } from '@/stores/overview.ts';
|
||||||
import { useStatisticsStore } from '@/stores/statistics.ts';
|
import { useStatisticsStore } from '@/stores/statistics.ts';
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ import { useAppLockPageBase } from '@/views/base/settings/AppLockPageBase.ts';
|
|||||||
|
|
||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
|
|
||||||
import { registerWebAuthnCredential } from '@/lib/webauthn.ts';
|
import { registerWebAuthnCredential } from '@/lib/webauthn.ts';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -149,7 +149,7 @@
|
|||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useAccountsStore } from '@/stores/account.ts';
|
import { useAccountsStore } from '@/stores/account.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
import { useStatisticsStore } from '@/stores/statistics.ts';
|
import { useStatisticsStore } from '@/stores/statistics.ts';
|
||||||
|
|
||||||
import { AccountType, AccountCategory } from '@/core/account.ts';
|
import { AccountType, AccountCategory } from '@/core/account.ts';
|
||||||
|
|||||||
@@ -146,7 +146,7 @@
|
|||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
import { useStatisticsStore } from '@/stores/statistics.ts';
|
import { useStatisticsStore } from '@/stores/statistics.ts';
|
||||||
|
|
||||||
import { CategoryType } from '@/core/category.ts';
|
import { CategoryType } from '@/core/category.ts';
|
||||||
|
|||||||
@@ -133,7 +133,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
import { useStatisticsStore } from '@/stores/statistics.ts';
|
import { useStatisticsStore } from '@/stores/statistics.ts';
|
||||||
|
|
||||||
import { TransactionTagFilterType } from '@/core/transaction.ts';
|
import { TransactionTagFilterType } from '@/core/transaction.ts';
|
||||||
|
|||||||
@@ -593,7 +593,7 @@ import { useUserStore } from '@/stores/user.ts';
|
|||||||
import { useAccountsStore } from '@/stores/account.ts';
|
import { useAccountsStore } from '@/stores/account.ts';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
|
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
|
||||||
|
|
||||||
import { DateRangeScene, DateRange } from '@/core/datetime.ts';
|
import { DateRangeScene, DateRange } from '@/core/datetime.ts';
|
||||||
@@ -629,7 +629,7 @@ import {
|
|||||||
transactionTypeToCategoryType
|
transactionTypeToCategoryType
|
||||||
} from '@/lib/category.ts';
|
} from '@/lib/category.ts';
|
||||||
import { getUnifiedSelectedAccountsCurrencyOrDefaultCurrency } from '@/lib/account.ts';
|
import { getUnifiedSelectedAccountsCurrencyOrDefaultCurrency } from '@/lib/account.ts';
|
||||||
import { getTransactionDisplayAmount } from '@/lib/transaction.js';
|
import { getTransactionDisplayAmount } from '@/lib/transaction.ts';
|
||||||
import { isDataImportingEnabled } from '@/lib/server_settings.ts';
|
import { isDataImportingEnabled } from '@/lib/server_settings.ts';
|
||||||
import { scrollToSelectedItem } from '@/lib/ui/desktop.ts';
|
import { scrollToSelectedItem } from '@/lib/ui/desktop.ts';
|
||||||
|
|
||||||
|
|||||||
@@ -115,11 +115,11 @@
|
|||||||
:readonly="mode === 'view'"
|
:readonly="mode === 'view'"
|
||||||
:disabled="loading || submitting || !hasAvailableExpenseCategories"
|
:disabled="loading || submitting || !hasAvailableExpenseCategories"
|
||||||
:show-selection-primary-text="true"
|
:show-selection-primary-text="true"
|
||||||
:custom-selection-primary-text="getPrimaryCategoryName(transaction.expenseCategory, allCategories[allCategoryTypes.Expense])"
|
:custom-selection-primary-text="getPrimaryCategoryName(transaction.expenseCategoryId, allCategories[allCategoryTypes.Expense])"
|
||||||
:custom-selection-secondary-text="getSecondaryCategoryName(transaction.expenseCategory, allCategories[allCategoryTypes.Expense])"
|
:custom-selection-secondary-text="getSecondaryCategoryName(transaction.expenseCategoryId, allCategories[allCategoryTypes.Expense])"
|
||||||
:label="$t('Category')" :placeholder="$t('Category')"
|
:label="$t('Category')" :placeholder="$t('Category')"
|
||||||
:items="allCategories[allCategoryTypes.Expense]"
|
:items="allCategories[allCategoryTypes.Expense]"
|
||||||
v-model="transaction.expenseCategory">
|
v-model="transaction.expenseCategoryId">
|
||||||
</two-column-select>
|
</two-column-select>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="12" v-if="transaction.type === allTransactionTypes.Income">
|
<v-col cols="12" md="12" v-if="transaction.type === allTransactionTypes.Income">
|
||||||
@@ -132,11 +132,11 @@
|
|||||||
:readonly="mode === 'view'"
|
:readonly="mode === 'view'"
|
||||||
:disabled="loading || submitting || !hasAvailableIncomeCategories"
|
:disabled="loading || submitting || !hasAvailableIncomeCategories"
|
||||||
:show-selection-primary-text="true"
|
:show-selection-primary-text="true"
|
||||||
:custom-selection-primary-text="getPrimaryCategoryName(transaction.incomeCategory, allCategories[allCategoryTypes.Income])"
|
:custom-selection-primary-text="getPrimaryCategoryName(transaction.incomeCategoryId, allCategories[allCategoryTypes.Income])"
|
||||||
:custom-selection-secondary-text="getSecondaryCategoryName(transaction.incomeCategory, allCategories[allCategoryTypes.Income])"
|
:custom-selection-secondary-text="getSecondaryCategoryName(transaction.incomeCategoryId, allCategories[allCategoryTypes.Income])"
|
||||||
:label="$t('Category')" :placeholder="$t('Category')"
|
:label="$t('Category')" :placeholder="$t('Category')"
|
||||||
:items="allCategories[allCategoryTypes.Income]"
|
:items="allCategories[allCategoryTypes.Income]"
|
||||||
v-model="transaction.incomeCategory">
|
v-model="transaction.incomeCategoryId">
|
||||||
</two-column-select>
|
</two-column-select>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="12" v-if="transaction.type === allTransactionTypes.Transfer">
|
<v-col cols="12" md="12" v-if="transaction.type === allTransactionTypes.Transfer">
|
||||||
@@ -149,11 +149,11 @@
|
|||||||
:readonly="mode === 'view'"
|
:readonly="mode === 'view'"
|
||||||
:disabled="loading || submitting || !hasAvailableTransferCategories"
|
:disabled="loading || submitting || !hasAvailableTransferCategories"
|
||||||
:show-selection-primary-text="true"
|
:show-selection-primary-text="true"
|
||||||
:custom-selection-primary-text="getPrimaryCategoryName(transaction.transferCategory, allCategories[allCategoryTypes.Transfer])"
|
:custom-selection-primary-text="getPrimaryCategoryName(transaction.transferCategoryId, allCategories[allCategoryTypes.Transfer])"
|
||||||
:custom-selection-secondary-text="getSecondaryCategoryName(transaction.transferCategory, allCategories[allCategoryTypes.Transfer])"
|
:custom-selection-secondary-text="getSecondaryCategoryName(transaction.transferCategoryId, allCategories[allCategoryTypes.Transfer])"
|
||||||
:label="$t('Category')" :placeholder="$t('Category')"
|
:label="$t('Category')" :placeholder="$t('Category')"
|
||||||
:items="allCategories[allCategoryTypes.Transfer]"
|
:items="allCategories[allCategoryTypes.Transfer]"
|
||||||
v-model="transaction.transferCategory">
|
v-model="transaction.transferCategoryId">
|
||||||
</two-column-select>
|
</two-column-select>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" :md="transaction.type === allTransactionTypes.Transfer ? 6 : 12">
|
<v-col cols="12" :md="transaction.type === allTransactionTypes.Transfer ? 6 : 12">
|
||||||
@@ -396,7 +396,7 @@ import { useUserStore } from '@/stores/user.ts';
|
|||||||
import { useAccountsStore } from '@/stores/account.ts';
|
import { useAccountsStore } from '@/stores/account.ts';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
|
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
|
||||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||||
|
|
||||||
@@ -423,7 +423,7 @@ import {
|
|||||||
getTransactionSecondaryCategoryName,
|
getTransactionSecondaryCategoryName,
|
||||||
getFirstAvailableCategoryId
|
getFirstAvailableCategoryId
|
||||||
} from '@/lib/category.ts';
|
} from '@/lib/category.ts';
|
||||||
import { setTransactionModelByTransaction } from '@/lib/transaction.js';
|
import { setTransactionModelByTransaction } from '@/lib/transaction.ts';
|
||||||
import {
|
import {
|
||||||
isTransactionPicturesEnabled,
|
isTransactionPicturesEnabled,
|
||||||
getMapProvider
|
getMapProvider
|
||||||
@@ -715,7 +715,7 @@ export default {
|
|||||||
},
|
},
|
||||||
inputEmptyProblemMessage() {
|
inputEmptyProblemMessage() {
|
||||||
if (this.transaction.type === this.allTransactionTypes.Expense) {
|
if (this.transaction.type === this.allTransactionTypes.Expense) {
|
||||||
if (!this.transaction.expenseCategory || this.transaction.expenseCategory === '') {
|
if (!this.transaction.expenseCategoryId || this.transaction.expenseCategoryId === '') {
|
||||||
return 'Transaction category cannot be blank';
|
return 'Transaction category cannot be blank';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -723,7 +723,7 @@ export default {
|
|||||||
return 'Transaction account cannot be blank';
|
return 'Transaction account cannot be blank';
|
||||||
}
|
}
|
||||||
} else if (this.transaction.type === this.allTransactionTypes.Income) {
|
} else if (this.transaction.type === this.allTransactionTypes.Income) {
|
||||||
if (!this.transaction.incomeCategory || this.transaction.incomeCategory === '') {
|
if (!this.transaction.incomeCategoryId || this.transaction.incomeCategoryId === '') {
|
||||||
return 'Transaction category cannot be blank';
|
return 'Transaction category cannot be blank';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -731,7 +731,7 @@ export default {
|
|||||||
return 'Transaction account cannot be blank';
|
return 'Transaction account cannot be blank';
|
||||||
}
|
}
|
||||||
} else if (this.transaction.type === this.allTransactionTypes.Transfer) {
|
} else if (this.transaction.type === this.allTransactionTypes.Transfer) {
|
||||||
if (!this.transaction.transferCategory || this.transaction.transferCategory === '') {
|
if (!this.transaction.transferCategoryId || this.transaction.transferCategoryId === '') {
|
||||||
return 'Transaction category cannot be blank';
|
return 'Transaction category cannot be blank';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -869,7 +869,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
self.mode = 'add';
|
self.mode = 'add';
|
||||||
self.editId = null;
|
self.editId = null;
|
||||||
self.transaction.id = null;
|
self.transaction.id = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1047,12 +1047,12 @@ export default {
|
|||||||
|
|
||||||
this.editId = null;
|
this.editId = null;
|
||||||
this.duplicateFromId = this.transaction.id;
|
this.duplicateFromId = this.transaction.id;
|
||||||
this.transaction.id = null;
|
this.transaction.id = '';
|
||||||
this.transaction.time = getCurrentUnixTime();
|
this.transaction.time = getCurrentUnixTime();
|
||||||
this.transaction.timeZone = this.settingsStore.appSettings.timeZone;
|
this.transaction.timeZone = this.settingsStore.appSettings.timeZone;
|
||||||
this.transaction.utcOffset = getTimezoneOffsetMinutes(this.transaction.timeZone);
|
this.transaction.utcOffset = getTimezoneOffsetMinutes(this.transaction.timeZone);
|
||||||
this.transaction.geoLocation = null;
|
this.transaction.removeGeoLocation();
|
||||||
this.transaction.pictures = [];
|
this.transaction.clearPictures();
|
||||||
this.mode = 'add';
|
this.mode = 'add';
|
||||||
},
|
},
|
||||||
edit() {
|
edit() {
|
||||||
@@ -1157,10 +1157,7 @@ export default {
|
|||||||
|
|
||||||
self.geoLocationStatus = 'success';
|
self.geoLocationStatus = 'success';
|
||||||
|
|
||||||
self.transaction.geoLocation = {
|
self.transaction.setLatitudeAndLongitude(position.coords.latitude, position.coords.longitude);
|
||||||
latitude: position.coords.latitude,
|
|
||||||
longitude: position.coords.longitude
|
|
||||||
};
|
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
logger.error('cannot retrieve current position', err);
|
logger.error('cannot retrieve current position', err);
|
||||||
self.geoLocationStatus = 'error';
|
self.geoLocationStatus = 'error';
|
||||||
@@ -1175,7 +1172,7 @@ export default {
|
|||||||
clearGeoLocation() {
|
clearGeoLocation() {
|
||||||
this.geoMenuState = false;
|
this.geoMenuState = false;
|
||||||
this.geoLocationStatus = null;
|
this.geoLocationStatus = null;
|
||||||
this.transaction.geoLocation = null;
|
this.transaction.removeGeoLocation();
|
||||||
},
|
},
|
||||||
saveNewTag(tagName) {
|
saveNewTag(tagName) {
|
||||||
const self = this;
|
const self = this;
|
||||||
@@ -1232,12 +1229,7 @@ export default {
|
|||||||
self.submitting = true;
|
self.submitting = true;
|
||||||
|
|
||||||
self.transactionsStore.uploadTransactionPicture({ pictureFile }).then(response => {
|
self.transactionsStore.uploadTransactionPicture({ pictureFile }).then(response => {
|
||||||
if (!isArray(self.transaction.pictures)) {
|
self.transaction.addPicture(response);
|
||||||
self.transaction.pictures = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.transaction.pictures.push(response);
|
|
||||||
|
|
||||||
self.uploadingPicture = false;
|
self.uploadingPicture = false;
|
||||||
self.submitting = false;
|
self.submitting = false;
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@@ -1262,23 +1254,15 @@ export default {
|
|||||||
self.submitting = true;
|
self.submitting = true;
|
||||||
|
|
||||||
self.transactionsStore.removeUnusedTransactionPicture({ pictureInfo }).then(response => {
|
self.transactionsStore.removeUnusedTransactionPicture({ pictureInfo }).then(response => {
|
||||||
if (response && isArray(self.transaction.pictures)) {
|
if (response) {
|
||||||
for (let i = 0; i < self.transaction.pictures.length; i++) {
|
self.transaction.removePicture(pictureInfo);
|
||||||
if (self.transaction.pictures[i].pictureId === pictureInfo.pictureId) {
|
|
||||||
self.transaction.pictures.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.removingPictureId = '';
|
self.removingPictureId = '';
|
||||||
self.submitting = false;
|
self.submitting = false;
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
if (error.error && error.error.errorCode === KnownErrorCode.TransactionPictureNotFound) {
|
if (error.error && error.error.errorCode === KnownErrorCode.TransactionPictureNotFound) {
|
||||||
for (let i = 0; i < self.transaction.pictures.length; i++) {
|
self.transaction.removePicture(pictureInfo);
|
||||||
if (self.transaction.pictures[i].pictureId === pictureInfo.pictureId) {
|
|
||||||
self.transaction.pictures.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (!error.processed) {
|
} else if (!error.processed) {
|
||||||
self.$refs.snackbar.showError(error);
|
self.$refs.snackbar.showError(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -602,13 +602,15 @@ import { useUserStore } from '@/stores/user.ts';
|
|||||||
import { useAccountsStore } from '@/stores/account.ts';
|
import { useAccountsStore } from '@/stores/account.ts';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
import { useOverviewStore } from '@/stores/overview.ts';
|
import { useOverviewStore } from '@/stores/overview.ts';
|
||||||
import { useStatisticsStore } from '@/stores/statistics.ts';
|
import { useStatisticsStore } from '@/stores/statistics.ts';
|
||||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||||
|
|
||||||
import { CategoryType } from '@/core/category.ts';
|
import { CategoryType } from '@/core/category.ts';
|
||||||
import { TransactionType } from '@/core/transaction.ts';
|
import { TransactionType } from '@/core/transaction.ts';
|
||||||
|
import { ImportTransaction } from '@/models/imported_transaction.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
isString,
|
isString,
|
||||||
isNumber,
|
isNumber,
|
||||||
@@ -1139,17 +1141,12 @@ export default {
|
|||||||
fileType: fileType,
|
fileType: fileType,
|
||||||
importFile: self.importFile
|
importFile: self.importFile
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
const parsedTransactions = response.items;
|
const parsedTransactions = [];
|
||||||
|
|
||||||
if (parsedTransactions) {
|
if (response.items) {
|
||||||
for (let i = 0; i < parsedTransactions.length; i++) {
|
for (let i = 0; i < response.items.length; i++) {
|
||||||
const transaction = parsedTransactions[i];
|
const parsedTransaction = ImportTransaction.of(response.items[i], i);
|
||||||
transaction.index = i;
|
parsedTransactions.push(parsedTransaction);
|
||||||
transaction.selected = false;
|
|
||||||
transaction.valid = self.isTransactionValid(transaction);
|
|
||||||
transaction.actualCategoryName = transaction.originalCategoryName;
|
|
||||||
transaction.actualSourceAccountName = transaction.originalSourceAccountName;
|
|
||||||
transaction.actualDestinationAccountName = transaction.originalDestinationAccountName;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1408,7 +1405,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateTransactionData(transaction) {
|
updateTransactionData(transaction) {
|
||||||
transaction.valid = this.isTransactionValid(transaction);
|
transaction.valid = transaction.isTransactionValid();
|
||||||
|
|
||||||
if (transaction.categoryId && this.allCategoriesMap[transaction.categoryId]) {
|
if (transaction.categoryId && this.allCategoriesMap[transaction.categoryId]) {
|
||||||
transaction.actualCategoryName = this.allCategoriesMap[transaction.categoryId].name;
|
transaction.actualCategoryName = this.allCategoriesMap[transaction.categoryId].name;
|
||||||
@@ -1717,33 +1714,6 @@ export default {
|
|||||||
|
|
||||||
return invalidTags;
|
return invalidTags;
|
||||||
},
|
},
|
||||||
isTransactionValid(transaction) {
|
|
||||||
if (!transaction) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transaction.type !== this.allTransactionTypes.ModifyBalance && (!transaction.categoryId || transaction.categoryId === '0')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!transaction.sourceAccountId || transaction.sourceAccountId === '0') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transaction.type === this.allTransactionTypes.Transfer && (!transaction.destinationAccountId || transaction.destinationAccountId === '0')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transaction.tagIds && transaction.tagIds.length) {
|
|
||||||
for (let j = 0; j < transaction.tagIds.length; j++) {
|
|
||||||
if (!transaction.tagIds[j] || transaction.tagIds[j] === '0') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
isTagValid(tagIds, tagIndex) {
|
isTagValid(tagIds, tagIndex) {
|
||||||
if (!tagIds || !tagIds[tagIndex]) {
|
if (!tagIds || !tagIds[tagIndex]) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ import { useAppLockPageBase } from '@/views/base/settings/AppLockPageBase.ts';
|
|||||||
|
|
||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
|
|
||||||
import { registerWebAuthnCredential } from '@/lib/webauthn.ts';
|
import { registerWebAuthnCredential } from '@/lib/webauthn.ts';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -135,7 +135,7 @@
|
|||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useAccountsStore } from '@/stores/account.ts';
|
import { useAccountsStore } from '@/stores/account.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
import { useStatisticsStore } from '@/stores/statistics.ts';
|
import { useStatisticsStore } from '@/stores/statistics.ts';
|
||||||
|
|
||||||
import { AccountType, AccountCategory } from '@/core/account.ts';
|
import { AccountType, AccountCategory } from '@/core/account.ts';
|
||||||
|
|||||||
@@ -142,7 +142,7 @@
|
|||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
import { useStatisticsStore } from '@/stores/statistics.ts';
|
import { useStatisticsStore } from '@/stores/statistics.ts';
|
||||||
|
|
||||||
import { CategoryType } from '@/core/category.ts';
|
import { CategoryType } from '@/core/category.ts';
|
||||||
|
|||||||
@@ -113,7 +113,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
import { useStatisticsStore } from '@/stores/statistics.ts';
|
import { useStatisticsStore } from '@/stores/statistics.ts';
|
||||||
|
|
||||||
import { TransactionTagFilterType } from '@/core/transaction.ts';
|
import { TransactionTagFilterType } from '@/core/transaction.ts';
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ import type { Router } from 'framework7/types';
|
|||||||
import { useI18n } from '@/locales/helpers.ts';
|
import { useI18n } from '@/locales/helpers.ts';
|
||||||
import { useI18nUIComponents } from '@/lib/ui/mobile.ts';
|
import { useI18nUIComponents } from '@/lib/ui/mobile.ts';
|
||||||
|
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
|
|
||||||
import { AmountFilterType } from '@/core/numeral.ts';
|
import { AmountFilterType } from '@/core/numeral.ts';
|
||||||
import { TRANSACTION_MIN_AMOUNT, TRANSACTION_MAX_AMOUNT } from '@/consts/transaction.ts';
|
import { TRANSACTION_MIN_AMOUNT, TRANSACTION_MAX_AMOUNT } from '@/consts/transaction.ts';
|
||||||
|
|||||||
@@ -104,9 +104,9 @@
|
|||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="list-item-custom-title" v-if="hasAvailableExpenseCategories">
|
<div class="list-item-custom-title" v-if="hasAvailableExpenseCategories">
|
||||||
<span>{{ getPrimaryCategoryName(transaction.expenseCategory, allCategories[allCategoryTypes.Expense]) }}</span>
|
<span>{{ getPrimaryCategoryName(transaction.expenseCategoryId, allCategories[allCategoryTypes.Expense]) }}</span>
|
||||||
<f7-icon class="category-separate-icon" f7="chevron_right"></f7-icon>
|
<f7-icon class="category-separate-icon" f7="chevron_right"></f7-icon>
|
||||||
<span>{{ getSecondaryCategoryName(transaction.expenseCategory, allCategories[allCategoryTypes.Expense]) }}</span>
|
<span>{{ getSecondaryCategoryName(transaction.expenseCategoryId, allCategories[allCategoryTypes.Expense]) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-item-custom-title" v-else-if="!hasAvailableExpenseCategories">
|
<div class="list-item-custom-title" v-else-if="!hasAvailableExpenseCategories">
|
||||||
<span>{{ $t('None') }}</span>
|
<span>{{ $t('None') }}</span>
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
secondary-hidden-field="hidden"
|
secondary-hidden-field="hidden"
|
||||||
:items="allCategories[allCategoryTypes.Expense]"
|
:items="allCategories[allCategoryTypes.Expense]"
|
||||||
v-model:show="showCategorySheet"
|
v-model:show="showCategorySheet"
|
||||||
v-model="transaction.expenseCategory">
|
v-model="transaction.expenseCategoryId">
|
||||||
</tree-view-selection-sheet>
|
</tree-view-selection-sheet>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
|
|
||||||
@@ -135,9 +135,9 @@
|
|||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="list-item-custom-title" v-if="hasAvailableIncomeCategories">
|
<div class="list-item-custom-title" v-if="hasAvailableIncomeCategories">
|
||||||
<span>{{ getPrimaryCategoryName(transaction.incomeCategory, allCategories[allCategoryTypes.Income]) }}</span>
|
<span>{{ getPrimaryCategoryName(transaction.incomeCategoryId, allCategories[allCategoryTypes.Income]) }}</span>
|
||||||
<f7-icon class="category-separate-icon" f7="chevron_right"></f7-icon>
|
<f7-icon class="category-separate-icon" f7="chevron_right"></f7-icon>
|
||||||
<span>{{ getSecondaryCategoryName(transaction.incomeCategory, allCategories[allCategoryTypes.Income]) }}</span>
|
<span>{{ getSecondaryCategoryName(transaction.incomeCategoryId, allCategories[allCategoryTypes.Income]) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-item-custom-title" v-else-if="!hasAvailableIncomeCategories">
|
<div class="list-item-custom-title" v-else-if="!hasAvailableIncomeCategories">
|
||||||
<span>{{ $t('None') }}</span>
|
<span>{{ $t('None') }}</span>
|
||||||
@@ -151,7 +151,7 @@
|
|||||||
secondary-hidden-field="hidden"
|
secondary-hidden-field="hidden"
|
||||||
:items="allCategories[allCategoryTypes.Income]"
|
:items="allCategories[allCategoryTypes.Income]"
|
||||||
v-model:show="showCategorySheet"
|
v-model:show="showCategorySheet"
|
||||||
v-model="transaction.incomeCategory">
|
v-model="transaction.incomeCategoryId">
|
||||||
</tree-view-selection-sheet>
|
</tree-view-selection-sheet>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
|
|
||||||
@@ -166,9 +166,9 @@
|
|||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="list-item-custom-title" v-if="hasAvailableTransferCategories">
|
<div class="list-item-custom-title" v-if="hasAvailableTransferCategories">
|
||||||
<span>{{ getPrimaryCategoryName(transaction.transferCategory, allCategories[allCategoryTypes.Transfer]) }}</span>
|
<span>{{ getPrimaryCategoryName(transaction.transferCategoryId, allCategories[allCategoryTypes.Transfer]) }}</span>
|
||||||
<f7-icon class="category-separate-icon" f7="chevron_right"></f7-icon>
|
<f7-icon class="category-separate-icon" f7="chevron_right"></f7-icon>
|
||||||
<span>{{ getSecondaryCategoryName(transaction.transferCategory, allCategories[allCategoryTypes.Transfer]) }}</span>
|
<span>{{ getSecondaryCategoryName(transaction.transferCategoryId, allCategories[allCategoryTypes.Transfer]) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-item-custom-title" v-else-if="!hasAvailableTransferCategories">
|
<div class="list-item-custom-title" v-else-if="!hasAvailableTransferCategories">
|
||||||
<span>{{ $t('None') }}</span>
|
<span>{{ $t('None') }}</span>
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
secondary-hidden-field="hidden"
|
secondary-hidden-field="hidden"
|
||||||
:items="allCategories[allCategoryTypes.Transfer]"
|
:items="allCategories[allCategoryTypes.Transfer]"
|
||||||
v-model:show="showCategorySheet"
|
v-model:show="showCategorySheet"
|
||||||
v-model="transaction.transferCategory">
|
v-model="transaction.transferCategoryId">
|
||||||
</tree-view-selection-sheet>
|
</tree-view-selection-sheet>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
|
|
||||||
@@ -436,7 +436,7 @@ import { useUserStore } from '@/stores/user.ts';
|
|||||||
import { useAccountsStore } from '@/stores/account.ts';
|
import { useAccountsStore } from '@/stores/account.ts';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
|
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
|
||||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||||
|
|
||||||
@@ -446,6 +446,7 @@ import { TemplateType, ScheduledTemplateFrequencyType } from '@/core/template.ts
|
|||||||
import { TRANSACTION_MIN_AMOUNT, TRANSACTION_MAX_AMOUNT, TRANSACTION_MAX_PICTURE_COUNT } from '@/consts/transaction.ts';
|
import { TRANSACTION_MIN_AMOUNT, TRANSACTION_MAX_AMOUNT, TRANSACTION_MAX_PICTURE_COUNT } from '@/consts/transaction.ts';
|
||||||
import { KnownErrorCode } from '@/consts/api.ts';
|
import { KnownErrorCode } from '@/consts/api.ts';
|
||||||
import { SUPPORTED_IMAGE_EXTENSIONS } from '@/consts/file.ts';
|
import { SUPPORTED_IMAGE_EXTENSIONS } from '@/consts/file.ts';
|
||||||
|
|
||||||
import logger from '@/lib/logger.ts';
|
import logger from '@/lib/logger.ts';
|
||||||
import {
|
import {
|
||||||
isArray,
|
isArray,
|
||||||
@@ -464,7 +465,7 @@ import {
|
|||||||
getTransactionSecondaryCategoryName,
|
getTransactionSecondaryCategoryName,
|
||||||
getFirstAvailableCategoryId
|
getFirstAvailableCategoryId
|
||||||
} from '@/lib/category.ts';
|
} from '@/lib/category.ts';
|
||||||
import { setTransactionModelByTransaction } from '@/lib/transaction.js';
|
import { setTransactionModelByTransaction } from '@/lib/transaction.ts';
|
||||||
import {
|
import {
|
||||||
isTransactionPicturesEnabled,
|
isTransactionPicturesEnabled,
|
||||||
getMapProvider
|
getMapProvider
|
||||||
@@ -840,7 +841,7 @@ export default {
|
|||||||
},
|
},
|
||||||
inputEmptyProblemMessage() {
|
inputEmptyProblemMessage() {
|
||||||
if (this.transaction.type === this.allTransactionTypes.Expense) {
|
if (this.transaction.type === this.allTransactionTypes.Expense) {
|
||||||
if (!this.transaction.expenseCategory || this.transaction.expenseCategory === '') {
|
if (!this.transaction.expenseCategoryId || this.transaction.expenseCategoryId === '') {
|
||||||
return 'Transaction category cannot be blank';
|
return 'Transaction category cannot be blank';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -848,7 +849,7 @@ export default {
|
|||||||
return 'Transaction account cannot be blank';
|
return 'Transaction account cannot be blank';
|
||||||
}
|
}
|
||||||
} else if (this.transaction.type === this.allTransactionTypes.Income) {
|
} else if (this.transaction.type === this.allTransactionTypes.Income) {
|
||||||
if (!this.transaction.incomeCategory || this.transaction.incomeCategory === '') {
|
if (!this.transaction.incomeCategoryId || this.transaction.incomeCategoryId === '') {
|
||||||
return 'Transaction category cannot be blank';
|
return 'Transaction category cannot be blank';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -856,7 +857,7 @@ export default {
|
|||||||
return 'Transaction account cannot be blank';
|
return 'Transaction account cannot be blank';
|
||||||
}
|
}
|
||||||
} else if (this.transaction.type === this.allTransactionTypes.Transfer) {
|
} else if (this.transaction.type === this.allTransactionTypes.Transfer) {
|
||||||
if (!this.transaction.transferCategory || this.transaction.transferCategory === '') {
|
if (!this.transaction.transferCategoryId || this.transaction.transferCategoryId === '') {
|
||||||
return 'Transaction category cannot be blank';
|
return 'Transaction category cannot be blank';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1226,10 +1227,7 @@ export default {
|
|||||||
|
|
||||||
self.geoLocationStatus = 'success';
|
self.geoLocationStatus = 'success';
|
||||||
|
|
||||||
self.transaction.geoLocation = {
|
self.transaction.setLatitudeAndLongitude(position.coords.latitude, position.coords.longitude);
|
||||||
latitude: position.coords.latitude,
|
|
||||||
longitude: position.coords.longitude
|
|
||||||
};
|
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
logger.error('cannot retrieve current position', err);
|
logger.error('cannot retrieve current position', err);
|
||||||
self.geoLocationStatus = 'error';
|
self.geoLocationStatus = 'error';
|
||||||
@@ -1243,7 +1241,7 @@ export default {
|
|||||||
},
|
},
|
||||||
clearGeoLocation() {
|
clearGeoLocation() {
|
||||||
this.geoLocationStatus = null;
|
this.geoLocationStatus = null;
|
||||||
this.transaction.geoLocation = null;
|
this.transaction.removeGeoLocation();
|
||||||
},
|
},
|
||||||
swapTransactionData(swapAccount, swapAmount) {
|
swapTransactionData(swapAccount, swapAmount) {
|
||||||
if (swapAccount) {
|
if (swapAccount) {
|
||||||
@@ -1287,12 +1285,7 @@ export default {
|
|||||||
self.submitting = true;
|
self.submitting = true;
|
||||||
|
|
||||||
self.transactionsStore.uploadTransactionPicture({ pictureFile }).then(response => {
|
self.transactionsStore.uploadTransactionPicture({ pictureFile }).then(response => {
|
||||||
if (!isArray(self.transaction.pictures)) {
|
self.transaction.addPicture(response);
|
||||||
self.transaction.pictures = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.transaction.pictures.push(response);
|
|
||||||
|
|
||||||
self.uploadingPicture = false;
|
self.uploadingPicture = false;
|
||||||
self.submitting = false;
|
self.submitting = false;
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@@ -1317,23 +1310,15 @@ export default {
|
|||||||
self.submitting = true;
|
self.submitting = true;
|
||||||
|
|
||||||
self.transactionsStore.removeUnusedTransactionPicture({ pictureInfo }).then(response => {
|
self.transactionsStore.removeUnusedTransactionPicture({ pictureInfo }).then(response => {
|
||||||
if (response && isArray(self.transaction.pictures)) {
|
if (response) {
|
||||||
for (let i = 0; i < self.transaction.pictures.length; i++) {
|
self.transaction.removePicture(pictureInfo);
|
||||||
if (self.transaction.pictures[i].pictureId === pictureInfo.pictureId) {
|
|
||||||
self.transaction.pictures.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.removingPictureId = '';
|
self.removingPictureId = '';
|
||||||
self.submitting = false;
|
self.submitting = false;
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
if (error.error && error.error.errorCode === KnownErrorCode.TransactionPictureNotFound) {
|
if (error.error && error.error.errorCode === KnownErrorCode.TransactionPictureNotFound) {
|
||||||
for (let i = 0; i < self.transaction.pictures.length; i++) {
|
self.transaction.removePicture(pictureInfo);
|
||||||
if (self.transaction.pictures[i].pictureId === pictureInfo.pictureId) {
|
|
||||||
self.transaction.pictures.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (!error.processed) {
|
} else if (!error.processed) {
|
||||||
self.$toast(error.message || error);
|
self.$toast(error.message || error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -526,7 +526,7 @@ import { useUserStore } from '@/stores/user.ts';
|
|||||||
import { useAccountsStore } from '@/stores/account.ts';
|
import { useAccountsStore } from '@/stores/account.ts';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||||
import { useTransactionsStore } from '@/stores/transaction.js';
|
import { useTransactionsStore } from '@/stores/transaction.ts';
|
||||||
|
|
||||||
import { DateRangeScene, DateRange } from '@/core/datetime.ts';
|
import { DateRangeScene, DateRange } from '@/core/datetime.ts';
|
||||||
import { AmountFilterType } from '@/core/numeral.ts';
|
import { AmountFilterType } from '@/core/numeral.ts';
|
||||||
@@ -550,7 +550,7 @@ import {
|
|||||||
} from '@/lib/datetime.ts';
|
} from '@/lib/datetime.ts';
|
||||||
import { categoryTypeToTransactionType, transactionTypeToCategoryType } from '@/lib/category.ts';
|
import { categoryTypeToTransactionType, transactionTypeToCategoryType } from '@/lib/category.ts';
|
||||||
import { getUnifiedSelectedAccountsCurrencyOrDefaultCurrency } from '@/lib/account.ts';
|
import { getUnifiedSelectedAccountsCurrencyOrDefaultCurrency } from '@/lib/account.ts';
|
||||||
import { getTransactionDisplayAmount } from '@/lib/transaction.js';
|
import { getTransactionDisplayAmount } from '@/lib/transaction.ts';
|
||||||
import { onSwipeoutDeleted, scrollToSelectedItem } from '@/lib/ui/mobile.ts';
|
import { onSwipeoutDeleted, scrollToSelectedItem } from '@/lib/ui/mobile.ts';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
Reference in New Issue
Block a user