mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-19 09:14:27 +08:00
support setting timezone type for the time range of statistical data
This commit is contained in:
+16
-2
@@ -238,8 +238,15 @@ func (a *TransactionsApi) TransactionStatisticsHandler(c *core.Context) (any, *e
|
|||||||
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
|
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utcOffset, err := c.GetClientTimezoneOffset()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.WarnfWithRequestId(c, "[transactions.TransactionStatisticsHandler] cannot get client timezone offset, because %s", err.Error())
|
||||||
|
return nil, errs.ErrClientTimezoneOffsetInvalid
|
||||||
|
}
|
||||||
|
|
||||||
uid := c.GetCurrentUid()
|
uid := c.GetCurrentUid()
|
||||||
totalAmounts, err := a.transactions.GetAccountsAndCategoriesTotalIncomeAndExpense(c, uid, statisticReq.StartTime, statisticReq.EndTime)
|
totalAmounts, err := a.transactions.GetAccountsAndCategoriesTotalIncomeAndExpense(c, uid, statisticReq.StartTime, statisticReq.EndTime, utcOffset, statisticReq.UseTransactionTimezone)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ErrorfWithRequestId(c, "[transactions.TransactionStatisticsHandler] failed to get accounts and categories total income and expense for user \"uid:%d\", because %s", uid, err.Error())
|
log.ErrorfWithRequestId(c, "[transactions.TransactionStatisticsHandler] failed to get accounts and categories total income and expense for user \"uid:%d\", because %s", uid, err.Error())
|
||||||
@@ -292,6 +299,13 @@ func (a *TransactionsApi) TransactionAmountsHandler(c *core.Context) (any, *errs
|
|||||||
return nil, errs.ErrQueryItemsTooMuch
|
return nil, errs.ErrQueryItemsTooMuch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utcOffset, err := c.GetClientTimezoneOffset()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.WarnfWithRequestId(c, "[transactions.TransactionAmountsHandler] cannot get client timezone offset, because %s", err.Error())
|
||||||
|
return nil, errs.ErrClientTimezoneOffsetInvalid
|
||||||
|
}
|
||||||
|
|
||||||
uid := c.GetCurrentUid()
|
uid := c.GetCurrentUid()
|
||||||
|
|
||||||
accounts, err := a.accounts.GetAllAccountsByUid(c, uid)
|
accounts, err := a.accounts.GetAllAccountsByUid(c, uid)
|
||||||
@@ -307,7 +321,7 @@ func (a *TransactionsApi) TransactionAmountsHandler(c *core.Context) (any, *errs
|
|||||||
for i := 0; i < len(requestItems); i++ {
|
for i := 0; i < len(requestItems); i++ {
|
||||||
requestItem := requestItems[i]
|
requestItem := requestItems[i]
|
||||||
|
|
||||||
incomeAmounts, expenseAmounts, err := a.transactions.GetAccountsTotalIncomeAndExpense(c, uid, requestItem.StartTime, requestItem.EndTime)
|
incomeAmounts, expenseAmounts, err := a.transactions.GetAccountsTotalIncomeAndExpense(c, uid, requestItem.StartTime, requestItem.EndTime, utcOffset, transactionAmountsReq.UseTransactionTimezone)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ErrorfWithRequestId(c, "[transactions.TransactionAmountsHandler] failed to get transaction amounts item for user \"uid:%d\", because %s", uid, err.Error())
|
log.ErrorfWithRequestId(c, "[transactions.TransactionAmountsHandler] failed to get transaction amounts item for user \"uid:%d\", because %s", uid, err.Error())
|
||||||
|
|||||||
@@ -135,13 +135,15 @@ type TransactionListInMonthByPageRequest struct {
|
|||||||
|
|
||||||
// TransactionStatisticRequest represents all parameters of transaction statistic request
|
// TransactionStatisticRequest represents all parameters of transaction statistic request
|
||||||
type TransactionStatisticRequest struct {
|
type TransactionStatisticRequest struct {
|
||||||
StartTime int64 `form:"start_time" binding:"min=0"`
|
StartTime int64 `form:"start_time" binding:"min=0"`
|
||||||
EndTime int64 `form:"end_time" binding:"min=0"`
|
EndTime int64 `form:"end_time" binding:"min=0"`
|
||||||
|
UseTransactionTimezone bool `form:"use_transaction_timezone"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionAmountsRequest represents all parameters of transaction amounts request
|
// TransactionAmountsRequest represents all parameters of transaction amounts request
|
||||||
type TransactionAmountsRequest struct {
|
type TransactionAmountsRequest struct {
|
||||||
Query string `form:"query"`
|
Query string `form:"query"`
|
||||||
|
UseTransactionTimezone bool `form:"use_transaction_timezone"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionAmountsRequestItem represents an item of transaction amounts request
|
// TransactionAmountsRequestItem represents an item of transaction amounts request
|
||||||
|
|||||||
+151
-19
@@ -15,6 +15,8 @@ import (
|
|||||||
"github.com/mayswind/ezbookkeeping/pkg/uuid"
|
"github.com/mayswind/ezbookkeeping/pkg/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const pageCountForLoadTransactionAmounts = 1000
|
||||||
|
|
||||||
// TransactionService represents transaction service
|
// TransactionService represents transaction service
|
||||||
type TransactionService struct {
|
type TransactionService struct {
|
||||||
ServiceUsingDB
|
ServiceUsingDB
|
||||||
@@ -1004,45 +1006,112 @@ func (s *TransactionService) GetRelatedTransferTransaction(originalTransaction *
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetAccountsTotalIncomeAndExpense returns the every accounts total income and expense amount by specific date range
|
// GetAccountsTotalIncomeAndExpense returns the every accounts total income and expense amount by specific date range
|
||||||
func (s *TransactionService) GetAccountsTotalIncomeAndExpense(c *core.Context, uid int64, startUnixTime int64, endUnixTime int64) (map[int64]int64, map[int64]int64, error) {
|
func (s *TransactionService) GetAccountsTotalIncomeAndExpense(c *core.Context, uid int64, startUnixTime int64, endUnixTime int64, utcOffset int16, useTransactionTimezone bool) (map[int64]int64, map[int64]int64, error) {
|
||||||
if uid <= 0 {
|
if uid <= 0 {
|
||||||
return nil, nil, errs.ErrUserIdInvalid
|
return nil, nil, errs.ErrUserIdInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clientLocation := time.FixedZone("Client Timezone", int(utcOffset)*60)
|
||||||
|
startLocalDateTime := utils.FormatUnixTimeToNumericLocalDateTime(startUnixTime, clientLocation)
|
||||||
|
endLocalDateTime := utils.FormatUnixTimeToNumericLocalDateTime(endUnixTime, clientLocation)
|
||||||
|
|
||||||
|
startUnixTime = utils.GetMinUnixTimeWithSameLocalDateTime(startUnixTime, utcOffset)
|
||||||
|
endUnixTime = utils.GetMaxUnixTimeWithSameLocalDateTime(endUnixTime, utcOffset)
|
||||||
|
|
||||||
startTransactionTime := utils.GetMinTransactionTimeFromUnixTime(startUnixTime)
|
startTransactionTime := utils.GetMinTransactionTimeFromUnixTime(startUnixTime)
|
||||||
endTransactionTime := utils.GetMaxTransactionTimeFromUnixTime(endUnixTime)
|
endTransactionTime := utils.GetMaxTransactionTimeFromUnixTime(endUnixTime)
|
||||||
|
|
||||||
var transactionTotalAmounts []*models.Transaction
|
condition := "uid=? AND deleted=? AND (type=? OR type=?) AND transaction_time>=? AND transaction_time<=?"
|
||||||
err := s.UserDataDB(uid).NewSession(c).Select("type, account_id, SUM(amount) as amount").Where("uid=? AND deleted=? AND (type=? OR type=?) AND transaction_time>=? AND transaction_time<=?", uid, false, models.TRANSACTION_DB_TYPE_INCOME, models.TRANSACTION_DB_TYPE_EXPENSE, startTransactionTime, endTransactionTime).GroupBy("type, account_id").Find(&transactionTotalAmounts)
|
conditionParams := make([]any, 0, 4)
|
||||||
|
conditionParams = append(conditionParams, uid)
|
||||||
|
conditionParams = append(conditionParams, false)
|
||||||
|
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_INCOME)
|
||||||
|
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_EXPENSE)
|
||||||
|
|
||||||
if err != nil {
|
minTransactionTime := startTransactionTime
|
||||||
return nil, nil, err
|
maxTransactionTime := endTransactionTime
|
||||||
|
var allTransactions []*models.Transaction
|
||||||
|
|
||||||
|
for maxTransactionTime > 0 {
|
||||||
|
var transactions []*models.Transaction
|
||||||
|
|
||||||
|
finalConditionParams := make([]any, 0, 6)
|
||||||
|
finalConditionParams = append(finalConditionParams, conditionParams...)
|
||||||
|
finalConditionParams = append(finalConditionParams, minTransactionTime)
|
||||||
|
finalConditionParams = append(finalConditionParams, maxTransactionTime)
|
||||||
|
|
||||||
|
err := s.UserDataDB(uid).NewSession(c).Select("type, account_id, transaction_time, timezone_utc_offset, amount").Where(condition, finalConditionParams...).Limit(pageCountForLoadTransactionAmounts, 0).OrderBy("transaction_time desc").Find(&transactions)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
allTransactions = append(allTransactions, transactions...)
|
||||||
|
|
||||||
|
if len(transactions) < pageCountForLoadTransactionAmounts {
|
||||||
|
maxTransactionTime = 0
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
maxTransactionTime = transactions[len(transactions)-1].TransactionTime - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
incomeAmounts := make(map[int64]int64)
|
incomeAmounts := make(map[int64]int64)
|
||||||
expenseAmounts := make(map[int64]int64)
|
expenseAmounts := make(map[int64]int64)
|
||||||
|
|
||||||
for i := 0; i < len(transactionTotalAmounts); i++ {
|
for i := 0; i < len(allTransactions); i++ {
|
||||||
transactionTotalAmount := transactionTotalAmounts[i]
|
transaction := allTransactions[i]
|
||||||
|
timeZone := clientLocation
|
||||||
|
|
||||||
if transactionTotalAmount.Type == models.TRANSACTION_DB_TYPE_INCOME {
|
if useTransactionTimezone {
|
||||||
incomeAmounts[transactionTotalAmount.AccountId] = transactionTotalAmount.Amount
|
timeZone = time.FixedZone("Transaction Timezone", int(transaction.TimezoneUtcOffset)*60)
|
||||||
} else if transactionTotalAmount.Type == models.TRANSACTION_DB_TYPE_EXPENSE {
|
|
||||||
expenseAmounts[transactionTotalAmount.AccountId] = transactionTotalAmount.Amount
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localDateTime := utils.FormatUnixTimeToNumericLocalDateTime(utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime), timeZone)
|
||||||
|
|
||||||
|
if localDateTime < startLocalDateTime || localDateTime > endLocalDateTime {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var amountsMap map[int64]int64
|
||||||
|
|
||||||
|
if transaction.Type == models.TRANSACTION_DB_TYPE_INCOME {
|
||||||
|
amountsMap = incomeAmounts
|
||||||
|
} else if transaction.Type == models.TRANSACTION_DB_TYPE_EXPENSE {
|
||||||
|
amountsMap = expenseAmounts
|
||||||
|
}
|
||||||
|
|
||||||
|
totalAmounts, exists := amountsMap[transaction.AccountId]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
totalAmounts = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
totalAmounts += transaction.Amount
|
||||||
|
amountsMap[transaction.AccountId] = totalAmounts
|
||||||
}
|
}
|
||||||
|
|
||||||
return incomeAmounts, expenseAmounts, nil
|
return incomeAmounts, expenseAmounts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAccountsAndCategoriesTotalIncomeAndExpense returns the every accounts and categories total income and expense amount by specific date range
|
// GetAccountsAndCategoriesTotalIncomeAndExpense returns the every accounts and categories total income and expense amount by specific date range
|
||||||
func (s *TransactionService) GetAccountsAndCategoriesTotalIncomeAndExpense(c *core.Context, uid int64, startUnixTime int64, endUnixTime int64) ([]*models.Transaction, error) {
|
func (s *TransactionService) GetAccountsAndCategoriesTotalIncomeAndExpense(c *core.Context, uid int64, startUnixTime int64, endUnixTime int64, utcOffset int16, useTransactionTimezone bool) ([]*models.Transaction, error) {
|
||||||
if uid <= 0 {
|
if uid <= 0 {
|
||||||
return nil, errs.ErrUserIdInvalid
|
return nil, errs.ErrUserIdInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clientLocation := time.FixedZone("Client Timezone", int(utcOffset)*60)
|
||||||
|
startLocalDateTime := utils.FormatUnixTimeToNumericLocalDateTime(startUnixTime, clientLocation)
|
||||||
|
endLocalDateTime := utils.FormatUnixTimeToNumericLocalDateTime(endUnixTime, clientLocation)
|
||||||
|
|
||||||
|
startUnixTime = utils.GetMinUnixTimeWithSameLocalDateTime(startUnixTime, utcOffset)
|
||||||
|
endUnixTime = utils.GetMaxUnixTimeWithSameLocalDateTime(endUnixTime, utcOffset)
|
||||||
|
|
||||||
|
startTransactionTime := utils.GetMinTransactionTimeFromUnixTime(startUnixTime)
|
||||||
|
endTransactionTime := utils.GetMaxTransactionTimeFromUnixTime(endUnixTime)
|
||||||
|
|
||||||
condition := "uid=? AND deleted=? AND (type=? OR type=?)"
|
condition := "uid=? AND deleted=? AND (type=? OR type=?)"
|
||||||
conditionParams := make([]any, 0, 8)
|
conditionParams := make([]any, 0, 4)
|
||||||
conditionParams = append(conditionParams, uid)
|
conditionParams = append(conditionParams, uid)
|
||||||
conditionParams = append(conditionParams, false)
|
conditionParams = append(conditionParams, false)
|
||||||
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_INCOME)
|
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_INCOME)
|
||||||
@@ -1050,19 +1119,82 @@ func (s *TransactionService) GetAccountsAndCategoriesTotalIncomeAndExpense(c *co
|
|||||||
|
|
||||||
if startUnixTime > 0 {
|
if startUnixTime > 0 {
|
||||||
condition = condition + " AND transaction_time>=?"
|
condition = condition + " AND transaction_time>=?"
|
||||||
conditionParams = append(conditionParams, utils.GetMinTransactionTimeFromUnixTime(startUnixTime))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if endUnixTime > 0 {
|
if endUnixTime > 0 {
|
||||||
condition = condition + " AND transaction_time<=?"
|
condition = condition + " AND transaction_time<=?"
|
||||||
conditionParams = append(conditionParams, utils.GetMaxTransactionTimeFromUnixTime(endUnixTime))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var transactionTotalAmounts []*models.Transaction
|
minTransactionTime := startTransactionTime
|
||||||
err := s.UserDataDB(uid).NewSession(c).Select("category_id, account_id, SUM(amount) as amount").Where(condition, conditionParams...).GroupBy("category_id, account_id").Find(&transactionTotalAmounts)
|
maxTransactionTime := endTransactionTime
|
||||||
|
var allTransactions []*models.Transaction
|
||||||
|
|
||||||
if err != nil {
|
for maxTransactionTime > 0 {
|
||||||
return nil, err
|
var transactions []*models.Transaction
|
||||||
|
|
||||||
|
finalConditionParams := make([]any, 0, 6)
|
||||||
|
finalConditionParams = append(finalConditionParams, conditionParams...)
|
||||||
|
|
||||||
|
if startUnixTime > 0 {
|
||||||
|
finalConditionParams = append(finalConditionParams, minTransactionTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
if endUnixTime > 0 {
|
||||||
|
finalConditionParams = append(finalConditionParams, maxTransactionTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.UserDataDB(uid).NewSession(c).Select("category_id, account_id, transaction_time, timezone_utc_offset, amount").Where(condition, finalConditionParams...).Limit(pageCountForLoadTransactionAmounts, 0).OrderBy("transaction_time desc").Find(&transactions)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
allTransactions = append(allTransactions, transactions...)
|
||||||
|
|
||||||
|
if len(transactions) < pageCountForLoadTransactionAmounts {
|
||||||
|
maxTransactionTime = 0
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
maxTransactionTime = transactions[len(transactions)-1].TransactionTime - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionTotalAmountsMap := make(map[string]*models.Transaction)
|
||||||
|
|
||||||
|
for i := 0; i < len(allTransactions); i++ {
|
||||||
|
transaction := allTransactions[i]
|
||||||
|
timeZone := clientLocation
|
||||||
|
|
||||||
|
if useTransactionTimezone {
|
||||||
|
timeZone = time.FixedZone("Transaction Timezone", int(transaction.TimezoneUtcOffset)*60)
|
||||||
|
}
|
||||||
|
|
||||||
|
localDateTime := utils.FormatUnixTimeToNumericLocalDateTime(utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime), timeZone)
|
||||||
|
|
||||||
|
if localDateTime < startLocalDateTime || localDateTime > endLocalDateTime {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
groupKey := fmt.Sprintf("%d_%d", transaction.CategoryId, transaction.AccountId)
|
||||||
|
totalAmounts, exists := transactionTotalAmountsMap[groupKey]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
totalAmounts = &models.Transaction{
|
||||||
|
CategoryId: transaction.CategoryId,
|
||||||
|
AccountId: transaction.AccountId,
|
||||||
|
Amount: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionTotalAmountsMap[groupKey] = totalAmounts
|
||||||
|
}
|
||||||
|
|
||||||
|
totalAmounts.Amount += transaction.Amount
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionTotalAmounts := make([]*models.Transaction, 0, len(transactionTotalAmountsMap))
|
||||||
|
|
||||||
|
for _, totalAmounts := range transactionTotalAmountsMap {
|
||||||
|
transactionTotalAmounts = append(transactionTotalAmounts, totalAmounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transactionTotalAmounts, nil
|
return transactionTotalAmounts, nil
|
||||||
|
|||||||
@@ -44,6 +44,34 @@ func FormatUnixTimeToYearMonth(unixTime int64, timezone *time.Location) string {
|
|||||||
return t.Format(yearMonthDateTimeFormat)
|
return t.Format(yearMonthDateTimeFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FormatUnixTimeToNumericLocalDateTime returns numeric year, month, day, hour, minute and second of specified unix time
|
||||||
|
func FormatUnixTimeToNumericLocalDateTime(unixTime int64, timezone *time.Location) int64 {
|
||||||
|
t := parseFromUnixTime(unixTime)
|
||||||
|
|
||||||
|
if timezone != nil {
|
||||||
|
t = t.In(timezone)
|
||||||
|
}
|
||||||
|
|
||||||
|
localDateTime := int64(t.Year())
|
||||||
|
localDateTime = localDateTime*100 + int64(t.Month())
|
||||||
|
localDateTime = localDateTime*100 + int64(t.Day())
|
||||||
|
localDateTime = localDateTime*100 + int64(t.Hour())
|
||||||
|
localDateTime = localDateTime*100 + int64(t.Minute())
|
||||||
|
localDateTime = localDateTime*100 + int64(t.Second())
|
||||||
|
|
||||||
|
return localDateTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMinUnixTimeWithSameLocalDateTime returns the minimum UnixTime for date with the same local date
|
||||||
|
func GetMinUnixTimeWithSameLocalDateTime(unixTime int64, currentUtcOffset int16) int64 {
|
||||||
|
return unixTime + int64(currentUtcOffset)*60 - easternmostTimezoneUtcOffset*60
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMaxUnixTimeWithSameLocalDateTime returns the maximum UnixTime for date with the same local date
|
||||||
|
func GetMaxUnixTimeWithSameLocalDateTime(unixTime int64, currentUtcOffset int16) int64 {
|
||||||
|
return unixTime + int64(currentUtcOffset)*60 - westernmostTimezoneUtcOffset*60
|
||||||
|
}
|
||||||
|
|
||||||
// ParseFromLongDateTimeToMinUnixTime parses a formatted string in long date time format to minimal unix time (the westernmost timezone)
|
// ParseFromLongDateTimeToMinUnixTime parses a formatted string in long date time format to minimal unix time (the westernmost timezone)
|
||||||
func ParseFromLongDateTimeToMinUnixTime(t string) (time.Time, error) {
|
func ParseFromLongDateTimeToMinUnixTime(t string) (time.Time, error) {
|
||||||
timezone := time.FixedZone("Timezone", easternmostTimezoneUtcOffset*60)
|
timezone := time.FixedZone("Timezone", easternmostTimezoneUtcOffset*60)
|
||||||
|
|||||||
@@ -35,6 +35,38 @@ func TestFormatUnixTimeToYearMonth(t *testing.T) {
|
|||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFormatUnixTimeToNumericLocalDateTime(t *testing.T) {
|
||||||
|
unixTime := int64(1617228083)
|
||||||
|
utcTimezone := time.FixedZone("Test Timezone", 0) // UTC
|
||||||
|
utc8Timezone := time.FixedZone("Test Timezone", 28800) // UTC+8
|
||||||
|
|
||||||
|
expectedValue := int64(20210331220123)
|
||||||
|
actualValue := FormatUnixTimeToNumericLocalDateTime(unixTime, utcTimezone)
|
||||||
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
|
||||||
|
expectedValue = int64(20210401060123)
|
||||||
|
actualValue = FormatUnixTimeToNumericLocalDateTime(unixTime, utc8Timezone)
|
||||||
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetMinUnixTimeWithSameLocalDateTime(t *testing.T) {
|
||||||
|
expectedValue := int64(1690797600)
|
||||||
|
actualValue := GetMinUnixTimeWithSameLocalDateTime(1690819200, 480)
|
||||||
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
|
||||||
|
actualValue = GetMinUnixTimeWithSameLocalDateTime(1690873200, -420)
|
||||||
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetMaxUnixTimeWithSameLocalDateTime(t *testing.T) {
|
||||||
|
expectedValue := int64(1690891200)
|
||||||
|
actualValue := GetMaxUnixTimeWithSameLocalDateTime(1690819200, 480)
|
||||||
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
|
||||||
|
actualValue = GetMaxUnixTimeWithSameLocalDateTime(1690873200, -420)
|
||||||
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseFromLongDateTimeToMinUnixTime(t *testing.T) {
|
func TestParseFromLongDateTimeToMinUnixTime(t *testing.T) {
|
||||||
expectedValue := int64(1690797600)
|
expectedValue := int64(1690797600)
|
||||||
actualTime, err := ParseFromLongDateTimeToMinUnixTime("2023-08-01 00:00:00")
|
actualTime, err := ParseFromLongDateTimeToMinUnixTime("2023-08-01 00:00:00")
|
||||||
|
|||||||
+10
-1
@@ -592,7 +592,16 @@ const allAvailableTimezones = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const allTimezoneTypesUsedForStatistics = {
|
||||||
|
ApplicationTimezone: 0,
|
||||||
|
TransactionTimezone: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultTimezoneTypesUsedForStatistics = allTimezoneTypesUsedForStatistics.ApplicationTimezone;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
all: allAvailableTimezones,
|
all: allAvailableTimezones,
|
||||||
utcTimezoneName: 'Etc/GMT'
|
utcTimezoneName: 'Etc/GMT',
|
||||||
|
allTimezoneTypesUsedForStatistics: allTimezoneTypesUsedForStatistics,
|
||||||
|
defaultTimezoneTypesUsedForStatistics: defaultTimezoneTypesUsedForStatistics
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -762,6 +762,21 @@ function getDateRangeDisplayName(userStore, dateType, startTime, endTime, transl
|
|||||||
return `${displayStartTime} ~ ${displayEndTime}`;
|
return `${displayStartTime} ~ ${displayEndTime}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAllTimezoneTypesUsedForStatistics(currentTimezone, translateFn) {
|
||||||
|
const currentTimezoneOffset = getTimezoneOffset(currentTimezone);
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
displayName: translateFn('Application Timezone') + ` (UTC${currentTimezoneOffset})`,
|
||||||
|
type: timezone.allTimezoneTypesUsedForStatistics.ApplicationTimezone
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: translateFn('Transaction Timezone'),
|
||||||
|
type: timezone.allTimezoneTypesUsedForStatistics.TransactionTimezone
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
function getAllAccountCategories(translateFn) {
|
function getAllAccountCategories(translateFn) {
|
||||||
const allAccountCategories = [];
|
const allAccountCategories = [];
|
||||||
|
|
||||||
@@ -1333,6 +1348,7 @@ export function i18nFunctions(i18nGlobal) {
|
|||||||
getAllDateRanges: (includeCustom) => getAllDateRanges(includeCustom, i18nGlobal.t),
|
getAllDateRanges: (includeCustom) => getAllDateRanges(includeCustom, i18nGlobal.t),
|
||||||
getAllRecentMonthDateRanges: (userStore, includeAll, includeCustom) => getAllRecentMonthDateRanges(userStore, includeAll, includeCustom, i18nGlobal.t),
|
getAllRecentMonthDateRanges: (userStore, includeAll, includeCustom) => getAllRecentMonthDateRanges(userStore, includeAll, includeCustom, i18nGlobal.t),
|
||||||
getDateRangeDisplayName: (userStore, dateType, startTime, endTime) => getDateRangeDisplayName(userStore, dateType, startTime, endTime, i18nGlobal.t),
|
getDateRangeDisplayName: (userStore, dateType, startTime, endTime) => getDateRangeDisplayName(userStore, dateType, startTime, endTime, i18nGlobal.t),
|
||||||
|
getAllTimezoneTypesUsedForStatistics: (currentTimezone) => getAllTimezoneTypesUsedForStatistics(currentTimezone, i18nGlobal.t),
|
||||||
getAllAccountCategories: () => getAllAccountCategories(i18nGlobal.t),
|
getAllAccountCategories: () => getAllAccountCategories(i18nGlobal.t),
|
||||||
getAllAccountTypes: () => getAllAccountTypes(i18nGlobal.t),
|
getAllAccountTypes: () => getAllAccountTypes(i18nGlobal.t),
|
||||||
getAllStatisticsChartDataTypes: () => getAllStatisticsChartDataTypes(i18nGlobal.t),
|
getAllStatisticsChartDataTypes: () => getAllStatisticsChartDataTypes(i18nGlobal.t),
|
||||||
|
|||||||
+4
-4
@@ -283,7 +283,7 @@ export default {
|
|||||||
keyword = encodeURIComponent(keyword);
|
keyword = encodeURIComponent(keyword);
|
||||||
return axios.get(`v1/transactions/list/by_month.json?year=${year}&month=${month}&type=${type}&category_id=${categoryId}&account_id=${accountId}&keyword=${keyword}&trim_account=true&trim_category=true&trim_tag=true`);
|
return axios.get(`v1/transactions/list/by_month.json?year=${year}&month=${month}&type=${type}&category_id=${categoryId}&account_id=${accountId}&keyword=${keyword}&trim_account=true&trim_category=true&trim_tag=true`);
|
||||||
},
|
},
|
||||||
getTransactionStatistics: ({ startTime, endTime }) => {
|
getTransactionStatistics: ({ startTime, endTime, useTransactionTimezone }) => {
|
||||||
const queryParams = [];
|
const queryParams = [];
|
||||||
|
|
||||||
if (startTime) {
|
if (startTime) {
|
||||||
@@ -294,9 +294,9 @@ export default {
|
|||||||
queryParams.push(`end_time=${endTime}`);
|
queryParams.push(`end_time=${endTime}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return axios.get('v1/transactions/statistics.json' + (queryParams.length ? '?' + queryParams.join('&') : ''));
|
return axios.get(`v1/transactions/statistics.json?use_transaction_timezone=${useTransactionTimezone}` + (queryParams.length ? '&' + queryParams.join('&') : ''));
|
||||||
},
|
},
|
||||||
getTransactionAmounts: ({ today, thisWeek, thisMonth, thisYear, lastMonth, monthBeforeLastMonth, monthBeforeLast2Months, monthBeforeLast3Months, monthBeforeLast4Months, monthBeforeLast5Months, monthBeforeLast6Months, monthBeforeLast7Months, monthBeforeLast8Months, monthBeforeLast9Months, monthBeforeLast10Months }) => {
|
getTransactionAmounts: ({ useTransactionTimezone, today, thisWeek, thisMonth, thisYear, lastMonth, monthBeforeLastMonth, monthBeforeLast2Months, monthBeforeLast3Months, monthBeforeLast4Months, monthBeforeLast5Months, monthBeforeLast6Months, monthBeforeLast7Months, monthBeforeLast8Months, monthBeforeLast9Months, monthBeforeLast10Months }) => {
|
||||||
const queryParams = [];
|
const queryParams = [];
|
||||||
|
|
||||||
if (today) {
|
if (today) {
|
||||||
@@ -359,7 +359,7 @@ export default {
|
|||||||
queryParams.push(`monthBeforeLast10Months_${monthBeforeLast10Months.startTime}_${monthBeforeLast10Months.endTime}`);
|
queryParams.push(`monthBeforeLast10Months_${monthBeforeLast10Months.startTime}_${monthBeforeLast10Months.endTime}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return axios.get('v1/transactions/amounts.json' + (queryParams.length ? '?query=' + queryParams.join('|') : ''));
|
return axios.get(`v1/transactions/amounts.json?use_transaction_timezone=${useTransactionTimezone}` + (queryParams.length ? '&query=' + queryParams.join('|') : ''));
|
||||||
},
|
},
|
||||||
getTransaction: ({ id }) => {
|
getTransaction: ({ id }) => {
|
||||||
return axios.get(`v1/transactions/get.json?id=${id}&trim_account=true&trim_category=true&trim_tag=true`);
|
return axios.get(`v1/transactions/get.json?id=${id}&trim_account=true&trim_category=true&trim_tag=true`);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import currencyConstants from '@/consts/currency.js';
|
import currencyConstants from '@/consts/currency.js';
|
||||||
|
import timezoneConstants from '@/consts/timezone.js';
|
||||||
import statisticsConstants from '@/consts/statistics.js';
|
import statisticsConstants from '@/consts/statistics.js';
|
||||||
|
|
||||||
const settingsLocalStorageKey = 'ebk_app_settings';
|
const settingsLocalStorageKey = 'ebk_app_settings';
|
||||||
@@ -15,6 +16,7 @@ const defaultSettings = {
|
|||||||
thousandsSeparator: true,
|
thousandsSeparator: true,
|
||||||
currencyDisplayMode: currencyConstants.defaultCurrencyDisplayMode,
|
currencyDisplayMode: currencyConstants.defaultCurrencyDisplayMode,
|
||||||
showAmountInHomePage: true,
|
showAmountInHomePage: true,
|
||||||
|
timezoneUsedForStatisticsInHomePage: timezoneConstants.defaultTimezoneTypesUsedForStatistics,
|
||||||
itemsCountInTransactionListPage: 15,
|
itemsCountInTransactionListPage: 15,
|
||||||
showTotalAmountInTransactionListPage: true,
|
showTotalAmountInTransactionListPage: true,
|
||||||
showAccountBalance: true,
|
showAccountBalance: true,
|
||||||
@@ -22,6 +24,7 @@ const defaultSettings = {
|
|||||||
defaultChartType: statisticsConstants.defaultChartType,
|
defaultChartType: statisticsConstants.defaultChartType,
|
||||||
defaultChartDataType: statisticsConstants.defaultChartDataType,
|
defaultChartDataType: statisticsConstants.defaultChartDataType,
|
||||||
defaultDataRangeType: statisticsConstants.defaultDataRangeType,
|
defaultDataRangeType: statisticsConstants.defaultDataRangeType,
|
||||||
|
defaultTimezoneType: timezoneConstants.defaultTimezoneTypesUsedForStatistics,
|
||||||
defaultAccountFilter: {},
|
defaultAccountFilter: {},
|
||||||
defaultTransactionCategoryFilter: {},
|
defaultTransactionCategoryFilter: {},
|
||||||
defaultSortingType: statisticsConstants.defaultSortingType
|
defaultSortingType: statisticsConstants.defaultSortingType
|
||||||
@@ -186,6 +189,14 @@ export function setShowAmountInHomePage(value) {
|
|||||||
setOption('showAmountInHomePage', value);
|
setOption('showAmountInHomePage', value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getTimezoneUsedForStatisticsInHomePage() {
|
||||||
|
return getOption('timezoneUsedForStatisticsInHomePage');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setTimezoneUsedForStatisticsInHomePage(value) {
|
||||||
|
setOption('timezoneUsedForStatisticsInHomePage', value);
|
||||||
|
}
|
||||||
|
|
||||||
export function getItemsCountInTransactionListPage() {
|
export function getItemsCountInTransactionListPage() {
|
||||||
return getOption('itemsCountInTransactionListPage');
|
return getOption('itemsCountInTransactionListPage');
|
||||||
}
|
}
|
||||||
@@ -230,6 +241,14 @@ export function getStatisticsDefaultDateRange() {
|
|||||||
return getSubOption('statistics', 'defaultDataRangeType');
|
return getSubOption('statistics', 'defaultDataRangeType');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getStatisticsDefaultTimezoneType() {
|
||||||
|
return getSubOption('statistics', 'defaultTimezoneType');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setStatisticsDefaultTimezoneType(value) {
|
||||||
|
setSubOption('statistics', 'defaultTimezoneType', value);
|
||||||
|
}
|
||||||
|
|
||||||
export function setStatisticsDefaultDateRange(value) {
|
export function setStatisticsDefaultDateRange(value) {
|
||||||
setSubOption('statistics', 'defaultDataRangeType', value);
|
setSubOption('statistics', 'defaultDataRangeType', value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1019,6 +1019,7 @@ export default {
|
|||||||
'Default Transaction Category Filter': 'Default Transaction Category Filter',
|
'Default Transaction Category Filter': 'Default Transaction Category Filter',
|
||||||
'Sort Order': 'Sort Order',
|
'Sort Order': 'Sort Order',
|
||||||
'Default Sort Order': 'Default Sort Order',
|
'Default Sort Order': 'Default Sort Order',
|
||||||
|
'Timezone Used for Date Range': 'Timezone Used for Date Range',
|
||||||
'Amount': 'Amount',
|
'Amount': 'Amount',
|
||||||
'Display Order': 'Display Order',
|
'Display Order': 'Display Order',
|
||||||
'Name': 'Name',
|
'Name': 'Name',
|
||||||
@@ -1047,6 +1048,9 @@ export default {
|
|||||||
'Hide Account Balance': 'Hide Account Balance',
|
'Hide Account Balance': 'Hide Account Balance',
|
||||||
'Page Settings': 'Page Settings',
|
'Page Settings': 'Page Settings',
|
||||||
'Overview Page': 'Overview Page',
|
'Overview Page': 'Overview Page',
|
||||||
|
'Timezone Used for Statistics': 'Timezone Used for Statistics',
|
||||||
|
'Timezone Type': 'Timezone Type',
|
||||||
|
'Application Timezone': 'Application Timezone',
|
||||||
'Transaction List Page': 'Transaction List Page',
|
'Transaction List Page': 'Transaction List Page',
|
||||||
'Transactions Per Page': 'Transactions Per Page',
|
'Transactions Per Page': 'Transactions Per Page',
|
||||||
'Show Monthly Total Amount': 'Show Monthly Total Amount',
|
'Show Monthly Total Amount': 'Show Monthly Total Amount',
|
||||||
|
|||||||
@@ -1019,6 +1019,7 @@ export default {
|
|||||||
'Default Transaction Category Filter': '默认交易分类过滤',
|
'Default Transaction Category Filter': '默认交易分类过滤',
|
||||||
'Sort Order': '排序方式',
|
'Sort Order': '排序方式',
|
||||||
'Default Sort Order': '默认排序方式',
|
'Default Sort Order': '默认排序方式',
|
||||||
|
'Timezone Used for Date Range': '时间范围使用的时区',
|
||||||
'Amount': '金额',
|
'Amount': '金额',
|
||||||
'Display Order': '显示顺序',
|
'Display Order': '显示顺序',
|
||||||
'Name': '名称',
|
'Name': '名称',
|
||||||
@@ -1047,6 +1048,9 @@ export default {
|
|||||||
'Hide Account Balance': '隐藏账户余额',
|
'Hide Account Balance': '隐藏账户余额',
|
||||||
'Page Settings': '页面设置',
|
'Page Settings': '页面设置',
|
||||||
'Overview Page': '总览页面',
|
'Overview Page': '总览页面',
|
||||||
|
'Timezone Used for Statistics': '统计时使用的时区',
|
||||||
|
'Timezone Type': '时区类型',
|
||||||
|
'Application Timezone': '应用时区',
|
||||||
'Transaction List Page': '交易列表页面',
|
'Transaction List Page': '交易列表页面',
|
||||||
'Transactions Per Page': '每页交易数',
|
'Transactions Per Page': '每页交易数',
|
||||||
'Show Monthly Total Amount': '显示月度总金额',
|
'Show Monthly Total Amount': '显示月度总金额',
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
import { useSettingsStore } from '@/stores/setting.js';
|
||||||
import { useUserStore } from './user.js';
|
import { useUserStore } from './user.js';
|
||||||
import { useExchangeRatesStore } from './exchangeRates.js';
|
import { useExchangeRatesStore } from './exchangeRates.js';
|
||||||
|
|
||||||
@@ -219,6 +220,8 @@ export const useOverviewStore = defineStore('overview', {
|
|||||||
this.transactionOverviewStateInvalid = true;
|
this.transactionOverviewStateInvalid = true;
|
||||||
},
|
},
|
||||||
loadTransactionOverview({ force, loadLast11Months }) {
|
loadTransactionOverview({ force, loadLast11Months }) {
|
||||||
|
const settingsStore = useSettingsStore();
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
let dateChanged = false;
|
let dateChanged = false;
|
||||||
let rangeChanged = false;
|
let rangeChanged = false;
|
||||||
@@ -239,6 +242,7 @@ export const useOverviewStore = defineStore('overview', {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const requestParams = {
|
const requestParams = {
|
||||||
|
useTransactionTimezone: settingsStore.appSettings.timezoneUsedForStatisticsInHomePage,
|
||||||
today: self.transactionDataRange.today,
|
today: self.transactionDataRange.today,
|
||||||
thisWeek: self.transactionDataRange.thisWeek,
|
thisWeek: self.transactionDataRange.thisWeek,
|
||||||
thisMonth: self.transactionDataRange.thisMonth,
|
thisMonth: self.transactionDataRange.thisMonth,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export const useSettingsStore = defineStore('settings', {
|
|||||||
thousandsSeparator: settings.isEnableThousandsSeparator(),
|
thousandsSeparator: settings.isEnableThousandsSeparator(),
|
||||||
currencyDisplayMode: settings.getCurrencyDisplayMode(),
|
currencyDisplayMode: settings.getCurrencyDisplayMode(),
|
||||||
showAmountInHomePage: settings.isShowAmountInHomePage(),
|
showAmountInHomePage: settings.isShowAmountInHomePage(),
|
||||||
|
timezoneUsedForStatisticsInHomePage: settings.getTimezoneUsedForStatisticsInHomePage(),
|
||||||
itemsCountInTransactionListPage: settings.getItemsCountInTransactionListPage(),
|
itemsCountInTransactionListPage: settings.getItemsCountInTransactionListPage(),
|
||||||
showTotalAmountInTransactionListPage: settings.isShowTotalAmountInTransactionListPage(),
|
showTotalAmountInTransactionListPage: settings.isShowTotalAmountInTransactionListPage(),
|
||||||
showAccountBalance: settings.isShowAccountBalance(),
|
showAccountBalance: settings.isShowAccountBalance(),
|
||||||
@@ -24,6 +25,7 @@ export const useSettingsStore = defineStore('settings', {
|
|||||||
defaultChartType: settings.getStatisticsDefaultChartType(),
|
defaultChartType: settings.getStatisticsDefaultChartType(),
|
||||||
defaultChartDataType: settings.getStatisticsDefaultChartDataType(),
|
defaultChartDataType: settings.getStatisticsDefaultChartDataType(),
|
||||||
defaultDataRangeType: settings.getStatisticsDefaultDateRange(),
|
defaultDataRangeType: settings.getStatisticsDefaultDateRange(),
|
||||||
|
defaultTimezoneType: settings.getStatisticsDefaultTimezoneType(),
|
||||||
defaultAccountFilter: settings.getStatisticsDefaultAccountFilter(),
|
defaultAccountFilter: settings.getStatisticsDefaultAccountFilter(),
|
||||||
defaultTransactionCategoryFilter: settings.getStatisticsDefaultTransactionCategoryFilter(),
|
defaultTransactionCategoryFilter: settings.getStatisticsDefaultTransactionCategoryFilter(),
|
||||||
defaultSortingType: settings.getStatisticsSortingType()
|
defaultSortingType: settings.getStatisticsSortingType()
|
||||||
@@ -76,6 +78,10 @@ export const useSettingsStore = defineStore('settings', {
|
|||||||
settings.setShowAmountInHomePage(value);
|
settings.setShowAmountInHomePage(value);
|
||||||
this.appSettings.showAmountInHomePage = value;
|
this.appSettings.showAmountInHomePage = value;
|
||||||
},
|
},
|
||||||
|
setTimezoneUsedForStatisticsInHomePage(value) {
|
||||||
|
settings.setTimezoneUsedForStatisticsInHomePage(value);
|
||||||
|
this.appSettings.timezoneUsedForStatisticsInHomePage = value;
|
||||||
|
},
|
||||||
setItemsCountInTransactionListPage(value) {
|
setItemsCountInTransactionListPage(value) {
|
||||||
settings.setItemsCountInTransactionListPage(value);
|
settings.setItemsCountInTransactionListPage(value);
|
||||||
this.appSettings.itemsCountInTransactionListPage = value;
|
this.appSettings.itemsCountInTransactionListPage = value;
|
||||||
@@ -100,6 +106,10 @@ export const useSettingsStore = defineStore('settings', {
|
|||||||
settings.setStatisticsDefaultDateRange(value);
|
settings.setStatisticsDefaultDateRange(value);
|
||||||
this.appSettings.statistics.defaultDataRangeType = value;
|
this.appSettings.statistics.defaultDataRangeType = value;
|
||||||
},
|
},
|
||||||
|
setStatisticsDefaultTimezoneType(value) {
|
||||||
|
settings.setStatisticsDefaultTimezoneType(value);
|
||||||
|
this.appSettings.statistics.defaultTimezoneType = value;
|
||||||
|
},
|
||||||
setStatisticsDefaultAccountFilter(value) {
|
setStatisticsDefaultAccountFilter(value) {
|
||||||
settings.setStatisticsDefaultAccountFilter(value);
|
settings.setStatisticsDefaultAccountFilter(value);
|
||||||
this.appSettings.statistics.defaultAccountFilter = value;
|
this.appSettings.statistics.defaultAccountFilter = value;
|
||||||
|
|||||||
@@ -580,11 +580,13 @@ export const useStatisticsStore = defineStore('statistics', {
|
|||||||
},
|
},
|
||||||
loadTransactionStatistics({ force }) {
|
loadTransactionStatistics({ force }) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
const settingsStore = useSettingsStore();
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
services.getTransactionStatistics({
|
services.getTransactionStatistics({
|
||||||
startTime: self.transactionStatisticsFilter.startTime,
|
startTime: self.transactionStatisticsFilter.startTime,
|
||||||
endTime: self.transactionStatisticsFilter.endTime
|
endTime: self.transactionStatisticsFilter.endTime,
|
||||||
|
useTransactionTimezone: settingsStore.appSettings.statistics.defaultTimezoneType
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
const data = response.data;
|
const data = response.data;
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,18 @@
|
|||||||
v-model="showAmountInHomePage"
|
v-model="showAmountInHomePage"
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-select
|
||||||
|
item-title="displayName"
|
||||||
|
item-value="type"
|
||||||
|
persistent-placeholder
|
||||||
|
:label="$t('Timezone Used for Statistics')"
|
||||||
|
:placeholder="$t('Timezone Used for Statistics')"
|
||||||
|
:items="allTimezoneTypesUsedForStatistics"
|
||||||
|
v-model="timezoneUsedForStatisticsInHomePage"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-form>
|
</v-form>
|
||||||
@@ -197,6 +209,9 @@ export default {
|
|||||||
allCurrencyDisplayModes() {
|
allCurrencyDisplayModes() {
|
||||||
return currencyConstants.allCurrencyDisplayModes;
|
return currencyConstants.allCurrencyDisplayModes;
|
||||||
},
|
},
|
||||||
|
allTimezoneTypesUsedForStatistics() {
|
||||||
|
return this.$locale.getAllTimezoneTypesUsedForStatistics(this.timeZone);
|
||||||
|
},
|
||||||
theme: {
|
theme: {
|
||||||
get: function () {
|
get: function () {
|
||||||
return this.settingsStore.appSettings.theme;
|
return this.settingsStore.appSettings.theme;
|
||||||
@@ -265,6 +280,15 @@ export default {
|
|||||||
this.settingsStore.setShowAmountInHomePage(value);
|
this.settingsStore.setShowAmountInHomePage(value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
timezoneUsedForStatisticsInHomePage: {
|
||||||
|
get: function () {
|
||||||
|
return this.settingsStore.appSettings.timezoneUsedForStatisticsInHomePage;
|
||||||
|
},
|
||||||
|
set: function (value) {
|
||||||
|
this.settingsStore.setTimezoneUsedForStatisticsInHomePage(value);
|
||||||
|
this.overviewStore.updateTransactionOverviewInvalidState(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
showTotalAmountInTransactionListPage: {
|
showTotalAmountInTransactionListPage: {
|
||||||
get: function () {
|
get: function () {
|
||||||
return this.settingsStore.appSettings.showTotalAmountInTransactionListPage;
|
return this.settingsStore.appSettings.showTotalAmountInTransactionListPage;
|
||||||
|
|||||||
@@ -44,6 +44,18 @@
|
|||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-select
|
||||||
|
item-title="displayName"
|
||||||
|
item-value="type"
|
||||||
|
persistent-placeholder
|
||||||
|
:label="$t('Timezone Used for Date Range')"
|
||||||
|
:placeholder="$t('Timezone Used for Date Range')"
|
||||||
|
:items="allTimezoneTypesUsedForStatistics"
|
||||||
|
v-model="defaultTimezoneType"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
<v-col cols="12" md="6">
|
<v-col cols="12" md="6">
|
||||||
<v-select
|
<v-select
|
||||||
item-title="displayName"
|
item-title="displayName"
|
||||||
@@ -99,6 +111,9 @@ export default {
|
|||||||
allDateRanges() {
|
allDateRanges() {
|
||||||
return this.$locale.getAllDateRanges(false);
|
return this.$locale.getAllDateRanges(false);
|
||||||
},
|
},
|
||||||
|
allTimezoneTypesUsedForStatistics() {
|
||||||
|
return this.$locale.getAllTimezoneTypesUsedForStatistics();
|
||||||
|
},
|
||||||
defaultChartType: {
|
defaultChartType: {
|
||||||
get: function () {
|
get: function () {
|
||||||
return this.settingsStore.appSettings.statistics.defaultChartType;
|
return this.settingsStore.appSettings.statistics.defaultChartType;
|
||||||
@@ -123,6 +138,14 @@ export default {
|
|||||||
this.settingsStore.setStatisticsDefaultDateRange(value);
|
this.settingsStore.setStatisticsDefaultDateRange(value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
defaultTimezoneType: {
|
||||||
|
get: function () {
|
||||||
|
return this.settingsStore.appSettings.statistics.defaultTimezoneType;
|
||||||
|
},
|
||||||
|
set: function (value) {
|
||||||
|
this.settingsStore.setStatisticsDefaultTimezoneType(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
defaultSortingType: {
|
defaultSortingType: {
|
||||||
get: function () {
|
get: function () {
|
||||||
return this.settingsStore.appSettings.statistics.defaultSortingType;
|
return this.settingsStore.appSettings.statistics.defaultSortingType;
|
||||||
|
|||||||
@@ -8,6 +8,16 @@
|
|||||||
<span>{{ $t('Show Amount') }}</span>
|
<span>{{ $t('Show Amount') }}</span>
|
||||||
<f7-toggle :checked="showAmountInHomePage" @toggle:change="showAmountInHomePage = $event"></f7-toggle>
|
<f7-toggle :checked="showAmountInHomePage" @toggle:change="showAmountInHomePage = $event"></f7-toggle>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
|
|
||||||
|
<f7-list-item
|
||||||
|
:title="$t('Timezone Used for Statistics')"
|
||||||
|
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Timezone Type'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), popupCloseLinkText: $t('Done') }">
|
||||||
|
<select v-model="timezoneUsedForStatisticsInHomePage">
|
||||||
|
<option :value="timezoneType.type"
|
||||||
|
:key="timezoneType.type"
|
||||||
|
v-for="timezoneType in allTimezoneTypesUsedForStatistics">{{ timezoneType.displayName }}</option>
|
||||||
|
</select>
|
||||||
|
</f7-list-item>
|
||||||
</f7-list>
|
</f7-list>
|
||||||
|
|
||||||
<f7-block-title>{{ $t('Transaction List Page') }}</f7-block-title>
|
<f7-block-title>{{ $t('Transaction List Page') }}</f7-block-title>
|
||||||
@@ -31,10 +41,14 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useSettingsStore } from '@/stores/setting.js';
|
import { useSettingsStore } from '@/stores/setting.js';
|
||||||
|
import { useOverviewStore } from '@/stores/overview.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
computed: {
|
computed: {
|
||||||
...mapStores(useSettingsStore),
|
...mapStores(useSettingsStore, useOverviewStore),
|
||||||
|
allTimezoneTypesUsedForStatistics() {
|
||||||
|
return this.$locale.getAllTimezoneTypesUsedForStatistics();
|
||||||
|
},
|
||||||
showAmountInHomePage: {
|
showAmountInHomePage: {
|
||||||
get: function () {
|
get: function () {
|
||||||
return this.settingsStore.appSettings.showAmountInHomePage;
|
return this.settingsStore.appSettings.showAmountInHomePage;
|
||||||
@@ -43,6 +57,15 @@ export default {
|
|||||||
this.settingsStore.setShowAmountInHomePage(value);
|
this.settingsStore.setShowAmountInHomePage(value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
timezoneUsedForStatisticsInHomePage: {
|
||||||
|
get: function () {
|
||||||
|
return this.settingsStore.appSettings.timezoneUsedForStatisticsInHomePage;
|
||||||
|
},
|
||||||
|
set: function (value) {
|
||||||
|
this.settingsStore.setTimezoneUsedForStatisticsInHomePage(value);
|
||||||
|
this.overviewStore.updateTransactionOverviewInvalidState(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
showTotalAmountInTransactionListPage: {
|
showTotalAmountInTransactionListPage: {
|
||||||
get: function () {
|
get: function () {
|
||||||
return this.settingsStore.appSettings.showTotalAmountInTransactionListPage;
|
return this.settingsStore.appSettings.showTotalAmountInTransactionListPage;
|
||||||
|
|||||||
@@ -32,6 +32,16 @@
|
|||||||
</select>
|
</select>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
|
|
||||||
|
<f7-list-item
|
||||||
|
:title="$t('Timezone Used for Date Range')"
|
||||||
|
smart-select :smart-select-params="{ openIn: 'popup', popupPush: true, closeOnSelect: true, scrollToSelectedItem: true, searchbar: true, searchbarPlaceholder: $t('Timezone Type'), searchbarDisableText: $t('Cancel'), appendSearchbarNotFound: $t('No results'), popupCloseLinkText: $t('Done') }">
|
||||||
|
<select v-model="defaultTimezoneType">
|
||||||
|
<option :value="timezoneType.type"
|
||||||
|
:key="timezoneType.type"
|
||||||
|
v-for="timezoneType in allTimezoneTypesUsedForStatistics">{{ timezoneType.displayName }}</option>
|
||||||
|
</select>
|
||||||
|
</f7-list-item>
|
||||||
|
|
||||||
<f7-list-item :title="$t('Default Account Filter')" link="/statistic/filter/account?modifyDefault=1"></f7-list-item>
|
<f7-list-item :title="$t('Default Account Filter')" link="/statistic/filter/account?modifyDefault=1"></f7-list-item>
|
||||||
|
|
||||||
<f7-list-item :title="$t('Default Transaction Category Filter')" link="/statistic/filter/category?modifyDefault=1"></f7-list-item>
|
<f7-list-item :title="$t('Default Transaction Category Filter')" link="/statistic/filter/category?modifyDefault=1"></f7-list-item>
|
||||||
@@ -70,6 +80,9 @@ export default {
|
|||||||
allDateRanges() {
|
allDateRanges() {
|
||||||
return this.$locale.getAllDateRanges(false);
|
return this.$locale.getAllDateRanges(false);
|
||||||
},
|
},
|
||||||
|
allTimezoneTypesUsedForStatistics() {
|
||||||
|
return this.$locale.getAllTimezoneTypesUsedForStatistics();
|
||||||
|
},
|
||||||
defaultChartType: {
|
defaultChartType: {
|
||||||
get: function () {
|
get: function () {
|
||||||
return this.settingsStore.appSettings.statistics.defaultChartType;
|
return this.settingsStore.appSettings.statistics.defaultChartType;
|
||||||
@@ -94,6 +107,14 @@ export default {
|
|||||||
this.settingsStore.setStatisticsDefaultDateRange(value);
|
this.settingsStore.setStatisticsDefaultDateRange(value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
defaultTimezoneType: {
|
||||||
|
get: function () {
|
||||||
|
return this.settingsStore.appSettings.statistics.defaultTimezoneType;
|
||||||
|
},
|
||||||
|
set: function (value) {
|
||||||
|
this.settingsStore.setStatisticsDefaultTimezoneType(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
defaultSortingType: {
|
defaultSortingType: {
|
||||||
get: function () {
|
get: function () {
|
||||||
return this.settingsStore.appSettings.statistics.defaultSortingType;
|
return this.settingsStore.appSettings.statistics.defaultSortingType;
|
||||||
|
|||||||
Reference in New Issue
Block a user