mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-14 06:57:35 +08:00
support batch update categories for transactions in insights explorer
This commit is contained in:
@@ -1338,6 +1338,105 @@ func (a *TransactionsApi) TransactionModifyHandler(c *core.WebContext) (any, *er
|
||||
return newTransactionResp, nil
|
||||
}
|
||||
|
||||
// TransactionBatchUpdateCategoriesHandler batch updates categories of transactions by request parameters for current user
|
||||
func (a *TransactionsApi) TransactionBatchUpdateCategoriesHandler(c *core.WebContext) (any, *errs.Error) {
|
||||
var transactionBatchUpdateReq models.TransactionBatchUpdateCategoryRequest
|
||||
err := c.ShouldBindJSON(&transactionBatchUpdateReq)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf(c, "[transactions.TransactionBatchUpdateCategoriesHandler] parse request failed, because %s", err.Error())
|
||||
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
|
||||
}
|
||||
|
||||
clientTimezone, err := c.GetClientTimezone()
|
||||
|
||||
if err != nil {
|
||||
log.Warnf(c, "[transactions.TransactionBatchUpdateCategoriesHandler] cannot get client timezone, because %s", err.Error())
|
||||
return nil, errs.ErrClientTimezoneOffsetInvalid
|
||||
}
|
||||
|
||||
transactionIds, err := utils.StringArrayToInt64Array(transactionBatchUpdateReq.TransactionIds)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf(c, "[transactions.TransactionBatchUpdateCategoriesHandler] parse transaction ids failed, because %s", err.Error())
|
||||
return nil, errs.ErrTransactionIdInvalid
|
||||
}
|
||||
|
||||
uid := c.GetCurrentUid()
|
||||
user, err := a.users.GetUserById(c, uid)
|
||||
|
||||
if err != nil {
|
||||
if !errs.IsCustomError(err) {
|
||||
log.Errorf(c, "[transactions.TransactionBatchUpdateCategoriesHandler] failed to get user, because %s", err.Error())
|
||||
}
|
||||
|
||||
return nil, errs.ErrUserNotFound
|
||||
}
|
||||
|
||||
category, err := a.transactionCategories.GetCategoryByCategoryId(c, uid, transactionBatchUpdateReq.CategoryId)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transactions.TransactionBatchUpdateCategoriesHandler] failed to get category \"id:%d\" for user \"uid:%d\", because %s", transactionBatchUpdateReq.CategoryId, uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
if category.ParentCategoryId == models.LevelOneTransactionCategoryParentId {
|
||||
log.Warnf(c, "[transactions.TransactionBatchUpdateCategoriesHandler] transaction category \"id:%d\" is not a sub category", category.CategoryId)
|
||||
return nil, errs.ErrCannotUsePrimaryCategoryForTransaction
|
||||
}
|
||||
|
||||
var expectedTransactionType models.TransactionDbType
|
||||
|
||||
if category.Type == models.CATEGORY_TYPE_EXPENSE {
|
||||
expectedTransactionType = models.TRANSACTION_DB_TYPE_EXPENSE
|
||||
} else if category.Type == models.CATEGORY_TYPE_INCOME {
|
||||
expectedTransactionType = models.TRANSACTION_DB_TYPE_INCOME
|
||||
} else if category.Type == models.CATEGORY_TYPE_TRANSFER {
|
||||
expectedTransactionType = models.TRANSACTION_DB_TYPE_TRANSFER_OUT
|
||||
}
|
||||
|
||||
transactions, err := a.transactions.GetTransactionsByTransactionIds(c, uid, transactionIds)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transactions.TransactionBatchUpdateCategoriesHandler] failed to get transactions for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
allTransactionIds := make([]int64, 0, len(transactions))
|
||||
|
||||
for i := 0; i < len(transactions); i++ {
|
||||
transaction := transactions[i]
|
||||
|
||||
if transaction.Type != expectedTransactionType {
|
||||
log.Warnf(c, "[transactions.TransactionBatchUpdateCategoriesHandler] transaction \"id:%d\" type is not expected type \"%d\" for user \"uid:%d\"", transaction.TransactionId, expectedTransactionType, uid)
|
||||
return nil, errs.ErrTransactionTypeInvalid
|
||||
}
|
||||
|
||||
transactionEditable := user.CanEditTransactionByTransactionTime(transaction.TransactionTime, clientTimezone)
|
||||
|
||||
if !transactionEditable {
|
||||
log.Warnf(c, "[transactions.TransactionBatchUpdateCategoriesHandler] transaction \"id:%d\" is not editable for user \"uid:%d\"", transaction.TransactionId, uid)
|
||||
return nil, errs.ErrCannotModifyTransactionWithThisTransactionTime
|
||||
}
|
||||
|
||||
allTransactionIds = append(allTransactionIds, transaction.TransactionId)
|
||||
|
||||
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT {
|
||||
allTransactionIds = append(allTransactionIds, transaction.RelatedId)
|
||||
}
|
||||
}
|
||||
|
||||
err = a.transactions.BatchUpdateTransactionsCategory(c, uid, allTransactionIds, category.CategoryId)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transactions.TransactionBatchUpdateCategoriesHandler] failed to batch update transactions category for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
log.Infof(c, "[transactions.TransactionBatchUpdateCategoriesHandler] user \"uid:%d\" has batch updated category of %d transactions successfully", uid, len(transactionBatchUpdateReq.TransactionIds))
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// TransactionMoveAllBetweenAccountsHandler moves all transactions from one account to another account for current user
|
||||
func (a *TransactionsApi) TransactionMoveAllBetweenAccountsHandler(c *core.WebContext) (any, *errs.Error) {
|
||||
var transactionMoveReq models.TransactionMoveBetweenAccountsRequest
|
||||
|
||||
@@ -325,6 +325,12 @@ type TransactionGetRequest struct {
|
||||
TrimTag bool `form:"trim_tag"`
|
||||
}
|
||||
|
||||
// TransactionBatchUpdateCategoryRequest represents all parameters of transaction batch update category request
|
||||
type TransactionBatchUpdateCategoryRequest struct {
|
||||
TransactionIds []string `json:"transactionIds,string" binding:"required"`
|
||||
CategoryId int64 `json:"categoryId,string" binding:"required"`
|
||||
}
|
||||
|
||||
// TransactionMoveBetweenAccountsRequest represents all parameters of moving all transactions between accounts request
|
||||
type TransactionMoveBetweenAccountsRequest struct {
|
||||
FromAccountId int64 `json:"fromAccountId,string" binding:"required,min=1"`
|
||||
|
||||
@@ -434,6 +434,22 @@ func (s *TransactionService) GetTransactionByTransactionId(c core.Context, uid i
|
||||
return transaction, nil
|
||||
}
|
||||
|
||||
// GetTransactionsByTransactionIds returns transaction models according to transaction ids
|
||||
func (s *TransactionService) GetTransactionsByTransactionIds(c core.Context, uid int64, transactionIds []int64) ([]*models.Transaction, error) {
|
||||
if uid <= 0 {
|
||||
return nil, errs.ErrUserIdInvalid
|
||||
}
|
||||
|
||||
if len(transactionIds) <= 0 {
|
||||
return nil, errs.ErrTransactionIdInvalid
|
||||
}
|
||||
|
||||
var transactions []*models.Transaction
|
||||
err := s.UserDataDB(uid).NewSession(c).Where("uid=? AND deleted=?", uid, false).In("transaction_id", transactionIds).Find(&transactions)
|
||||
|
||||
return transactions, err
|
||||
}
|
||||
|
||||
// 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, false, "", "")
|
||||
@@ -1322,6 +1338,42 @@ func (s *TransactionService) ModifyTransaction(c core.Context, transaction *mode
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchUpdateTransactionsCategory batch updates the categories of transactions
|
||||
func (s *TransactionService) BatchUpdateTransactionsCategory(c core.Context, uid int64, transactionIds []int64, newCategoryId int64) error {
|
||||
if uid <= 0 {
|
||||
return errs.ErrUserIdInvalid
|
||||
}
|
||||
|
||||
if len(transactionIds) < 1 {
|
||||
return errs.ErrTransactionIdInvalid
|
||||
}
|
||||
|
||||
if newCategoryId <= 0 {
|
||||
return errs.ErrTransactionCategoryIdInvalid
|
||||
}
|
||||
|
||||
uniqueTransactionIds := utils.ToUniqueInt64Slice(transactionIds)
|
||||
now := time.Now().Unix()
|
||||
|
||||
updateModel := &models.Transaction{
|
||||
CategoryId: newCategoryId,
|
||||
UpdatedUnixTime: now,
|
||||
}
|
||||
|
||||
return s.UserDataDB(uid).DoTransaction(c, func(sess *xorm.Session) error {
|
||||
updatedRows, err := sess.Cols("category_id", "updated_unix_time").Where("uid=? AND deleted=?", uid, false).In("transaction_id", uniqueTransactionIds).Update(updateModel)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if updatedRows < int64(len(uniqueTransactionIds)) {
|
||||
return errs.ErrTransactionNotFound
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// MoveAllTransactionsBetweenAccounts moves all transactions from one account to another account, and combine balance modification transactions if necessary
|
||||
func (s *TransactionService) MoveAllTransactionsBetweenAccounts(c core.Context, uid int64, fromAccountId int64, toAccountId int64) error {
|
||||
if uid <= 0 {
|
||||
return errs.ErrUserIdInvalid
|
||||
|
||||
Reference in New Issue
Block a user