mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-14 06:57:35 +08:00
support filtering transactions by time zone minute offset, day of week, day of month, month of year and transaction hour in insights explorer
This commit is contained in:
@@ -600,3 +600,6 @@ export const ALL_TIMEZONES: TimezoneInfo[] = [
|
||||
timezoneName: 'Pacific/Kiritimati'
|
||||
}
|
||||
];
|
||||
|
||||
export const WESTERNMOST_TIMEZONE_UTC_OFFSET: number = -720; // Etc/GMT+12 (UTC-12:00)
|
||||
export const EASTERNMOST_TIMEZONE_UTC_OFFSET: number = 840; // Pacific/Kiritimati (UTC+14:00)
|
||||
|
||||
@@ -31,6 +31,7 @@ export interface DateTime {
|
||||
isLocalizedCalendarFirstDayOfMonth(options: DateTimeFormatOptions): boolean;
|
||||
getGregorianCalendarYearDashMonthDashDay(): TextualYearMonthDay;
|
||||
getGregorianCalendarYearDashMonth(): TextualYearMonth;
|
||||
getMaxDayOfGregorianCalendarMonth(): number;
|
||||
getWeekDay(): WeekDay;
|
||||
getWeekDayDisplayName(options: DateTimeFormatOptions): string
|
||||
getWeekDayDisplayShortName(options: DateTimeFormatOptions): string;
|
||||
|
||||
@@ -25,6 +25,11 @@ export const TransactionExplorerConditionRelationPriority: Record<TransactionExp
|
||||
|
||||
export enum TransactionExplorerConditionFieldType {
|
||||
Undefined = 'undefined',
|
||||
TransactionTimeDayOfWeek = 'transactionTimeDayOfWeek',
|
||||
TransactionTimeDayOfMonth = 'transactionTimeDayOfMonth',
|
||||
TransactionTimeMonthOfYear = 'transactionTimeMonthOfYear',
|
||||
TransactionTimeHourOfDay = 'transactionTimeHourOfDay',
|
||||
TransactionTimezone = 'transactionTimezone',
|
||||
TransactionType = 'transactionType',
|
||||
TransactionCategory = 'transactionCategory',
|
||||
SourceAccount = 'sourceAccount',
|
||||
@@ -41,6 +46,11 @@ export class TransactionExplorerConditionField implements NameValue {
|
||||
private static readonly allInstances: TransactionExplorerConditionField[] = [];
|
||||
private static readonly allInstancesByValue: Record<string, TransactionExplorerConditionField> = {};
|
||||
|
||||
public static readonly TransactionTimeDayOfWeek = new TransactionExplorerConditionField('Transaction Day of Week', TransactionExplorerConditionFieldType.TransactionTimeDayOfWeek);
|
||||
public static readonly TransactionTimeDayOfMonth = new TransactionExplorerConditionField('Transaction Day of Month', TransactionExplorerConditionFieldType.TransactionTimeDayOfMonth)
|
||||
public static readonly TransactionTimeMonthOfYear = new TransactionExplorerConditionField('Transaction Month of Year', TransactionExplorerConditionFieldType.TransactionTimeMonthOfYear);
|
||||
public static readonly TransactionTimeHourOfDay = new TransactionExplorerConditionField('Transaction Hour of Day', TransactionExplorerConditionFieldType.TransactionTimeHourOfDay);
|
||||
public static readonly TransactionTimezone = new TransactionExplorerConditionField('Transaction Timezone', TransactionExplorerConditionFieldType.TransactionTimezone);
|
||||
public static readonly TransactionType = new TransactionExplorerConditionField('Transaction Type', TransactionExplorerConditionFieldType.TransactionType);
|
||||
public static readonly TransactionCategory = new TransactionExplorerConditionField('Category', TransactionExplorerConditionFieldType.TransactionCategory);
|
||||
public static readonly SourceAccount = new TransactionExplorerConditionField('Source Account', TransactionExplorerConditionFieldType.SourceAccount);
|
||||
@@ -95,6 +105,8 @@ export enum TransactionExplorerConditionOperatorType {
|
||||
NotEndsWith = 'notEndsWith',
|
||||
RegexMatch = 'regexMatch',
|
||||
NotRegexMatch = 'notRegexMatch',
|
||||
MinuteOffsetBetween = 'minuteOffsetBetween',
|
||||
MinuteOffsetNotBetween = 'minuteOffsetNotBetween',
|
||||
LatitudeBetween = 'latitudeBetween',
|
||||
LatitudeNotBetween = 'latitudeNotBetween',
|
||||
LongitudeBetween = 'longitudeBetween',
|
||||
@@ -127,6 +139,8 @@ export class TransactionExplorerConditionOperator implements NameValue {
|
||||
public static readonly NotEndsWith = new TransactionExplorerConditionOperator('Does not end with', TransactionExplorerConditionOperatorType.NotEndsWith);
|
||||
public static readonly RegexMatch = new TransactionExplorerConditionOperator('Matches regex', TransactionExplorerConditionOperatorType.RegexMatch);
|
||||
public static readonly NotRegexMatch = new TransactionExplorerConditionOperator('Does not match regex', TransactionExplorerConditionOperatorType.NotRegexMatch);
|
||||
public static readonly MinuteOffsetBetween = new TransactionExplorerConditionOperator('Minute offset is between', TransactionExplorerConditionOperatorType.MinuteOffsetBetween);
|
||||
public static readonly MinuteOffsetNotBetween = new TransactionExplorerConditionOperator('Minute offset is not between', TransactionExplorerConditionOperatorType.MinuteOffsetNotBetween);
|
||||
public static readonly LatitudeBetween = new TransactionExplorerConditionOperator('Latitude is between', TransactionExplorerConditionOperatorType.LatitudeBetween);
|
||||
public static readonly LatitudeNotBetween = new TransactionExplorerConditionOperator('Latitude is not between', TransactionExplorerConditionOperatorType.LatitudeNotBetween);
|
||||
public static readonly LongitudeBetween = new TransactionExplorerConditionOperator('Longitude is between', TransactionExplorerConditionOperatorType.LongitudeBetween);
|
||||
|
||||
+10
-4
@@ -51,6 +51,11 @@ import {
|
||||
NumeralSystem
|
||||
} from '@/core/numeral.ts';
|
||||
|
||||
import {
|
||||
WESTERNMOST_TIMEZONE_UTC_OFFSET,
|
||||
EASTERNMOST_TIMEZONE_UTC_OFFSET,
|
||||
} from '@/consts/timezone.ts';
|
||||
|
||||
import {
|
||||
isFunction,
|
||||
isDefined,
|
||||
@@ -74,15 +79,12 @@ interface DateTimeFormatResult {
|
||||
|
||||
type DateTimeTokenFormatFunction = (d: MomentDateTime, options: DateTimeFormatOptions) => DateTimeFormatResult;
|
||||
|
||||
const westernmostTimezoneUtcOffset: number = -720; // Etc/GMT+12 (UTC-12:00)
|
||||
const easternmostTimezoneUtcOffset: number = 840; // Pacific/Kiritimati (UTC+14:00)
|
||||
|
||||
function getFixedTimezoneName(utcOffset: number): string {
|
||||
return `Fixed/Timezone${utcOffset}`;
|
||||
}
|
||||
|
||||
(function initFixedTimezone(): void {
|
||||
for (let utcOffset = westernmostTimezoneUtcOffset; utcOffset <= easternmostTimezoneUtcOffset; utcOffset += 15) {
|
||||
for (let utcOffset = WESTERNMOST_TIMEZONE_UTC_OFFSET; utcOffset <= EASTERNMOST_TIMEZONE_UTC_OFFSET; utcOffset += 15) {
|
||||
const timezoneName = getFixedTimezoneName(utcOffset);
|
||||
|
||||
if (moment.tz.zone(timezoneName)) {
|
||||
@@ -254,6 +256,10 @@ class MomentDateTime implements DateTime {
|
||||
return (this.instance.year() + '-' + (this.instance.month() + 1).toString().padStart(2, NumeralSystem.WesternArabicNumerals.digitZero)) as TextualYearMonth;
|
||||
}
|
||||
|
||||
public getMaxDayOfGregorianCalendarMonth(): number {
|
||||
return this.instance.clone().endOf('month').date();
|
||||
}
|
||||
|
||||
public getWeekDay(): WeekDay {
|
||||
return WeekDay.valueOf(this.instance.day()) as WeekDay;
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "{hours} Stunde(n) und {minutes} Minute(n) hinter der Standardzeitzone",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "{hours} Stunde(n) und {minutes} Minute(n) vor der Standardzeitzone",
|
||||
"monthDay": "{ordinal} Tag",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} Tage",
|
||||
"everyMultiDaysOfWeek": "Jeden {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "Letzte 5 Jahre",
|
||||
"Previous Billing Cycle": "Vorheriger Abrechnungszeitraum",
|
||||
"Current Billing Cycle": "Aktueller Abrechnungszeitraum",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "Benutzerdefiniertes Datum",
|
||||
"Start Date": "Startdatum",
|
||||
"End Date": "Enddatum",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Endet nicht mit",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Breitengrad zwischen",
|
||||
"Latitude is not between": "Breitengrad nicht zwischen",
|
||||
"Longitude is between": "Längengrad zwischen",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "{hours} hour(s) and {minutes} minutes behind default timezone",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "{hours} hour(s) and {minutes} minutes ahead of default timezone",
|
||||
"monthDay": "{ordinal} day",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} days",
|
||||
"everyMultiDaysOfWeek": "Every {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "Recent 5 years",
|
||||
"Previous Billing Cycle": "Previous Billing Cycle",
|
||||
"Current Billing Cycle": "Current Billing Cycle",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "Custom Date",
|
||||
"Start Date": "Start Date",
|
||||
"End Date": "End Date",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "{hours} hora(s) y {minutes} minutos de retraso en la zona horaria predeterminada",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "{hours} hora(s) y {minutes} minutos antes de la zona horaria predeterminada",
|
||||
"monthDay": "día {ordinal}",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} días",
|
||||
"everyMultiDaysOfWeek": "Cada {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "Últimos 5 años",
|
||||
"Previous Billing Cycle": "Ciclo de facturación anterior",
|
||||
"Current Billing Cycle": "Ciclo de facturación actual",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "Fecha personalizada",
|
||||
"Start Date": "Fecha de Inicio",
|
||||
"End Date": "Fecha de Finalización",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "No termina en",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "{hours} heure(s) et {minutes} minutes de retard sur le fuseau horaire par défaut",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "{hours} heure(s) et {minutes} minutes d'avance sur le fuseau horaire par défaut",
|
||||
"monthDay": "{ordinal}e jour",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} jours",
|
||||
"everyMultiDaysOfWeek": "Tous les {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "5 dernières années",
|
||||
"Previous Billing Cycle": "Cycle de facturation précédent",
|
||||
"Current Billing Cycle": "Cycle de facturation actuel",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "Date personnalisée",
|
||||
"Start Date": "Date de début",
|
||||
"End Date": "Date de fin",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -195,6 +195,7 @@ import {
|
||||
} from '@/lib/common.ts';
|
||||
|
||||
import {
|
||||
getCurrentDateTime,
|
||||
formatCurrentTime,
|
||||
formatGregorianCalendarYearDashMonthDashDay,
|
||||
formatGregorianCalendarMonthDashDay,
|
||||
@@ -1059,6 +1060,20 @@ export function useI18n() {
|
||||
return getAllWeekdayNames('min');
|
||||
}
|
||||
|
||||
function getAllMonths(): TypeAndDisplayName[] {
|
||||
const ret: TypeAndDisplayName[] = [];
|
||||
const allMonths = Month.values();
|
||||
|
||||
for (const month of allMonths) {
|
||||
ret.push({
|
||||
type: month.month,
|
||||
displayName: t(`datetime.${month.name}.long`)
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getAllWeekDays(firstDayOfWeek?: WeekDayValue): TypeAndDisplayName[] {
|
||||
const ret: TypeAndDisplayName[] = [];
|
||||
const allWeekDays = WeekDay.values();
|
||||
@@ -1088,6 +1103,51 @@ export function useI18n() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getAllHours(): TypeAndDisplayName[] {
|
||||
const ret: TypeAndDisplayName[] = [];
|
||||
const now: DateTime = getCurrentDateTime();
|
||||
const format: string = getLocalizedShortTimeFormat();
|
||||
const options: DateTimeFormatOptions = getDateTimeFormatOptions();
|
||||
|
||||
for (let i = 0; i < 24; i++) {
|
||||
const dateTime = now.set({
|
||||
hour: i,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
millisecond: 0
|
||||
});
|
||||
|
||||
ret.push({
|
||||
type: i,
|
||||
displayName: dateTime.format(format, options)
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getAvailableMonthDays(daysInMonth: number, lastDaysOfMonth?: number): TypeAndDisplayName[] {
|
||||
const ret: TypeAndDisplayName[] = [];
|
||||
|
||||
for (let i = 1; i <= daysInMonth; i++) {
|
||||
ret.push({
|
||||
type: i,
|
||||
displayName: getMonthdayShortName(i),
|
||||
});
|
||||
}
|
||||
|
||||
if (isNumber(lastDaysOfMonth) && lastDaysOfMonth > 0) {
|
||||
for (let i = -lastDaysOfMonth; i < 0; i++) {
|
||||
ret.push({
|
||||
type: i,
|
||||
displayName: (i === -1) ? t('Last day') : getMonthLastDayShortName(-i),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getLocalizedDateTimeFormats<T extends DateFormat | TimeFormat>(type: string, allFormatMap: Record<string, T>, allFormatArray: T[], languageDefaultTypeNameKey: string, systemDefaultFormatType: T, numeralSystem: NumeralSystem, calendarType?: CalendarType): LocalizedDateTimeFormat[] {
|
||||
const defaultFormat = getLocalizedDateTimeFormat<T>(type, allFormatMap, allFormatArray, LANGUAGE_DEFAULT_DATE_TIME_FORMAT_VALUE, languageDefaultTypeNameKey, systemDefaultFormatType);
|
||||
const ret: LocalizedDateTimeFormat[] = [];
|
||||
@@ -1606,6 +1666,12 @@ export function useI18n() {
|
||||
});
|
||||
}
|
||||
|
||||
function getMonthLastDayShortName(ordinal: number): string {
|
||||
return t('format.misc.lastMonthDay', {
|
||||
ordinal: getMonthdayOrdinal(ordinal)
|
||||
});
|
||||
}
|
||||
|
||||
function getWeekdayShortName(weekDay: WeekDay): string {
|
||||
return t(`datetime.${weekDay.name}.short`);
|
||||
}
|
||||
@@ -2411,7 +2477,10 @@ export function useI18n() {
|
||||
getAllLongWeekdayNames,
|
||||
getAllShortWeekdayNames,
|
||||
getAllMinWeekdayNames,
|
||||
getAllMonths,
|
||||
getAllWeekDays,
|
||||
getAllHours,
|
||||
getAvailableMonthDays,
|
||||
getAllCalendarDisplayTypes: () => getAllLocalizedCalendarTypes(CalendarDisplayType.values(), CalendarDisplayType.parse(t('default.calendarDisplayType')), CalendarDisplayType.Default, CalendarDisplayType.LanguageDefaultType),
|
||||
getAllDateDisplayTypes: () => getAllLocalizedCalendarTypes(DateDisplayType.values(), DateDisplayType.parse(t('default.dateDisplayType')), DateDisplayType.Default, DateDisplayType.LanguageDefaultType),
|
||||
getAllLongDateFormats: (numeralSystem: NumeralSystem, calendarType: CalendarType) => getLocalizedDateTimeFormats<LongDateFormat>('longDate', LongDateFormat.all(), LongDateFormat.values(), 'longDateFormat', LongDateFormat.Default, numeralSystem, calendarType),
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "Indietro di {hours} ore e {minutes} minuti rispetto al fuso orario standard",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "Avanti di {hours} ore e {minutes} minuti rispetto al fuso orario standard",
|
||||
"monthDay": "{ordinal} giorno",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} giorni",
|
||||
"everyMultiDaysOfWeek": "Ogni {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "Ultimi 5 anni",
|
||||
"Previous Billing Cycle": "Ciclo di fatturazione precedente",
|
||||
"Current Billing Cycle": "Ciclo di fatturazione corrente",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "Data personalizzata",
|
||||
"Start Date": "Data di inizio",
|
||||
"End Date": "Data di fine",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "デフォルトのタイムゾーンより{hours}時間{minutes}分遅れています",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "デフォルトのタイムゾーンから{hours}時間{minutes}分進んでいます",
|
||||
"monthDay": "{ordinal}日",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays}日間",
|
||||
"everyMultiDaysOfWeek": "毎{days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "直近5年",
|
||||
"Previous Billing Cycle": "以前の請求サイクル",
|
||||
"Current Billing Cycle": "現在の請求サイクル",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "カスタム日付",
|
||||
"Start Date": "開始日",
|
||||
"End Date": "終了日",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "ಡೀಫಾಲ್ಟ್ ಸಮಯ ವಲಯಕ್ಕಿಂತ {hours} ಗಂಟೆ ಹಾಗೂ {minutes} ನಿಮಿಷಗಳು ಹಿಂದೆ",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "ಡೀಫಾಲ್ಟ್ ಸಮಯ ವಲಯಕ್ಕಿಂತ {hours} ಗಂಟೆ ಹಾಗೂ {minutes} ನಿಮಿಷಗಳು ಮುಂದೆ",
|
||||
"monthDay": "{ordinal} ದಿನ",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} ದಿನಗಳು",
|
||||
"everyMultiDaysOfWeek": "ಪ್ರತಿ {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "ಇತ್ತೀಚಿನ 5 ವರ್ಷಗಳು",
|
||||
"Previous Billing Cycle": "ಹಿಂದಿನ ಬಿಲ್ಲಿಂಗ್ ಚಕ್ರ",
|
||||
"Current Billing Cycle": "ಪ್ರಸ್ತುತ ಬಿಲ್ಲಿಂಗ್ ಚಕ್ರ",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "ಕಸ್ಟಮ್ ದಿನಾಂಕ",
|
||||
"Start Date": "ಪ್ರಾರಂಭ ದಿನಾಂಕ",
|
||||
"End Date": "ಅಂತ್ಯ ದಿನಾಂಕ",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "기본 시간대보다 {hours}시간 {minutes}분 느립니다",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "기본 시간대보다 {hours}시간 {minutes}분 빠릅니다",
|
||||
"monthDay": "{ordinal}일",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays}일",
|
||||
"everyMultiDaysOfWeek": "매주 {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "최근 5년",
|
||||
"Previous Billing Cycle": "이전 청구 주기",
|
||||
"Current Billing Cycle": "현재 청구 주기",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "사용자 지정 날짜",
|
||||
"Start Date": "시작 날짜",
|
||||
"End Date": "종료 날짜",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "{hours} uur en {minutes} minuten achter standaardtijdzone",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "{hours} uur en {minutes} minuten voor op standaardtijdzone",
|
||||
"monthDay": "{ordinal} dag",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} dagen",
|
||||
"everyMultiDaysOfWeek": "Elke {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "Afgelopen 5 jaar",
|
||||
"Previous Billing Cycle": "Vorige factureringsperiode",
|
||||
"Current Billing Cycle": "Huidige factureringsperiode",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "Aangepaste datum",
|
||||
"Start Date": "Begindatum",
|
||||
"End Date": "Einddatum",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "{hours} hora(s) e {minutes} minutos atrás do fuso horário padrão",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "{hours} hora(s) e {minutes} minutos à frente do fuso horário padrão",
|
||||
"monthDay": "{ordinal} dia",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} dias",
|
||||
"everyMultiDaysOfWeek": "A cada {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "Últimos 5 anos",
|
||||
"Previous Billing Cycle": "Ciclo de Cobrança Anterior",
|
||||
"Current Billing Cycle": "Ciclo de Cobrança Atual",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "Data Personalizada",
|
||||
"Start Date": "Data de Início",
|
||||
"End Date": "Data de Término",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Não termina com",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude entre",
|
||||
"Latitude is not between": "Latitude não entre",
|
||||
"Longitude is between": "Longitude entre",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "{hours} час(ов) и {minutes} минут позади часового пояса по умолчанию",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "{hours} час(ов) и {minutes} минут впереди часового пояса по умолчанию",
|
||||
"monthDay": "{ordinal} день",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} дней",
|
||||
"everyMultiDaysOfWeek": "Каждые {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "Последние 5 лет",
|
||||
"Previous Billing Cycle": "Предыдущий расчетный период",
|
||||
"Current Billing Cycle": "Текущий расчетный период",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "Выбрать дату",
|
||||
"Start Date": "Дата начала",
|
||||
"End Date": "Дата конца",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Не заканчивается с",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "{hours} ura(ur) in {minutes} minut za privzetim časovnim pasom",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "{hours} ura(ur) in {minutes} minut po privzetem časovnem pasu",
|
||||
"monthDay": "{ordinal} dan",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} dni",
|
||||
"everyMultiDaysOfWeek": "Vsak {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "Zadnjih 5 let",
|
||||
"Previous Billing Cycle": "Prejšnje obračunsko obdobje",
|
||||
"Current Billing Cycle": "Trenutno obračunsko obdobje",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "Datum po meri",
|
||||
"Start Date": "Datum začetka",
|
||||
"End Date": "Datum konca",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Se ne konča z",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "இயல்பு நேர மண்டலத்தை விட {hours} மணி நேரம் {minutes} நிமிடங்கள் பின்னால்",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "இயல்பு நேர மண்டலத்தை விட {hours} மணி நேரம் {minutes} நிமிடங்கள் முன்னால்",
|
||||
"monthDay": "{ordinal} நாள்",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} நாட்கள்",
|
||||
"everyMultiDaysOfWeek": "ஒவ்வொரு {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "சமீபத்திய 5 ஆண்டுகள்",
|
||||
"Previous Billing Cycle": "முந்தைய பில்லிங் சுழற்சி",
|
||||
"Current Billing Cycle": "தற்போதைய பில்லிங் சுழற்சி",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "தனிப்பயன் தேதி",
|
||||
"Start Date": "தொடக்கம் தேதி",
|
||||
"End Date": "முடிவு தேதி",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "முடியவில்லை",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "ช้ากว่าเขตเวลาเริ่มต้น {hours} ชั่วโมง {minutes} นาที",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "เร็วกว่าเขตเวลาเริ่มต้น {hours} ชั่วโมง {minutes} นาที",
|
||||
"monthDay": "วันที่ {ordinal}",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} วัน",
|
||||
"everyMultiDaysOfWeek": "ทุกๆ {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "5 ปีที่ผ่านมา",
|
||||
"Previous Billing Cycle": "รอบบิลก่อนหน้า",
|
||||
"Current Billing Cycle": "รอบบิลปัจจุบัน",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "วันที่กำหนดเอง",
|
||||
"Start Date": "วันที่เริ่มต้น",
|
||||
"End Date": "วันที่สิ้นสุด",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "Varsayılan saat diliminin {hours} saat {minutes} dakika gerisinde",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "Varsayılan saat diliminin {hours} saat {minutes} dakika ilerisinde",
|
||||
"monthDay": "{ordinal} gün",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} gün",
|
||||
"everyMultiDaysOfWeek": "Her {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "Son 5 yıl",
|
||||
"Previous Billing Cycle": "Önceki Fatura Dönemi",
|
||||
"Current Billing Cycle": "Mevcut Fatura Dönemi",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "Özel Tarih",
|
||||
"Start Date": "Başlangıç Tarihi",
|
||||
"End Date": "Bitiş Tarihi",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "{hours} год і {minutes} хв позаду часового поясу за замовчуванням",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "{hours} год і {minutes} хв попереду часового поясу за замовчуванням",
|
||||
"monthDay": "{ordinal} день",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} днів",
|
||||
"everyMultiDaysOfWeek": "Кожні {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "Останні 5 років",
|
||||
"Previous Billing Cycle": "Попередній розрахунковий період",
|
||||
"Current Billing Cycle": "Поточний розрахунковий період",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "Обрати дату",
|
||||
"Start Date": "Дата початку",
|
||||
"End Date": "Дата завершення",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "{hours} giờ và {minutes} phút sau múi giờ mặc định",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "{hours} giờ và {minutes} phút trước múi giờ mặc định",
|
||||
"monthDay": "Ngày {ordinal}",
|
||||
"lastMonthDay": "Last {ordinal} day",
|
||||
"eachMonthDayInMonthDays": "{ordinal}",
|
||||
"monthDays": "{multiMonthDays} ngày",
|
||||
"everyMultiDaysOfWeek": "Mỗi {days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "5 năm gần đây",
|
||||
"Previous Billing Cycle": "Previous Billing Cycle",
|
||||
"Current Billing Cycle": "Current Billing Cycle",
|
||||
"Last day": "Last day",
|
||||
"Custom Date": "Ngày tùy chỉnh",
|
||||
"Start Date": "Start Date",
|
||||
"End Date": "End Date",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "Does not end with",
|
||||
"Matches regex": "Matches regex",
|
||||
"Does not match regex": "Does not match regex",
|
||||
"Minute offset is between": "Minute offset is between",
|
||||
"Minute offset is not between": "Minute offset is not between",
|
||||
"Latitude is between": "Latitude is between",
|
||||
"Latitude is not between": "Latitude is not between",
|
||||
"Longitude is between": "Longitude is between",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "比默认时区晚{hours}小时{minutes}分",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "比默认时区早{hours}小时{minutes}分",
|
||||
"monthDay": "{ordinal}日",
|
||||
"lastMonthDay": "倒数第{ordinal}日",
|
||||
"eachMonthDayInMonthDays": "{ordinal}日",
|
||||
"monthDays": "{multiMonthDays}",
|
||||
"everyMultiDaysOfWeek": "每{days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "最近5年",
|
||||
"Previous Billing Cycle": "上个账单周期",
|
||||
"Current Billing Cycle": "当前账单周期",
|
||||
"Last day": "倒数第1日",
|
||||
"Custom Date": "自定义日期",
|
||||
"Start Date": "开始日期",
|
||||
"End Date": "结束日期",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "结尾不是",
|
||||
"Matches regex": "正则匹配",
|
||||
"Does not match regex": "不匹配正则",
|
||||
"Minute offset is between": "分钟偏移量介于",
|
||||
"Minute offset is not between": "分钟偏移量不介于",
|
||||
"Latitude is between": "纬度介于",
|
||||
"Latitude is not between": "纬度不介于",
|
||||
"Longitude is between": "经度介于",
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"hoursMinutesBehindDefaultTimezone": "比預設時區晚{hours}小時{minutes}分",
|
||||
"hoursMinutesAheadOfDefaultTimezone": "比預設時區早{hours}小時{minutes}分",
|
||||
"monthDay": "{ordinal}日",
|
||||
"lastMonthDay": "倒數第{ordinal}日",
|
||||
"eachMonthDayInMonthDays": "{ordinal}日",
|
||||
"monthDays": "{multiMonthDays}",
|
||||
"everyMultiDaysOfWeek": "每{days}",
|
||||
@@ -1540,6 +1541,7 @@
|
||||
"Recent 5 years": "最近5年",
|
||||
"Previous Billing Cycle": "上個帳單週期",
|
||||
"Current Billing Cycle": "當前帳單週期",
|
||||
"Last day": "倒數第1日",
|
||||
"Custom Date": "自訂日期",
|
||||
"Start Date": "開始日期",
|
||||
"End Date": "結束日期",
|
||||
@@ -1573,6 +1575,8 @@
|
||||
"Does not end with": "結尾不是",
|
||||
"Matches regex": "正則匹配",
|
||||
"Does not match regex": "不匹配正則",
|
||||
"Minute offset is between": "分钟偏移量介於",
|
||||
"Minute offset is not between": "分钟偏移量不介於",
|
||||
"Latitude is between": "緯度介於",
|
||||
"Latitude is not between": "緯度不介於",
|
||||
"Longitude is between": "經度介於",
|
||||
|
||||
+290
-3
@@ -1,4 +1,5 @@
|
||||
import { type PartialRecord, itemAndIndex, keysIfValueEquals } from '@/core/base.ts';
|
||||
import { type DateTime } from '@/core/datetime.ts';
|
||||
import { TimezoneTypeForStatistics } from '@/core/timezone.ts';
|
||||
import { AccountType } from '@/core/account.ts';
|
||||
import { TransactionType } from '@/core/transaction.ts';
|
||||
@@ -300,6 +301,21 @@ export class TransactionExplorerQuery {
|
||||
let condition: TransactionExplorerCondition;
|
||||
|
||||
switch (field) {
|
||||
case TransactionExplorerConditionField.TransactionTimeDayOfWeek:
|
||||
condition = new TransactionExplorerTransactionTimeDayOfWeekCondition(TransactionExplorerConditionOperatorType.In, []);
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionTimeDayOfMonth:
|
||||
condition = new TransactionExplorerTransactionTimeDayOfMonthCondition(TransactionExplorerConditionOperatorType.In, []);
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionTimeMonthOfYear:
|
||||
condition = new TransactionExplorerTransactionTimeMonthOfYearCondition(TransactionExplorerConditionOperatorType.In, []);
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionTimeHourOfDay:
|
||||
condition = new TransactionExplorerTransactionTimeHourOfDayCondition(TransactionExplorerConditionOperatorType.In, []);
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionTimezone:
|
||||
condition = new TransactionExplorerTransactionTimezoneCondition(TransactionExplorerConditionOperatorType.MinuteOffsetBetween, [ 0, 0 ]);
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionType:
|
||||
condition = new TransactionExplorerTransactionTypeCondition(TransactionExplorerConditionOperatorType.In, [ TransactionType.Expense, TransactionType.Income, TransactionType.Transfer ]);
|
||||
break;
|
||||
@@ -345,7 +361,7 @@ export class TransactionExplorerQuery {
|
||||
return new TransactionExplorerConditionWithRelation(new TransactionExplorerUndefinedCondition(), TransactionExplorerConditionRelation.SubEnd);
|
||||
}
|
||||
|
||||
public match(transaction: TransactionInsightDataItem): boolean {
|
||||
public match(transaction: TransactionInsightDataItem, context: InsightsExplorerMatchContext): boolean {
|
||||
if (!this.conditions || this.conditions.length < 1) {
|
||||
return true;
|
||||
}
|
||||
@@ -370,7 +386,7 @@ export class TransactionExplorerQuery {
|
||||
throw new Error('invalid postfix expression');
|
||||
}
|
||||
} else {
|
||||
stack.push(token.match(transaction));
|
||||
stack.push(token.match(transaction, context));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,6 +662,21 @@ export class TransactionExplorerConditionWithRelation {
|
||||
let operatorTypes: PartialRecord<TransactionExplorerConditionOperatorType, true> = {};
|
||||
|
||||
switch (this.condition.field) {
|
||||
case TransactionExplorerConditionField.TransactionTimeDayOfWeek.value:
|
||||
operatorTypes = TransactionExplorerTransactionTimeDayOfWeekCondition.supportedOperators;
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionTimeDayOfMonth.value:
|
||||
operatorTypes = TransactionExplorerTransactionTimeDayOfMonthCondition.supportedOperators;
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionTimeMonthOfYear.value:
|
||||
operatorTypes = TransactionExplorerTransactionTimeMonthOfYearCondition.supportedOperators;
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionTimeHourOfDay.value:
|
||||
operatorTypes = TransactionExplorerTransactionTimeHourOfDayCondition.supportedOperators;
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionTimezone.value:
|
||||
operatorTypes = TransactionExplorerTransactionTimezoneCondition.supportedOperators;
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionType.value:
|
||||
operatorTypes = TransactionExplorerTransactionTypeCondition.supportedOperators;
|
||||
break;
|
||||
@@ -736,6 +767,31 @@ export class TransactionExplorerConditionWithRelation {
|
||||
const conditionValue = conditionObject['value'];
|
||||
|
||||
switch (conditionField) {
|
||||
case TransactionExplorerConditionField.TransactionTimeDayOfWeek.value:
|
||||
if (TransactionExplorerTransactionTimeDayOfWeekCondition.supportedOperators[conditionOperator] && Array.isArray(conditionValue)) {
|
||||
condition = new TransactionExplorerTransactionTimeDayOfWeekCondition(conditionOperator as TransactionTimeDayOfWeekConditionOperator, conditionValue as number[]);
|
||||
}
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionTimeDayOfMonth.value:
|
||||
if (TransactionExplorerTransactionTimeDayOfMonthCondition.supportedOperators[conditionOperator] && Array.isArray(conditionValue)) {
|
||||
condition = new TransactionExplorerTransactionTimeDayOfMonthCondition(conditionOperator as TransactionTimeDayOfMonthConditionOperator, conditionValue as number[]);
|
||||
}
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionTimeMonthOfYear.value:
|
||||
if (TransactionExplorerTransactionTimeMonthOfYearCondition.supportedOperators[conditionOperator] && Array.isArray(conditionValue)) {
|
||||
condition = new TransactionExplorerTransactionTimeMonthOfYearCondition(conditionOperator as TransactionTimeMonthOfYearConditionOperator, conditionValue as number[]);
|
||||
}
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionTimeHourOfDay.value:
|
||||
if (TransactionExplorerTransactionTimeHourOfDayCondition.supportedOperators[conditionOperator] && Array.isArray(conditionValue)) {
|
||||
condition = new TransactionExplorerTransactionTimeHourOfDayCondition(conditionOperator as TransactionTimeHourOfDayConditionOperator, conditionValue as number[]);
|
||||
}
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionTimezone.value:
|
||||
if (TransactionExplorerTransactionTimezoneCondition.supportedOperators[conditionOperator] && Array.isArray(conditionValue) && conditionValue.length === 2) {
|
||||
condition = new TransactionExplorerTransactionTimezoneCondition(conditionOperator as TransactionTimezoneConditionOperator, conditionValue as [number, number]);
|
||||
}
|
||||
break;
|
||||
case TransactionExplorerConditionField.TransactionType.value:
|
||||
if (TransactionExplorerTransactionTypeCondition.supportedOperators[conditionOperator] && Array.isArray(conditionValue)) {
|
||||
condition = new TransactionExplorerTransactionTypeCondition(conditionOperator as TransactionTypeConditionOperator, conditionValue as number[]);
|
||||
@@ -803,13 +859,17 @@ export class TransactionExplorerConditionWithRelation {
|
||||
}
|
||||
}
|
||||
|
||||
export interface InsightsExplorerMatchContext {
|
||||
getTransactionDateTime(): DateTime;
|
||||
}
|
||||
|
||||
export interface TransactionExplorerCondition<T = TransactionExplorerConditionFieldType, V = string | string[] | number[]> {
|
||||
readonly field: T;
|
||||
readonly operator: TransactionExplorerConditionOperatorType;
|
||||
value: V;
|
||||
|
||||
getValueForStore(): V;
|
||||
match(transaction: TransactionInsightDataItem): boolean;
|
||||
match(transaction: TransactionInsightDataItem, context: InsightsExplorerMatchContext): boolean;
|
||||
toExpression(allCategoriesMap: Record<string, TransactionCategory>, allAccountsMap: Record<string, Account>, allTagsMap: Record<string, TransactionTag>): string;
|
||||
}
|
||||
|
||||
@@ -831,6 +891,233 @@ export class TransactionExplorerUndefinedCondition implements TransactionExplore
|
||||
}
|
||||
}
|
||||
|
||||
type TransactionTimeDayOfWeekConditionOperator = TransactionExplorerConditionOperatorType.In |
|
||||
TransactionExplorerConditionOperatorType.NotIn;
|
||||
|
||||
export class TransactionExplorerTransactionTimeDayOfWeekCondition implements TransactionExplorerCondition<TransactionExplorerConditionFieldType.TransactionTimeDayOfWeek, number[]> {
|
||||
public static readonly supportedOperators: PartialRecord<TransactionExplorerConditionOperatorType, true> = {
|
||||
[TransactionExplorerConditionOperatorType.In]: true,
|
||||
[TransactionExplorerConditionOperatorType.NotIn]: true
|
||||
};
|
||||
public readonly field = TransactionExplorerConditionFieldType.TransactionTimeDayOfWeek;
|
||||
public readonly operator: TransactionTimeDayOfWeekConditionOperator = TransactionExplorerConditionOperatorType.In;
|
||||
public value: number[];
|
||||
|
||||
constructor(operator: TransactionTimeDayOfWeekConditionOperator, value: number[]) {
|
||||
this.operator = operator;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public getValueForStore(): number[] {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public match(transaction: TransactionInsightDataItem, context: InsightsExplorerMatchContext): boolean {
|
||||
const transactionDateTime = context.getTransactionDateTime();
|
||||
|
||||
if (this.operator === TransactionExplorerConditionOperatorType.In) {
|
||||
return this.value.includes(transactionDateTime.getWeekDay().type);
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
|
||||
return !this.value.includes(transactionDateTime.getWeekDay().type);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public toExpression(): string {
|
||||
const textualDayOfWeeks = this.value.join(', ');
|
||||
|
||||
if (this.operator === TransactionExplorerConditionOperatorType.In) {
|
||||
return `DAY_OF_WEEK(transaction_time) IN (${textualDayOfWeeks})`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
|
||||
return `DAY_OF_WEEK(transaction_time) NOT IN (${textualDayOfWeeks})`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type TransactionTimeDayOfMonthConditionOperator = TransactionExplorerConditionOperatorType.In |
|
||||
TransactionExplorerConditionOperatorType.NotIn;
|
||||
|
||||
export class TransactionExplorerTransactionTimeDayOfMonthCondition implements TransactionExplorerCondition<TransactionExplorerConditionFieldType.TransactionTimeDayOfMonth, number[]> {
|
||||
public static readonly supportedOperators: PartialRecord<TransactionExplorerConditionOperatorType, true> = {
|
||||
[TransactionExplorerConditionOperatorType.In]: true,
|
||||
[TransactionExplorerConditionOperatorType.NotIn]: true
|
||||
};
|
||||
public readonly field = TransactionExplorerConditionFieldType.TransactionTimeDayOfMonth;
|
||||
public readonly operator: TransactionTimeDayOfMonthConditionOperator = TransactionExplorerConditionOperatorType.In;
|
||||
public value: number[];
|
||||
|
||||
constructor(operator: TransactionTimeDayOfMonthConditionOperator, value: number[]) {
|
||||
this.operator = operator;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public getValueForStore(): number[] {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public match(transaction: TransactionInsightDataItem, context: InsightsExplorerMatchContext): boolean {
|
||||
const transactionDateTime = context.getTransactionDateTime();
|
||||
const normalizedValue: number[] = this.value.map(day => day >= 0 ? day : transactionDateTime.getMaxDayOfGregorianCalendarMonth() + day + 1);
|
||||
|
||||
if (this.operator === TransactionExplorerConditionOperatorType.In) {
|
||||
return normalizedValue.includes(transactionDateTime.getGregorianCalendarDay());
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
|
||||
return !normalizedValue.includes(transactionDateTime.getGregorianCalendarDay());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public toExpression(): string {
|
||||
const textualDayOfMonths = this.value.join(', ');
|
||||
|
||||
if (this.operator === TransactionExplorerConditionOperatorType.In) {
|
||||
return `DAY(transaction_time) IN (${textualDayOfMonths})`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
|
||||
return `DAY(transaction_time) NOT IN (${textualDayOfMonths})`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type TransactionTimeMonthOfYearConditionOperator = TransactionExplorerConditionOperatorType.In |
|
||||
TransactionExplorerConditionOperatorType.NotIn;
|
||||
|
||||
export class TransactionExplorerTransactionTimeMonthOfYearCondition implements TransactionExplorerCondition<TransactionExplorerConditionFieldType.TransactionTimeMonthOfYear, number[]> {
|
||||
public static readonly supportedOperators: PartialRecord<TransactionExplorerConditionOperatorType, true> = {
|
||||
[TransactionExplorerConditionOperatorType.In]: true,
|
||||
[TransactionExplorerConditionOperatorType.NotIn]: true
|
||||
};
|
||||
public readonly field = TransactionExplorerConditionFieldType.TransactionTimeMonthOfYear;
|
||||
public readonly operator: TransactionTimeMonthOfYearConditionOperator = TransactionExplorerConditionOperatorType.In;
|
||||
public value: number[];
|
||||
|
||||
constructor(operator: TransactionTimeMonthOfYearConditionOperator, value: number[]) {
|
||||
this.operator = operator;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public getValueForStore(): number[] {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public match(transaction: TransactionInsightDataItem, context: InsightsExplorerMatchContext): boolean {
|
||||
const transactionDateTime = context.getTransactionDateTime();
|
||||
|
||||
if (this.operator === TransactionExplorerConditionOperatorType.In) {
|
||||
return this.value.includes(transactionDateTime.getGregorianCalendarMonth());
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
|
||||
return !this.value.includes(transactionDateTime.getGregorianCalendarMonth());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public toExpression(): string {
|
||||
const textualMonthOfYears = this.value.join(', ');
|
||||
|
||||
if (this.operator === TransactionExplorerConditionOperatorType.In) {
|
||||
return `MONTH(transaction_time) IN (${textualMonthOfYears})`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
|
||||
return `MONTH(transaction_time) NOT IN (${textualMonthOfYears})`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type TransactionTimeHourOfDayConditionOperator = TransactionExplorerConditionOperatorType.In |
|
||||
TransactionExplorerConditionOperatorType.NotIn;
|
||||
|
||||
export class TransactionExplorerTransactionTimeHourOfDayCondition implements TransactionExplorerCondition<TransactionExplorerConditionFieldType.TransactionTimeHourOfDay, number[]> {
|
||||
public static readonly supportedOperators: PartialRecord<TransactionExplorerConditionOperatorType, true> = {
|
||||
[TransactionExplorerConditionOperatorType.In]: true,
|
||||
[TransactionExplorerConditionOperatorType.NotIn]: true
|
||||
};
|
||||
public readonly field = TransactionExplorerConditionFieldType.TransactionTimeHourOfDay;
|
||||
public readonly operator: TransactionTimeHourOfDayConditionOperator = TransactionExplorerConditionOperatorType.In;
|
||||
public value: number[];
|
||||
|
||||
constructor(operator: TransactionTimeHourOfDayConditionOperator, value: number[]) {
|
||||
this.operator = operator;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public getValueForStore(): number[] {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public match(transaction: TransactionInsightDataItem, context: InsightsExplorerMatchContext): boolean {
|
||||
const transactionDateTime = context.getTransactionDateTime();
|
||||
|
||||
if (this.operator === TransactionExplorerConditionOperatorType.In) {
|
||||
return this.value.includes(transactionDateTime.getHour());
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
|
||||
return !this.value.includes(transactionDateTime.getHour());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public toExpression(): string {
|
||||
const textualHourOfDays = this.value.join(', ');
|
||||
|
||||
if (this.operator === TransactionExplorerConditionOperatorType.In) {
|
||||
return `HOUR(transaction_time) IN (${textualHourOfDays})`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.NotIn) {
|
||||
return `HOUR(transaction_time) NOT IN (${textualHourOfDays})`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type TransactionTimezoneConditionOperator = TransactionExplorerConditionOperatorType.MinuteOffsetBetween |
|
||||
TransactionExplorerConditionOperatorType.MinuteOffsetNotBetween;
|
||||
|
||||
export class TransactionExplorerTransactionTimezoneCondition implements TransactionExplorerCondition<TransactionExplorerConditionFieldType.TransactionTimezone, [number, number]> {
|
||||
public static readonly supportedOperators: PartialRecord<TransactionExplorerConditionOperatorType, true> = {
|
||||
[TransactionExplorerConditionOperatorType.MinuteOffsetBetween]: true,
|
||||
[TransactionExplorerConditionOperatorType.MinuteOffsetNotBetween]: true
|
||||
};
|
||||
public readonly field = TransactionExplorerConditionFieldType.TransactionTimezone;
|
||||
public readonly operator: TransactionTimezoneConditionOperator = TransactionExplorerConditionOperatorType.MinuteOffsetBetween;
|
||||
public value: [number, number];
|
||||
|
||||
constructor(operator: TransactionTimezoneConditionOperator, value: [number, number]) {
|
||||
this.operator = operator;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public getValueForStore(): [number, number] {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public match(transaction: TransactionInsightDataItem): boolean {
|
||||
if (this.operator === TransactionExplorerConditionOperatorType.MinuteOffsetBetween) {
|
||||
return transaction.utcOffset >= this.value[0] && transaction.utcOffset <= this.value[1];
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.MinuteOffsetNotBetween) {
|
||||
return transaction.utcOffset < this.value[0] || transaction.utcOffset > this.value[1];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public toExpression(): string {
|
||||
if (this.operator === TransactionExplorerConditionOperatorType.MinuteOffsetBetween) {
|
||||
return `(UTC_OFFSET(timezone) >= ${this.value[0]} AND UTC_OFFSET(timezone) <= ${this.value[1]})`;
|
||||
} else if (this.operator === TransactionExplorerConditionOperatorType.MinuteOffsetNotBetween) {
|
||||
return `(UTC_OFFSET(timezone) < ${this.value[0]} OR UTC_OFFSET(timezone) > ${this.value[1]})`;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
type TransactionTypeConditionOperator = TransactionExplorerConditionOperatorType.In |
|
||||
TransactionExplorerConditionOperatorType.NotIn;
|
||||
|
||||
|
||||
+22
-3
@@ -10,7 +10,7 @@ import { useExchangeRatesStore } from './exchangeRates.ts';
|
||||
|
||||
import { type BeforeResolveFunction, itemAndIndex, reversed, keys, values } from '@/core/base.ts';
|
||||
import { NumeralSystem, AmountFilterType } from '@/core/numeral.ts';
|
||||
import { DateRangeScene, DateRange } from '@/core/datetime.ts';
|
||||
import { type DateTime, DateRangeScene, DateRange } from '@/core/datetime.ts';
|
||||
import { TimezoneTypeForStatistics } from '@/core/timezone.ts';
|
||||
import { AccountCategory } from '@/core/account.ts';
|
||||
import { TransactionType } from '@/core/transaction.ts';
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
import {
|
||||
type InsightsExplorerNewDisplayOrderRequest,
|
||||
type InsightsExplorerInfoResponse,
|
||||
type InsightsExplorerMatchContext,
|
||||
InsightsExplorer,
|
||||
InsightsExplorerBasicInfo
|
||||
} from '@/models/explorer.ts';
|
||||
@@ -151,6 +152,20 @@ export const useExplorersStore = defineStore('explorers', () => {
|
||||
return result;
|
||||
})();
|
||||
|
||||
function buildInsightsExplorerMatchContext(insightsExplorer: InsightsExplorer, transaction: TransactionInsightDataItem): InsightsExplorerMatchContext {
|
||||
return {
|
||||
getTransactionDateTime(): DateTime {
|
||||
let transactionTimeUtfOffset: number | undefined = undefined;
|
||||
|
||||
if (insightsExplorer.timezoneUsedForDateRange === TimezoneTypeForStatistics.TransactionTimezone.type) {
|
||||
transactionTimeUtfOffset = transaction.utcOffset;
|
||||
}
|
||||
|
||||
return isDefined(transactionTimeUtfOffset) ? parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transactionTimeUtfOffset) : parseDateTimeFromUnixTime(transaction.time);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getDataCategoryInfo(timezoneUsedForDateRange: number, dimension: TransactionExplorerDataDimension, queryName: string, queryIndex: number, transaction: TransactionInsightDataItem): CategoriedInfo {
|
||||
let transactionTimeUtfOffset: number | undefined = undefined;
|
||||
|
||||
@@ -600,12 +615,14 @@ export const useExplorersStore = defineStore('explorers', () => {
|
||||
const result: TransactionInsightDataItem[] = [];
|
||||
|
||||
for (const transaction of allTransactions.value) {
|
||||
const matchOptions: InsightsExplorerMatchContext = buildInsightsExplorerMatchContext(currentInsightsExplorer.value, transaction);
|
||||
|
||||
for (const query of currentInsightsExplorer.value.queries) {
|
||||
if (currentInsightsExplorer.value.datatableQuerySource && currentInsightsExplorer.value.datatableQuerySource !== query.id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (query.match(transaction)) {
|
||||
if (query.match(transaction, matchOptions)) {
|
||||
result.push(transaction);
|
||||
break;
|
||||
}
|
||||
@@ -751,8 +768,10 @@ export const useExplorersStore = defineStore('explorers', () => {
|
||||
continue;
|
||||
}
|
||||
|
||||
const matchContext: InsightsExplorerMatchContext = buildInsightsExplorerMatchContext(currentInsightsExplorer.value, transaction);
|
||||
|
||||
for (const [query, index] of itemAndIndex(currentInsightsExplorer.value.queries)) {
|
||||
if (query.match(transaction)) {
|
||||
if (query.match(transaction, matchContext)) {
|
||||
addTransactionToCategoriedDataMap(currentInsightsExplorer.value.timezoneUsedForDateRange, categoriedDataMap, categoryDimension, seriesDimension, query.name, index, transaction);
|
||||
|
||||
if (categoryDimension !== TransactionExplorerDataDimension.Query) {
|
||||
|
||||
@@ -153,6 +153,119 @@
|
||||
/>
|
||||
|
||||
<div class="d-flex w-100 flex-1-1" style="min-width: 280px;">
|
||||
<v-select
|
||||
multiple chips closable-chips
|
||||
density="compact"
|
||||
item-title="displayName"
|
||||
item-value="type"
|
||||
:disabled="loading || disabled || !!editingQuery"
|
||||
:placeholder="tt('None')"
|
||||
:items="allAvailableDayOfWeekOptions"
|
||||
v-model="conditionWithRelation.condition.value"
|
||||
v-if="conditionWithRelation.condition.field === TransactionExplorerConditionField.TransactionTimeDayOfWeek.value"
|
||||
>
|
||||
<template #item="{ props, item }">
|
||||
<v-list-item :value="item.value" v-bind="props">
|
||||
<template #title>
|
||||
<v-list-item-title>
|
||||
<div class="d-flex align-center">{{ item.title }}</div>
|
||||
</v-list-item-title>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-select>
|
||||
|
||||
<v-select
|
||||
multiple chips closable-chips
|
||||
density="compact"
|
||||
item-title="displayName"
|
||||
item-value="type"
|
||||
:disabled="loading || disabled || !!editingQuery"
|
||||
:placeholder="tt('None')"
|
||||
:items="allAvailableDayOfMonthOptions"
|
||||
v-model="conditionWithRelation.condition.value"
|
||||
v-else-if="conditionWithRelation.condition.field === TransactionExplorerConditionField.TransactionTimeDayOfMonth.value"
|
||||
>
|
||||
<template #item="{ props, item }">
|
||||
<v-list-item :value="item.value" v-bind="props">
|
||||
<template #title>
|
||||
<v-list-item-title>
|
||||
<div class="d-flex align-center">{{ item.title }}</div>
|
||||
</v-list-item-title>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-select>
|
||||
|
||||
<v-select
|
||||
multiple chips closable-chips
|
||||
density="compact"
|
||||
item-title="displayName"
|
||||
item-value="type"
|
||||
:disabled="loading || disabled || !!editingQuery"
|
||||
:placeholder="tt('None')"
|
||||
:items="allAvailableMonthOfYearOptions"
|
||||
v-model="conditionWithRelation.condition.value"
|
||||
v-else-if="conditionWithRelation.condition.field === TransactionExplorerConditionField.TransactionTimeMonthOfYear.value"
|
||||
>
|
||||
<template #item="{ props, item }">
|
||||
<v-list-item :value="item.value" v-bind="props">
|
||||
<template #title>
|
||||
<v-list-item-title>
|
||||
<div class="d-flex align-center">{{ item.title }}</div>
|
||||
</v-list-item-title>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-select>
|
||||
|
||||
<v-select
|
||||
multiple chips closable-chips
|
||||
density="compact"
|
||||
item-title="displayName"
|
||||
item-value="type"
|
||||
:disabled="loading || disabled || !!editingQuery"
|
||||
:placeholder="tt('None')"
|
||||
:items="allAvailableHourOfDayOptions"
|
||||
v-model="conditionWithRelation.condition.value"
|
||||
v-else-if="conditionWithRelation.condition.field === TransactionExplorerConditionField.TransactionTimeHourOfDay.value"
|
||||
>
|
||||
<template #item="{ props, item }">
|
||||
<v-list-item :value="item.value" v-bind="props">
|
||||
<template #title>
|
||||
<v-list-item-title>
|
||||
<div class="d-flex align-center">{{ item.title }}</div>
|
||||
</v-list-item-title>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-select>
|
||||
|
||||
<div class="d-flex w-100 align-center gap-2"
|
||||
v-else-if="conditionWithRelation.condition.field === TransactionExplorerConditionField.TransactionTimezone.value">
|
||||
<number-input density="compact"
|
||||
:disabled="loading || disabled || !!editingQuery"
|
||||
:min-value="WESTERNMOST_TIMEZONE_UTC_OFFSET"
|
||||
:max-value="EASTERNMOST_TIMEZONE_UTC_OFFSET"
|
||||
:max-decimal-count="0"
|
||||
v-model="conditionWithRelation.condition.value[0]"
|
||||
v-if="conditionWithRelation.condition.operator === TransactionExplorerConditionOperator.MinuteOffsetBetween.value ||
|
||||
conditionWithRelation.condition.operator === TransactionExplorerConditionOperator.MinuteOffsetNotBetween.value"
|
||||
/>
|
||||
<span class="ms-2 me-2"
|
||||
v-if="conditionWithRelation.condition.operator === TransactionExplorerConditionOperator.MinuteOffsetBetween.value ||
|
||||
conditionWithRelation.condition.operator === TransactionExplorerConditionOperator.MinuteOffsetNotBetween.value">~</span>
|
||||
<number-input density="compact"
|
||||
:disabled="loading || disabled || !!editingQuery"
|
||||
:min-value="WESTERNMOST_TIMEZONE_UTC_OFFSET"
|
||||
:max-value="EASTERNMOST_TIMEZONE_UTC_OFFSET"
|
||||
:max-decimal-count="0"
|
||||
v-model="conditionWithRelation.condition.value[1]"
|
||||
v-if="conditionWithRelation.condition.operator === TransactionExplorerConditionOperator.MinuteOffsetBetween.value ||
|
||||
conditionWithRelation.condition.operator === TransactionExplorerConditionOperator.MinuteOffsetNotBetween.value"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<v-select
|
||||
multiple chips closable-chips
|
||||
density="compact"
|
||||
@@ -166,7 +279,7 @@
|
||||
{ type: TransactionType.Transfer, displayName: tt('Transfer') }
|
||||
]"
|
||||
v-model="conditionWithRelation.condition.value"
|
||||
v-if="conditionWithRelation.condition.field === TransactionExplorerConditionField.TransactionType.value"
|
||||
v-else-if="conditionWithRelation.condition.field === TransactionExplorerConditionField.TransactionType.value"
|
||||
>
|
||||
<template #item="{ props, item }">
|
||||
<v-list-item :value="item.value" v-bind="props">
|
||||
@@ -410,7 +523,7 @@ import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||
import { useTransactionTagsStore } from '@/stores/transactionTag.ts';
|
||||
import { useExplorersStore } from '@/stores/explorer.ts';
|
||||
|
||||
import { type NameValue, values } from '@/core/base.ts';
|
||||
import { type NameValue, type TypeAndDisplayName, values } from '@/core/base.ts';
|
||||
import { AccountType } from '@/core/account.ts';
|
||||
import { TransactionType } from '@/core/transaction.ts';
|
||||
import {
|
||||
@@ -419,6 +532,11 @@ import {
|
||||
TransactionExplorerConditionOperator
|
||||
} from '@/core/explorer.ts';
|
||||
|
||||
import {
|
||||
WESTERNMOST_TIMEZONE_UTC_OFFSET,
|
||||
EASTERNMOST_TIMEZONE_UTC_OFFSET,
|
||||
} from '@/consts/timezone.ts';
|
||||
|
||||
import {
|
||||
type TransactionExplorerCondition,
|
||||
TransactionExplorerQuery,
|
||||
@@ -457,6 +575,10 @@ const props = defineProps<ExplorerQueryTabProps>();
|
||||
const {
|
||||
tt,
|
||||
joinMultiText,
|
||||
getAllMonths,
|
||||
getAllWeekDays,
|
||||
getAllHours,
|
||||
getAvailableMonthDays,
|
||||
getAllTransactionExplorerConditionFields,
|
||||
getAllTransactionExplorerConditionOperators
|
||||
} = useI18n();
|
||||
@@ -489,6 +611,10 @@ const hasAnyAccount = computed<boolean>(() => accountsStore.allPlainAccounts.len
|
||||
const hasAnyTransactionCategory = computed<boolean>(() => !isObjectEmpty(transactionCategoriesStore.allTransactionCategoriesMap));
|
||||
|
||||
const allTransactionExplorerConditionFields = computed<NameValue[]>(() => getAllTransactionExplorerConditionFields());
|
||||
const allAvailableDayOfWeekOptions = computed<TypeAndDisplayName[]>(() => getAllWeekDays(userStore.currentUserFirstDayOfWeek));
|
||||
const allAvailableDayOfMonthOptions = computed<TypeAndDisplayName[]>(() => getAvailableMonthDays(31, 3));
|
||||
const allAvailableMonthOfYearOptions = computed<TypeAndDisplayName[]>(() => getAllMonths());
|
||||
const allAvailableHourOfDayOptions = computed<TypeAndDisplayName[]>(() => getAllHours());
|
||||
|
||||
function getFilteredAccountsDisplayContent(filterAccountIds?: Record<string, boolean>): string {
|
||||
if ((props.loading && !hasAnyAccount.value) || !accountsStore.allVisiblePlainAccounts || !accountsStore.allVisiblePlainAccounts.length) {
|
||||
|
||||
Reference in New Issue
Block a user