add amount range to axis / category / series in insights explorer

This commit is contained in:
MaysWind
2026-04-19 01:51:56 +08:00
parent e89aa10137
commit 6a4ab4c145
23 changed files with 686 additions and 54 deletions
+52 -28
View File
@@ -240,51 +240,75 @@ export enum TransactionExplorerDataDimensionType {
DestinationAccount = 'destinationAccount',
DestinationAccountCategory = 'destinationAccountCategory',
DestinationAccountCurrency = 'destinationAccountCurrency',
PrimaryCategory = 'primaryCategory',
SecondaryCategory = 'secondaryCategory',
SourceAmount = 'sourceAmount',
DestinationAmount = 'destinationAmount',
PrimaryCategory = 'primaryCategory',
SecondaryCategory = 'secondaryCategory'
SourceAmountRangeEqualFrequency = 'sourceAmountRangeEqualFrequency',
SourceAmountRangeEqualWidth = 'sourceAmountRangeEqualWidth',
SourceAmountRangeLogScale = 'sourceAmountRangeLogScale',
SourceAmountRangeStandardDeviation = 'sourceAmountRangeStandardDeviation',
SourceAmountRangeNaturalBreaks = 'sourceAmountRangeNaturalBreaks',
DestinationAmountRangeEqualFrequency = 'destinationAmountRangeEqualFrequency',
DestinationAmountRangeEqualWidth = 'destinationAmountRangeEqualWidth',
DestinationAmountRangeLogScale = 'destinationAmountRangeLogScale',
DestinationAmountRangeStandardDeviation = 'destinationAmountRangeStandardDeviation',
DestinationAmountRangeNaturalBreaks = 'destinationAmountRangeNaturalBreaks'
}
export class TransactionExplorerDataDimension implements NameValue {
private static readonly allInstances: TransactionExplorerDataDimension[] = [];
private static readonly allInstancesByValue: Record<string, TransactionExplorerDataDimension> = {};
public static readonly None = new TransactionExplorerDataDimension('None', TransactionExplorerDataDimensionType.None);
public static readonly Query = new TransactionExplorerDataDimension('Query', TransactionExplorerDataDimensionType.Query);
public static readonly DateTime = new TransactionExplorerDataDimension('Transaction Time', TransactionExplorerDataDimensionType.DateTime);
public static readonly DateTimeByYearMonthDay = new TransactionExplorerDataDimension('Transaction Date', TransactionExplorerDataDimensionType.DateTimeByYearMonthDay);
public static readonly DateTimeByYearMonth = new TransactionExplorerDataDimension('Transaction Year-Month', TransactionExplorerDataDimensionType.DateTimeByYearMonth);
public static readonly DateTimeByYearQuarter = new TransactionExplorerDataDimension('Transaction Year-Quarter', TransactionExplorerDataDimensionType.DateTimeByYearQuarter);
public static readonly DateTimeByYear = new TransactionExplorerDataDimension('Transaction Year', TransactionExplorerDataDimensionType.DateTimeByYear);
public static readonly DateTimeByFiscalYear = new TransactionExplorerDataDimension('Transaction Fiscal Year', TransactionExplorerDataDimensionType.DateTimeByFiscalYear);
public static readonly DateTimeByDayOfWeek = new TransactionExplorerDataDimension('Transaction Day of Week', TransactionExplorerDataDimensionType.DateTimeByDayOfWeek);
public static readonly DateTimeByDayOfMonth = new TransactionExplorerDataDimension('Transaction Day of Month', TransactionExplorerDataDimensionType.DateTimeByDayOfMonth);
public static readonly DateTimeByMonthOfYear = new TransactionExplorerDataDimension('Transaction Month of Year', TransactionExplorerDataDimensionType.DateTimeByMonthOfYear);
public static readonly DateTimeByQuarterOfYear = new TransactionExplorerDataDimension('Transaction Quarter of Year', TransactionExplorerDataDimensionType.DateTimeByQuarterOfYear);
public static readonly DateTimeByHourOfDay = new TransactionExplorerDataDimension('Transaction Hour of Day', TransactionExplorerDataDimensionType.DateTimeByHourOfDay);
public static readonly TimezoneOffset = new TransactionExplorerDataDimension('Transaction Timezone', TransactionExplorerDataDimensionType.TimezoneOffset);
public static readonly TransactionType = new TransactionExplorerDataDimension('Transaction Type', TransactionExplorerDataDimensionType.TransactionType);
public static readonly SourceAccount = new TransactionExplorerDataDimension('Source Account', TransactionExplorerDataDimensionType.SourceAccount);
public static readonly SourceAccountCategory = new TransactionExplorerDataDimension('Source Account Category', TransactionExplorerDataDimensionType.SourceAccountCategory);
public static readonly SourceAccountCurrency = new TransactionExplorerDataDimension('Source Account Currency', TransactionExplorerDataDimensionType.SourceAccountCurrency);
public static readonly DestinationAccount = new TransactionExplorerDataDimension('Destination Account', TransactionExplorerDataDimensionType.DestinationAccount);
public static readonly DestinationAccountCategory = new TransactionExplorerDataDimension('Destination Account Category', TransactionExplorerDataDimensionType.DestinationAccountCategory);
public static readonly DestinationAccountCurrency = new TransactionExplorerDataDimension('Destination Account Currency', TransactionExplorerDataDimensionType.DestinationAccountCurrency);
public static readonly PrimaryCategory = new TransactionExplorerDataDimension('Primary Category', TransactionExplorerDataDimensionType.PrimaryCategory);
public static readonly SecondaryCategory = new TransactionExplorerDataDimension('Secondary Category', TransactionExplorerDataDimensionType.SecondaryCategory);
public static readonly SourceAmount = new TransactionExplorerDataDimension('Amount', TransactionExplorerDataDimensionType.SourceAmount);
public static readonly DestinationAmount = new TransactionExplorerDataDimension('Transfer In Amount', TransactionExplorerDataDimensionType.DestinationAmount);
public static readonly None = new TransactionExplorerDataDimension('None', TransactionExplorerDataDimensionType.None, false, false);
public static readonly Query = new TransactionExplorerDataDimension('Query', TransactionExplorerDataDimensionType.Query, false, false);
public static readonly DateTime = new TransactionExplorerDataDimension('Transaction Time', TransactionExplorerDataDimensionType.DateTime, false, false);
public static readonly DateTimeByYearMonthDay = new TransactionExplorerDataDimension('Transaction Date', TransactionExplorerDataDimensionType.DateTimeByYearMonthDay, false, false);
public static readonly DateTimeByYearMonth = new TransactionExplorerDataDimension('Transaction Year-Month', TransactionExplorerDataDimensionType.DateTimeByYearMonth, false, false);
public static readonly DateTimeByYearQuarter = new TransactionExplorerDataDimension('Transaction Year-Quarter', TransactionExplorerDataDimensionType.DateTimeByYearQuarter, false, false);
public static readonly DateTimeByYear = new TransactionExplorerDataDimension('Transaction Year', TransactionExplorerDataDimensionType.DateTimeByYear, false, false);
public static readonly DateTimeByFiscalYear = new TransactionExplorerDataDimension('Transaction Fiscal Year', TransactionExplorerDataDimensionType.DateTimeByFiscalYear, false, false);
public static readonly DateTimeByDayOfWeek = new TransactionExplorerDataDimension('Transaction Day of Week', TransactionExplorerDataDimensionType.DateTimeByDayOfWeek, false, false);
public static readonly DateTimeByDayOfMonth = new TransactionExplorerDataDimension('Transaction Day of Month', TransactionExplorerDataDimensionType.DateTimeByDayOfMonth, false, false);
public static readonly DateTimeByMonthOfYear = new TransactionExplorerDataDimension('Transaction Month of Year', TransactionExplorerDataDimensionType.DateTimeByMonthOfYear, false, false);
public static readonly DateTimeByQuarterOfYear = new TransactionExplorerDataDimension('Transaction Quarter of Year', TransactionExplorerDataDimensionType.DateTimeByQuarterOfYear, false, false);
public static readonly DateTimeByHourOfDay = new TransactionExplorerDataDimension('Transaction Hour of Day', TransactionExplorerDataDimensionType.DateTimeByHourOfDay, false, false);
public static readonly TimezoneOffset = new TransactionExplorerDataDimension('Transaction Timezone', TransactionExplorerDataDimensionType.TimezoneOffset, false, false);
public static readonly TransactionType = new TransactionExplorerDataDimension('Transaction Type', TransactionExplorerDataDimensionType.TransactionType, false, false);
public static readonly SourceAccount = new TransactionExplorerDataDimension('Source Account', TransactionExplorerDataDimensionType.SourceAccount, false, false);
public static readonly SourceAccountCategory = new TransactionExplorerDataDimension('Source Account Category', TransactionExplorerDataDimensionType.SourceAccountCategory, false, false);
public static readonly SourceAccountCurrency = new TransactionExplorerDataDimension('Source Account Currency', TransactionExplorerDataDimensionType.SourceAccountCurrency, false, false);
public static readonly DestinationAccount = new TransactionExplorerDataDimension('Destination Account', TransactionExplorerDataDimensionType.DestinationAccount, false, false);
public static readonly DestinationAccountCategory = new TransactionExplorerDataDimension('Destination Account Category', TransactionExplorerDataDimensionType.DestinationAccountCategory, false, false);
public static readonly DestinationAccountCurrency = new TransactionExplorerDataDimension('Destination Account Currency', TransactionExplorerDataDimensionType.DestinationAccountCurrency, false, false);
public static readonly PrimaryCategory = new TransactionExplorerDataDimension('Primary Category', TransactionExplorerDataDimensionType.PrimaryCategory, false, false);
public static readonly SecondaryCategory = new TransactionExplorerDataDimension('Secondary Category', TransactionExplorerDataDimensionType.SecondaryCategory, false, false);
public static readonly SourceAmount = new TransactionExplorerDataDimension('Amount', TransactionExplorerDataDimensionType.SourceAmount, false, false);
public static readonly DestinationAmount = new TransactionExplorerDataDimension('Transfer In Amount', TransactionExplorerDataDimensionType.DestinationAmount, false, false);
public static readonly SourceAmountRangeEqualFrequency = new TransactionExplorerDataDimension('Amount Range (Equal Frequency)', TransactionExplorerDataDimensionType.SourceAmountRangeEqualFrequency, true, false);
public static readonly SourceAmountRangeEqualWidth = new TransactionExplorerDataDimension('Amount Range (Equal Width)', TransactionExplorerDataDimensionType.SourceAmountRangeEqualWidth, true, false);
public static readonly SourceAmountRangeLogScale = new TransactionExplorerDataDimension('Amount Range (Log Scale)', TransactionExplorerDataDimensionType.SourceAmountRangeLogScale, true, false);
public static readonly SourceAmountRangeStandardDeviation = new TransactionExplorerDataDimension('Amount Range (Standard Deviation)', TransactionExplorerDataDimensionType.SourceAmountRangeStandardDeviation, true, false);
public static readonly SourceAmountRangeNaturalBreaks = new TransactionExplorerDataDimension('Amount Range (Natural Breaks)', TransactionExplorerDataDimensionType.SourceAmountRangeNaturalBreaks, true, false);
public static readonly DestinationAmountRangeEqualFrequency = new TransactionExplorerDataDimension('Transfer In Amount Range (Equal Frequency)', TransactionExplorerDataDimensionType.DestinationAmountRangeEqualFrequency, false, true);
public static readonly DestinationAmountRangeEqualWidth = new TransactionExplorerDataDimension('Transfer In Amount Range (Equal Width)', TransactionExplorerDataDimensionType.DestinationAmountRangeEqualWidth, false, true);
public static readonly DestinationAmountRangeLogScale = new TransactionExplorerDataDimension('Transfer In Amount Range (Log Scale)', TransactionExplorerDataDimensionType.DestinationAmountRangeLogScale, false, true);
public static readonly DestinationAmountRangeStandardDeviation = new TransactionExplorerDataDimension('Transfer In Amount Range (Standard Deviation)', TransactionExplorerDataDimensionType.DestinationAmountRangeStandardDeviation, false, true);
public static readonly DestinationAmountRangeNaturalBreaks = new TransactionExplorerDataDimension('Transfer In Amount Range (Natural Breaks)', TransactionExplorerDataDimensionType.DestinationAmountRangeNaturalBreaks, false, true);
public static readonly CategoryDimensionDefault = TransactionExplorerDataDimension.Query;
public static readonly SeriesDimensionDefault = TransactionExplorerDataDimension.None;
public readonly name: string;
public readonly value: TransactionExplorerDataDimensionType;
public readonly isSourceAmountRange: boolean;
public readonly isDestinationAmountRange: boolean;
private constructor(name: string, value: TransactionExplorerDataDimensionType) {
private constructor(name: string, value: TransactionExplorerDataDimensionType, isSourceAmountRange: boolean, isDestinationAmountRange: boolean) {
this.name = name;
this.value = value;
this.isSourceAmountRange = isSourceAmountRange;
this.isDestinationAmountRange = isDestinationAmountRange;
TransactionExplorerDataDimension.allInstances.push(this);
TransactionExplorerDataDimension.allInstancesByValue[value] = this;
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Quellkonto-Währung",
"Destination Account Category": "Zielkonto-Kategorie",
"Destination Account Currency": "Zielkonto-Währung",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Wertmetrik",
"Transaction Count": "Transaktionsanzahl",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Source Account Currency",
"Destination Account Category": "Destination Account Category",
"Destination Account Currency": "Destination Account Currency",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Value Metric",
"Transaction Count": "Transaction Count",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Moneda de la cuenta de origen",
"Destination Account Category": "Categoría de la cuenta de destino",
"Destination Account Currency": "Moneda de la cuenta de destino",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Métrica de valor",
"Transaction Count": "Recuento de transacciones",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Source Account Currency",
"Destination Account Category": "Destination Account Category",
"Destination Account Currency": "Destination Account Currency",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Value Metric",
"Transaction Count": "Transaction Count",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Source Account Currency",
"Destination Account Category": "Destination Account Category",
"Destination Account Currency": "Destination Account Currency",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Value Metric",
"Transaction Count": "Transaction Count",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Source Account Currency",
"Destination Account Category": "Destination Account Category",
"Destination Account Currency": "Destination Account Currency",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Value Metric",
"Transaction Count": "Transaction Count",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Source Account Currency",
"Destination Account Category": "Destination Account Category",
"Destination Account Currency": "Destination Account Currency",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Value Metric",
"Transaction Count": "Transaction Count",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "출처 계좌 통화",
"Destination Account Category": "목적지 계좌 분류",
"Destination Account Currency": "목적지 계좌 통화",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "값 메트릭",
"Transaction Count": "거래 수",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Source Account Currency",
"Destination Account Category": "Destination Account Category",
"Destination Account Currency": "Destination Account Currency",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Value Metric",
"Transaction Count": "Transaction Count",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Moeda da Conta de Origem",
"Destination Account Category": "Categoria da Conta de Destino",
"Destination Account Currency": "Moeda da Conta de Destino",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Métrica de Valor",
"Transaction Count": "Quantidade de Transações",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Валюта исходного счёта",
"Destination Account Category": "Категория целевого счёта",
"Destination Account Currency": "Валюта целевого счёта",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Метрика значения",
"Transaction Count": "Количество транзакций",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Valuta izvornega računa",
"Destination Account Category": "Kategorija ciljnega računa",
"Destination Account Currency": "Valuta ciljnega računa",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Metrika vrednosti",
"Transaction Count": "Število transakcij",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "மூல கணக்கு நாணயம்",
"Destination Account Category": "இலக்கு கணக்கு வகை",
"Destination Account Currency": "இலக்கு கணக்கு நாணயம்",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "மதிப்பு அளவீடு",
"Transaction Count": "பரிவர்த்தனை எண்ணிக்கை",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Source Account Currency",
"Destination Account Category": "Destination Account Category",
"Destination Account Currency": "Destination Account Currency",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Value Metric",
"Transaction Count": "Transaction Count",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Source Account Currency",
"Destination Account Category": "Destination Account Category",
"Destination Account Currency": "Destination Account Currency",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Value Metric",
"Transaction Count": "Transaction Count",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Source Account Currency",
"Destination Account Category": "Destination Account Category",
"Destination Account Currency": "Destination Account Currency",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Value Metric",
"Transaction Count": "Transaction Count",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "Source Account Currency",
"Destination Account Category": "Destination Account Category",
"Destination Account Currency": "Destination Account Currency",
"Amount Range (Equal Frequency)": "Amount Range (Equal Frequency)",
"Amount Range (Equal Width)": "Amount Range (Equal Width)",
"Amount Range (Log Scale)": "Amount Range (Log Scale)",
"Amount Range (Standard Deviation)": "Amount Range (Standard Deviation)",
"Amount Range (Natural Breaks)": "Amount Range (Natural Breaks)",
"Transfer In Amount Range (Equal Frequency)": "Transfer In Amount Range (Equal Frequency)",
"Transfer In Amount Range (Equal Width)": "Transfer In Amount Range (Equal Width)",
"Transfer In Amount Range (Log Scale)": "Transfer In Amount Range (Log Scale)",
"Transfer In Amount Range (Standard Deviation)": "Transfer In Amount Range (Standard Deviation)",
"Transfer In Amount Range (Natural Breaks)": "Transfer In Amount Range (Natural Breaks)",
"Number of Amount Ranges": "Number of Amount Ranges",
"Value Metric": "Value Metric",
"Transaction Count": "Transaction Count",
"Active Transaction Days": "Active Transaction Days",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "来源账户货币",
"Destination Account Category": "目标账户分类",
"Destination Account Currency": "目标账户货币",
"Amount Range (Equal Frequency)": "金额区间(等频)",
"Amount Range (Equal Width)": "金额区间(等宽)",
"Amount Range (Log Scale)": "金额区间(对数刻度)",
"Amount Range (Standard Deviation)": "金额区间(标准差)",
"Amount Range (Natural Breaks)": "金额区间(自然断点)",
"Transfer In Amount Range (Equal Frequency)": "转入金额区间(等频)",
"Transfer In Amount Range (Equal Width)": "转入金额区间(等宽)",
"Transfer In Amount Range (Log Scale)": "转入金额区间(对数刻度)",
"Transfer In Amount Range (Standard Deviation)": "转入金额区间(标准差)",
"Transfer In Amount Range (Natural Breaks)": "转入金额区间(自然断点)",
"Number of Amount Ranges": "金额区间数量",
"Value Metric": "值类型",
"Transaction Count": "交易数量",
"Active Transaction Days": "活跃交易日",
+11
View File
@@ -1804,6 +1804,17 @@
"Source Account Currency": "來源帳戶貨幣",
"Destination Account Category": "目標帳戶分類",
"Destination Account Currency": "目標帳戶貨幣",
"Amount Range (Equal Frequency)": "金額區間(等頻)",
"Amount Range (Equal Width)": "金額區間(等寬)",
"Amount Range (Log Scale)": "金額區間(對數刻度)",
"Amount Range (Standard Deviation)": "金額區間(標準差)",
"Amount Range (Natural Breaks)": "金額區間(自然斷點)",
"Transfer In Amount Range (Equal Frequency)": "轉入金額區間(等頻)",
"Transfer In Amount Range (Equal Width)": "轉入金額區間(等寬)",
"Transfer In Amount Range (Log Scale)": "轉入金額區間(對數刻度)",
"Transfer In Amount Range (Standard Deviation)": "转入金額區間(標準差)",
"Transfer In Amount Range (Natural Breaks)": "转入金額區間(自然斷點)",
"Number of Amount Ranges": "金額區間數量",
"Value Metric": "值類型",
"Transaction Count": "交易數量",
"Active Transaction Days": "活躍交易日數",
+12 -1
View File
@@ -72,6 +72,7 @@ export class InsightsExplorer implements InsightsExplorerInfoResponse {
public chartType: TransactionExplorerChartTypeValue;
public categoryDimension: TransactionExplorerDataDimensionType;
public seriesDimension: TransactionExplorerDataDimensionType;
public amountRangeCount: number;
public valueMetric: TransactionExplorerValueMetricType;
public chartSortingType: number;
@@ -87,11 +88,12 @@ export class InsightsExplorer implements InsightsExplorerInfoResponse {
TransactionExplorerChartType.Default.value,
TransactionExplorerDataDimension.CategoryDimensionDefault.value,
TransactionExplorerDataDimension.SeriesDimensionDefault.value,
5,
TransactionExplorerValueMetric.Default.value,
ChartSortingType.Default.type
);
private constructor(id: string, name: string, displayOrder: number, hidden: boolean, queries: TransactionExplorerQuery[], timezoneUsedForDateRange: number, datatableQuerySource: string, countPerPage: number, chartType: TransactionExplorerChartTypeValue, categoryDimension: TransactionExplorerDataDimensionType, seriesDimension: TransactionExplorerDataDimensionType, valueMetric: TransactionExplorerValueMetricType, chartSortingType: number) {
private constructor(id: string, name: string, displayOrder: number, hidden: boolean, queries: TransactionExplorerQuery[], timezoneUsedForDateRange: number, datatableQuerySource: string, countPerPage: number, chartType: TransactionExplorerChartTypeValue, categoryDimension: TransactionExplorerDataDimensionType, seriesDimension: TransactionExplorerDataDimensionType, amountRangeCount: number, valueMetric: TransactionExplorerValueMetricType, chartSortingType: number) {
this.id = id;
this.name = name;
this.displayOrder = displayOrder;
@@ -103,6 +105,7 @@ export class InsightsExplorer implements InsightsExplorerInfoResponse {
this.chartType = chartType;
this.categoryDimension = categoryDimension;
this.seriesDimension = seriesDimension;
this.amountRangeCount = amountRangeCount;
this.valueMetric = valueMetric;
this.chartSortingType = chartSortingType;
}
@@ -116,6 +119,7 @@ export class InsightsExplorer implements InsightsExplorerInfoResponse {
chartType: this.chartType,
categoryDimension: this.categoryDimension,
seriesDimension: this.seriesDimension,
amountRangeCount: this.amountRangeCount,
valueMetric: this.valueMetric,
chartSortingType: this.chartSortingType
};
@@ -147,6 +151,7 @@ export class InsightsExplorer implements InsightsExplorerInfoResponse {
let chartType = InsightsExplorer.Default.chartType;
let categoryDimension = InsightsExplorer.Default.categoryDimension;
let seriesDimension = InsightsExplorer.Default.seriesDimension;
let amountRangeCount = InsightsExplorer.Default.amountRangeCount;
let valueMetric = InsightsExplorer.Default.valueMetric;
let chartSortingType = InsightsExplorer.Default.chartSortingType;
let hasDatatableQuerySource = false;
@@ -176,6 +181,10 @@ export class InsightsExplorer implements InsightsExplorerInfoResponse {
seriesDimension = data['seriesDimension'] as TransactionExplorerDataDimensionType;
}
if (typeof data['amountRangeCount'] === 'number') {
amountRangeCount = data['amountRangeCount'] as number;
}
if (typeof data['valueMetric'] === 'string') {
valueMetric = data['valueMetric'] as TransactionExplorerValueMetricType;
}
@@ -217,6 +226,7 @@ export class InsightsExplorer implements InsightsExplorerInfoResponse {
chartType,
categoryDimension,
seriesDimension,
amountRangeCount,
valueMetric,
chartSortingType
);
@@ -235,6 +245,7 @@ export class InsightsExplorer implements InsightsExplorerInfoResponse {
InsightsExplorer.Default.chartType,
InsightsExplorer.Default.categoryDimension,
InsightsExplorer.Default.seriesDimension,
InsightsExplorer.Default.amountRangeCount,
InsightsExplorer.Default.valueMetric,
InsightsExplorer.Default.chartSortingType
);
+359 -7
View File
@@ -46,6 +46,7 @@ import {
getObjectOwnFieldCount
} from '@/lib/common.ts';
import {
mean,
median,
percentile,
sumMaxN,
@@ -127,6 +128,19 @@ export interface CategoriedTransactionExplorerDataItem extends SeriesInfo {
value: number;
}
export interface AmountRanges {
categorySourceAmountRanges?: number[];
categoryDestinationAmountRanges?: number[];
seriesSourceAmountRanges?: number[];
seriesDestinationAmountRanges?: number[];
}
export interface TransactionInsightDataItemInQuery {
queryIndex: number;
queryName: string;
transaction: TransactionInsightDataItem;
}
export interface InsightsExplorerTransactionStatisticData {
totalCount: number;
totalAmount: number;
@@ -180,7 +194,180 @@ export const useExplorersStore = defineStore('explorers', () => {
};
}
function getDataCategoryInfo(timezoneUsedForDateRange: number, dimension: TransactionExplorerDataDimension, queryName: string, queryIndex: number, transaction: TransactionInsightDataItem): CategoriedInfo {
function calculateAmountRanges(sortedAmounts: number[], dimension: TransactionExplorerDataDimension, rangeCount: number): number[] {
const result: number[] = [];
if (sortedAmounts.length < 1 || rangeCount <= 0) {
return result;
}
const minAmount = sortedAmounts[0] as number;
const maxAmount = sortedAmounts[sortedAmounts.length - 1] as number;
rangeCount = Math.min(rangeCount, sortedAmounts.length);
// [min1, max1), [min2, max2), ..., [minN, maxN]
if (dimension === TransactionExplorerDataDimension.SourceAmountRangeEqualFrequency
|| dimension === TransactionExplorerDataDimension.DestinationAmountRangeEqualFrequency) {
for (let i = 0; i < rangeCount; i++) {
result.push(sortedAmounts[Math.floor(i * (sortedAmounts.length - 1) / rangeCount)] as number);
}
result.push(maxAmount);
} else if (dimension === TransactionExplorerDataDimension.SourceAmountRangeEqualWidth
|| dimension === TransactionExplorerDataDimension.DestinationAmountRangeEqualWidth) {
if (minAmount === maxAmount) {
return [minAmount, maxAmount];
}
const width: number = (maxAmount - minAmount) / rangeCount;
for (let i = 0; i < rangeCount; i++) {
result.push(minAmount + i * width);
}
result.push(maxAmount);
} else if (dimension === TransactionExplorerDataDimension.SourceAmountRangeLogScale
|| dimension === TransactionExplorerDataDimension.DestinationAmountRangeLogScale) {
const epsilon: number = 1e-9;
const transform = (x: number): number => {
if (x === 0) {
return 0;
}
return Math.sign(x) * Math.log(Math.abs(x) + epsilon);
};
const inverse = (y: number): number => {
if (y === 0) {
return 0;
}
return Math.sign(y) * (Math.exp(Math.abs(y)) - epsilon);
};
const transformed = sortedAmounts.map(transform).sort((a, b) => a - b);
const tMin: number = transformed[0] as number;
const tMax: number = transformed[transformed.length - 1] as number;
if (tMin === tMax) {
return [minAmount, maxAmount];
}
const width: number = (tMax - tMin) / rangeCount;
result.push(minAmount);
for (let i = 1; i < rangeCount; i++) {
result.push(inverse(tMin + i * width));
}
result.push(maxAmount);
} else if (dimension === TransactionExplorerDataDimension.SourceAmountRangeStandardDeviation
|| dimension === TransactionExplorerDataDimension.DestinationAmountRangeStandardDeviation) {
if (minAmount === maxAmount) {
return [minAmount, maxAmount];
}
const averageAmountForVarianceCalculation: number = mean(sortedAmounts, item => item) / AMOUNT_FACTOR;
const { standardDeviation } = varianceAndStandardDeviation(sortedAmounts, averageAmountForVarianceCalculation, item => item / AMOUNT_FACTOR);
if (standardDeviation === 0) {
return [minAmount, maxAmount];
}
const rawBreaks: number[] = [];
const halfCount = Math.floor(rangeCount / 2);
if (rangeCount % 2 === 1) {
for (let i = -halfCount; i <= halfCount; i++) {
rawBreaks.push((averageAmountForVarianceCalculation + i * standardDeviation) * AMOUNT_FACTOR);
}
} else {
for (let i = -halfCount; i <= halfCount; i++) {
if (i === 0) {
continue;
}
rawBreaks.push((averageAmountForVarianceCalculation + (i - 0.5) * standardDeviation) * AMOUNT_FACTOR);
}
rawBreaks.sort((a, b) => a - b);
}
const clipped = rawBreaks.map((v) => Math.max(minAmount, Math.min(maxAmount, v)))
.filter((v, i, arr) => i === 0 || v !== arr[i - 1]);
clipped[0] = minAmount;
if (clipped[clipped.length - 1] !== maxAmount) {
clipped.push(maxAmount);
}
return clipped;
} else if (dimension === TransactionExplorerDataDimension.SourceAmountRangeNaturalBreaks
|| dimension === TransactionExplorerDataDimension.DestinationAmountRangeNaturalBreaks) {
if (minAmount === maxAmount) {
return [minAmount, maxAmount];
}
const n = sortedAmounts.length;
const k = Math.min(rangeCount, n);
const lowerClassLimits: number[][] = Array.from({ length: n + 1 }, () => new Array(k + 1).fill(0));
const varianceCombinations: number[][] = Array.from({ length: n + 1 }, () => new Array(k + 1).fill(Infinity));
for (let i = 1; i <= k; i++) {
lowerClassLimits[1]![i] = 1;
varianceCombinations[1]![i] = 0;
}
for (let l = 2; l <= n; l++) {
let sumZ = 0;
let sumZ2 = 0;
for (let m = 1; m <= l; m++) {
const val = sortedAmounts[l - m] as number;
sumZ += val;
sumZ2 += val * val;
const variance = sumZ2 - (sumZ * sumZ) / m;
if (m === l) {
for (let j = 1; j <= k; j++) {
if (variance < varianceCombinations[l]![j]!) {
lowerClassLimits[l]![j] = 1;
varianceCombinations[l]![j] = variance;
}
}
} else {
for (let j = 2; j <= k; j++) {
const combined = varianceCombinations[l - m]![j - 1]! + variance;
if (combined < varianceCombinations[l]![j]!) {
lowerClassLimits[l]![j] = l - m + 1;
varianceCombinations[l]![j] = combined;
}
}
}
}
}
const breaks: number[] = new Array(k + 1);
breaks[k] = maxAmount;
let currentK = k;
let currentIdx = n;
while (currentK >= 2) {
const lowerIdx = lowerClassLimits[currentIdx]![currentK]!;
breaks[currentK - 1] = sortedAmounts[lowerIdx - 1] as number;
currentIdx = lowerIdx - 1;
currentK--;
}
breaks[0] = minAmount;
return breaks;
}
return result;
}
function getDataCategoryInfo(timezoneUsedForDateRange: number, dimension: TransactionExplorerDataDimension, sourceAmountRanges: number[] | undefined, destinationAmountRanges: number[] | undefined, queryName: string, queryIndex: number, transaction: TransactionInsightDataItem): CategoriedInfo {
const defaultCurrency = userStore.currentUserDefaultCurrency;
let transactionTimeUtfOffset: number | undefined = undefined;
@@ -468,6 +655,91 @@ export const useExplorersStore = defineStore('explorers', () => {
categoryIdType: TransactionExplorerDimensionType.Amount,
categoryDisplayOrders: [amountInDefaultCurrency]
};
} else if (dimension.isSourceAmountRange || dimension.isDestinationAmountRange) {
const isSourceAmount = dimension.isSourceAmountRange;
if (dimension.isDestinationAmountRange && transaction.type !== TransactionType.Transfer) {
return {
categoryName: 'None',
categoryNameNeedI18n: true,
categoryId: 'none',
categoryIdType: TransactionExplorerDimensionType.Other,
categoryDisplayOrders: [Number.MAX_SAFE_INTEGER]
};
}
const amount = dimension.isSourceAmountRange ? transaction.sourceAmount : transaction.destinationAmount;
const account = dimension.isSourceAmountRange ? transaction.sourceAccount : transaction.destinationAccount;
let amountInDefaultCurrency: number = amount;
if (!account) {
return {
categoryName: 'Unknown',
categoryNameNeedI18n: true,
categoryId: 'unknown',
categoryIdType: TransactionExplorerDimensionType.Other,
categoryDisplayOrders: [Number.MAX_SAFE_INTEGER]
};
}
if (account.currency !== defaultCurrency) {
const exchangedAmount = exchangeRatesStore.getExchangedAmount(amount, account.currency, defaultCurrency);
if (isNumber(exchangedAmount)) {
amountInDefaultCurrency = Math.trunc(exchangedAmount);
} else {
return {
categoryName: 'Unknown',
categoryNameNeedI18n: true,
categoryId: 'unknown',
categoryIdType: TransactionExplorerDimensionType.Other,
categoryDisplayOrders: [Number.MAX_SAFE_INTEGER]
};
}
}
const amountRanges: number[] = isSourceAmount ? (sourceAmountRanges ?? []) : (destinationAmountRanges ?? []);
let matchAmountRangeMin: number | undefined = undefined;
let matchAmountRangeMax: number | undefined = undefined;
let matchAmountRangeIndex: number | undefined = undefined;
for (let i = 1; i < amountRanges.length; i++) {
const amountRangeMin = amountRanges[i - 1] as number;
const amountRangeMax = amountRanges[i] as number;
if (amountInDefaultCurrency < amountRangeMin) {
continue;
}
if (amountInDefaultCurrency > amountRangeMax) {
continue;
}
if (i < amountRanges.length - 1 && amountInDefaultCurrency === amountRangeMax) {
continue;
}
matchAmountRangeMin = amountRangeMin;
matchAmountRangeMax = amountRangeMax;
matchAmountRangeIndex = i - 1;
}
if (isNumber(matchAmountRangeMin) && isNumber(matchAmountRangeMax) && isNumber(matchAmountRangeIndex)) {
return {
categoryName: `${matchAmountRangeMin.toString(10)}|${matchAmountRangeMax.toString(10)}`,
categoryId: matchAmountRangeIndex.toString(10),
categoryIdType: TransactionExplorerDimensionType.Other,
categoryDisplayOrders: [matchAmountRangeIndex]
};
} else {
return {
categoryName: 'Other',
categoryNameNeedI18n: true,
categoryId: 'other',
categoryIdType: TransactionExplorerDimensionType.Other,
categoryDisplayOrders: [Number.MAX_SAFE_INTEGER]
};
}
} else {
return {
categoryName: '',
@@ -478,8 +750,37 @@ export const useExplorersStore = defineStore('explorers', () => {
}
}
function addTransactionToCategoriedDataMap(timezoneUsedForDateRange: number, categoriedDataMap: Record<string, CategoriedTransactions>, categoryDimension: TransactionExplorerDataDimension, seriesDemension: TransactionExplorerDataDimension, queryName: string, queryIndex: number, transaction: TransactionInsightDataItem): void {
const categoriedInfo = getDataCategoryInfo(timezoneUsedForDateRange, categoryDimension, queryName, queryIndex, transaction);
function addTransactionToFilteredList(filteredTransactions: TransactionInsightDataItemInQuery[], filteredTransactionSourceAmountsInDefaultCurrency: number[], filteredTransactionDestinationAmountsInDefaultCurrency: number[], defaultCurrency: string, queryName: string, queryIndex: number, transaction: TransactionInsightDataItem): void {
filteredTransactions.push({
queryIndex: queryIndex,
queryName: queryName,
transaction: transaction
});
let sourceAmountInDefaultCurrency: number | undefined = transaction.sourceAmount;
let destinationAmountInDefaultCurrency: number | undefined = transaction.type === TransactionType.Transfer && transaction.destinationAccount ? transaction.destinationAmount : undefined;
if (transaction.sourceAccount.currency !== defaultCurrency) {
const amount = exchangeRatesStore.getExchangedAmount(transaction.sourceAmount, transaction.sourceAccount.currency, defaultCurrency);
sourceAmountInDefaultCurrency = isNumber(amount) ? Math.trunc(amount) : undefined;
}
if (transaction.type === TransactionType.Transfer && transaction.destinationAccount && transaction.destinationAccount.currency !== defaultCurrency) {
const amount = exchangeRatesStore.getExchangedAmount(transaction.destinationAmount, transaction.destinationAccount.currency, defaultCurrency);
destinationAmountInDefaultCurrency = isNumber(amount) ? Math.trunc(amount) : undefined;
}
if (isNumber(sourceAmountInDefaultCurrency)) {
filteredTransactionSourceAmountsInDefaultCurrency.push(sourceAmountInDefaultCurrency);
}
if (isNumber(destinationAmountInDefaultCurrency)) {
filteredTransactionDestinationAmountsInDefaultCurrency.push(destinationAmountInDefaultCurrency);
}
}
function addTransactionToCategoriedDataMap(timezoneUsedForDateRange: number, categoriedDataMap: Record<string, CategoriedTransactions>, categoryDimension: TransactionExplorerDataDimension, seriesDemension: TransactionExplorerDataDimension, allAmountRanges: AmountRanges, queryName: string, queryIndex: number, transaction: TransactionInsightDataItem): void {
const categoriedInfo = getDataCategoryInfo(timezoneUsedForDateRange, categoryDimension, allAmountRanges.categorySourceAmountRanges, allAmountRanges.categoryDestinationAmountRanges, queryName, queryIndex, transaction);
let categoriedData = categoriedDataMap[categoriedInfo.categoryId];
if (!categoriedData) {
@@ -495,7 +796,7 @@ export const useExplorersStore = defineStore('explorers', () => {
categoriedDataMap[categoriedInfo.categoryId] = categoriedData;
}
const seriesInfo = getDataCategoryInfo(timezoneUsedForDateRange, seriesDemension, queryName, queryIndex, transaction);
const seriesInfo = getDataCategoryInfo(timezoneUsedForDateRange, seriesDemension, allAmountRanges.seriesSourceAmountRanges, allAmountRanges.seriesDestinationAmountRanges, queryName, queryIndex, transaction);
let seriesData = categoriedData.trasactions[seriesInfo.categoryId];
if (!seriesData) {
@@ -514,6 +815,37 @@ export const useExplorersStore = defineStore('explorers', () => {
seriesData.trasactions.push(transaction);
}
function buildAllAmountRanges(categoryDimension: TransactionExplorerDataDimension, seriesDimension: TransactionExplorerDataDimension, filteredTransactionSourceAmountsInDefaultCurrency: number[], filteredTransactionDestinationAmountsInDefaultCurrency: number[], rangeCount: number): AmountRanges {
const allAmountRanges: AmountRanges = {};
if (categoryDimension.isSourceAmountRange || seriesDimension.isSourceAmountRange) {
filteredTransactionSourceAmountsInDefaultCurrency.sort((a, b) => a - b);
const sorteUniqueAmounts = filteredTransactionSourceAmountsInDefaultCurrency.filter((v, i, a) => i === 0 || v !== a[i - 1]);
if (categoryDimension.isSourceAmountRange) {
allAmountRanges.categorySourceAmountRanges = calculateAmountRanges(sorteUniqueAmounts, categoryDimension, rangeCount);
}
if (seriesDimension.isSourceAmountRange) {
allAmountRanges.seriesSourceAmountRanges = calculateAmountRanges(sorteUniqueAmounts, seriesDimension, rangeCount);
}
}
if (categoryDimension.isDestinationAmountRange || seriesDimension.isDestinationAmountRange) {
filteredTransactionDestinationAmountsInDefaultCurrency.sort((a, b) => a - b);
const sorteUniqueAmounts = filteredTransactionDestinationAmountsInDefaultCurrency.filter((v, i, a) => i === 0 || v !== a[i - 1]);
if (categoryDimension.isDestinationAmountRange) {
allAmountRanges.categoryDestinationAmountRanges = calculateAmountRanges(sorteUniqueAmounts, categoryDimension, rangeCount);
}
if (seriesDimension.isDestinationAmountRange) {
allAmountRanges.seriesDestinationAmountRanges = calculateAmountRanges(sorteUniqueAmounts, seriesDimension, rangeCount);
}
}
return allAmountRanges;
}
function loadInsightsExplorerList(explorers: InsightsExplorerBasicInfo[]): void {
allInsightsExplorerBasicInfos.value = explorers;
allInsightsExplorerBasicInfosMap.value = {};
@@ -650,6 +982,15 @@ export const useExplorersStore = defineStore('explorers', () => {
return result;
});
const isUsingAmountRange = computed<boolean>(() => {
const chartType = TransactionExplorerChartType.valueOf(currentInsightsExplorer.value.chartType);
const categoryDimension = TransactionExplorerDataDimension.valueOf(currentInsightsExplorer.value.categoryDimension);
const seriesDimension = chartType?.seriesDimensionRequired ? TransactionExplorerDataDimension.valueOf(currentInsightsExplorer.value.seriesDimension) : TransactionExplorerDataDimension.SeriesDimensionDefault;
return categoryDimension?.isSourceAmountRange || seriesDimension?.isSourceAmountRange
|| categoryDimension?.isDestinationAmountRange || seriesDimension?.isDestinationAmountRange
|| false;
});
const filteredTransactionsInDataTable = computed<TransactionInsightDataItem[]>(() => {
if (!allTransactions.value || allTransactions.value.length < 1) {
return [];
@@ -795,11 +1136,14 @@ export const useExplorersStore = defineStore('explorers', () => {
return {};
}
const categoriedDataMap: Record<string, CategoriedTransactions> = {};
const defaultCurrency = userStore.currentUserDefaultCurrency;
const filteredTransactions: TransactionInsightDataItemInQuery[] = [];
const filteredTransactionSourceAmountsInDefaultCurrency: number[] = [];
const filteredTransactionDestinationAmountsInDefaultCurrency: number[] = [];
for (const transaction of allTransactions.value) {
if (!currentInsightsExplorer.value.queries || currentInsightsExplorer.value.queries.length < 1) {
addTransactionToCategoriedDataMap(currentInsightsExplorer.value.timezoneUsedForDateRange, categoriedDataMap, categoryDimension, seriesDimension, '', 0, transaction);
addTransactionToFilteredList(filteredTransactions, filteredTransactionSourceAmountsInDefaultCurrency, filteredTransactionDestinationAmountsInDefaultCurrency, defaultCurrency, '', 0, transaction);
continue;
}
@@ -807,7 +1151,7 @@ export const useExplorersStore = defineStore('explorers', () => {
for (const [query, index] of itemAndIndex(currentInsightsExplorer.value.queries)) {
if (query.match(transaction, matchContext)) {
addTransactionToCategoriedDataMap(currentInsightsExplorer.value.timezoneUsedForDateRange, categoriedDataMap, categoryDimension, seriesDimension, query.name, index, transaction);
addTransactionToFilteredList(filteredTransactions, filteredTransactionSourceAmountsInDefaultCurrency, filteredTransactionDestinationAmountsInDefaultCurrency, defaultCurrency, query.name, index, transaction);
if (categoryDimension !== TransactionExplorerDataDimension.Query) {
break;
@@ -816,6 +1160,13 @@ export const useExplorersStore = defineStore('explorers', () => {
}
}
const categoriedDataMap: Record<string, CategoriedTransactions> = {};
const allAmountRanges: AmountRanges = buildAllAmountRanges(categoryDimension, seriesDimension, filteredTransactionSourceAmountsInDefaultCurrency, filteredTransactionDestinationAmountsInDefaultCurrency, currentInsightsExplorer.value.amountRangeCount);
for (const item of filteredTransactions) {
addTransactionToCategoriedDataMap(currentInsightsExplorer.value.timezoneUsedForDateRange, categoriedDataMap, categoryDimension, seriesDimension, allAmountRanges, item.queryName, item.queryIndex, item.transaction);
}
return categoriedDataMap;
});
@@ -1523,6 +1874,7 @@ export const useExplorersStore = defineStore('explorers', () => {
currentInsightsExplorer,
insightsExplorerListStateInvalid,
// computed
isUsingAmountRange,
filteredTransactionsInDataTable,
filteredTransactionsInDataTableStatistic,
categoriedTransactionExplorerData,
@@ -46,6 +46,18 @@
</v-list-item>
</template>
</v-select>
<v-select
class="flex-0-0"
min-width="220"
item-title="name"
item-value="value"
density="compact"
:disabled="loading || disabled"
:label="tt('Number of Amount Ranges')"
:items="allAmountRangeCounts"
v-model="currentExplorer.amountRangeCount"
v-if="isUsingAmountRange"
/>
<v-select
class="flex-0-0"
min-width="150"
@@ -211,7 +223,7 @@ import {
useExplorersStore
} from '@/stores/explorer.ts';
import { type NameValue, type TypeAndDisplayName, itemAndIndex, entries } from '@/core/base.ts';
import { type NameValue, type NameNumeralValue, type TypeAndDisplayName, itemAndIndex, entries } from '@/core/base.ts';
import { NumeralSystem } from '@/core/numeral.ts';
import { Month, WeekDay } from '@/core/datetime.ts';
import { ChartSortingType, ExportMermaidChartType } from '@/core/statistics.ts';
@@ -274,6 +286,7 @@ const {
getMonthdayShortName,
getWeekdayLongName,
getQuarterName,
getCurrentNumeralSystemType,
getCurrencyName,
formatDateTimeToShortDateTime,
formatDateTimeToShortDate,
@@ -292,6 +305,7 @@ const explorersStore = useExplorersStore();
const axisChart = useTemplateRef<AxisChartType>('axisChart');
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
const allTransactionExplorerDataDimensions = computed<NameValue[]>(() => getAllTransactionExplorerDataDimensions());
@@ -301,6 +315,17 @@ const allTransactionExplorerChartSortingTypes = computed<TypeAndDisplayName[]>((
const currentTransactionExplorerCategoryDimensionName = computed<string>(() => findNameByValue(allTransactionExplorerDataDimensions.value, currentExplorer.value.categoryDimension) ?? tt('Unknown'));
const currentExplorer = computed<InsightsExplorer>(() => explorersStore.currentInsightsExplorer);
const isUsingAmountRange = computed<boolean>(() => explorersStore.isUsingAmountRange);
const allAmountRangeCounts = computed<NameNumeralValue[]>(() => {
const pageCounts: NameNumeralValue[] = [];
for (let i = 3; i <= 20; i++) {
pageCounts.push({ value: i, name: numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(i.toString()) });
}
return pageCounts;
});
const categoryDimensionTransactionExplorerData = computed<CategoryDimensionData[]>(() => {
if (currentExplorer.value.chartType !== TransactionExplorerChartType.Pie.value && currentExplorer.value.chartType !== TransactionExplorerChartType.Radar.value) {
@@ -573,22 +598,23 @@ function getCategoriedDataDisplayName(info: CategoriedInfo | SeriesInfo): string
let needI18n: boolean | undefined = false;
let i18nParameters: Record<string, unknown> | undefined = undefined;
let dimessionType: TransactionExplorerDimensionType = TransactionExplorerDimensionType.Other;
let dimession: TransactionExplorerDataDimensionType = TransactionExplorerDataDimension.None.value;
let dimessionValue: TransactionExplorerDataDimensionType = TransactionExplorerDataDimension.None.value;
if ('categoryName' in info) {
name = info.categoryName;
needI18n = info.categoryNameNeedI18n;
i18nParameters = info.categoryNameI18nParameters;
dimessionType = info.categoryIdType;
dimession = currentExplorer.value.categoryDimension;
dimessionValue = currentExplorer.value.categoryDimension;
} else if ('seriesName' in info) {
name = info.seriesName;
needI18n = info.seriesNameNeedI18n;
i18nParameters = info.seriesNameI18nParameters;
dimessionType = info.seriesIdType;
dimession = currentExplorer.value.seriesDimension;
dimessionValue = currentExplorer.value.seriesDimension;
}
const dimession = TransactionExplorerDataDimension.valueOf(dimessionValue);
let displayName: string = name;
// convert the name to i18n if needed
@@ -599,38 +625,38 @@ function getCategoriedDataDisplayName(info: CategoriedInfo | SeriesInfo): string
}
// convert the name to formatted date time if needed
if (dimession === TransactionExplorerDataDimension.DateTime.value) {
if (dimession === TransactionExplorerDataDimension.DateTime) {
const dateTime = parseDateTimeFromString(name, dimessionType);
displayName = dateTime ? formatDateTimeToShortDateTime(dateTime) : tt('Unknown');
} else if (dimession === TransactionExplorerDataDimension.DateTimeByYearMonthDay.value) {
} else if (dimession === TransactionExplorerDataDimension.DateTimeByYearMonthDay) {
const dateTime = parseDateTimeFromString(name, dimessionType);
displayName = dateTime ? formatDateTimeToShortDate(dateTime) : tt('Unknown');
} else if (dimession === TransactionExplorerDataDimension.DateTimeByYearMonth.value) {
} else if (dimession === TransactionExplorerDataDimension.DateTimeByYearMonth) {
const dateTime = parseDateTimeFromString(name, dimessionType);
displayName = dateTime ? formatDateTimeToGregorianLikeShortYearMonth(dateTime) : tt('Unknown');
} else if (dimession === TransactionExplorerDataDimension.DateTimeByYearQuarter.value) {
} else if (dimession === TransactionExplorerDataDimension.DateTimeByYearQuarter) {
const parts = name.split('-');
const year = parts.length === 2 ? parts[0] : '';
const quarter = parts.length === 2 ? parseInt(parts[1] as string) : 0;
const quarterLastMonth = quarter * 3;
const dateTime = year && quarterLastMonth ? parseDateTimeFromString(`${year}-${quarterLastMonth.toString(10).padStart(2, NumeralSystem.WesternArabicNumerals.digitZero)}`, TransactionExplorerDimensionType.YearMonth) : undefined;
displayName = dateTime ? formatDateTimeToGregorianLikeYearQuarter(dateTime) : tt('Unknown');
} else if (dimession === TransactionExplorerDataDimension.DateTimeByYear.value) {
} else if (dimession === TransactionExplorerDataDimension.DateTimeByYear) {
const dateTime = parseDateTimeFromString(name, dimessionType);
displayName = dateTime ? formatDateTimeToGregorianLikeShortYear(dateTime) : tt('Unknown');
} else if (dimession === TransactionExplorerDataDimension.DateTimeByFiscalYear.value) {
} else if (dimession === TransactionExplorerDataDimension.DateTimeByFiscalYear) {
displayName = formatGregorianYearToGregorianLikeFiscalYear(parseInt(name));
} else if (dimession === TransactionExplorerDataDimension.DateTimeByDayOfWeek.value) {
} else if (dimession === TransactionExplorerDataDimension.DateTimeByDayOfWeek) {
const weekDay = WeekDay.parse(name);
displayName = weekDay ? getWeekdayLongName(weekDay) : tt('Unknown');
} else if (dimession === TransactionExplorerDataDimension.DateTimeByDayOfMonth.value) {
} else if (dimession === TransactionExplorerDataDimension.DateTimeByDayOfMonth) {
displayName = getMonthdayShortName(parseInt(name));
} else if (dimession === TransactionExplorerDataDimension.DateTimeByMonthOfYear.value) {
} else if (dimession === TransactionExplorerDataDimension.DateTimeByMonthOfYear) {
const month = Month.valueOf(parseInt(name));
displayName = month ? getMonthLongName(month.name) : tt('Unknown');
} else if (dimession === TransactionExplorerDataDimension.DateTimeByQuarterOfYear.value) {
} else if (dimession === TransactionExplorerDataDimension.DateTimeByQuarterOfYear) {
displayName = getQuarterName(parseInt(name));
} else if (dimession === TransactionExplorerDataDimension.DateTimeByHourOfDay.value) {
} else if (dimession === TransactionExplorerDataDimension.DateTimeByHourOfDay) {
const dateTime = getCurrentDateTime().set({
hour: parseInt(name),
minute: 0,
@@ -638,19 +664,29 @@ function getCategoriedDataDisplayName(info: CategoriedInfo | SeriesInfo): string
millisecond: 0
});
displayName = formatDateTimeToShortTime(dateTime);
} else if (dimession === TransactionExplorerDataDimension.SourceAccountCurrency.value || dimession === TransactionExplorerDataDimension.DestinationAccountCurrency.value) {
} else if (dimession === TransactionExplorerDataDimension.SourceAccountCurrency || dimession === TransactionExplorerDataDimension.DestinationAccountCurrency) {
if (!needI18n) {
displayName = getCurrencyName(name);
}
}
if (dimession === TransactionExplorerDataDimension.SourceAmount.value
|| dimession === TransactionExplorerDataDimension.DestinationAmount.value) {
if (dimession === TransactionExplorerDataDimension.SourceAmount
|| dimession === TransactionExplorerDataDimension.DestinationAmount) {
if (name !== '' && name !== 'none' && Number.isFinite(parseInt(name))) {
displayName = formatAmountToLocalizedNumerals(parseInt(name), defaultCurrency.value);
}
}
if (dimession?.isSourceAmountRange || dimession?.isDestinationAmountRange) {
const rangeParts = name.split('|');
if (rangeParts && rangeParts.length === 2 && Number.isFinite(parseInt(rangeParts[0] as string)) && Number.isFinite(parseInt(rangeParts[1] as string))) {
const from = formatAmountToLocalizedNumerals(parseInt(rangeParts[0] as string), defaultCurrency.value);
const to = formatAmountToLocalizedNumerals(parseInt(rangeParts[1] as string), defaultCurrency.value);
displayName = `${from} ~ ${to}`;
}
}
return displayName;
}