move all transactions from one account to another account (#288)

This commit is contained in:
MaysWind
2025-10-11 01:10:13 +08:00
parent 3ce7f6e99a
commit 2cb47bfd75
29 changed files with 974 additions and 41 deletions
+57
View File
@@ -1114,6 +1114,63 @@ func (a *TransactionsApi) TransactionModifyHandler(c *core.WebContext) (any, *er
return newTransactionResp, 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
err := c.ShouldBindJSON(&transactionMoveReq)
if err != nil {
log.Warnf(c, "[transactions.TransactionMoveAllBetweenAccountsHandler] parse request failed, because %s", err.Error())
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
}
if transactionMoveReq.FromAccountId == transactionMoveReq.ToAccountId {
return nil, errs.ErrCannotMoveTransactionToSameAccount
}
uid := c.GetCurrentUid()
accountMap, err := a.accounts.GetAccountsByAccountIds(c, uid, []int64{transactionMoveReq.FromAccountId, transactionMoveReq.ToAccountId})
if err != nil {
log.Errorf(c, "[transactions.TransactionMoveAllBetweenAccountsHandler] failed to get accounts for user \"uid:%d\", because %s", uid, err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed)
}
fromAccount, exists := accountMap[transactionMoveReq.FromAccountId]
if !exists {
return nil, errs.ErrSourceAccountNotFound
}
toAccount, exists := accountMap[transactionMoveReq.ToAccountId]
if !exists {
return nil, errs.ErrDestinationAccountNotFound
}
if fromAccount.Hidden || toAccount.Hidden {
return nil, errs.ErrCannotMoveTransactionFromOrToHiddenAccount
}
if fromAccount.Type == models.ACCOUNT_TYPE_MULTI_SUB_ACCOUNTS || toAccount.Type == models.ACCOUNT_TYPE_MULTI_SUB_ACCOUNTS {
return nil, errs.ErrCannotMoveTransactionFromOrToParentAccount
}
if fromAccount.Currency != toAccount.Currency {
return nil, errs.ErrCannotMoveTransactionBetweenAccountsWithDifferentCurrencies
}
err = a.transactions.MoveAllTransactionsBetweenAccounts(c, uid, transactionMoveReq.FromAccountId, transactionMoveReq.ToAccountId)
if err != nil {
log.Errorf(c, "[transactions.TransactionMoveAllBetweenAccountsHandler] failed to move all transactions from account \"id:%d\" to account \"id:%d\" for user \"uid:%d\", because %s", transactionMoveReq.FromAccountId, transactionMoveReq.ToAccountId, uid, err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed)
}
log.Infof(c, "[transactions.TransactionMoveAllBetweenAccountsHandler] user \"uid:%d\" has moved all transactions from account \"id:%d\" to account \"id:%d\" successfully", uid, transactionMoveReq.FromAccountId, transactionMoveReq.ToAccountId)
return true, nil
}
// TransactionDeleteHandler deletes an existed transaction by request parameters for current user
func (a *TransactionsApi) TransactionDeleteHandler(c *core.WebContext) (any, *errs.Error) {
var transactionDeleteReq models.TransactionDeleteRequest
+41 -37
View File
@@ -4,41 +4,45 @@ import "net/http"
// Error codes related to transaction
var (
ErrTransactionIdInvalid = NewNormalError(NormalSubcategoryTransaction, 0, http.StatusBadRequest, "transaction id is invalid")
ErrTransactionNotFound = NewNormalError(NormalSubcategoryTransaction, 1, http.StatusBadRequest, "transaction not found")
ErrTransactionTypeInvalid = NewNormalError(NormalSubcategoryTransaction, 2, http.StatusBadRequest, "transaction type is invalid")
ErrTransactionSourceAndDestinationIdCannotBeEqual = NewNormalError(NormalSubcategoryTransaction, 3, http.StatusBadRequest, "transaction source and destination account id cannot be equal")
ErrTransactionSourceAndDestinationAmountNotEqual = NewNormalError(NormalSubcategoryTransaction, 4, http.StatusBadRequest, "transaction source and destination amount not equal")
ErrTransactionDestinationAccountCannotBeSet = NewNormalError(NormalSubcategoryTransaction, 5, http.StatusBadRequest, "transaction destination account cannot be set")
ErrTransactionDestinationAmountCannotBeSet = NewNormalError(NormalSubcategoryTransaction, 6, http.StatusBadRequest, "transaction destination amount cannot be set")
ErrTooMuchTransactionInOneSecond = NewNormalError(NormalSubcategoryTransaction, 7, http.StatusBadRequest, "too much transaction in one second")
ErrBalanceModificationTransactionCannotSetCategory = NewNormalError(NormalSubcategoryTransaction, 8, http.StatusBadRequest, "balance modification transaction cannot set category")
ErrBalanceModificationTransactionCannotChangeAccountId = NewNormalError(NormalSubcategoryTransaction, 9, http.StatusBadRequest, "balance modification transaction cannot change account id")
ErrBalanceModificationTransactionCannotAddWhenNotEmpty = NewNormalError(NormalSubcategoryTransaction, 10, http.StatusBadRequest, "balance modification transaction cannot add when other transaction exists")
ErrCannotAddTransactionToHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 11, http.StatusBadRequest, "cannot add transaction to hidden account")
ErrCannotModifyTransactionInHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 12, http.StatusBadRequest, "cannot modify transaction of hidden account")
ErrCannotDeleteTransactionInHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 13, http.StatusBadRequest, "cannot delete transaction in hidden account")
ErrCannotAddTransactionToParentAccount = NewNormalError(NormalSubcategoryTransaction, 14, http.StatusBadRequest, "cannot add transaction to parent account")
ErrCannotModifyTransactionInParentAccount = NewNormalError(NormalSubcategoryTransaction, 15, http.StatusBadRequest, "cannot modify transaction of parent account")
ErrCannotDeleteTransactionInParentAccount = NewNormalError(NormalSubcategoryTransaction, 16, http.StatusBadRequest, "cannot delete transaction in parent account")
ErrCannotCreateTransactionWithThisTransactionTime = NewNormalError(NormalSubcategoryTransaction, 17, http.StatusBadRequest, "cannot add transaction with this transaction time")
ErrCannotModifyTransactionWithThisTransactionTime = NewNormalError(NormalSubcategoryTransaction, 18, http.StatusBadRequest, "cannot modify transaction with this transaction time")
ErrCannotDeleteTransactionWithThisTransactionTime = NewNormalError(NormalSubcategoryTransaction, 19, http.StatusBadRequest, "cannot delete transaction with this transaction time")
ErrCannotUseHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 20, http.StatusBadRequest, "cannot use hidden account")
ErrCannotUseHiddenTransactionCategory = NewNormalError(NormalSubcategoryTransaction, 21, http.StatusBadRequest, "cannot use hidden transaction category")
ErrCannotUseHiddenTransactionTag = NewNormalError(NormalSubcategoryTransaction, 22, http.StatusBadRequest, "cannot use hidden transaction tag")
ErrTransactionHasTooManyTags = NewNormalError(NormalSubcategoryTransaction, 23, http.StatusBadRequest, "transaction has too many tags")
ErrTransactionHasTooManyPictures = NewNormalError(NormalSubcategoryTransaction, 24, http.StatusBadRequest, "transaction has too many pictures")
ErrImportFileTypeIsEmpty = NewNormalError(NormalSubcategoryTransaction, 25, http.StatusBadRequest, "import file type is empty")
ErrImportFileTypeNotSupported = NewNormalError(NormalSubcategoryTransaction, 26, http.StatusBadRequest, "import file type not supported")
ErrNoDataToImport = NewNormalError(NormalSubcategoryTransaction, 27, http.StatusBadRequest, "no data to import")
ErrCannotAddTransactionBeforeBalanceModificationTransaction = NewNormalError(NormalSubcategoryTransaction, 28, http.StatusBadRequest, "cannot add transaction before balance modification transaction")
ErrBalanceModificationTransactionCannotModifyTime = NewNormalError(NormalSubcategoryTransaction, 29, http.StatusBadRequest, "balance modification transaction cannot modify transaction time")
ErrTransferTransactionAmountCannotBeLessThanZero = NewNormalError(NormalSubcategoryTransaction, 30, http.StatusBadRequest, "transfer transaction amount cannot be less than zero")
ErrImportFileEncodingIsEmpty = NewNormalError(NormalSubcategoryTransaction, 31, http.StatusBadRequest, "import file encoding is empty")
ErrImportFileEncodingNotSupported = NewNormalError(NormalSubcategoryTransaction, 32, http.StatusBadRequest, "import file encoding not supported")
ErrImportFileColumnMappingInvalid = NewNormalError(NormalSubcategoryTransaction, 33, http.StatusBadRequest, "column mapping invalid")
ErrImportFileTransactionTypeMappingInvalid = NewNormalError(NormalSubcategoryTransaction, 34, http.StatusBadRequest, "transaction type mapping invalid")
ErrImportFileTransactionTimeFormatInvalid = NewNormalError(NormalSubcategoryTransaction, 35, http.StatusBadRequest, "transaction time format invalid")
ErrImportFileTransactionTimezoneFormatInvalid = NewNormalError(NormalSubcategoryTransaction, 36, http.StatusBadRequest, "transaction time zone format invalid")
ErrTransactionIdInvalid = NewNormalError(NormalSubcategoryTransaction, 0, http.StatusBadRequest, "transaction id is invalid")
ErrTransactionNotFound = NewNormalError(NormalSubcategoryTransaction, 1, http.StatusBadRequest, "transaction not found")
ErrTransactionTypeInvalid = NewNormalError(NormalSubcategoryTransaction, 2, http.StatusBadRequest, "transaction type is invalid")
ErrTransactionSourceAndDestinationIdCannotBeEqual = NewNormalError(NormalSubcategoryTransaction, 3, http.StatusBadRequest, "transaction source and destination account id cannot be equal")
ErrTransactionSourceAndDestinationAmountNotEqual = NewNormalError(NormalSubcategoryTransaction, 4, http.StatusBadRequest, "transaction source and destination amount not equal")
ErrTransactionDestinationAccountCannotBeSet = NewNormalError(NormalSubcategoryTransaction, 5, http.StatusBadRequest, "transaction destination account cannot be set")
ErrTransactionDestinationAmountCannotBeSet = NewNormalError(NormalSubcategoryTransaction, 6, http.StatusBadRequest, "transaction destination amount cannot be set")
ErrTooMuchTransactionInOneSecond = NewNormalError(NormalSubcategoryTransaction, 7, http.StatusBadRequest, "too much transaction in one second")
ErrBalanceModificationTransactionCannotSetCategory = NewNormalError(NormalSubcategoryTransaction, 8, http.StatusBadRequest, "balance modification transaction cannot set category")
ErrBalanceModificationTransactionCannotChangeAccountId = NewNormalError(NormalSubcategoryTransaction, 9, http.StatusBadRequest, "balance modification transaction cannot change account id")
ErrBalanceModificationTransactionCannotAddWhenNotEmpty = NewNormalError(NormalSubcategoryTransaction, 10, http.StatusBadRequest, "balance modification transaction cannot add when other transaction exists")
ErrCannotAddTransactionToHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 11, http.StatusBadRequest, "cannot add transaction to hidden account")
ErrCannotModifyTransactionInHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 12, http.StatusBadRequest, "cannot modify transaction of hidden account")
ErrCannotDeleteTransactionInHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 13, http.StatusBadRequest, "cannot delete transaction in hidden account")
ErrCannotAddTransactionToParentAccount = NewNormalError(NormalSubcategoryTransaction, 14, http.StatusBadRequest, "cannot add transaction to parent account")
ErrCannotModifyTransactionInParentAccount = NewNormalError(NormalSubcategoryTransaction, 15, http.StatusBadRequest, "cannot modify transaction of parent account")
ErrCannotDeleteTransactionInParentAccount = NewNormalError(NormalSubcategoryTransaction, 16, http.StatusBadRequest, "cannot delete transaction in parent account")
ErrCannotCreateTransactionWithThisTransactionTime = NewNormalError(NormalSubcategoryTransaction, 17, http.StatusBadRequest, "cannot add transaction with this transaction time")
ErrCannotModifyTransactionWithThisTransactionTime = NewNormalError(NormalSubcategoryTransaction, 18, http.StatusBadRequest, "cannot modify transaction with this transaction time")
ErrCannotDeleteTransactionWithThisTransactionTime = NewNormalError(NormalSubcategoryTransaction, 19, http.StatusBadRequest, "cannot delete transaction with this transaction time")
ErrCannotUseHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 20, http.StatusBadRequest, "cannot use hidden account")
ErrCannotUseHiddenTransactionCategory = NewNormalError(NormalSubcategoryTransaction, 21, http.StatusBadRequest, "cannot use hidden transaction category")
ErrCannotUseHiddenTransactionTag = NewNormalError(NormalSubcategoryTransaction, 22, http.StatusBadRequest, "cannot use hidden transaction tag")
ErrTransactionHasTooManyTags = NewNormalError(NormalSubcategoryTransaction, 23, http.StatusBadRequest, "transaction has too many tags")
ErrTransactionHasTooManyPictures = NewNormalError(NormalSubcategoryTransaction, 24, http.StatusBadRequest, "transaction has too many pictures")
ErrImportFileTypeIsEmpty = NewNormalError(NormalSubcategoryTransaction, 25, http.StatusBadRequest, "import file type is empty")
ErrImportFileTypeNotSupported = NewNormalError(NormalSubcategoryTransaction, 26, http.StatusBadRequest, "import file type not supported")
ErrNoDataToImport = NewNormalError(NormalSubcategoryTransaction, 27, http.StatusBadRequest, "no data to import")
ErrCannotAddTransactionBeforeBalanceModificationTransaction = NewNormalError(NormalSubcategoryTransaction, 28, http.StatusBadRequest, "cannot add transaction before balance modification transaction")
ErrBalanceModificationTransactionCannotModifyTime = NewNormalError(NormalSubcategoryTransaction, 29, http.StatusBadRequest, "balance modification transaction cannot modify transaction time")
ErrTransferTransactionAmountCannotBeLessThanZero = NewNormalError(NormalSubcategoryTransaction, 30, http.StatusBadRequest, "transfer transaction amount cannot be less than zero")
ErrImportFileEncodingIsEmpty = NewNormalError(NormalSubcategoryTransaction, 31, http.StatusBadRequest, "import file encoding is empty")
ErrImportFileEncodingNotSupported = NewNormalError(NormalSubcategoryTransaction, 32, http.StatusBadRequest, "import file encoding not supported")
ErrImportFileColumnMappingInvalid = NewNormalError(NormalSubcategoryTransaction, 33, http.StatusBadRequest, "column mapping invalid")
ErrImportFileTransactionTypeMappingInvalid = NewNormalError(NormalSubcategoryTransaction, 34, http.StatusBadRequest, "transaction type mapping invalid")
ErrImportFileTransactionTimeFormatInvalid = NewNormalError(NormalSubcategoryTransaction, 35, http.StatusBadRequest, "transaction time format invalid")
ErrImportFileTransactionTimezoneFormatInvalid = NewNormalError(NormalSubcategoryTransaction, 36, http.StatusBadRequest, "transaction time zone format invalid")
ErrCannotMoveTransactionToSameAccount = NewNormalError(NormalSubcategoryTransaction, 37, http.StatusBadRequest, "cannot move transaction to same account")
ErrCannotMoveTransactionFromOrToHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 38, http.StatusBadRequest, "cannot move transaction from or to hidden account")
ErrCannotMoveTransactionFromOrToParentAccount = NewNormalError(NormalSubcategoryTransaction, 39, http.StatusBadRequest, "cannot move transaction from or to parent account")
ErrCannotMoveTransactionBetweenAccountsWithDifferentCurrencies = NewNormalError(NormalSubcategoryTransaction, 40, http.StatusBadRequest, "cannot move transaction between accounts with different currencies")
)
+6
View File
@@ -279,6 +279,12 @@ type TransactionGetRequest struct {
TrimTag bool `form:"trim_tag"`
}
// TransactionMoveBetweenAccountsRequest represents all parameters of moving all transactions between accounts request
type TransactionMoveBetweenAccountsRequest struct {
FromAccountId int64 `json:"fromAccountId,string" binding:"required,min=1"`
ToAccountId int64 `json:"toAccountId,string" binding:"required,min=1"`
}
// TransactionDeleteRequest represents all parameters of transaction deleting request
type TransactionDeleteRequest struct {
Id int64 `json:"id,string" binding:"required,min=1"`
+213
View File
@@ -1168,6 +1168,219 @@ func (s *TransactionService) ModifyTransaction(c core.Context, transaction *mode
return nil
}
func (s *TransactionService) MoveAllTransactionsBetweenAccounts(c core.Context, uid int64, fromAccountId int64, toAccountId int64) error {
if uid <= 0 {
return errs.ErrUserIdInvalid
}
if fromAccountId <= 0 || toAccountId <= 0 {
return errs.ErrAccountIdInvalid
}
if fromAccountId == toAccountId {
return errs.ErrCannotMoveTransactionToSameAccount
}
return s.UserDataDB(uid).DoTransaction(c, func(sess *xorm.Session) error {
// get and verify from and to account
fromAccount := &models.Account{}
has, err := sess.ID(fromAccountId).Where("uid=? AND deleted=?", uid, false).Get(fromAccount)
if err != nil {
return err
} else if !has {
return errs.ErrAccountNotFound
}
toAccount := &models.Account{}
has, err = sess.ID(toAccountId).Where("uid=? AND deleted=?", uid, false).Get(toAccount)
if err != nil {
return err
} else if !has {
return errs.ErrAccountNotFound
}
if fromAccount.Hidden || toAccount.Hidden {
return errs.ErrCannotMoveTransactionFromOrToHiddenAccount
}
if fromAccount.Type == models.ACCOUNT_TYPE_MULTI_SUB_ACCOUNTS || toAccount.Type == models.ACCOUNT_TYPE_MULTI_SUB_ACCOUNTS {
return errs.ErrCannotMoveTransactionFromOrToParentAccount
}
if fromAccount.Currency != toAccount.Currency {
return errs.ErrCannotMoveTransactionBetweenAccountsWithDifferentCurrencies
}
// combine balance modification transaction
var balanceModificationTransactions []*models.Transaction
err = sess.Where("uid=? AND deleted=? AND type=? AND (account_id=? OR account_id=?)", uid, false, models.TRANSACTION_DB_TYPE_MODIFY_BALANCE, fromAccountId, toAccountId).Find(&balanceModificationTransactions)
if err != nil {
return err
}
if len(balanceModificationTransactions) > 2 {
log.Errorf(c, "[transactions.MoveAllTransactionsBetweenAccounts] user \"uid:%d\" has more than 2 balance modification transactions in account \"id:%d\" and account \"id:%d\", cannot combine balance modification transaction", uid, fromAccountId, toAccountId)
return errs.ErrOperationFailed
} else if len(balanceModificationTransactions) == 2 && balanceModificationTransactions[0].AccountId != balanceModificationTransactions[1].AccountId {
// if two balance modification transactions exist, merge the amounts into the earlier one and delete the later transaction
var earlierTransaction *models.Transaction
var laterTransaction *models.Transaction
if balanceModificationTransactions[0].TransactionTime < balanceModificationTransactions[1].TransactionTime {
earlierTransaction = balanceModificationTransactions[0]
laterTransaction = balanceModificationTransactions[1]
} else {
earlierTransaction = balanceModificationTransactions[1]
laterTransaction = balanceModificationTransactions[0]
}
earlierTransaction.Amount += laterTransaction.Amount
earlierTransaction.RelatedAccountAmount += laterTransaction.RelatedAccountAmount
earlierTransaction.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(earlierTransaction.TransactionId).Cols("amount", "related_account_amount", "updated_unix_time").Where("uid=? AND deleted=?", uid, false).Update(earlierTransaction)
if err != nil {
return err
} else if updatedRows < 1 {
log.Errorf(c, "[transactions.MoveAllTransactionsBetweenAccounts] failed to update earlier balance modification transaction")
return errs.ErrDatabaseOperationFailed
}
laterTransaction.Deleted = true
laterTransaction.DeletedUnixTime = time.Now().Unix()
deletedRows, err := sess.ID(laterTransaction.TransactionId).Cols("deleted", "deleted_unix_time").Where("uid=? AND deleted=?", uid, false).Update(laterTransaction)
if err != nil {
return err
} else if deletedRows < 1 {
log.Errorf(c, "[transactions.MoveAllTransactionsBetweenAccounts] failed to delete later balance modification transaction")
return errs.ErrDatabaseOperationFailed
}
log.Infof(c, "[transactions.MoveAllTransactionsBetweenAccounts] user \"uid:%d\" has combined two balance modification transactions \"id:%d\" and \"id:%d\", retained transaction is \"id:%d\"", uid, earlierTransaction.TransactionId, laterTransaction.TransactionId, earlierTransaction.TransactionId)
} else if len(balanceModificationTransactions) == 1 {
// when merging a new balance modification transaction, if its date is later than the account's earliest transaction, update the balance modification transaction time accordingly
anotherAccountId := int64(0)
if balanceModificationTransactions[0].AccountId == fromAccountId {
anotherAccountId = toAccountId
} else if balanceModificationTransactions[0].AccountId == toAccountId {
anotherAccountId = fromAccountId
} else {
log.Errorf(c, "[transactions.MoveAllTransactionsBetweenAccounts] user \"uid:%d\" has a balance modification transaction \"id:%d\" which account id is neither \"%d\" nor \"%d\"", uid, balanceModificationTransactions[0].TransactionId, fromAccountId, toAccountId)
return errs.ErrOperationFailed
}
earliestTransaction := &models.Transaction{}
has, err := sess.Where("uid=? AND deleted=? AND account_id=?", uid, false, anotherAccountId).OrderBy("transaction_time asc").Limit(1).Get(earliestTransaction)
if err != nil {
return err
} else if has && balanceModificationTransactions[0].TransactionTime > earliestTransaction.TransactionTime {
balanceModificationTransaction := balanceModificationTransactions[0]
balanceModificationTransaction.TransactionTime = utils.GetMinTransactionTimeFromUnixTime(utils.GetUnixTimeFromTransactionTime(earliestTransaction.TransactionTime) - 1)
balanceModificationTransaction.UpdatedUnixTime = time.Now().Unix()
if balanceModificationTransaction.TransactionTime < 0 {
balanceModificationTransaction.TransactionTime = 0
}
updatedRows, err := sess.ID(balanceModificationTransaction.TransactionId).Cols("transaction_time", "updated_unix_time").Where("uid=? AND deleted=?", uid, false).Update(balanceModificationTransaction)
if err != nil {
return err
} else if updatedRows < 1 {
log.Errorf(c, "[transactions.MoveAllTransactionsBetweenAccounts] failed to update balance modification transaction time")
return errs.ErrDatabaseOperationFailed
}
log.Infof(c, "[transactions.MoveAllTransactionsBetweenAccounts] user \"uid:%d\" has updated balance modification transaction \"id:%d\" time to %d, because earliest transaction time in account \"id:%d\" is %d", uid, balanceModificationTransaction.TransactionId, balanceModificationTransaction.TransactionTime, toAccountId, earliestTransaction.TransactionTime)
}
}
// update all transactions of from account
updateModel := &models.Transaction{
AccountId: toAccountId,
UpdatedUnixTime: time.Now().Unix(),
}
updatedRows, err := sess.Cols("account_id", "updated_unix_time").Where("uid=? AND deleted=? AND account_id=?", uid, false, fromAccountId).Update(updateModel)
if err != nil {
return err
}
if updatedRows > 0 {
log.Infof(c, "[transactions.MoveAllTransactionsBetweenAccounts] user \"uid:%d\" has moved %d transactions from account \"id:%d\" to account \"id:%d\"", uid, updatedRows, fromAccountId, toAccountId)
}
// update all related transactions of from account
updateRelatedModel := &models.Transaction{
RelatedAccountId: toAccountId,
UpdatedUnixTime: time.Now().Unix(),
}
relatedUpdatedRows, err := sess.Cols("related_account_id", "updated_unix_time").Where("uid=? AND deleted=? AND related_account_id=?", uid, false, fromAccountId).Update(updateRelatedModel)
if err != nil {
return err
}
if updatedRows > 0 {
log.Infof(c, "[transactions.MoveAllTransactionsBetweenAccounts] user \"uid:%d\" has moved %d related transactions from account \"id:%d\" to account \"id:%d\"", uid, relatedUpdatedRows, fromAccountId, toAccountId)
}
// delete all transfer transactions which related account id and account id are both
deletedModel := &models.Transaction{
Deleted: true,
DeletedUnixTime: time.Now().Unix(),
}
deletedRows, err := sess.Cols("deleted", "deleted_unix_time").Where("uid=? AND deleted=? AND (type=? OR type=?) AND account_id=? AND related_account_id=?", uid, false, models.TRANSACTION_DB_TYPE_TRANSFER_OUT, models.TRANSACTION_DB_TYPE_TRANSFER_IN, toAccountId, toAccountId).Update(deletedModel)
if err != nil {
return err
}
if deletedRows > 0 {
log.Infof(c, "[transactions.MoveAllTransactionsBetweenAccounts] user \"uid:%d\" has deleted %d transactions which account id and related account id are both \"%d\"", uid, deletedRows, toAccountId)
}
// update account balance
if fromAccount.Balance != 0 {
toAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(toAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)", fromAccount.Balance)).Cols("updated_unix_time").Where("uid=? AND deleted=?", uid, false).Update(toAccount)
if err != nil {
return err
} else if updatedRows < 1 {
log.Errorf(c, "[transactions.MoveAllTransactionsBetweenAccounts] failed to update to account balance")
return errs.ErrDatabaseOperationFailed
}
log.Infof(c, "[transactions.MoveAllTransactionsBetweenAccounts] user \"uid:%d\" has updated account \"id:%d\" balance from %d to %d", uid, toAccountId, toAccount.Balance, toAccount.Balance+fromAccount.Balance)
fromAccount.Balance = 0
fromAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err = sess.ID(fromAccount.AccountId).Cols("balance", "updated_unix_time").Where("uid=? AND deleted=?", fromAccount.Uid, false).Update(fromAccount)
if err != nil {
return err
} else if updatedRows < 1 {
log.Errorf(c, "[transactions.MoveAllTransactionsBetweenAccounts] failed to update from account balance")
return errs.ErrDatabaseOperationFailed
}
}
return nil
})
}
// DeleteTransaction deletes an existed transaction from database
func (s *TransactionService) DeleteTransaction(c core.Context, uid int64, transactionId int64) error {
if uid <= 0 {