945 lines
47 KiB
JavaScript
945 lines
47 KiB
JavaScript
import { defineStore } from 'pinia';
|
|
|
|
import { useSettingsStore } from './setting.js';
|
|
import { useUserStore } from './user.js';
|
|
import { useAccountsStore } from './account.js';
|
|
import { useTransactionCategoriesStore } from './transactionCategory.js';
|
|
import { useExchangeRatesStore } from './exchangeRates.js';
|
|
|
|
import datetimeConstants from '@/consts/datetime.js';
|
|
import statisticsConstants from '@/consts/statistics.js';
|
|
import categoryConstants from '@/consts/category.js';
|
|
import iconConstants from '@/consts/icon.js';
|
|
import colorConstants from '@/consts/color.js';
|
|
import services from '@/lib/services.js';
|
|
import logger from '@/lib/logger.js';
|
|
import {
|
|
isEquals,
|
|
isNumber,
|
|
isObject,
|
|
isInteger,
|
|
isYearMonth,
|
|
isYearMonthEquals,
|
|
isObjectEmpty,
|
|
objectFieldToArrayItem
|
|
} from '@/lib/common.js';
|
|
import {
|
|
getYearAndMonthFromUnixTime,
|
|
getDateRangeByDateType
|
|
} from '@/lib/datetime.js';
|
|
import {
|
|
getFinalAccountIdsByFilteredAccountIds
|
|
} from '@/lib/account.js';
|
|
import {
|
|
getFinalCategoryIdsByFilteredCategoryIds
|
|
} from '@/lib/category.js';
|
|
import {
|
|
sortStatisticsItems
|
|
} from '@/lib/statistics.js';
|
|
|
|
function assembleAccountAndCategoryInfo(userStore, accountsStore, transactionCategoriesStore, exchangeRatesStore, items) {
|
|
const finalItems = [];
|
|
const defaultCurrency = userStore.currentUserDefaultCurrency;
|
|
|
|
for (let i = 0; i < items.length; i++) {
|
|
const dataItem = items[i];
|
|
const item = {
|
|
categoryId: dataItem.categoryId,
|
|
accountId: dataItem.accountId,
|
|
amount: dataItem.amount
|
|
};
|
|
|
|
if (item.accountId) {
|
|
item.account = accountsStore.allAccountsMap[item.accountId];
|
|
}
|
|
|
|
if (item.account && item.account.parentId !== '0') {
|
|
item.primaryAccount = accountsStore.allAccountsMap[item.account.parentId];
|
|
} else {
|
|
item.primaryAccount = item.account;
|
|
}
|
|
|
|
if (item.categoryId) {
|
|
item.category = transactionCategoriesStore.allTransactionCategoriesMap[item.categoryId];
|
|
}
|
|
|
|
if (item.category && item.category.parentId !== '0') {
|
|
item.primaryCategory = transactionCategoriesStore.allTransactionCategoriesMap[item.category.parentId];
|
|
} else {
|
|
item.primaryCategory = item.category;
|
|
}
|
|
|
|
if (item.account && item.account.currency !== defaultCurrency) {
|
|
const amount = exchangeRatesStore.getExchangedAmount(item.amount, item.account.currency, defaultCurrency);
|
|
|
|
if (isNumber(amount)) {
|
|
item.amountInDefaultCurrency = Math.floor(amount);
|
|
}
|
|
} else if (item.account && item.account.currency === defaultCurrency) {
|
|
item.amountInDefaultCurrency = item.amount;
|
|
} else {
|
|
item.amountInDefaultCurrency = null;
|
|
}
|
|
|
|
finalItems.push(item);
|
|
}
|
|
|
|
return finalItems;
|
|
}
|
|
|
|
function getCategoryTotalAmountItems(items, transactionStatisticsFilter) {
|
|
const allDataItems = {};
|
|
let totalAmount = 0;
|
|
let totalNonNegativeAmount = 0;
|
|
|
|
for (let i = 0; i < items.length; i++) {
|
|
const item = items[i];
|
|
|
|
if (!item.primaryAccount || !item.account || !item.primaryCategory || !item.category) {
|
|
continue;
|
|
}
|
|
|
|
if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type ||
|
|
transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type ||
|
|
transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type ||
|
|
transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalExpense.type) {
|
|
if (item.category.type !== categoryConstants.allCategoryTypes.Expense) {
|
|
continue;
|
|
}
|
|
} else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type ||
|
|
transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type ||
|
|
transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type ||
|
|
transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalIncome.type) {
|
|
if (item.category.type !== categoryConstants.allCategoryTypes.Income) {
|
|
continue;
|
|
}
|
|
} else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalBalance.type) {
|
|
// Do Nothing
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
if (transactionStatisticsFilter.filterAccountIds && transactionStatisticsFilter.filterAccountIds[item.account.id]) {
|
|
continue;
|
|
}
|
|
|
|
if (transactionStatisticsFilter.filterCategoryIds && transactionStatisticsFilter.filterCategoryIds[item.category.id]) {
|
|
continue;
|
|
}
|
|
|
|
if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type ||
|
|
transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type) {
|
|
if (isNumber(item.amountInDefaultCurrency)) {
|
|
let data = allDataItems[item.account.id];
|
|
|
|
if (data) {
|
|
data.totalAmount += item.amountInDefaultCurrency;
|
|
} else {
|
|
data = {
|
|
name: item.account.name,
|
|
type: 'account',
|
|
id: item.account.id,
|
|
icon: item.account.icon || iconConstants.defaultAccountIcon.icon,
|
|
color: item.account.color || colorConstants.defaultAccountColor,
|
|
hidden: item.primaryAccount.hidden || item.account.hidden,
|
|
displayOrders: [item.primaryAccount.category, item.primaryAccount.displayOrder, item.account.displayOrder],
|
|
totalAmount: item.amountInDefaultCurrency
|
|
}
|
|
}
|
|
|
|
totalAmount += item.amountInDefaultCurrency;
|
|
|
|
if (item.amountInDefaultCurrency > 0) {
|
|
totalNonNegativeAmount += item.amountInDefaultCurrency;
|
|
}
|
|
|
|
allDataItems[item.account.id] = data;
|
|
}
|
|
} else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type ||
|
|
transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type) {
|
|
if (isNumber(item.amountInDefaultCurrency)) {
|
|
let data = allDataItems[item.primaryCategory.id];
|
|
|
|
if (data) {
|
|
data.totalAmount += item.amountInDefaultCurrency;
|
|
} else {
|
|
data = {
|
|
name: item.primaryCategory.name,
|
|
type: 'category',
|
|
id: item.primaryCategory.id,
|
|
icon: item.primaryCategory.icon || iconConstants.defaultCategoryIcon.icon,
|
|
color: item.primaryCategory.color || colorConstants.defaultCategoryColor,
|
|
hidden: item.primaryCategory.hidden,
|
|
displayOrders: [item.primaryCategory.type, item.primaryCategory.displayOrder],
|
|
totalAmount: item.amountInDefaultCurrency
|
|
}
|
|
}
|
|
|
|
totalAmount += item.amountInDefaultCurrency;
|
|
|
|
if (item.amountInDefaultCurrency > 0) {
|
|
totalNonNegativeAmount += item.amountInDefaultCurrency;
|
|
}
|
|
|
|
allDataItems[item.primaryCategory.id] = data;
|
|
}
|
|
} else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type ||
|
|
transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type) {
|
|
if (isNumber(item.amountInDefaultCurrency)) {
|
|
let data = allDataItems[item.category.id];
|
|
|
|
if (data) {
|
|
data.totalAmount += item.amountInDefaultCurrency;
|
|
} else {
|
|
data = {
|
|
name: item.category.name,
|
|
type: 'category',
|
|
id: item.category.id,
|
|
icon: item.category.icon || iconConstants.defaultCategoryIcon.icon,
|
|
color: item.category.color || colorConstants.defaultCategoryColor,
|
|
hidden: item.primaryCategory.hidden || item.category.hidden,
|
|
displayOrders: [item.primaryCategory.type, item.primaryCategory.displayOrder, item.category.displayOrder],
|
|
totalAmount: item.amountInDefaultCurrency
|
|
}
|
|
}
|
|
|
|
totalAmount += item.amountInDefaultCurrency;
|
|
|
|
if (item.amountInDefaultCurrency > 0) {
|
|
totalNonNegativeAmount += item.amountInDefaultCurrency;
|
|
}
|
|
|
|
allDataItems[item.category.id] = data;
|
|
}
|
|
} else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalExpense.type ||
|
|
transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalIncome.type ||
|
|
transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalBalance.type) {
|
|
if (isNumber(item.amountInDefaultCurrency)) {
|
|
let data = allDataItems['total'];
|
|
let amount = item.amountInDefaultCurrency;
|
|
|
|
if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalBalance.type &&
|
|
item.category.type === categoryConstants.allCategoryTypes.Expense) {
|
|
amount = -amount;
|
|
}
|
|
|
|
if (data) {
|
|
data.totalAmount += amount;
|
|
} else {
|
|
let name = '';
|
|
|
|
if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalExpense.type) {
|
|
name = statisticsConstants.allChartDataTypes.TotalExpense.name;
|
|
} else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalIncome.type) {
|
|
name = statisticsConstants.allChartDataTypes.TotalIncome.name;
|
|
} else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalBalance.type) {
|
|
name = statisticsConstants.allChartDataTypes.TotalBalance.name;
|
|
}
|
|
|
|
data = {
|
|
name: name,
|
|
type: 'total',
|
|
id: 'total',
|
|
icon: '',
|
|
color: '',
|
|
hidden: false,
|
|
displayOrders: [1],
|
|
totalAmount: amount
|
|
}
|
|
}
|
|
|
|
totalAmount += amount;
|
|
|
|
if (item.amountInDefaultCurrency > 0) {
|
|
totalNonNegativeAmount += amount;
|
|
}
|
|
|
|
allDataItems['total'] = data;
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
totalAmount: totalAmount,
|
|
totalNonNegativeAmount: totalNonNegativeAmount,
|
|
items: allDataItems
|
|
};
|
|
}
|
|
|
|
function sortCategoryTotalAmountItems(items, transactionStatisticsFilter) {
|
|
sortStatisticsItems(items, transactionStatisticsFilter.sortingType)
|
|
}
|
|
|
|
export const useStatisticsStore = defineStore('statistics', {
|
|
state: () => ({
|
|
transactionStatisticsFilter: {
|
|
chartDataType: statisticsConstants.defaultChartDataType,
|
|
categoricalChartType: statisticsConstants.defaultCategoricalChartType,
|
|
categoricalChartDateType: statisticsConstants.defaultCategoricalChartDataRangeType,
|
|
categoricalChartStartTime: 0,
|
|
categoricalChartEndTime: 0,
|
|
trendChartType: statisticsConstants.defaultTrendChartType,
|
|
trendChartDateType: statisticsConstants.defaultTrendChartDataRangeType,
|
|
trendChartStartYearMonth: '',
|
|
trendChartEndYearMonth: '',
|
|
filterAccountIds: {},
|
|
filterCategoryIds: {}
|
|
},
|
|
transactionCategoryStatisticsData: {},
|
|
transactionCategoryTrendsData: {},
|
|
transactionStatisticsStateInvalid: true
|
|
}),
|
|
getters: {
|
|
categoricalAnalysisChartDataCategory(state) {
|
|
if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type ||
|
|
state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type ||
|
|
state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalAssets.type ||
|
|
state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalLiabilities.type) {
|
|
return 'account';
|
|
} else if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type ||
|
|
state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type ||
|
|
state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type ||
|
|
state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type) {
|
|
return 'category';
|
|
} else {
|
|
return '';
|
|
}
|
|
},
|
|
transactionCategoryStatisticsDataWithCategoryAndAccountInfo(state) {
|
|
const statistics = state.transactionCategoryStatisticsData;
|
|
const finalStatistics = {
|
|
startTime: statistics.startTime,
|
|
endTime: statistics.endTime,
|
|
items: []
|
|
};
|
|
|
|
if (statistics && statistics.items && statistics.items.length) {
|
|
const userStore = useUserStore();
|
|
const accountsStore = useAccountsStore();
|
|
const transactionCategoriesStore = useTransactionCategoriesStore();
|
|
const exchangeRatesStore = useExchangeRatesStore();
|
|
|
|
finalStatistics.items = assembleAccountAndCategoryInfo(userStore, accountsStore, transactionCategoriesStore, exchangeRatesStore, statistics.items);
|
|
}
|
|
|
|
return finalStatistics;
|
|
},
|
|
transactionCategoryTotalAmountAnalysisData(state) {
|
|
if (!state.transactionCategoryStatisticsDataWithCategoryAndAccountInfo || !state.transactionCategoryStatisticsDataWithCategoryAndAccountInfo.items) {
|
|
return null;
|
|
}
|
|
|
|
return getCategoryTotalAmountItems(state.transactionCategoryStatisticsDataWithCategoryAndAccountInfo.items, state.transactionStatisticsFilter);
|
|
},
|
|
accountTotalAmountAnalysisData(state) {
|
|
const userStore = useUserStore();
|
|
const accountsStore = useAccountsStore();
|
|
const exchangeRatesStore = useExchangeRatesStore();
|
|
|
|
if (!accountsStore.allPlainAccounts) {
|
|
return null;
|
|
}
|
|
|
|
const allDataItems = {};
|
|
let totalAmount = 0;
|
|
let totalNonNegativeAmount = 0;
|
|
|
|
for (let i = 0; i < accountsStore.allPlainAccounts.length; i++) {
|
|
const account = accountsStore.allPlainAccounts[i];
|
|
|
|
if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalAssets.type) {
|
|
if (!account.isAsset) {
|
|
continue;
|
|
}
|
|
} else if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalLiabilities.type) {
|
|
if (!account.isLiability) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (state.transactionStatisticsFilter.filterAccountIds && state.transactionStatisticsFilter.filterAccountIds[account.id]) {
|
|
continue;
|
|
}
|
|
|
|
let primaryAccount = accountsStore.allAccountsMap[account.parentId];
|
|
|
|
if (!primaryAccount) {
|
|
primaryAccount = account;
|
|
}
|
|
|
|
let amount = account.balance;
|
|
|
|
if (account.currency !== userStore.currentUserDefaultCurrency) {
|
|
amount = Math.floor(exchangeRatesStore.getExchangedAmount(amount, account.currency, userStore.currentUserDefaultCurrency));
|
|
|
|
if (!isNumber(amount)) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (account.isLiability) {
|
|
amount = -amount;
|
|
}
|
|
|
|
const data = {
|
|
name: account.name,
|
|
type: 'account',
|
|
id: account.id,
|
|
icon: account.icon || iconConstants.defaultAccountIcon.icon,
|
|
color: account.color || colorConstants.defaultAccountColor,
|
|
hidden: primaryAccount.hidden || account.hidden,
|
|
displayOrders: [primaryAccount.category, primaryAccount.displayOrder, account.displayOrder],
|
|
totalAmount: amount
|
|
};
|
|
|
|
totalAmount += amount;
|
|
|
|
if (amount > 0) {
|
|
totalNonNegativeAmount += amount;
|
|
}
|
|
|
|
allDataItems[account.id] = data;
|
|
}
|
|
|
|
return {
|
|
totalAmount: totalAmount,
|
|
totalNonNegativeAmount: totalNonNegativeAmount,
|
|
items: allDataItems
|
|
}
|
|
},
|
|
categoricalAnalysisData(state) {
|
|
let combinedData = {
|
|
items: [],
|
|
totalAmount: 0
|
|
};
|
|
|
|
if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type ||
|
|
state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type ||
|
|
state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type ||
|
|
state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type ||
|
|
state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type ||
|
|
state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type) {
|
|
combinedData = state.transactionCategoryTotalAmountAnalysisData;
|
|
} else if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalAssets.type ||
|
|
state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalLiabilities.type) {
|
|
combinedData = state.accountTotalAmountAnalysisData;
|
|
}
|
|
|
|
const allStatisticsItems = [];
|
|
|
|
for (let id in combinedData.items) {
|
|
if (!Object.prototype.hasOwnProperty.call(combinedData.items, id)) {
|
|
continue;
|
|
}
|
|
|
|
const data = combinedData.items[id];
|
|
|
|
if (data.totalAmount > 0) {
|
|
data.percent = data.totalAmount * 100 / combinedData.totalNonNegativeAmount;
|
|
} else {
|
|
data.percent = 0;
|
|
}
|
|
|
|
if (data.percent < 0) {
|
|
data.percent = 0;
|
|
}
|
|
|
|
allStatisticsItems.push(data);
|
|
}
|
|
|
|
sortCategoryTotalAmountItems(allStatisticsItems, state.transactionStatisticsFilter);
|
|
|
|
return {
|
|
totalAmount: combinedData.totalAmount,
|
|
items: allStatisticsItems
|
|
};
|
|
},
|
|
transactionCategoryTrendsDataWithCategoryAndAccountInfo(state) {
|
|
const trendsData = state.transactionCategoryTrendsData;
|
|
const finalTrendsData = [];
|
|
|
|
if (trendsData && trendsData.length) {
|
|
const userStore = useUserStore();
|
|
const accountsStore = useAccountsStore();
|
|
const transactionCategoriesStore = useTransactionCategoriesStore();
|
|
const exchangeRatesStore = useExchangeRatesStore();
|
|
|
|
for (let i = 0; i < trendsData.length; i++) {
|
|
const trendItem = trendsData[i];
|
|
const finalTrendItem = {
|
|
year: trendItem.year,
|
|
month: trendItem.month,
|
|
items: []
|
|
};
|
|
|
|
if (trendItem && trendItem.items && trendItem.items.length) {
|
|
finalTrendItem.items = assembleAccountAndCategoryInfo(userStore, accountsStore, transactionCategoriesStore, exchangeRatesStore, trendItem.items);
|
|
}
|
|
|
|
finalTrendsData.push(finalTrendItem);
|
|
}
|
|
}
|
|
|
|
return finalTrendsData;
|
|
},
|
|
trendsAnalysisData(state) {
|
|
if (!state.transactionCategoryTrendsDataWithCategoryAndAccountInfo || !state.transactionCategoryTrendsDataWithCategoryAndAccountInfo.length) {
|
|
return null;
|
|
}
|
|
|
|
const combinedDataMap = {};
|
|
|
|
for (let i = 0; i < state.transactionCategoryTrendsDataWithCategoryAndAccountInfo.length; i++) {
|
|
const trendItem = state.transactionCategoryTrendsDataWithCategoryAndAccountInfo[i];
|
|
const totalAmountItems = getCategoryTotalAmountItems(trendItem.items, state.transactionStatisticsFilter);
|
|
|
|
for (let id in totalAmountItems.items) {
|
|
if (!Object.prototype.hasOwnProperty.call(totalAmountItems.items, id)) {
|
|
continue;
|
|
}
|
|
|
|
const item = totalAmountItems.items[id];
|
|
let combinedData = combinedDataMap[id];
|
|
|
|
if (!combinedData) {
|
|
combinedData = {
|
|
name: item.name,
|
|
type: item.type,
|
|
id: item.id,
|
|
icon: item.icon,
|
|
color: item.color,
|
|
hidden: item.hidden,
|
|
displayOrders: item.displayOrders,
|
|
totalAmount: 0,
|
|
items: []
|
|
};
|
|
}
|
|
|
|
combinedData.items.push({
|
|
year: trendItem.year,
|
|
month: trendItem.month,
|
|
totalAmount: item.totalAmount
|
|
});
|
|
|
|
combinedData.totalAmount += item.totalAmount;
|
|
combinedDataMap[id] = combinedData;
|
|
}
|
|
}
|
|
|
|
const totalAmountsTrends = [];
|
|
|
|
for (let id in combinedDataMap) {
|
|
if (!Object.prototype.hasOwnProperty.call(combinedDataMap, id)) {
|
|
continue;
|
|
}
|
|
|
|
const trendData = combinedDataMap[id];
|
|
totalAmountsTrends.push(trendData);
|
|
}
|
|
|
|
sortCategoryTotalAmountItems(totalAmountsTrends, state.transactionStatisticsFilter);
|
|
|
|
return {
|
|
items: totalAmountsTrends
|
|
};
|
|
}
|
|
},
|
|
actions: {
|
|
updateTransactionStatisticsInvalidState(invalidState) {
|
|
this.transactionStatisticsStateInvalid = invalidState;
|
|
},
|
|
resetTransactionStatistics() {
|
|
this.transactionStatisticsFilter.chartDataType = statisticsConstants.defaultChartDataType;
|
|
this.transactionStatisticsFilter.categoricalChartType = statisticsConstants.defaultCategoricalChartType;
|
|
this.transactionStatisticsFilter.categoricalChartDateType = statisticsConstants.defaultCategoricalChartDataRangeType;
|
|
this.transactionStatisticsFilter.categoricalChartStartTime = 0;
|
|
this.transactionStatisticsFilter.categoricalChartEndTime = 0;
|
|
this.transactionStatisticsFilter.trendChartType = statisticsConstants.defaultTrendChartType;
|
|
this.transactionStatisticsFilter.trendChartDateType = statisticsConstants.defaultTrendChartDataRangeType;
|
|
this.transactionStatisticsFilter.trendChartStartYearMonth = '';
|
|
this.transactionStatisticsFilter.trendChartEndYearMonth = '';
|
|
this.transactionStatisticsFilter.filterAccountIds = {};
|
|
this.transactionStatisticsFilter.filterCategoryIds = {};
|
|
this.transactionCategoryStatisticsData = {};
|
|
this.transactionCategoryTrendsData = {};
|
|
this.transactionStatisticsStateInvalid = true;
|
|
},
|
|
initTransactionStatisticsFilter(analysisType, filter) {
|
|
const settingsStore = useSettingsStore();
|
|
const userStore = useUserStore();
|
|
|
|
if (filter && isInteger(filter.chartDataType)) {
|
|
this.transactionStatisticsFilter.chartDataType = filter.chartDataType;
|
|
} else {
|
|
this.transactionStatisticsFilter.chartDataType = settingsStore.appSettings.statistics.defaultChartDataType;
|
|
}
|
|
|
|
if (analysisType === statisticsConstants.allAnalysisTypes.CategoricalAnalysis || analysisType === statisticsConstants.allAnalysisTypes.TrendAnalysis) {
|
|
if (!statisticsConstants.allChartDataTypesMap[this.transactionStatisticsFilter.chartDataType] ||
|
|
!statisticsConstants.allChartDataTypesMap[this.transactionStatisticsFilter.chartDataType].availableAnalysisTypes[analysisType]) {
|
|
this.transactionStatisticsFilter.chartDataType = statisticsConstants.defaultChartDataType;
|
|
}
|
|
}
|
|
|
|
if (filter && isInteger(filter.categoricalChartType)) {
|
|
this.transactionStatisticsFilter.categoricalChartType = filter.categoricalChartType;
|
|
} else {
|
|
this.transactionStatisticsFilter.categoricalChartType = settingsStore.appSettings.statistics.defaultCategoricalChartType;
|
|
}
|
|
|
|
if (this.transactionStatisticsFilter.categoricalChartType !== statisticsConstants.allCategoricalChartTypes.Pie && this.transactionStatisticsFilter.categoricalChartType !== statisticsConstants.allCategoricalChartTypes.Bar) {
|
|
this.transactionStatisticsFilter.categoricalChartType = statisticsConstants.defaultCategoricalChartType;
|
|
}
|
|
|
|
if (filter && isInteger(filter.categoricalChartDateType)) {
|
|
this.transactionStatisticsFilter.categoricalChartDateType = filter.categoricalChartDateType;
|
|
} else {
|
|
this.transactionStatisticsFilter.categoricalChartDateType = settingsStore.appSettings.statistics.defaultCategoricalChartDataRangeType;
|
|
}
|
|
|
|
let categoricalChartDateTypeValid = true;
|
|
|
|
if (!datetimeConstants.allDateRangesMap[this.transactionStatisticsFilter.categoricalChartDateType] ||
|
|
!datetimeConstants.allDateRangesMap[this.transactionStatisticsFilter.categoricalChartDateType].availableScenes[datetimeConstants.allDateRangeScenes.Normal]) {
|
|
this.transactionStatisticsFilter.categoricalChartDateType = statisticsConstants.defaultCategoricalChartDataRangeType;
|
|
categoricalChartDateTypeValid = false;
|
|
}
|
|
|
|
if (categoricalChartDateTypeValid && this.transactionStatisticsFilter.categoricalChartDateType === datetimeConstants.allDateRanges.Custom.type) {
|
|
if (filter && isInteger(filter.categoricalChartStartTime)) {
|
|
this.transactionStatisticsFilter.categoricalChartStartTime = filter.categoricalChartStartTime;
|
|
} else {
|
|
this.transactionStatisticsFilter.categoricalChartStartTime = 0;
|
|
}
|
|
|
|
if (filter && isInteger(filter.categoricalChartEndTime)) {
|
|
this.transactionStatisticsFilter.categoricalChartEndTime = filter.categoricalChartEndTime;
|
|
} else {
|
|
this.transactionStatisticsFilter.categoricalChartEndTime = 0;
|
|
}
|
|
} else {
|
|
const categoricalChartDateRange = getDateRangeByDateType(this.transactionStatisticsFilter.categoricalChartDateType, userStore.currentUserFirstDayOfWeek);
|
|
this.transactionStatisticsFilter.categoricalChartDateType = categoricalChartDateRange.dateType;
|
|
this.transactionStatisticsFilter.categoricalChartStartTime = categoricalChartDateRange.minTime;
|
|
this.transactionStatisticsFilter.categoricalChartEndTime = categoricalChartDateRange.maxTime;
|
|
}
|
|
|
|
if (filter && isInteger(filter.trendChartType)) {
|
|
this.transactionStatisticsFilter.trendChartType = filter.trendChartType;
|
|
} else {
|
|
this.transactionStatisticsFilter.trendChartType = settingsStore.appSettings.statistics.defaultTrendChartType;
|
|
}
|
|
|
|
if (this.transactionStatisticsFilter.trendChartType !== statisticsConstants.allTrendChartTypes.Area && this.transactionStatisticsFilter.trendChartType !== statisticsConstants.allTrendChartTypes.Column) {
|
|
this.transactionStatisticsFilter.trendChartType = statisticsConstants.defaultTrendChartType;
|
|
}
|
|
|
|
if (filter && isInteger(filter.trendChartDateType)) {
|
|
this.transactionStatisticsFilter.trendChartDateType = filter.trendChartDateType;
|
|
} else {
|
|
this.transactionStatisticsFilter.trendChartDateType = settingsStore.appSettings.statistics.defaultTrendChartDataRangeType;
|
|
}
|
|
|
|
let trendChartDateTypeValid = true;
|
|
|
|
if (!datetimeConstants.allDateRangesMap[this.transactionStatisticsFilter.trendChartDateType] ||
|
|
!datetimeConstants.allDateRangesMap[this.transactionStatisticsFilter.trendChartDateType].availableScenes[datetimeConstants.allDateRangeScenes.TrendAnalysis]) {
|
|
this.transactionStatisticsFilter.trendChartDateType = statisticsConstants.defaultTrendChartDataRangeType;
|
|
trendChartDateTypeValid = false;
|
|
}
|
|
|
|
if (trendChartDateTypeValid && this.transactionStatisticsFilter.trendChartDateType === datetimeConstants.allDateRanges.Custom.type) {
|
|
if (filter && isYearMonth(filter.trendChartStartYearMonth)) {
|
|
this.transactionStatisticsFilter.trendChartStartYearMonth = filter.trendChartStartYearMonth;
|
|
} else {
|
|
this.transactionStatisticsFilter.trendChartStartYearMonth = '';
|
|
}
|
|
|
|
if (filter && isYearMonth(filter.trendChartEndYearMonth)) {
|
|
this.transactionStatisticsFilter.trendChartEndYearMonth = filter.trendChartEndYearMonth;
|
|
} else {
|
|
this.transactionStatisticsFilter.trendChartEndYearMonth = '';
|
|
}
|
|
} else {
|
|
const trendChartDateRange = getDateRangeByDateType(this.transactionStatisticsFilter.trendChartDateType, userStore.currentUserFirstDayOfWeek);
|
|
this.transactionStatisticsFilter.trendChartDateType = trendChartDateRange.dateType;
|
|
this.transactionStatisticsFilter.trendChartStartYearMonth = getYearAndMonthFromUnixTime(trendChartDateRange.minTime);
|
|
this.transactionStatisticsFilter.trendChartEndYearMonth = getYearAndMonthFromUnixTime(trendChartDateRange.maxTime);
|
|
}
|
|
|
|
if (filter && isObject(filter.filterAccountIds)) {
|
|
this.transactionStatisticsFilter.filterAccountIds = filter.filterAccountIds;
|
|
} else {
|
|
this.transactionStatisticsFilter.filterAccountIds = settingsStore.appSettings.statistics.defaultAccountFilter || {};
|
|
}
|
|
|
|
if (filter && isObject(filter.filterCategoryIds)) {
|
|
this.transactionStatisticsFilter.filterCategoryIds = filter.filterCategoryIds;
|
|
} else {
|
|
this.transactionStatisticsFilter.filterCategoryIds = settingsStore.appSettings.statistics.defaultTransactionCategoryFilter || {};
|
|
}
|
|
|
|
if (filter && isInteger(filter.sortingType)) {
|
|
this.transactionStatisticsFilter.sortingType = filter.sortingType;
|
|
} else {
|
|
this.transactionStatisticsFilter.sortingType = settingsStore.appSettings.statistics.defaultSortingType;
|
|
}
|
|
|
|
if (this.transactionStatisticsFilter.sortingType < statisticsConstants.allSortingTypes.Amount.type || this.transactionStatisticsFilter.sortingType > statisticsConstants.allSortingTypes.Name.type) {
|
|
this.transactionStatisticsFilter.sortingType = statisticsConstants.defaultSortingType;
|
|
}
|
|
},
|
|
updateTransactionStatisticsFilter(filter) {
|
|
let changed = false;
|
|
|
|
if (filter && isInteger(filter.chartDataType) && this.transactionStatisticsFilter.chartDataType !== filter.chartDataType) {
|
|
this.transactionStatisticsFilter.chartDataType = filter.chartDataType;
|
|
changed = true;
|
|
}
|
|
|
|
if (filter && isInteger(filter.categoricalChartType) && this.transactionStatisticsFilter.categoricalChartType !== filter.categoricalChartType) {
|
|
this.transactionStatisticsFilter.categoricalChartType = filter.categoricalChartType;
|
|
changed = true;
|
|
}
|
|
|
|
if (filter && isInteger(filter.categoricalChartDateType) && this.transactionStatisticsFilter.categoricalChartDateType !== filter.categoricalChartDateType) {
|
|
this.transactionStatisticsFilter.categoricalChartDateType = filter.categoricalChartDateType;
|
|
changed = true;
|
|
}
|
|
|
|
if (filter && isInteger(filter.categoricalChartStartTime) && this.transactionStatisticsFilter.categoricalChartStartTime !== filter.categoricalChartStartTime) {
|
|
this.transactionStatisticsFilter.categoricalChartStartTime = filter.categoricalChartStartTime;
|
|
changed = true;
|
|
}
|
|
|
|
if (filter && isInteger(filter.categoricalChartEndTime) && this.transactionStatisticsFilter.categoricalChartEndTime !== filter.categoricalChartEndTime) {
|
|
this.transactionStatisticsFilter.categoricalChartEndTime = filter.categoricalChartEndTime;
|
|
changed = true;
|
|
}
|
|
|
|
if (filter && isInteger(filter.trendChartType) && this.transactionStatisticsFilter.trendChartType !== filter.trendChartType) {
|
|
this.transactionStatisticsFilter.trendChartType = filter.trendChartType;
|
|
changed = true;
|
|
}
|
|
|
|
if (filter && isInteger(filter.trendChartDateType) && this.transactionStatisticsFilter.trendChartDateType !== filter.trendChartDateType) {
|
|
this.transactionStatisticsFilter.trendChartDateType = filter.trendChartDateType;
|
|
changed = true;
|
|
}
|
|
|
|
if (filter && (isYearMonth(filter.trendChartStartYearMonth) || filter.trendChartStartYearMonth === '') && !isYearMonthEquals(this.transactionStatisticsFilter.trendChartStartYearMonth, filter.trendChartStartYearMonth)) {
|
|
this.transactionStatisticsFilter.trendChartStartYearMonth = filter.trendChartStartYearMonth;
|
|
changed = true;
|
|
}
|
|
|
|
if (filter && (isYearMonth(filter.trendChartEndYearMonth) || filter.trendChartEndYearMonth === '') && !isYearMonthEquals(this.transactionStatisticsFilter.trendChartEndYearMonth, filter.trendChartEndYearMonth)) {
|
|
this.transactionStatisticsFilter.trendChartEndYearMonth = filter.trendChartEndYearMonth;
|
|
changed = true;
|
|
}
|
|
|
|
if (filter && isObject(filter.filterAccountIds) && !isEquals(this.transactionStatisticsFilter.filterAccountIds, filter.filterAccountIds)) {
|
|
this.transactionStatisticsFilter.filterAccountIds = filter.filterAccountIds;
|
|
changed = true;
|
|
}
|
|
|
|
if (filter && isObject(filter.filterCategoryIds) && !isEquals(this.transactionStatisticsFilter.filterCategoryIds, filter.filterCategoryIds)) {
|
|
this.transactionStatisticsFilter.filterCategoryIds = filter.filterCategoryIds;
|
|
changed = true;
|
|
}
|
|
|
|
if (filter && isInteger(filter.sortingType) && this.transactionStatisticsFilter.sortingType !== filter.sortingType) {
|
|
this.transactionStatisticsFilter.sortingType = filter.sortingType;
|
|
changed = true;
|
|
}
|
|
|
|
return changed;
|
|
},
|
|
getTransactionStatisticsPageParams(analysisType, trendDateAggregationType) {
|
|
const querys = [];
|
|
|
|
querys.push('analysisType=' + analysisType);
|
|
querys.push('chartDataType=' + this.transactionStatisticsFilter.chartDataType);
|
|
|
|
if (analysisType === statisticsConstants.allAnalysisTypes.CategoricalAnalysis) {
|
|
querys.push('chartType=' + this.transactionStatisticsFilter.categoricalChartType);
|
|
querys.push('chartDateType=' + this.transactionStatisticsFilter.categoricalChartDateType);
|
|
|
|
if (this.transactionStatisticsFilter.categoricalChartDateType === datetimeConstants.allDateRanges.Custom.type) {
|
|
querys.push('startTime=' + this.transactionStatisticsFilter.categoricalChartStartTime);
|
|
querys.push('endTime=' + this.transactionStatisticsFilter.categoricalChartEndTime);
|
|
}
|
|
} else if (analysisType === statisticsConstants.allAnalysisTypes.TrendAnalysis) {
|
|
querys.push('chartType=' + this.transactionStatisticsFilter.trendChartType);
|
|
querys.push('chartDateType=' + this.transactionStatisticsFilter.trendChartDateType);
|
|
|
|
if (this.transactionStatisticsFilter.trendChartDateType === datetimeConstants.allDateRanges.Custom.type) {
|
|
querys.push('startTime=' + this.transactionStatisticsFilter.trendChartStartYearMonth);
|
|
querys.push('endTime=' + this.transactionStatisticsFilter.trendChartEndYearMonth);
|
|
}
|
|
|
|
if (trendDateAggregationType !== statisticsConstants.allDateAggregationTypes.Month.type) {
|
|
querys.push('trendDateAggregationType=' + trendDateAggregationType);
|
|
}
|
|
}
|
|
|
|
if (this.transactionStatisticsFilter.filterAccountIds) {
|
|
const ids = objectFieldToArrayItem(this.transactionStatisticsFilter.filterAccountIds);
|
|
|
|
if (ids && ids.length) {
|
|
querys.push('filterAccountIds=' + ids.join(','));
|
|
}
|
|
}
|
|
|
|
if (this.transactionStatisticsFilter.filterCategoryIds) {
|
|
const ids = objectFieldToArrayItem(this.transactionStatisticsFilter.filterCategoryIds);
|
|
|
|
if (ids && ids.length) {
|
|
querys.push('filterCategoryIds=' + ids.join(','));
|
|
}
|
|
}
|
|
|
|
querys.push('sortingType=' + this.transactionStatisticsFilter.sortingType);
|
|
|
|
return querys.join('&');
|
|
},
|
|
getTransactionListPageParams(analysisType, itemId, dateRange) {
|
|
const accountsStore = useAccountsStore();
|
|
const transactionCategoriesStore = useTransactionCategoriesStore();
|
|
const querys = [];
|
|
|
|
if (this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type
|
|
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type
|
|
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type
|
|
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalIncome.type) {
|
|
querys.push('type=2');
|
|
} else if (this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type
|
|
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type
|
|
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type
|
|
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalExpense.type) {
|
|
querys.push('type=3');
|
|
}
|
|
|
|
if (this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type
|
|
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type
|
|
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalAssets.type
|
|
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalLiabilities.type) {
|
|
querys.push('accountIds=' + itemId);
|
|
|
|
if (!isObjectEmpty(this.transactionStatisticsFilter.filterCategoryIds)) {
|
|
querys.push('categoryIds=' + getFinalCategoryIdsByFilteredCategoryIds(transactionCategoriesStore.allTransactionCategoriesMap, this.transactionStatisticsFilter.filterCategoryIds));
|
|
}
|
|
} else if (this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type
|
|
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type
|
|
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type
|
|
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type) {
|
|
querys.push('categoryIds=' + itemId);
|
|
|
|
if (!isObjectEmpty(this.transactionStatisticsFilter.filterAccountIds)) {
|
|
querys.push('accountIds=' + getFinalAccountIdsByFilteredAccountIds(accountsStore.allAccountsMap, this.transactionStatisticsFilter.filterAccountIds));
|
|
}
|
|
}
|
|
|
|
if (analysisType === statisticsConstants.allAnalysisTypes.CategoricalAnalysis
|
|
&& this.transactionStatisticsFilter.chartDataType !== statisticsConstants.allChartDataTypes.AccountTotalAssets.type
|
|
&& this.transactionStatisticsFilter.chartDataType !== statisticsConstants.allChartDataTypes.AccountTotalLiabilities.type) {
|
|
querys.push('dateType=' + this.transactionStatisticsFilter.categoricalChartDateType);
|
|
|
|
if (this.transactionStatisticsFilter.categoricalChartDateType === datetimeConstants.allDateRanges.Custom.type) {
|
|
querys.push('minTime=' + this.transactionStatisticsFilter.categoricalChartStartTime);
|
|
querys.push('maxTime=' + this.transactionStatisticsFilter.categoricalChartEndTime);
|
|
}
|
|
} else if (analysisType === statisticsConstants.allAnalysisTypes.TrendAnalysis && dateRange) {
|
|
querys.push('dateType=' + dateRange.type);
|
|
querys.push('minTime=' + dateRange.minTime);
|
|
querys.push('maxTime=' + dateRange.maxTime);
|
|
}
|
|
|
|
return querys.join('&');
|
|
},
|
|
loadCategoricalAnalysis({ force }) {
|
|
const self = this;
|
|
const settingsStore = useSettingsStore();
|
|
|
|
return new Promise((resolve, reject) => {
|
|
services.getTransactionStatistics({
|
|
startTime: self.transactionStatisticsFilter.categoricalChartStartTime,
|
|
endTime: self.transactionStatisticsFilter.categoricalChartEndTime,
|
|
useTransactionTimezone: settingsStore.appSettings.statistics.defaultTimezoneType
|
|
}).then(response => {
|
|
const data = response.data;
|
|
|
|
if (!data || !data.success || !data.result) {
|
|
reject({ message: 'Unable to retrieve transaction statistics' });
|
|
return;
|
|
}
|
|
|
|
if (self.transactionStatisticsStateInvalid) {
|
|
self.updateTransactionStatisticsInvalidState(false);
|
|
}
|
|
|
|
if (force && data.result && isEquals(self.transactionCategoryStatisticsData, data.result)) {
|
|
reject({ message: 'Data is up to date' });
|
|
return;
|
|
}
|
|
|
|
self.transactionCategoryStatisticsData = data.result;
|
|
|
|
resolve(data.result);
|
|
}).catch(error => {
|
|
logger.error('failed to retrieve transaction statistics', error);
|
|
|
|
if (error.response && error.response.data && error.response.data.errorMessage) {
|
|
reject({ error: error.response.data });
|
|
} else if (!error.processed) {
|
|
reject({ message: 'Unable to retrieve transaction statistics' });
|
|
} else {
|
|
reject(error);
|
|
}
|
|
});
|
|
});
|
|
},
|
|
loadTrendAnalysis({ force }) {
|
|
const self = this;
|
|
const settingsStore = useSettingsStore();
|
|
|
|
return new Promise((resolve, reject) => {
|
|
services.getTransactionStatisticsTrends({
|
|
startYearMonth: self.transactionStatisticsFilter.trendChartStartYearMonth,
|
|
endYearMonth: self.transactionStatisticsFilter.trendChartEndYearMonth,
|
|
useTransactionTimezone: settingsStore.appSettings.statistics.defaultTimezoneType
|
|
}).then(response => {
|
|
const data = response.data;
|
|
|
|
if (!data || !data.success || !data.result) {
|
|
reject({ message: 'Unable to retrieve transaction statistics' });
|
|
return;
|
|
}
|
|
|
|
if (self.transactionStatisticsStateInvalid) {
|
|
self.updateTransactionStatisticsInvalidState(false);
|
|
}
|
|
|
|
if (force && data.result && isEquals(self.transactionCategoryTrendsData, data.result)) {
|
|
reject({ message: 'Data is up to date' });
|
|
return;
|
|
}
|
|
|
|
self.transactionCategoryTrendsData = data.result;
|
|
|
|
resolve(data.result);
|
|
}).catch(error => {
|
|
logger.error('failed to retrieve transaction statistics', error);
|
|
|
|
if (error.response && error.response.data && error.response.data.errorMessage) {
|
|
reject({ error: error.response.data });
|
|
} else if (!error.processed) {
|
|
reject({ message: 'Unable to retrieve transaction statistics' });
|
|
} else {
|
|
reject(error);
|
|
}
|
|
});
|
|
});
|
|
},
|
|
}
|
|
});
|