add transaction tag index
This commit is contained in:
@@ -107,5 +107,13 @@ func updateAllDatabaseTablesStructure() error {
|
|||||||
log.BootInfof("[database.updateAllDatabaseTablesStructure] transaction tag table maintained successfully")
|
log.BootInfof("[database.updateAllDatabaseTablesStructure] transaction tag table maintained successfully")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = datastore.Container.UserDataStore.SyncStructs(new(models.TransactionTagIndex))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
log.BootInfof("[database.updateAllDatabaseTablesStructure] transaction tag index table maintained successfully")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ func (a *TransactionTagsApi) TagDeleteHandler(c *core.Context) (interface{}, *er
|
|||||||
}
|
}
|
||||||
|
|
||||||
uid := c.GetCurrentUid()
|
uid := c.GetCurrentUid()
|
||||||
err = a.tags.DeleteTags(uid, []int64{tagDeleteReq.Id})
|
err = a.tags.DeleteTag(uid, tagDeleteReq.Id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ErrorfWithRequestId(c, "[transaction_tags.TagDeleteHandler] failed to delete tag \"id:%d\" for user \"uid:%d\", because %s", tagDeleteReq.Id, uid, err.Error())
|
log.ErrorfWithRequestId(c, "[transaction_tags.TagDeleteHandler] failed to delete tag \"id:%d\" for user \"uid:%d\", because %s", tagDeleteReq.Id, uid, err.Error())
|
||||||
|
|||||||
+60
-8
@@ -8,15 +8,18 @@ import (
|
|||||||
"github.com/mayswind/lab/pkg/log"
|
"github.com/mayswind/lab/pkg/log"
|
||||||
"github.com/mayswind/lab/pkg/models"
|
"github.com/mayswind/lab/pkg/models"
|
||||||
"github.com/mayswind/lab/pkg/services"
|
"github.com/mayswind/lab/pkg/services"
|
||||||
|
"github.com/mayswind/lab/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TransactionsApi struct {
|
type TransactionsApi struct {
|
||||||
transactions *services.TransactionService
|
transactions *services.TransactionService
|
||||||
|
transactionTags *services.TransactionTagService
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Transactions = &TransactionsApi{
|
Transactions = &TransactionsApi{
|
||||||
transactions: services.Transactions,
|
transactions: services.Transactions,
|
||||||
|
transactionTags: services.TransactionTags,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,11 +46,25 @@ func (a *TransactionsApi) TransactionListHandler(c *core.Context) (interface{},
|
|||||||
finalCount = len(transactions)
|
finalCount = len(transactions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transactionIds := make([]int64, finalCount)
|
||||||
|
|
||||||
|
for i := 0; i < finalCount; i++ {
|
||||||
|
transactionIds[i] = transactions[i].TransactionId
|
||||||
|
}
|
||||||
|
|
||||||
|
allTransactionTagIds, err := a.transactionTags.GetAllTagIdsOfTransactions(uid, transactionIds)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorfWithRequestId(c, "[transactions.TransactionListHandler] failed to get transactions tag ids for user \"uid:%d\", because %s", uid, err.Error())
|
||||||
|
return nil, errs.ErrOperationFailed
|
||||||
|
}
|
||||||
|
|
||||||
transactionResps := &models.TransactionInfoPageWrapperResponse{}
|
transactionResps := &models.TransactionInfoPageWrapperResponse{}
|
||||||
transactionResps.Items = make(models.TransactionInfoResponseSlice, finalCount)
|
transactionResps.Items = make(models.TransactionInfoResponseSlice, finalCount)
|
||||||
|
|
||||||
for i := 0; i < finalCount; i++ {
|
for i := 0; i < finalCount; i++ {
|
||||||
transactionResps.Items[i] = transactions[i].ToTransactionInfoResponse(nil)
|
transactionTagIds := allTransactionTagIds[transactions[i].TransactionId]
|
||||||
|
transactionResps.Items[i] = transactions[i].ToTransactionInfoResponse(transactionTagIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(transactionResps.Items)
|
sort.Sort(transactionResps.Items)
|
||||||
@@ -76,10 +93,24 @@ func (a *TransactionsApi) TransactionMonthListHandler(c *core.Context) (interfac
|
|||||||
return nil, errs.ErrOperationFailed
|
return nil, errs.ErrOperationFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transactionIds := make([]int64, len(transactions))
|
||||||
|
|
||||||
|
for i := 0; i < len(transactions); i++ {
|
||||||
|
transactionIds[i] = transactions[i].TransactionId
|
||||||
|
}
|
||||||
|
|
||||||
|
allTransactionTagIds, err := a.transactionTags.GetAllTagIdsOfTransactions(uid, transactionIds)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorfWithRequestId(c, "[transactions.TransactionMonthListHandler] failed to get transactions tag ids for user \"uid:%d\", because %s", uid, err.Error())
|
||||||
|
return nil, errs.ErrOperationFailed
|
||||||
|
}
|
||||||
|
|
||||||
transactionResps := make([]*models.TransactionInfoResponse, len(transactions))
|
transactionResps := make([]*models.TransactionInfoResponse, len(transactions))
|
||||||
|
|
||||||
for i := 0; i < len(transactions); i++ {
|
for i := 0; i < len(transactions); i++ {
|
||||||
transactionResps[i] = transactions[i].ToTransactionInfoResponse(nil)
|
transactionTagIds := allTransactionTagIds[transactions[i].TransactionId]
|
||||||
|
transactionResps[i] = transactions[i].ToTransactionInfoResponse(transactionTagIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transactionResps, nil
|
return transactionResps, nil
|
||||||
@@ -102,7 +133,15 @@ func (a *TransactionsApi) TransactionGetHandler(c *core.Context) (interface{}, *
|
|||||||
return nil, errs.ErrOperationFailed
|
return nil, errs.ErrOperationFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
transactionResp := transaction.ToTransactionInfoResponse(nil)
|
allTransactionTagIds, err := a.transactionTags.GetAllTagIdsOfTransactions(uid, []int64{transaction.TransactionId})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorfWithRequestId(c, "[transactions.TransactionGetHandler] failed to get transactions tag ids for user \"uid:%d\", because %s", uid, err.Error())
|
||||||
|
return nil, errs.ErrOperationFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionTagIds := allTransactionTagIds[transaction.TransactionId]
|
||||||
|
transactionResp := transaction.ToTransactionInfoResponse(transactionTagIds)
|
||||||
|
|
||||||
return transactionResp, nil
|
return transactionResp, nil
|
||||||
}
|
}
|
||||||
@@ -142,7 +181,7 @@ func (a *TransactionsApi) TransactionCreateHandler(c *core.Context) (interface{}
|
|||||||
uid := c.GetCurrentUid()
|
uid := c.GetCurrentUid()
|
||||||
transaction := a.createNewTransactionModel(uid, &transactionCreateReq)
|
transaction := a.createNewTransactionModel(uid, &transactionCreateReq)
|
||||||
|
|
||||||
err = a.transactions.CreateTransaction(transaction)
|
err = a.transactions.CreateTransaction(transaction, transactionCreateReq.TagIds)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ErrorfWithRequestId(c, "[transactions.TransactionCreateHandler] failed to create transaction \"id:%d\" for user \"uid:%d\", because %s", transaction.TransactionId, uid, err.Error())
|
log.ErrorfWithRequestId(c, "[transactions.TransactionCreateHandler] failed to create transaction \"id:%d\" for user \"uid:%d\", because %s", transaction.TransactionId, uid, err.Error())
|
||||||
@@ -173,6 +212,17 @@ func (a *TransactionsApi) TransactionModifyHandler(c *core.Context) (interface{}
|
|||||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allTransactionTagIds, err := a.transactionTags.GetAllTagIdsOfTransactions(uid, []int64{transaction.TransactionId})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorfWithRequestId(c, "[transactions.TransactionModifyHandler] failed to get transactions tag ids for user \"uid:%d\", because %s", uid, err.Error())
|
||||||
|
return nil, errs.ErrOperationFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionTagIds := allTransactionTagIds[transaction.TransactionId]
|
||||||
|
addTransactionTagIds := utils.Int64SliceMinus(transactionModifyReq.TagIds, transactionTagIds)
|
||||||
|
removeTransactionTagIds := utils.Int64SliceMinus(transactionTagIds, transactionModifyReq.TagIds)
|
||||||
|
|
||||||
newTransaction := &models.Transaction{
|
newTransaction := &models.Transaction{
|
||||||
TransactionId: transaction.TransactionId,
|
TransactionId: transaction.TransactionId,
|
||||||
Uid: uid,
|
Uid: uid,
|
||||||
@@ -191,11 +241,13 @@ func (a *TransactionsApi) TransactionModifyHandler(c *core.Context) (interface{}
|
|||||||
newTransaction.DestinationAccountId == transaction.DestinationAccountId &&
|
newTransaction.DestinationAccountId == transaction.DestinationAccountId &&
|
||||||
newTransaction.SourceAmount == transaction.SourceAmount &&
|
newTransaction.SourceAmount == transaction.SourceAmount &&
|
||||||
newTransaction.DestinationAmount == transaction.DestinationAmount &&
|
newTransaction.DestinationAmount == transaction.DestinationAmount &&
|
||||||
newTransaction.Comment == transaction.Comment {
|
newTransaction.Comment == transaction.Comment &&
|
||||||
|
len(addTransactionTagIds) < 1 &&
|
||||||
|
len(removeTransactionTagIds) < 1 {
|
||||||
return nil, errs.ErrNothingWillBeUpdated
|
return nil, errs.ErrNothingWillBeUpdated
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.transactions.ModifyTransaction(newTransaction)
|
err = a.transactions.ModifyTransaction(newTransaction, addTransactionTagIds, removeTransactionTagIds)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.ErrorfWithRequestId(c, "[transactions.TransactionModifyHandler] failed to update transaction \"id:%d\" for user \"uid:%d\", because %s", transactionModifyReq.Id, uid, err.Error())
|
log.ErrorfWithRequestId(c, "[transactions.TransactionModifyHandler] failed to update transaction \"id:%d\" for user \"uid:%d\", because %s", transactionModifyReq.Id, uid, err.Error())
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ package errs
|
|||||||
import "net/http"
|
import "net/http"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrTransactionTagIdInvalid = NewNormalError(NORMAL_SUBCATEGORY_TAG, 0, http.StatusBadRequest, "transaction tag id is invalid")
|
ErrTransactionTagIdInvalid = NewNormalError(NORMAL_SUBCATEGORY_TAG, 0, http.StatusBadRequest, "transaction tag id is invalid")
|
||||||
ErrTransactionTagNotFound = NewNormalError(NORMAL_SUBCATEGORY_TAG, 1, http.StatusBadRequest, "transaction tag not found")
|
ErrTransactionTagNotFound = NewNormalError(NORMAL_SUBCATEGORY_TAG, 1, http.StatusBadRequest, "transaction tag not found")
|
||||||
ErrTransactionTagNameIsEmpty = NewNormalError(NORMAL_SUBCATEGORY_TAG, 2, http.StatusBadRequest, "transaction tag name is empty")
|
ErrTransactionTagNameIsEmpty = NewNormalError(NORMAL_SUBCATEGORY_TAG, 2, http.StatusBadRequest, "transaction tag name is empty")
|
||||||
ErrTransactionTagNameAlreadyExists = NewNormalError(NORMAL_SUBCATEGORY_TAG, 3, http.StatusBadRequest, "transaction tag name already exists")
|
ErrTransactionTagNameAlreadyExists = NewNormalError(NORMAL_SUBCATEGORY_TAG, 3, http.StatusBadRequest, "transaction tag name already exists")
|
||||||
|
ErrTransactionTagInUseCannotBeDeleted = NewNormalError(NORMAL_SUBCATEGORY_TAG, 4, http.StatusBadRequest, "transaction tag is in use and cannot be deleted")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
type TransactionTagIndex struct {
|
||||||
|
Uid int64 `xorm:"PK INDEX(IDX_transaction_tag_index_uid_tag_id_transaction_time) INDEX(IDX_transaction_tag_index_uid_transaction_id)"`
|
||||||
|
TagId int64 `xorm:"PK INDEX(IDX_transaction_tag_index_uid_tag_id_transaction_time)"`
|
||||||
|
TransactionId int64 `xorm:"PK INDEX(IDX_transaction_tag_index_uid_transaction_id)"`
|
||||||
|
TransactionTime int64 `xorm:"INDEX(IDX_transaction_tag_index_uid_tag_id_transaction_time) NOT NULL"`
|
||||||
|
CreatedUnixTime int64
|
||||||
|
UpdatedUnixTime int64
|
||||||
|
}
|
||||||
@@ -78,6 +78,32 @@ func (s *TransactionTagService) GetMaxDisplayOrder(uid int64) (int, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TransactionTagService) GetAllTagIdsOfTransactions(uid int64, transactionIds []int64) (map[int64][]int64, error) {
|
||||||
|
if uid <= 0 {
|
||||||
|
return nil, errs.ErrUserIdInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
var tagIndexs []*models.TransactionTagIndex
|
||||||
|
err := s.UserDataDB(uid).Where("uid=?", uid).In("transaction_id", transactionIds).Find(&tagIndexs)
|
||||||
|
|
||||||
|
allTransactionTagIds := make(map[int64][]int64)
|
||||||
|
|
||||||
|
for i := 0; i < len(tagIndexs); i++ {
|
||||||
|
tagIndex := tagIndexs[i]
|
||||||
|
|
||||||
|
var transactionTagIds []int64
|
||||||
|
|
||||||
|
if _, exists := allTransactionTagIds[tagIndex.TransactionId]; exists {
|
||||||
|
transactionTagIds = allTransactionTagIds[tagIndex.TransactionId]
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionTagIds = append(transactionTagIds, tagIndex.TagId)
|
||||||
|
allTransactionTagIds[tagIndex.TransactionId] = transactionTagIds
|
||||||
|
}
|
||||||
|
|
||||||
|
return allTransactionTagIds, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TransactionTagService) CreateTag(tag *models.TransactionTag) error {
|
func (s *TransactionTagService) CreateTag(tag *models.TransactionTag) error {
|
||||||
if tag.Uid <= 0 {
|
if tag.Uid <= 0 {
|
||||||
return errs.ErrUserIdInvalid
|
return errs.ErrUserIdInvalid
|
||||||
@@ -180,13 +206,19 @@ func (s *TransactionTagService) ModifyTagDisplayOrders(uid int64, tags []*models
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TransactionTagService) DeleteTags(uid int64, ids []int64) error {
|
func (s *TransactionTagService) DeleteTag(uid int64, tagId int64) error {
|
||||||
if uid <= 0 {
|
if uid <= 0 {
|
||||||
return errs.ErrUserIdInvalid
|
return errs.ErrUserIdInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.UserDataDB(uid).DoTransaction(func(sess *xorm.Session) error {
|
return s.UserDataDB(uid).DoTransaction(func(sess *xorm.Session) error {
|
||||||
deletedRows, err := sess.In("tag_id", ids).Where("uid=?", uid).Delete(&models.TransactionTag{})
|
exists, err := sess.Cols("uid", "tag_id").Where("uid=? AND tag_id=?", uid, tagId).Limit(1).Exist(&models.TransactionTagIndex{})
|
||||||
|
|
||||||
|
if exists {
|
||||||
|
return errs.ErrTransactionTagInUseCannotBeDeleted
|
||||||
|
}
|
||||||
|
|
||||||
|
deletedRows, err := sess.ID(tagId).Where("uid=?", uid).Delete(&models.TransactionTag{})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ func (s *TransactionService) GetMonthTransactionCount(uid int64, year int64, mon
|
|||||||
return s.UserDataDB(uid).Where("uid=? AND deleted=? AND transaction_time>=? AND transaction_time<?", uid, false, startUnixTime, endUnixTime).Count(&models.Transaction{})
|
return s.UserDataDB(uid).Where("uid=? AND deleted=? AND transaction_time>=? AND transaction_time<?", uid, false, startUnixTime, endUnixTime).Count(&models.Transaction{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TransactionService) CreateTransaction(transaction *models.Transaction) error {
|
func (s *TransactionService) CreateTransaction(transaction *models.Transaction, tagIds []int64) error {
|
||||||
if transaction.Uid <= 0 {
|
if transaction.Uid <= 0 {
|
||||||
return errs.ErrUserIdInvalid
|
return errs.ErrUserIdInvalid
|
||||||
}
|
}
|
||||||
@@ -143,11 +143,26 @@ func (s *TransactionService) CreateTransaction(transaction *models.Transaction)
|
|||||||
return errs.ErrTransactionTypeInvalid
|
return errs.ErrTransactionTypeInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
now := time.Now().Unix()
|
||||||
|
|
||||||
transaction.TransactionId = s.GenerateUuid(uuid.UUID_TYPE_TRANSACTION)
|
transaction.TransactionId = s.GenerateUuid(uuid.UUID_TYPE_TRANSACTION)
|
||||||
transaction.TransactionTime = utils.GetMinTransactionTimeFromUnixTime(utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime))
|
transaction.TransactionTime = utils.GetMinTransactionTimeFromUnixTime(utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime))
|
||||||
|
|
||||||
transaction.CreatedUnixTime = time.Now().Unix()
|
transaction.CreatedUnixTime = now
|
||||||
transaction.UpdatedUnixTime = time.Now().Unix()
|
transaction.UpdatedUnixTime = now
|
||||||
|
|
||||||
|
tagIds = utils.ToUniqueInt64Slice(tagIds)
|
||||||
|
transactionTagIndexs := make([]*models.TransactionTagIndex, len(tagIds))
|
||||||
|
|
||||||
|
for i := 0; i < len(tagIds); i++ {
|
||||||
|
transactionTagIndexs[i] = &models.TransactionTagIndex{
|
||||||
|
Uid: transaction.Uid,
|
||||||
|
TagId: tagIds[i],
|
||||||
|
TransactionId: transaction.TransactionId,
|
||||||
|
CreatedUnixTime: now,
|
||||||
|
UpdatedUnixTime: now,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return s.UserDataDB(transaction.Uid).DoTransaction(func(sess *xorm.Session) error {
|
return s.UserDataDB(transaction.Uid).DoTransaction(func(sess *xorm.Session) error {
|
||||||
// Get and verify source and destination account
|
// Get and verify source and destination account
|
||||||
@@ -204,6 +219,28 @@ func (s *TransactionService) CreateTransaction(transaction *models.Transaction)
|
|||||||
return errs.ErrTransactionCategoryTypeInvalid
|
return errs.ErrTransactionCategoryTypeInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get and verify tags
|
||||||
|
if len(transactionTagIndexs) > 0 {
|
||||||
|
var tags []*models.TransactionTag
|
||||||
|
err := sess.Where("uid=? AND deleted=?", transaction.Uid, false).In("tag_ids", tagIds).Find(&tags)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tagMap := make(map[int64]*models.TransactionTag)
|
||||||
|
|
||||||
|
for i := 0; i < len(tags); i++ {
|
||||||
|
tagMap[tags[i].TagId] = tags[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(transactionTagIndexs); i++ {
|
||||||
|
if _, exists := tagMap[transactionTagIndexs[i].TagId]; !exists {
|
||||||
|
return errs.ErrTransactionTagNotFound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Verify balance modification transaction and calculate real amount
|
// Verify balance modification transaction and calculate real amount
|
||||||
if transaction.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE {
|
if transaction.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE {
|
||||||
otherTransactionExists, err := sess.Where("uid=? AND deleted=? AND destination_account_id=?", transaction.Uid, false, destinationAccount.AccountId).Limit(1).Exist(&models.Transaction{})
|
otherTransactionExists, err := sess.Where("uid=? AND deleted=? AND destination_account_id=?", transaction.Uid, false, destinationAccount.AccountId).Limit(1).Exist(&models.Transaction{})
|
||||||
@@ -245,6 +282,18 @@ func (s *TransactionService) CreateTransaction(transaction *models.Transaction)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Insert transaction tag index
|
||||||
|
if len(transactionTagIndexs) > 0 {
|
||||||
|
for i := 0; i < len(transactionTagIndexs); i++ {
|
||||||
|
transactionTagIndex := transactionTagIndexs[i]
|
||||||
|
_, err := sess.Insert(transactionTagIndex)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update account table
|
// Update account table
|
||||||
if transaction.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE {
|
if transaction.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE {
|
||||||
destinationAccount.UpdatedUnixTime = time.Now().Unix()
|
destinationAccount.UpdatedUnixTime = time.Now().Unix()
|
||||||
@@ -297,7 +346,7 @@ func (s *TransactionService) CreateTransaction(transaction *models.Transaction)
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TransactionService) ModifyTransaction(transaction *models.Transaction) error {
|
func (s *TransactionService) ModifyTransaction(transaction *models.Transaction, addTagIds []int64, removeTagIds []int64) error {
|
||||||
if transaction.Uid <= 0 {
|
if transaction.Uid <= 0 {
|
||||||
return errs.ErrUserIdInvalid
|
return errs.ErrUserIdInvalid
|
||||||
}
|
}
|
||||||
@@ -310,6 +359,21 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction)
|
|||||||
transaction.UpdatedUnixTime = now
|
transaction.UpdatedUnixTime = now
|
||||||
updateCols = append(updateCols, "updated_unix_time")
|
updateCols = append(updateCols, "updated_unix_time")
|
||||||
|
|
||||||
|
addTagIds = utils.ToUniqueInt64Slice(addTagIds)
|
||||||
|
removeTagIds = utils.ToUniqueInt64Slice(removeTagIds)
|
||||||
|
|
||||||
|
transactionTagIndexs := make([]*models.TransactionTagIndex, len(addTagIds))
|
||||||
|
|
||||||
|
for i := 0; i < len(addTagIds); i++ {
|
||||||
|
transactionTagIndexs[i] = &models.TransactionTagIndex{
|
||||||
|
Uid: transaction.Uid,
|
||||||
|
TagId: addTagIds[i],
|
||||||
|
TransactionId: transaction.TransactionId,
|
||||||
|
CreatedUnixTime: now,
|
||||||
|
UpdatedUnixTime: now,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := s.UserDB().DoTransaction(func(sess *xorm.Session) error {
|
err := s.UserDB().DoTransaction(func(sess *xorm.Session) error {
|
||||||
// Get and verify current transaction
|
// Get and verify current transaction
|
||||||
oldTransaction := &models.Transaction{}
|
oldTransaction := &models.Transaction{}
|
||||||
@@ -435,6 +499,28 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction)
|
|||||||
updateCols = append(updateCols, "comment")
|
updateCols = append(updateCols, "comment")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get and verify tags
|
||||||
|
if len(transactionTagIndexs) > 0 {
|
||||||
|
var tags []*models.TransactionTag
|
||||||
|
err := sess.Where("uid=? AND deleted=?", transaction.Uid, false).In("tag_ids", addTagIds).Find(&tags)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tagMap := make(map[int64]*models.TransactionTag)
|
||||||
|
|
||||||
|
for i := 0; i < len(tags); i++ {
|
||||||
|
tagMap[tags[i].TagId] = tags[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(transactionTagIndexs); i++ {
|
||||||
|
if _, exists := tagMap[transactionTagIndexs[i].TagId]; !exists {
|
||||||
|
return errs.ErrTransactionTagNotFound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update transaction row
|
// Update transaction row
|
||||||
updatedRows, err := sess.ID(transaction.TransactionId).Cols(updateCols...).Where("uid=? AND deleted=?", transaction.Uid, false).Update(transaction)
|
updatedRows, err := sess.ID(transaction.TransactionId).Cols(updateCols...).Where("uid=? AND deleted=?", transaction.Uid, false).Update(transaction)
|
||||||
|
|
||||||
@@ -444,6 +530,30 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction)
|
|||||||
return errs.ErrTransactionNotFound
|
return errs.ErrTransactionNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update transaction tag index
|
||||||
|
if len(removeTagIds) > 0 {
|
||||||
|
deletedRows, err := sess.Where("uid=?", transaction.Uid).In("tag_id", removeTagIds).Delete(&models.TransactionTagIndex{})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if deletedRows < 1 {
|
||||||
|
return errs.ErrTransactionTagNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(transactionTagIndexs) > 0 {
|
||||||
|
for i := 0; i < len(transactionTagIndexs); i++ {
|
||||||
|
transactionTagIndex := transactionTagIndexs[i]
|
||||||
|
_, err := sess.Insert(transactionTagIndex)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update account table
|
// Update account table
|
||||||
if oldTransaction.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE {
|
if oldTransaction.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE {
|
||||||
if transaction.SourceAccountId != oldTransaction.SourceAccountId {
|
if transaction.SourceAccountId != oldTransaction.SourceAccountId {
|
||||||
|
|||||||
@@ -17,3 +17,40 @@ func IsStringSliceEuqals(s1, s2 []string) bool {
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Int64SliceMinus(s1, s2 []int64) []int64 {
|
||||||
|
if s1 == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s2ItemsMap := make(map[int64]bool)
|
||||||
|
var ret []int64
|
||||||
|
|
||||||
|
for i := 0; i < len(s2); i++ {
|
||||||
|
s2ItemsMap[s2[i]] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(s1); i++ {
|
||||||
|
if _, exists := s2ItemsMap[s1[i]]; !exists {
|
||||||
|
ret = append(ret, s1[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToUniqueInt64Slice(items []int64) []int64 {
|
||||||
|
var uniqueItems []int64
|
||||||
|
itemExistMap := make(map[int64]bool)
|
||||||
|
|
||||||
|
for i := 0; i < len(items); i++ {
|
||||||
|
item := items[i]
|
||||||
|
|
||||||
|
if _, exists := itemExistMap[item]; !exists {
|
||||||
|
uniqueItems = append(uniqueItems, item)
|
||||||
|
itemExistMap[item] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniqueItems
|
||||||
|
}
|
||||||
|
|||||||
@@ -329,6 +329,7 @@ export default {
|
|||||||
'transaction tag not found': 'Transaction tag is not found',
|
'transaction tag not found': 'Transaction tag is not found',
|
||||||
'transaction tag name is empty': 'Transaction tag title is empty',
|
'transaction tag name is empty': 'Transaction tag title is empty',
|
||||||
'transaction tag name already exists': 'Transaction tag title already exists',
|
'transaction tag name already exists': 'Transaction tag title already exists',
|
||||||
|
'transaction tag is in use and cannot be deleted': 'Transaction tag is in use and it cannot be deleted',
|
||||||
},
|
},
|
||||||
'parameter': {
|
'parameter': {
|
||||||
'id': 'ID',
|
'id': 'ID',
|
||||||
|
|||||||
@@ -329,6 +329,7 @@ export default {
|
|||||||
'transaction tag not found': '交易标签不存在',
|
'transaction tag not found': '交易标签不存在',
|
||||||
'transaction tag name is empty': '交易标签标题不能为空',
|
'transaction tag name is empty': '交易标签标题不能为空',
|
||||||
'transaction tag name already exists': '交易标签标题已经存在',
|
'transaction tag name already exists': '交易标签标题已经存在',
|
||||||
|
'transaction tag is in use and cannot be deleted': '交易标签正在被使用,无法删除',
|
||||||
},
|
},
|
||||||
'parameter': {
|
'parameter': {
|
||||||
'id': 'ID',
|
'id': 'ID',
|
||||||
|
|||||||
Reference in New Issue
Block a user