From 30ebe4987551327f5f69b7aa57a02211fe1dce61 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Fri, 26 Jul 2024 00:22:11 +0800 Subject: [PATCH] allow to filter without tags --- pkg/api/transactions.go | 47 ++++++++++++++------- pkg/services/transactions.go | 30 ++++++++++--- src/locales/en.js | 1 + src/locales/zh_Hans.js | 1 + src/views/desktop/transactions/ListPage.vue | 13 ++++++ src/views/mobile/transactions/ListPage.vue | 5 +++ 6 files changed, 76 insertions(+), 21 deletions(-) diff --git a/pkg/api/transactions.go b/pkg/api/transactions.go index 8b27373b..1939cd16 100644 --- a/pkg/api/transactions.go +++ b/pkg/api/transactions.go @@ -62,14 +62,19 @@ func (a *TransactionsApi) TransactionCountHandler(c *core.Context) (any, *errs.E return nil, errs.Or(err, errs.ErrOperationFailed) } - allTagIds, err := a.getTagIds(transactionCountReq.TagIds) + var allTagIds []int64 + noTags := transactionCountReq.TagIds == "none" - if err != nil { - log.WarnfWithRequestId(c, "[transactions.TransactionCountHandler] get transaction tag ids error, because %s", err.Error()) - return nil, errs.Or(err, errs.ErrOperationFailed) + if !noTags { + allTagIds, err = a.getTagIds(transactionCountReq.TagIds) + + if err != nil { + log.WarnfWithRequestId(c, "[transactions.TransactionCountHandler] get transaction tag ids error, because %s", err.Error()) + return nil, errs.Or(err, errs.ErrOperationFailed) + } } - totalCount, err := a.transactions.GetTransactionCount(c, uid, transactionCountReq.MaxTime, transactionCountReq.MinTime, transactionCountReq.Type, allCategoryIds, allAccountIds, allTagIds, transactionCountReq.AmountFilter, transactionCountReq.Keyword) + totalCount, err := a.transactions.GetTransactionCount(c, uid, transactionCountReq.MaxTime, transactionCountReq.MinTime, transactionCountReq.Type, allCategoryIds, allAccountIds, allTagIds, noTags, transactionCountReq.AmountFilter, transactionCountReq.Keyword) if err != nil { log.ErrorfWithRequestId(c, "[transactions.TransactionCountHandler] failed to get transaction count for user \"uid:%d\", because %s", uid, err.Error()) @@ -125,17 +130,22 @@ func (a *TransactionsApi) TransactionListHandler(c *core.Context) (any, *errs.Er return nil, errs.Or(err, errs.ErrOperationFailed) } - allTagIds, err := a.getTagIds(transactionListReq.TagIds) + var allTagIds []int64 + noTags := transactionListReq.TagIds == "none" - if err != nil { - log.WarnfWithRequestId(c, "[transactions.TransactionListHandler] get transaction tag ids error, because %s", err.Error()) - return nil, errs.Or(err, errs.ErrOperationFailed) + if !noTags { + allTagIds, err = a.getTagIds(transactionListReq.TagIds) + + if err != nil { + log.WarnfWithRequestId(c, "[transactions.TransactionListHandler] get transaction tag ids error, because %s", err.Error()) + return nil, errs.Or(err, errs.ErrOperationFailed) + } } var totalCount int64 if transactionListReq.WithCount { - totalCount, err = a.transactions.GetTransactionCount(c, uid, transactionListReq.MaxTime, transactionListReq.MinTime, transactionListReq.Type, allCategoryIds, allAccountIds, allTagIds, transactionListReq.AmountFilter, transactionListReq.Keyword) + totalCount, err = a.transactions.GetTransactionCount(c, uid, transactionListReq.MaxTime, transactionListReq.MinTime, transactionListReq.Type, allCategoryIds, allAccountIds, allTagIds, noTags, transactionListReq.AmountFilter, transactionListReq.Keyword) if err != nil { log.ErrorfWithRequestId(c, "[transactions.TransactionListHandler] failed to get transaction count for user \"uid:%d\", because %s", uid, err.Error()) @@ -143,7 +153,7 @@ func (a *TransactionsApi) TransactionListHandler(c *core.Context) (any, *errs.Er } } - transactions, err := a.transactions.GetTransactionsByMaxTime(c, uid, transactionListReq.MaxTime, transactionListReq.MinTime, transactionListReq.Type, allCategoryIds, allAccountIds, allTagIds, transactionListReq.AmountFilter, transactionListReq.Keyword, transactionListReq.Page, transactionListReq.Count, true, true) + transactions, err := a.transactions.GetTransactionsByMaxTime(c, uid, transactionListReq.MaxTime, transactionListReq.MinTime, transactionListReq.Type, allCategoryIds, allAccountIds, allTagIds, noTags, transactionListReq.AmountFilter, transactionListReq.Keyword, transactionListReq.Page, transactionListReq.Count, true, true) if err != nil { log.ErrorfWithRequestId(c, "[transactions.TransactionListHandler] failed to get transactions earlier than \"%d\" for user \"uid:%d\", because %s", transactionListReq.MaxTime, uid, err.Error()) @@ -223,14 +233,19 @@ func (a *TransactionsApi) TransactionMonthListHandler(c *core.Context) (any, *er return nil, errs.Or(err, errs.ErrOperationFailed) } - allTagIds, err := a.getTagIds(transactionListReq.TagIds) + var allTagIds []int64 + noTags := transactionListReq.TagIds == "none" - if err != nil { - log.WarnfWithRequestId(c, "[transactions.TransactionMonthListHandler] get transaction tag ids error, because %s", err.Error()) - return nil, errs.Or(err, errs.ErrOperationFailed) + if !noTags { + allTagIds, err = a.getTagIds(transactionListReq.TagIds) + + if err != nil { + log.WarnfWithRequestId(c, "[transactions.TransactionMonthListHandler] get transaction tag ids error, because %s", err.Error()) + return nil, errs.Or(err, errs.ErrOperationFailed) + } } - transactions, err := a.transactions.GetTransactionsInMonthByPage(c, uid, transactionListReq.Year, transactionListReq.Month, transactionListReq.Type, allCategoryIds, allAccountIds, allTagIds, transactionListReq.AmountFilter, transactionListReq.Keyword) + transactions, err := a.transactions.GetTransactionsInMonthByPage(c, uid, transactionListReq.Year, transactionListReq.Month, transactionListReq.Type, allCategoryIds, allAccountIds, allTagIds, noTags, transactionListReq.AmountFilter, transactionListReq.Keyword) if err != nil { log.ErrorfWithRequestId(c, "[transactions.TransactionMonthListHandler] failed to get transactions in month \"%d-%d\" for user \"uid:%d\", because %s", transactionListReq.Year, transactionListReq.Month, uid, err.Error()) diff --git a/pkg/services/transactions.go b/pkg/services/transactions.go index 9997d0e3..8030211d 100644 --- a/pkg/services/transactions.go +++ b/pkg/services/transactions.go @@ -74,11 +74,11 @@ func (s *TransactionService) GetAllTransactions(c *core.Context, uid int64, page // GetAllTransactionsByMaxTime returns all transactions before given time func (s *TransactionService) GetAllTransactionsByMaxTime(c *core.Context, uid int64, maxTransactionTime int64, count int32, noDuplicated bool) ([]*models.Transaction, error) { - return s.GetTransactionsByMaxTime(c, uid, maxTransactionTime, 0, 0, nil, nil, nil, "", "", 1, count, false, noDuplicated) + return s.GetTransactionsByMaxTime(c, uid, maxTransactionTime, 0, 0, nil, nil, nil, false, "", "", 1, count, false, noDuplicated) } // GetTransactionsByMaxTime returns transactions before given time -func (s *TransactionService) GetTransactionsByMaxTime(c *core.Context, uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, tagIds []int64, amountFilter string, keyword string, page int32, count int32, needOneMoreItem bool, noDuplicated bool) ([]*models.Transaction, error) { +func (s *TransactionService) GetTransactionsByMaxTime(c *core.Context, uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, tagIds []int64, noTags bool, amountFilter string, keyword string, page int32, count int32, needOneMoreItem bool, noDuplicated bool) ([]*models.Transaction, error) { if uid <= 0 { return nil, errs.ErrUserIdInvalid } @@ -107,6 +107,8 @@ func (s *TransactionService) GetTransactionsByMaxTime(c *core.Context, uid int64 if len(tagIds) > 0 { sess.In("transaction_id", s.getTransactionQueryByTagIdsCondition(uid, maxTransactionTime, minTransactionTime, tagIds)) + } else if noTags { + sess.NotIn("transaction_id", s.getTransactionQueryByAllTagIdsCondition(uid, maxTransactionTime, minTransactionTime)) } err = sess.Limit(int(actualCount), int(count*(page-1))).OrderBy("transaction_time desc").Find(&transactions) @@ -115,7 +117,7 @@ func (s *TransactionService) GetTransactionsByMaxTime(c *core.Context, uid int64 } // GetTransactionsInMonthByPage returns all transactions in given year and month -func (s *TransactionService) GetTransactionsInMonthByPage(c *core.Context, uid int64, year int32, month int32, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, tagIds []int64, amountFilter string, keyword string) ([]*models.Transaction, error) { +func (s *TransactionService) GetTransactionsInMonthByPage(c *core.Context, uid int64, year int32, month int32, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, tagIds []int64, noTags bool, amountFilter string, keyword string) ([]*models.Transaction, error) { if uid <= 0 { return nil, errs.ErrUserIdInvalid } @@ -133,6 +135,8 @@ func (s *TransactionService) GetTransactionsInMonthByPage(c *core.Context, uid i if len(tagIds) > 0 { sess.In("transaction_id", s.getTransactionQueryByTagIdsCondition(uid, maxTransactionTime, minTransactionTime, tagIds)) + } else if noTags { + sess.NotIn("transaction_id", s.getTransactionQueryByAllTagIdsCondition(uid, maxTransactionTime, minTransactionTime)) } err = sess.OrderBy("transaction_time desc").Find(&transactions) @@ -176,11 +180,11 @@ func (s *TransactionService) GetTransactionByTransactionId(c *core.Context, uid // GetAllTransactionCount returns total count of transactions func (s *TransactionService) GetAllTransactionCount(c *core.Context, uid int64) (int64, error) { - return s.GetTransactionCount(c, uid, 0, 0, 0, nil, nil, nil, "", "") + return s.GetTransactionCount(c, uid, 0, 0, 0, nil, nil, nil, false, "", "") } // GetTransactionCount returns count of transactions -func (s *TransactionService) GetTransactionCount(c *core.Context, uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, tagIds []int64, amountFilter string, keyword string) (int64, error) { +func (s *TransactionService) GetTransactionCount(c *core.Context, uid int64, maxTransactionTime int64, minTransactionTime int64, transactionType models.TransactionDbType, categoryIds []int64, accountIds []int64, tagIds []int64, noTags bool, amountFilter string, keyword string) (int64, error) { if uid <= 0 { return 0, errs.ErrUserIdInvalid } @@ -190,6 +194,8 @@ func (s *TransactionService) GetTransactionCount(c *core.Context, uid int64, max if len(tagIds) > 0 { sess.In("transaction_id", s.getTransactionQueryByTagIdsCondition(uid, maxTransactionTime, minTransactionTime, tagIds)) + } else if noTags { + sess.NotIn("transaction_id", s.getTransactionQueryByAllTagIdsCondition(uid, maxTransactionTime, minTransactionTime)) } return sess.Count(&models.Transaction{}) @@ -1535,6 +1541,20 @@ func (s *TransactionService) getTransactionQueryByTagIdsCondition(uid int64, max return nil } +func (s *TransactionService) getTransactionQueryByAllTagIdsCondition(uid int64, maxTransactionTime int64, minTransactionTime int64) *builder.Builder { + condition := builder.And(builder.Eq{"uid": uid}, builder.Eq{"deleted": false}) + + if maxTransactionTime > 0 { + condition = condition.And(builder.Lte{"transaction_time": maxTransactionTime}) + } + + if minTransactionTime > 0 { + condition = condition.And(builder.Gte{"transaction_time": minTransactionTime}) + } + + return builder.Select("transaction_id").From("transaction_tag_index").Where(condition) +} + func (s *TransactionService) isAccountIdValid(transaction *models.Transaction) error { if transaction.Type == models.TRANSACTION_DB_TYPE_MODIFY_BALANCE { if transaction.RelatedAccountId != 0 && transaction.RelatedAccountId != transaction.AccountId { diff --git a/src/locales/en.js b/src/locales/en.js index b9c3cb7b..82768081 100644 --- a/src/locales/en.js +++ b/src/locales/en.js @@ -1032,6 +1032,7 @@ export default { 'Multiple Accounts': 'Multiple Accounts', 'Source Account': 'Source Account', 'Destination Account': 'Destination Account', + 'Without Tags': 'Without Tags', 'Multiple Tags': 'Multiple Tags', 'Transaction Time': 'Transaction Time', 'Transaction Timezone': 'Transaction Timezone', diff --git a/src/locales/zh_Hans.js b/src/locales/zh_Hans.js index ee1fa4c7..38505c70 100644 --- a/src/locales/zh_Hans.js +++ b/src/locales/zh_Hans.js @@ -1032,6 +1032,7 @@ export default { 'Multiple Accounts': '多个账户', 'Source Account': '来源账户', 'Destination Account': '目标账户', + 'Without Tags': '没有标签', 'Multiple Tags': '多个标签', 'Transaction Time': '交易时间', 'Transaction Timezone': '交易时区', diff --git a/src/views/desktop/transactions/ListPage.vue b/src/views/desktop/transactions/ListPage.vue index ff904bbb..19f55878 100644 --- a/src/views/desktop/transactions/ListPage.vue +++ b/src/views/desktop/transactions/ListPage.vue @@ -331,6 +331,17 @@ + + +
+ + {{ $t('Without Tags') }} +
+
+
+ + +