code refactor

This commit is contained in:
MaysWind
2020-12-30 23:27:00 +08:00
parent f42f02bd54
commit 5118978915
8 changed files with 491 additions and 254 deletions
+62 -27
View File
@@ -36,7 +36,7 @@ func (a *TransactionsApi) TransactionListHandler(c *core.Context) (interface{},
}
uid := c.GetCurrentUid()
transactions, err := a.transactions.GetTransactionsByMaxTime(uid, transactionListReq.MaxTime, transactionListReq.Count+1)
transactions, err := a.transactions.GetTransactionsByMaxTime(uid, transactionListReq.MaxTime, nil, 0, 0, transactionListReq.Count+1)
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())
@@ -49,6 +49,12 @@ func (a *TransactionsApi) TransactionListHandler(c *core.Context) (interface{},
finalCount = len(transactions)
}
hasMore := false
if finalCount < len(transactions) {
hasMore = true
}
transactionIds := make([]int64, finalCount)
for i := 0; i < finalCount; i++ {
@@ -72,7 +78,7 @@ func (a *TransactionsApi) TransactionListHandler(c *core.Context) (interface{},
sort.Sort(transactionResps.Items)
if finalCount < len(transactions) {
if hasMore {
transactionResps.NextTimeSequenceId = &transactions[finalCount].TransactionTime
}
@@ -90,7 +96,7 @@ func (a *TransactionsApi) TransactionMonthListHandler(c *core.Context) (interfac
}
uid := c.GetCurrentUid()
transactions, err := a.transactions.GetTransactionsInMonthByPage(uid, transactionListReq.Year, transactionListReq.Month, transactionListReq.Page, transactionListReq.Count)
transactions, err := a.transactions.GetTransactionsInMonthByPage(uid, transactionListReq.Year, transactionListReq.Month, nil, 0, 0, transactionListReq.Page, transactionListReq.Count)
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())
@@ -138,6 +144,10 @@ func (a *TransactionsApi) TransactionGetHandler(c *core.Context) (interface{}, *
return nil, errs.ErrOperationFailed
}
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
transaction = a.transactions.GetRelatedTransferTransaction(transaction, transaction.RelatedId)
}
allTransactionTagIds, err := a.transactionTags.GetAllTagIdsOfTransactions(uid, []int64{transaction.TransactionId})
if err != nil {
@@ -178,17 +188,17 @@ func (a *TransactionsApi) TransactionCreateHandler(c *core.Context) (interface{}
return nil, errs.ErrBalanceModificationTransactionCannotSetCategory
}
if transactionCreateReq.Type != models.TRANSACTION_TYPE_TRANSFER && transactionCreateReq.SourceAccountId != transactionCreateReq.DestinationAccountId {
log.WarnfWithRequestId(c, "[transactions.TransactionCreateHandler] non-transfer transaction source account is not destination account")
return nil, errs.ErrTransactionSourceAndDestinationIdNotEqual
if transactionCreateReq.Type != models.TRANSACTION_TYPE_TRANSFER && transactionCreateReq.DestinationAccountId != 0 {
log.WarnfWithRequestId(c, "[transactions.TransactionCreateHandler] non-transfer transaction destination account cannot be set")
return nil, errs.ErrTransactionDestinationAccountCannotBeSet
} else if transactionCreateReq.Type == models.TRANSACTION_TYPE_TRANSFER && transactionCreateReq.SourceAccountId == transactionCreateReq.DestinationAccountId {
log.WarnfWithRequestId(c, "[transactions.TransactionCreateHandler] transfer transaction source account must not be destination account")
return nil, errs.ErrTransactionSourceAndDestinationIdCannotBeEqual
}
if transactionCreateReq.Type != models.TRANSACTION_TYPE_TRANSFER && transactionCreateReq.SourceAmount != transactionCreateReq.DestinationAmount {
log.WarnfWithRequestId(c, "[transactions.TransactionCreateHandler] non-transfer transaction source amount is not destination amount")
return nil, errs.ErrTransactionSourceAndDestinationAmountNotEqual
if transactionCreateReq.Type != models.TRANSACTION_TYPE_TRANSFER && transactionCreateReq.DestinationAmount != 0 {
log.WarnfWithRequestId(c, "[transactions.TransactionCreateHandler] non-transfer transaction destination amount cannot be set")
return nil, errs.ErrTransactionDestinationAmountCannotBeSet
}
uid := c.GetCurrentUid()
@@ -233,6 +243,11 @@ func (a *TransactionsApi) TransactionModifyHandler(c *core.Context) (interface{}
return nil, errs.Or(err, errs.ErrOperationFailed)
}
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
log.ErrorfWithRequestId(c, "[transactions.TransactionModifyHandler] cannot modify transaction \"id:%d\" for user \"uid:%d\", because transaction type is transfer in", transactionModifyReq.Id, uid)
return nil, errs.ErrTransactionTypeInvalid
}
allTransactionTagIds, err := a.transactionTags.GetAllTagIdsOfTransactions(uid, []int64{transaction.TransactionId})
if err != nil {
@@ -249,19 +264,22 @@ func (a *TransactionsApi) TransactionModifyHandler(c *core.Context) (interface{}
Uid: uid,
CategoryId: transactionModifyReq.CategoryId,
TransactionTime: utils.GetMinTransactionTimeFromUnixTime(transactionModifyReq.Time),
SourceAccountId: transactionModifyReq.SourceAccountId,
DestinationAccountId: transactionModifyReq.DestinationAccountId,
SourceAmount: transactionModifyReq.SourceAmount,
DestinationAmount: transactionModifyReq.DestinationAmount,
AccountId: transactionModifyReq.SourceAccountId,
Amount: transactionModifyReq.SourceAmount,
Comment: transactionModifyReq.Comment,
}
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT {
newTransaction.RelatedAccountId = transactionModifyReq.DestinationAccountId
newTransaction.RelatedAccountAmount = transactionModifyReq.DestinationAmount
}
if newTransaction.CategoryId == transaction.CategoryId &&
utils.GetUnixTimeFromTransactionTime(newTransaction.TransactionTime) == utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime) &&
newTransaction.SourceAccountId == transaction.SourceAccountId &&
newTransaction.DestinationAccountId == transaction.DestinationAccountId &&
newTransaction.SourceAmount == transaction.SourceAmount &&
newTransaction.DestinationAmount == transaction.DestinationAmount &&
newTransaction.AccountId == transaction.AccountId &&
newTransaction.Amount == transaction.Amount &&
(transaction.Type != models.TRANSACTION_DB_TYPE_TRANSFER_OUT || newTransaction.RelatedAccountId == transaction.RelatedAccountId) &&
(transaction.Type != models.TRANSACTION_DB_TYPE_TRANSFER_OUT || newTransaction.RelatedAccountAmount == transaction.RelatedAccountAmount) &&
newTransaction.Comment == transaction.Comment &&
len(addTransactionTagIds) < 1 &&
len(removeTransactionTagIds) < 1 {
@@ -303,15 +321,32 @@ func (a *TransactionsApi) TransactionDeleteHandler(c *core.Context) (interface{}
}
func (a *TransactionsApi) createNewTransactionModel(uid int64, transactionCreateReq *models.TransactionCreateRequest) *models.Transaction {
return &models.Transaction{
Uid: uid,
Type: transactionCreateReq.Type,
CategoryId: transactionCreateReq.CategoryId,
TransactionTime: utils.GetMinTransactionTimeFromUnixTime(transactionCreateReq.Time),
SourceAccountId: transactionCreateReq.SourceAccountId,
DestinationAccountId: transactionCreateReq.DestinationAccountId,
SourceAmount: transactionCreateReq.SourceAmount,
DestinationAmount: transactionCreateReq.DestinationAmount,
Comment: transactionCreateReq.Comment,
var transactionDbType models.TransactionDbType
if transactionCreateReq.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE {
transactionDbType = models.TRANSACTION_DB_TYPE_MODIFY_BALANCE
} else if transactionCreateReq.Type == models.TRANSACTION_TYPE_EXPENSE {
transactionDbType = models.TRANSACTION_DB_TYPE_EXPENSE
} else if transactionCreateReq.Type == models.TRANSACTION_TYPE_INCOME {
transactionDbType = models.TRANSACTION_DB_TYPE_INCOME
} else if transactionCreateReq.Type == models.TRANSACTION_TYPE_TRANSFER {
transactionDbType = models.TRANSACTION_DB_TYPE_TRANSFER_OUT
}
transaction := &models.Transaction{
Uid: uid,
Type: transactionDbType,
CategoryId: transactionCreateReq.CategoryId,
TransactionTime: utils.GetMinTransactionTimeFromUnixTime(transactionCreateReq.Time),
AccountId: transactionCreateReq.SourceAccountId,
Amount: transactionCreateReq.SourceAmount,
Comment: transactionCreateReq.Comment,
}
if transactionCreateReq.Type == models.TRANSACTION_TYPE_TRANSFER {
transaction.RelatedAccountId = transactionCreateReq.DestinationAccountId
transaction.RelatedAccountAmount = transactionCreateReq.DestinationAmount
}
return transaction
}
+11 -10
View File
@@ -7,14 +7,15 @@ 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")
ErrTransactionSourceAndDestinationIdNotEqual = NewNormalError(NormalSubcategoryTransaction, 3, http.StatusBadRequest, "transaction source and destination account id not equal")
ErrTransactionSourceAndDestinationIdCannotBeEqual = NewNormalError(NormalSubcategoryTransaction, 4, http.StatusBadRequest, "transaction source and destination account id cannot be equal")
ErrTransactionSourceAndDestinationAmountNotEqual = NewNormalError(NormalSubcategoryTransaction, 5, http.StatusBadRequest, "transaction source and destination amount not equal")
ErrTooMuchTransactionInOneSecond = NewNormalError(NormalSubcategoryTransaction, 6, http.StatusBadRequest, "too much transaction in one second")
ErrBalanceModificationTransactionCannotSetCategory = NewNormalError(NormalSubcategoryTransaction, 7, http.StatusBadRequest, "balance modification transaction cannot set category")
ErrBalanceModificationTransactionCannotChangeAccountId = NewNormalError(NormalSubcategoryTransaction, 8, http.StatusBadRequest, "balance modification transaction cannot change account id")
ErrBalanceModificationTransactionCannotAddWhenNotEmpty = NewNormalError(NormalSubcategoryTransaction, 9, http.StatusBadRequest, "balance modification transaction cannot add when other transaction exists")
ErrCannotAddTransactionToHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 10, http.StatusBadRequest, "cannot add transaction to hidden account")
ErrCannotModifyTransactionInHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 11, http.StatusBadRequest, "cannot modify transaction of hidden account")
ErrCannotDeleteTransactionInHiddenAccount = NewNormalError(NormalSubcategoryTransaction, 12, http.StatusBadRequest, "cannot delete transaction in hidden account")
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")
)
+66 -20
View File
@@ -13,19 +13,32 @@ const (
TRANSACTION_TYPE_TRANSFER TransactionType = 4
)
// TransactionDbType represents transaction type in database
type TransactionDbType byte
// Transaction db types
const (
TRANSACTION_DB_TYPE_MODIFY_BALANCE TransactionDbType = 1
TRANSACTION_DB_TYPE_INCOME TransactionDbType = 2
TRANSACTION_DB_TYPE_EXPENSE TransactionDbType = 3
TRANSACTION_DB_TYPE_TRANSFER_OUT TransactionDbType = 4
TRANSACTION_DB_TYPE_TRANSFER_IN TransactionDbType = 5
)
// Transaction represents transaction data stored in database
type Transaction struct {
TransactionId int64 `xorm:"PK"`
Uid int64 `xorm:"UNIQUE(UQE_transaction_uid_transaction_time) INDEX(IDX_transaction_uid_deleted_transaction_time) INDEX(IDX_transaction_uid_deleted_type_time) INDEX(IDX_transaction_uid_deleted_category_id_time) NOT NULL"`
Deleted bool `xorm:"INDEX(IDX_transaction_uid_deleted_transaction_time) INDEX(IDX_transaction_uid_deleted_type_time) INDEX(IDX_transaction_uid_deleted_category_id_time) NOT NULL"`
Type TransactionType `xorm:"INDEX(IDX_transaction_uid_deleted_type_time) NOT NULL"`
CategoryId int64 `xorm:"INDEX(IDX_transaction_uid_deleted_category_id_time) NOT NULL"`
TransactionTime int64 `xorm:"UNIQUE(UQE_transaction_uid_transaction_time) INDEX(IDX_transaction_uid_deleted_transaction_time) INDEX(IDX_transaction_uid_deleted_type_time) INDEX(IDX_transaction_uid_deleted_category_id_time) NOT NULL"`
SourceAccountId int64 `xorm:"NOT NULL"`
DestinationAccountId int64 `xorm:"NOT NULL"`
SourceAmount int64 `xorm:"NOT NULL"`
DestinationAmount int64 `xorm:"NOT NULL"`
Comment string `xorm:"VARCHAR(255) NOT NULL"`
TransactionId int64 `xorm:"PK"`
Uid int64 `xorm:"UNIQUE(UQE_transaction_uid_time) INDEX(IDX_transaction_uid_deleted_time) INDEX(IDX_transaction_uid_deleted_type_time) INDEX(IDX_transaction_uid_deleted_category_id_time) INDEX(IDX_transaction_uid_deleted_account_id_time) NOT NULL"`
Deleted bool `xorm:"INDEX(IDX_transaction_uid_deleted_time) INDEX(IDX_transaction_uid_deleted_type_time) INDEX(IDX_transaction_uid_deleted_category_id_time) INDEX(IDX_transaction_uid_deleted_account_id_time) NOT NULL"`
Type TransactionDbType `xorm:"INDEX(IDX_transaction_uid_deleted_type_time) NOT NULL"`
CategoryId int64 `xorm:"INDEX(IDX_transaction_uid_deleted_category_id_time) NOT NULL"`
AccountId int64 `xorm:"INDEX(IDX_transaction_uid_deleted_account_id_time) NOT NULL"`
TransactionTime int64 `xorm:"UNIQUE(UQE_transaction_uid_time) INDEX(IDX_transaction_uid_deleted_time) INDEX(IDX_transaction_uid_deleted_type_time) INDEX(IDX_transaction_uid_deleted_category_id_time) INDEX(IDX_transaction_uid_deleted_account_id_time) NOT NULL"`
Amount int64 `xorm:"NOT NULL"`
RelatedId int64 `xorm:"NOT NULL"`
RelatedAccountId int64 `xorm:"NOT NULL"`
RelatedAccountAmount int64 `xorm:"NOT NULL"`
Comment string `xorm:"VARCHAR(255) NOT NULL"`
CreatedUnixTime int64
UpdatedUnixTime int64
DeletedUnixTime int64
@@ -37,7 +50,7 @@ type TransactionCreateRequest struct {
CategoryId int64 `json:"categoryId,string"`
Time int64 `json:"time" binding:"required,min=1"`
SourceAccountId int64 `json:"sourceAccountId,string" binding:"required,min=1"`
DestinationAccountId int64 `json:"destinationAccountId,string" binding:"required,min=1"`
DestinationAccountId int64 `json:"destinationAccountId,string" binding:"min=0"`
SourceAmount int64 `json:"sourceAmount" binding:"min=-99999999999,max=99999999999"`
DestinationAmount int64 `json:"destinationAmount" binding:"min=-99999999999,max=99999999999"`
TagIds []string `json:"tagIds"`
@@ -50,7 +63,7 @@ type TransactionModifyRequest struct {
CategoryId int64 `json:"categoryId,string"`
Time int64 `json:"time" binding:"required,min=1"`
SourceAccountId int64 `json:"sourceAccountId,string" binding:"required,min=1"`
DestinationAccountId int64 `json:"destinationAccountId,string" binding:"required,min=1"`
DestinationAccountId int64 `json:"destinationAccountId,string" binding:"min=0"`
SourceAmount int64 `json:"sourceAmount" binding:"min=-99999999999,max=99999999999"`
DestinationAmount int64 `json:"destinationAmount" binding:"min=-99999999999,max=99999999999"`
TagIds []string `json:"tagIds"`
@@ -89,9 +102,9 @@ type TransactionInfoResponse struct {
CategoryId int64 `json:"categoryId,string"`
Time int64 `json:"time"`
SourceAccountId int64 `json:"sourceAccountId,string"`
DestinationAccountId int64 `json:"destinationAccountId,string"`
DestinationAccountId int64 `json:"destinationAccountId,string,omitempty"`
SourceAmount int64 `json:"sourceAmount"`
DestinationAmount int64 `json:"destinationAmount"`
DestinationAmount int64 `json:"destinationAmount,omitempty"`
TagIds []string `json:"tagIds"`
Comment string `json:"comment"`
}
@@ -104,16 +117,49 @@ type TransactionInfoPageWrapperResponse struct {
// ToTransactionInfoResponse returns a view-object according to database model
func (c *Transaction) ToTransactionInfoResponse(tagIds []int64) *TransactionInfoResponse {
var transactionType TransactionType
if c.Type == TRANSACTION_DB_TYPE_MODIFY_BALANCE {
transactionType = TRANSACTION_TYPE_MODIFY_BALANCE
} else if c.Type == TRANSACTION_DB_TYPE_EXPENSE {
transactionType = TRANSACTION_TYPE_EXPENSE
} else if c.Type == TRANSACTION_DB_TYPE_INCOME {
transactionType = TRANSACTION_TYPE_INCOME
} else if c.Type == TRANSACTION_DB_TYPE_TRANSFER_OUT {
transactionType = TRANSACTION_TYPE_TRANSFER
} else if c.Type == TRANSACTION_DB_TYPE_TRANSFER_IN {
transactionType = TRANSACTION_TYPE_TRANSFER
} else {
return nil
}
sourceAccountId := c.AccountId
sourceAmount := c.Amount
destinationAccountId := int64(0)
destinationAmount := int64(0)
if c.Type == TRANSACTION_DB_TYPE_TRANSFER_OUT {
destinationAccountId = c.RelatedAccountId
destinationAmount = c.RelatedAccountAmount
} else if c.Type == TRANSACTION_DB_TYPE_TRANSFER_IN {
sourceAccountId = c.RelatedAccountId
sourceAmount = c.RelatedAccountAmount
destinationAccountId = c.AccountId
destinationAmount = c.Amount
}
return &TransactionInfoResponse{
Id: c.TransactionId,
TimeSequenceId: c.TransactionTime,
Type: c.Type,
Type: transactionType,
CategoryId: c.CategoryId,
Time: utils.GetUnixTimeFromTransactionTime(c.TransactionTime),
SourceAccountId: c.SourceAccountId,
DestinationAccountId: c.DestinationAccountId,
SourceAmount: c.SourceAmount,
DestinationAmount: c.DestinationAmount,
SourceAccountId: sourceAccountId,
DestinationAccountId: destinationAccountId,
SourceAmount: sourceAmount,
DestinationAmount: destinationAmount,
TagIds: utils.Int64ArrayToStringArray(tagIds),
Comment: c.Comment,
}
+14 -37
View File
@@ -140,12 +140,12 @@ func (s *AccountService) CreateAccounts(mainAccount *models.Account, childrenAcc
TransactionId: s.GenerateUuid(uuid.UUID_TYPE_TRANSACTION),
Uid: allAccounts[i].Uid,
Deleted: false,
Type: models.TRANSACTION_TYPE_MODIFY_BALANCE,
Type: models.TRANSACTION_DB_TYPE_MODIFY_BALANCE,
TransactionTime: transactionTime,
SourceAccountId: allAccounts[i].AccountId,
DestinationAccountId: allAccounts[i].AccountId,
SourceAmount: allAccounts[i].Balance,
DestinationAmount: allAccounts[i].Balance,
AccountId: allAccounts[i].AccountId,
Amount: allAccounts[i].Balance,
RelatedAccountId: allAccounts[i].AccountId,
RelatedAccountAmount: allAccounts[i].Balance,
CreatedUnixTime: now,
UpdatedUnixTime: now,
}
@@ -287,49 +287,26 @@ func (s *AccountService) DeleteAccount(uid int64, accountId int64) error {
accountAndSubAccountIds[i] = accountAndSubAccounts[i].AccountId
}
var relatedTransactionsBySourceAccount []*models.Transaction
err = sess.Cols("uid", "deleted", "source_account_id", "type").Where("uid=? AND deleted=?", uid, false).In("source_account_id", accountAndSubAccountIds).Limit(len(accountAndSubAccounts) + 1).Find(&relatedTransactionsBySourceAccount)
var relatedTransactionsByAccount []*models.Transaction
err = sess.Cols("uid", "deleted", "account_id", "type").Where("uid=? AND deleted=?", uid, false).In("account_id", accountAndSubAccountIds).Limit(len(accountAndSubAccounts) + 1).Find(&relatedTransactionsByAccount)
if err != nil {
return err
} else if len(relatedTransactionsBySourceAccount) > len(accountAndSubAccountIds) {
} else if len(relatedTransactionsByAccount) > len(accountAndSubAccountIds) {
return errs.ErrAccountInUseCannotBeDeleted
} else if len(relatedTransactionsBySourceAccount) > 0 {
} else if len(relatedTransactionsByAccount) > 0 {
accountTransactionExists := make(map[int64]bool)
for i := 0; i < len(relatedTransactionsBySourceAccount); i++ {
transaction := relatedTransactionsBySourceAccount[i]
for i := 0; i < len(relatedTransactionsByAccount); i++ {
transaction := relatedTransactionsByAccount[i]
if transaction.Type != models.TRANSACTION_TYPE_MODIFY_BALANCE {
if transaction.Type != models.TRANSACTION_DB_TYPE_MODIFY_BALANCE {
return errs.ErrAccountInUseCannotBeDeleted
} else if _, exists := accountTransactionExists[transaction.SourceAccountId]; exists {
} else if _, exists := accountTransactionExists[transaction.AccountId]; exists {
return errs.ErrAccountInUseCannotBeDeleted
}
accountTransactionExists[transaction.SourceAccountId] = true
}
}
var relatedTransactionsByDestinationAccount []*models.Transaction
err = sess.Cols("uid", "deleted", "destination_account_id", "type").Where("uid=? AND deleted=?", uid, false).In("destination_account_id", accountAndSubAccountIds).Limit(len(accountAndSubAccounts) + 1).Find(&relatedTransactionsByDestinationAccount)
if err != nil {
return err
} else if len(relatedTransactionsByDestinationAccount) > len(accountAndSubAccountIds) {
return errs.ErrAccountInUseCannotBeDeleted
} else if len(relatedTransactionsByDestinationAccount) > 0 {
accountTransactionExists := make(map[int64]bool)
for i := 0; i < len(relatedTransactionsByDestinationAccount); i++ {
transaction := relatedTransactionsByDestinationAccount[i]
if transaction.Type != models.TRANSACTION_TYPE_MODIFY_BALANCE {
return errs.ErrAccountInUseCannotBeDeleted
} else if _, exists := accountTransactionExists[transaction.DestinationAccountId]; exists {
return errs.ErrAccountInUseCannotBeDeleted
}
accountTransactionExists[transaction.DestinationAccountId] = true
accountTransactionExists[transaction.AccountId] = true
}
}
+331 -155
View File
@@ -32,7 +32,7 @@ var (
)
// GetTransactionsByMaxTime returns transactions before given time
func (s *TransactionService) GetTransactionsByMaxTime(uid int64, maxTime int64, count int) ([]*models.Transaction, error) {
func (s *TransactionService) GetTransactionsByMaxTime(uid int64, maxTime int64, transactionType *models.TransactionDbType, categoryId int64, accountId int64, count int) ([]*models.Transaction, error) {
if uid <= 0 {
return nil, errs.ErrUserIdInvalid
}
@@ -44,17 +44,44 @@ func (s *TransactionService) GetTransactionsByMaxTime(uid int64, maxTime int64,
var transactions []*models.Transaction
var err error
if maxTime > 0 {
err = s.UserDataDB(uid).Where("uid=? AND deleted=? AND transaction_time<=?", uid, false, maxTime).Limit(count, 0).OrderBy("transaction_time desc").Find(&transactions)
} else {
err = s.UserDataDB(uid).Where("uid=? AND deleted=?", uid, false).Limit(count, 0).OrderBy("transaction_time desc").Find(&transactions)
condition := "uid=? AND deleted=?"
conditionParams := make([]interface{}, 0, 10)
conditionParams = append(conditionParams, uid)
conditionParams = append(conditionParams, false)
if transactionType != nil {
condition = condition + " AND type=?"
conditionParams = append(conditionParams, transactionType)
} else if accountId == 0 {
condition = condition + " AND (type=? OR type=? OR type=? OR type=?)"
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_MODIFY_BALANCE)
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_INCOME)
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_EXPENSE)
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_TRANSFER_OUT)
}
if categoryId > 0 {
condition = condition + " AND category_id=?"
conditionParams = append(conditionParams, categoryId)
}
if accountId > 0 {
condition = condition + " AND account_id=?"
conditionParams = append(conditionParams, accountId)
}
if maxTime > 0 {
condition = condition + " AND transaction_time<=?"
conditionParams = append(conditionParams, maxTime)
}
err = s.UserDataDB(uid).Where(condition, conditionParams...).Limit(count, 0).OrderBy("transaction_time desc").Find(&transactions)
return transactions, err
}
// GetTransactionsInMonthByPage returns transactions in given year and month
func (s *TransactionService) GetTransactionsInMonthByPage(uid int64, year int, month int, page int, count int) ([]*models.Transaction, error) {
func (s *TransactionService) GetTransactionsInMonthByPage(uid int64, year int, month int, transactionType *models.TransactionDbType, categoryId int64, accountId int64, page int, count int) ([]*models.Transaction, error) {
if uid <= 0 {
return nil, errs.ErrUserIdInvalid
}
@@ -79,7 +106,36 @@ func (s *TransactionService) GetTransactionsInMonthByPage(uid int64, year int, m
endUnixTime := endTime.Unix()
var transactions []*models.Transaction
err = s.UserDataDB(uid).Where("uid=? AND deleted=? AND transaction_time>=? AND transaction_time<?", uid, false, startUnixTime, endUnixTime).Limit(count, count*(page-1)).OrderBy("transaction_time desc").Find(&transactions)
condition := "uid=? AND deleted=? AND transaction_time>=? AND transaction_time<?"
conditionParams := make([]interface{}, 0, 12)
conditionParams = append(conditionParams, uid)
conditionParams = append(conditionParams, false)
conditionParams = append(conditionParams, startUnixTime)
conditionParams = append(conditionParams, endUnixTime)
if transactionType != nil {
condition = condition + " AND type=?"
conditionParams = append(conditionParams, transactionType)
} else if accountId == 0 {
condition = condition + " AND (type=? OR type=? OR type=? OR type=?)"
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_MODIFY_BALANCE)
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_INCOME)
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_EXPENSE)
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_TRANSFER_OUT)
}
if categoryId > 0 {
condition = condition + " AND category_id=?"
conditionParams = append(conditionParams, categoryId)
}
if accountId > 0 {
condition = condition + " AND account_id=?"
conditionParams = append(conditionParams, accountId)
}
err = s.UserDataDB(uid).Where(condition, conditionParams...).Limit(count, count*(page-1)).OrderBy("transaction_time desc").Find(&transactions)
return transactions, err
}
@@ -177,11 +233,12 @@ func (s *TransactionService) CreateTransaction(transaction *models.Transaction,
return err
}
if sourceAccount.Hidden || destinationAccount.Hidden {
if sourceAccount.Hidden || (destinationAccount != nil && destinationAccount.Hidden) {
return errs.ErrCannotAddTransactionToHiddenAccount
}
if sourceAccount.Currency == destinationAccount.Currency && transaction.SourceAmount != transaction.DestinationAmount {
if (transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN) &&
sourceAccount.Currency == destinationAccount.Currency && transaction.Amount != transaction.RelatedAccountAmount {
return errs.ErrTransactionSourceAndDestinationAmountNotEqual
}
@@ -200,8 +257,8 @@ func (s *TransactionService) CreateTransaction(transaction *models.Transaction,
}
// Verify balance modification transaction and calculate real amount
if transaction.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE {
otherTransactionExists, err := sess.Cols("uid", "deleted", "destination_account_id").Where("uid=? AND deleted=? AND destination_account_id=?", transaction.Uid, false, destinationAccount.AccountId).Limit(1).Exist(&models.Transaction{})
if transaction.Type == models.TRANSACTION_DB_TYPE_MODIFY_BALANCE {
otherTransactionExists, err := sess.Cols("uid", "deleted", "account_id").Where("uid=? AND deleted=? AND account_id=?", transaction.Uid, false, sourceAccount.AccountId).Limit(1).Exist(&models.Transaction{})
if err != nil {
return err
@@ -209,10 +266,18 @@ func (s *TransactionService) CreateTransaction(transaction *models.Transaction,
return errs.ErrBalanceModificationTransactionCannotAddWhenNotEmpty
}
transaction.DestinationAmount = transaction.SourceAmount - destinationAccount.Balance
transaction.RelatedAccountId = transaction.TransactionId
transaction.RelatedAccountAmount = transaction.Amount - sourceAccount.Balance
}
// Insert transaction row
var relatedTransaction *models.Transaction
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
relatedTransaction = s.GetRelatedTransferTransaction(transaction, s.GenerateUuid(uuid.UUID_TYPE_TRANSACTION))
transaction.RelatedId = relatedTransaction.TransactionId
}
createdRows, err := sess.Insert(transaction)
if err != nil || createdRows < 1 { // maybe another transaction has same time
@@ -240,6 +305,22 @@ func (s *TransactionService) CreateTransaction(transaction *models.Transaction,
}
}
if relatedTransaction != nil {
relatedTransaction.TransactionTime = transaction.TransactionTime + 1
if utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime) != utils.GetUnixTimeFromTransactionTime(relatedTransaction.TransactionTime) {
return errs.ErrTooMuchTransactionInOneSecond
}
createdRows, err := sess.Insert(relatedTransaction)
if err != nil {
return err
} else if createdRows < 1 {
return errs.ErrDatabaseOperationFailed
}
}
err = nil
// Insert transaction tag index
@@ -255,36 +336,36 @@ func (s *TransactionService) CreateTransaction(transaction *models.Transaction,
}
// Update account table
if transaction.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE {
destinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(destinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)", transaction.DestinationAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", destinationAccount.Uid, false).Update(destinationAccount)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if transaction.Type == models.TRANSACTION_TYPE_INCOME {
destinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(destinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)", transaction.DestinationAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", destinationAccount.Uid, false).Update(destinationAccount)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if transaction.Type == models.TRANSACTION_TYPE_EXPENSE {
destinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(destinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)", transaction.DestinationAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", destinationAccount.Uid, false).Update(destinationAccount)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if transaction.Type == models.TRANSACTION_TYPE_TRANSFER {
if transaction.Type == models.TRANSACTION_DB_TYPE_MODIFY_BALANCE {
sourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedSourceRows, err := sess.ID(sourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)", transaction.SourceAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", sourceAccount.Uid, false).Update(sourceAccount)
updatedRows, err := sess.ID(sourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)", transaction.RelatedAccountAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", sourceAccount.Uid, false).Update(sourceAccount)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if transaction.Type == models.TRANSACTION_DB_TYPE_INCOME {
sourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(sourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)", transaction.Amount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", sourceAccount.Uid, false).Update(sourceAccount)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if transaction.Type == models.TRANSACTION_DB_TYPE_EXPENSE {
sourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(sourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)", transaction.Amount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", sourceAccount.Uid, false).Update(sourceAccount)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT {
sourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedSourceRows, err := sess.ID(sourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)", transaction.Amount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", sourceAccount.Uid, false).Update(sourceAccount)
if err != nil {
return err
@@ -293,13 +374,15 @@ func (s *TransactionService) CreateTransaction(transaction *models.Transaction,
}
destinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedDestinationRows, err := sess.ID(destinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)", transaction.DestinationAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", destinationAccount.Uid, false).Update(destinationAccount)
updatedDestinationRows, err := sess.ID(destinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)", transaction.RelatedAccountAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", destinationAccount.Uid, false).Update(destinationAccount)
if err != nil {
return err
} else if updatedDestinationRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
return errs.ErrTransactionTypeInvalid
}
return err
@@ -348,6 +431,10 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction,
transaction.Type = oldTransaction.Type
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT {
transaction.RelatedId = oldTransaction.RelatedId
}
// Check whether account id is valid
err = s.isAccountIdValid(transaction)
@@ -362,11 +449,12 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction,
return err
}
if sourceAccount.Hidden || destinationAccount.Hidden {
if sourceAccount.Hidden || (destinationAccount != nil && destinationAccount.Hidden) {
return errs.ErrCannotModifyTransactionInHiddenAccount
}
if sourceAccount.Currency == destinationAccount.Currency && transaction.SourceAmount != transaction.DestinationAmount {
if (transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN) &&
sourceAccount.Currency == destinationAccount.Currency && transaction.Amount != transaction.RelatedAccountAmount {
return errs.ErrTransactionSourceAndDestinationAmountNotEqual
}
@@ -376,7 +464,7 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction,
return err
}
if oldSourceAccount.Hidden || oldDestinationAccount.Hidden {
if oldSourceAccount.Hidden || (oldDestinationAccount != nil && oldDestinationAccount.Hidden) {
return errs.ErrCannotAddTransactionToHiddenAccount
}
@@ -412,25 +500,28 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction,
updateCols = append(updateCols, "transaction_time")
}
if transaction.SourceAccountId != oldTransaction.SourceAccountId {
updateCols = append(updateCols, "source_account_id")
if transaction.AccountId != oldTransaction.AccountId {
updateCols = append(updateCols, "account_id")
}
if transaction.DestinationAccountId != oldTransaction.DestinationAccountId {
updateCols = append(updateCols, "destination_account_id")
}
if transaction.SourceAmount != oldTransaction.SourceAmount {
if oldTransaction.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE {
originalBalance := sourceAccount.Balance - oldTransaction.DestinationAmount
transaction.DestinationAmount = transaction.SourceAmount - originalBalance
if transaction.Amount != oldTransaction.Amount {
if oldTransaction.Type == models.TRANSACTION_DB_TYPE_MODIFY_BALANCE {
originalBalance := sourceAccount.Balance - oldTransaction.RelatedAccountAmount
transaction.RelatedAccountAmount = transaction.Amount - originalBalance
updateCols = append(updateCols, "related_account_amount")
}
updateCols = append(updateCols, "source_amount")
updateCols = append(updateCols, "amount")
}
if transaction.DestinationAmount != oldTransaction.DestinationAmount {
updateCols = append(updateCols, "destination_amount")
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
if transaction.RelatedAccountId != oldTransaction.RelatedAccountId {
updateCols = append(updateCols, "related_account_id")
}
if transaction.RelatedAccountAmount != oldTransaction.RelatedAccountAmount {
updateCols = append(updateCols, "related_account_amount")
}
}
if transaction.Comment != oldTransaction.Comment {
@@ -453,6 +544,22 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction,
return errs.ErrTransactionNotFound
}
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
relatedTransaction := s.GetRelatedTransferTransaction(transaction, transaction.RelatedId)
if utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime) != utils.GetUnixTimeFromTransactionTime(relatedTransaction.TransactionTime) {
return errs.ErrTooMuchTransactionInOneSecond
}
updatedRows, err := sess.ID(relatedTransaction.TransactionId).Cols(updateCols...).Where("uid=? AND deleted=?", relatedTransaction.Uid, false).Update(relatedTransaction)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrDatabaseOperationFailed
}
}
// Update transaction tag index
if len(removeTagIds) > 0 {
deletedRows, err := sess.Where("uid=?", transaction.Uid).In("tag_id", removeTagIds).Delete(&models.TransactionTagIndex{})
@@ -476,14 +583,14 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction,
}
// Update account table
if oldTransaction.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE {
if transaction.DestinationAccountId != oldTransaction.DestinationAccountId {
if oldTransaction.Type == models.TRANSACTION_DB_TYPE_MODIFY_BALANCE {
if transaction.AccountId != oldTransaction.AccountId {
return errs.ErrBalanceModificationTransactionCannotChangeAccountId
}
if transaction.DestinationAmount != oldTransaction.DestinationAmount {
destinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(destinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)+(%d)", oldTransaction.DestinationAmount, transaction.DestinationAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", destinationAccount.Uid, false).Update(destinationAccount)
if transaction.RelatedAccountAmount != oldTransaction.RelatedAccountAmount {
sourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(sourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)+(%d)", oldTransaction.RelatedAccountAmount, transaction.RelatedAccountAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", sourceAccount.Uid, false).Update(sourceAccount)
if err != nil {
return err
@@ -491,19 +598,19 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction,
return errs.ErrDatabaseOperationFailed
}
}
} else if oldTransaction.Type == models.TRANSACTION_TYPE_INCOME {
} else if oldTransaction.Type == models.TRANSACTION_DB_TYPE_INCOME {
var oldAccountNewAmount int64 = 0
var newAccountNewAmount int64 = 0
if transaction.DestinationAccountId == oldTransaction.DestinationAccountId {
oldAccountNewAmount = transaction.DestinationAmount
} else if transaction.DestinationAccountId != oldTransaction.DestinationAccountId {
newAccountNewAmount = transaction.DestinationAmount
if transaction.AccountId == oldTransaction.AccountId {
oldAccountNewAmount = transaction.Amount
} else if transaction.AccountId != oldTransaction.AccountId {
newAccountNewAmount = transaction.Amount
}
if oldAccountNewAmount != oldTransaction.DestinationAmount {
oldDestinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(oldDestinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)+(%d)", oldTransaction.DestinationAmount, oldAccountNewAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", oldDestinationAccount.Uid, false).Update(oldDestinationAccount)
if oldAccountNewAmount != oldTransaction.Amount {
oldSourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(oldSourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)+(%d)", oldTransaction.Amount, oldAccountNewAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", oldSourceAccount.Uid, false).Update(oldSourceAccount)
if err != nil {
return err
@@ -513,8 +620,8 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction,
}
if newAccountNewAmount != 0 {
destinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(destinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)", newAccountNewAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", destinationAccount.Uid, false).Update(destinationAccount)
sourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(sourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)", newAccountNewAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", sourceAccount.Uid, false).Update(sourceAccount)
if err != nil {
return err
@@ -522,19 +629,19 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction,
return errs.ErrDatabaseOperationFailed
}
}
} else if oldTransaction.Type == models.TRANSACTION_TYPE_EXPENSE {
} else if oldTransaction.Type == models.TRANSACTION_DB_TYPE_EXPENSE {
var oldAccountNewAmount int64 = 0
var newAccountNewAmount int64 = 0
if transaction.DestinationAccountId == oldTransaction.DestinationAccountId {
oldAccountNewAmount = transaction.DestinationAmount
} else if transaction.DestinationAccountId != oldTransaction.DestinationAccountId {
newAccountNewAmount = transaction.DestinationAmount
if transaction.AccountId == oldTransaction.AccountId {
oldAccountNewAmount = transaction.Amount
} else if transaction.AccountId != oldTransaction.AccountId {
newAccountNewAmount = transaction.Amount
}
if oldAccountNewAmount != oldTransaction.DestinationAmount {
oldDestinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(oldDestinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)-(%d)", oldTransaction.DestinationAmount, oldAccountNewAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", oldDestinationAccount.Uid, false).Update(oldDestinationAccount)
if oldAccountNewAmount != oldTransaction.Amount {
oldSourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(oldSourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)-(%d)", oldTransaction.Amount, oldAccountNewAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", oldSourceAccount.Uid, false).Update(oldSourceAccount)
if err != nil {
return err
@@ -544,8 +651,8 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction,
}
if newAccountNewAmount != 0 {
destinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(destinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)", newAccountNewAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", destinationAccount.Uid, false).Update(destinationAccount)
sourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(sourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)", newAccountNewAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", sourceAccount.Uid, false).Update(sourceAccount)
if err != nil {
return err
@@ -553,19 +660,19 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction,
return errs.ErrDatabaseOperationFailed
}
}
} else if oldTransaction.Type == models.TRANSACTION_TYPE_TRANSFER {
} else if oldTransaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT {
var oldSourceAccountNewAmount int64 = 0
var newSourceAccountNewAmount int64 = 0
if transaction.SourceAccountId == oldTransaction.SourceAccountId {
oldSourceAccountNewAmount = transaction.SourceAmount
} else if transaction.SourceAccountId != oldTransaction.SourceAccountId {
newSourceAccountNewAmount = transaction.SourceAmount
if transaction.AccountId == oldTransaction.AccountId {
oldSourceAccountNewAmount = transaction.Amount
} else if transaction.AccountId != oldTransaction.AccountId {
newSourceAccountNewAmount = transaction.Amount
}
if oldSourceAccountNewAmount != oldTransaction.SourceAmount {
if oldSourceAccountNewAmount != oldTransaction.Amount {
oldSourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(oldSourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)-(%d)", oldTransaction.SourceAmount, oldSourceAccountNewAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", oldSourceAccount.Uid, false).Update(oldSourceAccount)
updatedRows, err := sess.ID(oldSourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)-(%d)", oldTransaction.Amount, oldSourceAccountNewAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", oldSourceAccount.Uid, false).Update(oldSourceAccount)
if err != nil {
return err
@@ -588,15 +695,15 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction,
var oldDestinationAccountNewAmount int64 = 0
var newDestinationAccountNewAmount int64 = 0
if transaction.DestinationAccountId == oldTransaction.DestinationAccountId {
oldDestinationAccountNewAmount = transaction.DestinationAmount
} else if transaction.DestinationAccountId != oldTransaction.DestinationAccountId {
newDestinationAccountNewAmount = transaction.DestinationAmount
if transaction.RelatedAccountId == oldTransaction.RelatedAccountId {
oldDestinationAccountNewAmount = transaction.RelatedAccountAmount
} else if transaction.RelatedAccountId != oldTransaction.RelatedAccountId {
newDestinationAccountNewAmount = transaction.RelatedAccountAmount
}
if oldDestinationAccountNewAmount != oldTransaction.DestinationAmount {
if oldDestinationAccountNewAmount != oldTransaction.RelatedAccountAmount {
oldDestinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(oldDestinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)+(%d)", oldTransaction.DestinationAmount, oldDestinationAccountNewAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", oldDestinationAccount.Uid, false).Update(oldDestinationAccount)
updatedRows, err := sess.ID(oldDestinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)+(%d)", oldTransaction.RelatedAccountAmount, oldDestinationAccountNewAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", oldDestinationAccount.Uid, false).Update(oldDestinationAccount)
if err != nil {
return err
@@ -615,6 +722,8 @@ func (s *TransactionService) ModifyTransaction(transaction *models.Transaction,
return errs.ErrDatabaseOperationFailed
}
}
} else if oldTransaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
return errs.ErrTransactionTypeInvalid
}
return nil
@@ -658,12 +767,12 @@ func (s *TransactionService) DeleteTransaction(uid int64, transactionId int64) e
return err
}
if sourceAccount.Hidden || destinationAccount.Hidden {
if sourceAccount.Hidden || (destinationAccount != nil && destinationAccount.Hidden) {
return errs.ErrCannotDeleteTransactionInHiddenAccount
}
// Update transaction row to deleted
deletedRows, err := sess.ID(transactionId).Cols("deleted", "deleted_unix_time").Where("uid=? AND deleted=?", uid, false).Update(updateModel)
deletedRows, err := sess.ID(oldTransaction.TransactionId).Cols("deleted", "deleted_unix_time").Where("uid=? AND deleted=?", uid, false).Update(updateModel)
if err != nil {
return err
@@ -671,37 +780,47 @@ func (s *TransactionService) DeleteTransaction(uid int64, transactionId int64) e
return errs.ErrTransactionNotFound
}
if oldTransaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || oldTransaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
deletedRows, err = sess.ID(oldTransaction.RelatedId).Cols("deleted", "deleted_unix_time").Where("uid=? AND deleted=?", uid, false).Update(updateModel)
if err != nil {
return err
} else if deletedRows < 1 {
return errs.ErrTransactionNotFound
}
}
// Update account table
if oldTransaction.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE {
destinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(destinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)", oldTransaction.DestinationAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", destinationAccount.Uid, false).Update(destinationAccount)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if oldTransaction.Type == models.TRANSACTION_TYPE_INCOME {
destinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(destinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)", oldTransaction.DestinationAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", destinationAccount.Uid, false).Update(destinationAccount)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if oldTransaction.Type == models.TRANSACTION_TYPE_EXPENSE {
destinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(destinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)", oldTransaction.DestinationAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", destinationAccount.Uid, false).Update(destinationAccount)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if oldTransaction.Type == models.TRANSACTION_TYPE_TRANSFER {
if oldTransaction.Type == models.TRANSACTION_DB_TYPE_MODIFY_BALANCE {
sourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedSourceRows, err := sess.ID(sourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)", oldTransaction.SourceAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", sourceAccount.Uid, false).Update(sourceAccount)
updatedRows, err := sess.ID(sourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)", oldTransaction.RelatedAccountAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", sourceAccount.Uid, false).Update(sourceAccount)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if oldTransaction.Type == models.TRANSACTION_DB_TYPE_INCOME {
sourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(sourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)", oldTransaction.Amount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", sourceAccount.Uid, false).Update(sourceAccount)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if oldTransaction.Type == models.TRANSACTION_DB_TYPE_EXPENSE {
sourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedRows, err := sess.ID(sourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)", oldTransaction.Amount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", sourceAccount.Uid, false).Update(sourceAccount)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if oldTransaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT {
sourceAccount.UpdatedUnixTime = time.Now().Unix()
updatedSourceRows, err := sess.ID(sourceAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance+(%d)", oldTransaction.Amount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", sourceAccount.Uid, false).Update(sourceAccount)
if err != nil {
return err
@@ -710,32 +829,74 @@ func (s *TransactionService) DeleteTransaction(uid int64, transactionId int64) e
}
destinationAccount.UpdatedUnixTime = time.Now().Unix()
updatedDestinationRows, err := sess.ID(destinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)", oldTransaction.DestinationAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", destinationAccount.Uid, false).Update(destinationAccount)
updatedDestinationRows, err := sess.ID(destinationAccount.AccountId).SetExpr("balance", fmt.Sprintf("balance-(%d)", oldTransaction.RelatedAccountAmount)).Cols("updated_unix_time").Where("uid=? AND deleted=?", destinationAccount.Uid, false).Update(destinationAccount)
if err != nil {
return err
} else if updatedDestinationRows < 1 {
return errs.ErrDatabaseOperationFailed
}
} else if oldTransaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
return errs.ErrTransactionTypeInvalid
}
return err
})
}
func (s *TransactionService) GetRelatedTransferTransaction(originalTransaction *models.Transaction, relatedTransactionId int64) *models.Transaction {
var relatedType models.TransactionDbType
var relatedTransactionTime int64
if originalTransaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT {
relatedType = models.TRANSACTION_DB_TYPE_TRANSFER_IN
relatedTransactionTime = originalTransaction.TransactionTime + 1
} else if originalTransaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
relatedType = models.TRANSACTION_DB_TYPE_TRANSFER_OUT
relatedTransactionTime = originalTransaction.TransactionTime - 1
} else {
return nil
}
relatedTransaction := &models.Transaction{
TransactionId: relatedTransactionId,
Uid: originalTransaction.Uid,
Deleted: originalTransaction.Deleted,
Type: relatedType,
CategoryId: originalTransaction.CategoryId,
TransactionTime: relatedTransactionTime,
AccountId: originalTransaction.RelatedAccountId,
Amount: originalTransaction.RelatedAccountAmount,
RelatedId: originalTransaction.TransactionId,
RelatedAccountId: originalTransaction.AccountId,
RelatedAccountAmount: originalTransaction.Amount,
Comment: originalTransaction.Comment,
CreatedUnixTime: originalTransaction.CreatedUnixTime,
UpdatedUnixTime: originalTransaction.UpdatedUnixTime,
DeletedUnixTime: originalTransaction.DeletedUnixTime,
}
return relatedTransaction
}
func (s *TransactionService) isAccountIdValid(transaction *models.Transaction) error {
if transaction.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE ||
transaction.Type == models.TRANSACTION_TYPE_INCOME ||
transaction.Type == models.TRANSACTION_TYPE_EXPENSE {
if transaction.SourceAccountId != transaction.DestinationAccountId {
return errs.ErrTransactionSourceAndDestinationIdNotEqual
} else if transaction.SourceAmount != transaction.DestinationAmount {
return errs.ErrTransactionSourceAndDestinationAmountNotEqual
if transaction.Type == models.TRANSACTION_DB_TYPE_MODIFY_BALANCE {
if transaction.RelatedAccountId != 0 && transaction.RelatedAccountId != transaction.AccountId {
return errs.ErrTransactionDestinationAccountCannotBeSet
}
} else if transaction.Type == models.TRANSACTION_TYPE_TRANSFER {
if transaction.SourceAccountId == transaction.DestinationAccountId {
} else if transaction.Type == models.TRANSACTION_DB_TYPE_INCOME ||
transaction.Type == models.TRANSACTION_DB_TYPE_EXPENSE {
if transaction.RelatedAccountId != 0 {
return errs.ErrTransactionDestinationAccountCannotBeSet
} else if transaction.RelatedAccountAmount != 0 {
return errs.ErrTransactionDestinationAmountCannotBeSet
}
} else if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT {
if transaction.AccountId == transaction.RelatedAccountId {
return errs.ErrTransactionSourceAndDestinationIdCannotBeEqual
}
} else if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
return errs.ErrTransactionTypeInvalid
} else {
return errs.ErrTransactionTypeInvalid
}
@@ -747,7 +908,7 @@ func (s *TransactionService) getAccountModels(sess *xorm.Session, transaction *m
sourceAccount = &models.Account{}
destinationAccount = &models.Account{}
has, err := sess.ID(transaction.SourceAccountId).Where("uid=? AND deleted=?", transaction.Uid, false).Get(sourceAccount)
has, err := sess.ID(transaction.AccountId).Where("uid=? AND deleted=?", transaction.Uid, false).Get(sourceAccount)
if err != nil {
return nil, nil, err
@@ -755,17 +916,32 @@ func (s *TransactionService) getAccountModels(sess *xorm.Session, transaction *m
return nil, nil, errs.ErrSourceAccountNotFound
}
if transaction.DestinationAccountId == transaction.SourceAccountId {
destinationAccount = sourceAccount
} else {
has, err = sess.ID(transaction.DestinationAccountId).Where("uid=? AND deleted=?", transaction.Uid, false).Get(destinationAccount)
if transaction.Type == models.TRANSACTION_DB_TYPE_MODIFY_BALANCE {
if transaction.RelatedAccountId != 0 && transaction.RelatedAccountId != transaction.AccountId {
return nil, nil, errs.ErrAccountIdInvalid
} else {
destinationAccount = sourceAccount
}
} else if transaction.Type == models.TRANSACTION_DB_TYPE_INCOME || transaction.Type == models.TRANSACTION_DB_TYPE_EXPENSE {
if transaction.RelatedAccountId != 0 {
return nil, nil, errs.ErrAccountIdInvalid
}
if err != nil {
return nil, nil, err
} else if !has {
return nil, nil, errs.ErrDestinationAccountNotFound
destinationAccount = nil
} else if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
if transaction.RelatedAccountId <= 0 {
return nil, nil, errs.ErrAccountIdInvalid
} else {
has, err = sess.ID(transaction.RelatedAccountId).Where("uid=? AND deleted=?", transaction.Uid, false).Get(destinationAccount)
if err != nil {
return nil, nil, err
} else if !has {
return nil, nil, errs.ErrDestinationAccountNotFound
}
}
}
return sourceAccount, destinationAccount, nil
}
@@ -773,10 +949,10 @@ func (s *TransactionService) getOldAccountModels(sess *xorm.Session, transaction
oldSourceAccount = &models.Account{}
oldDestinationAccount = &models.Account{}
if transaction.SourceAccountId == oldTransaction.SourceAccountId {
if transaction.AccountId == oldTransaction.AccountId {
oldSourceAccount = sourceAccount
} else {
has, err := sess.ID(oldTransaction.SourceAccountId).Where("uid=? AND deleted=?", transaction.Uid, false).Get(oldSourceAccount)
has, err := sess.ID(oldTransaction.AccountId).Where("uid=? AND deleted=?", transaction.Uid, false).Get(oldSourceAccount)
if err != nil {
return nil, nil, err
@@ -785,10 +961,10 @@ func (s *TransactionService) getOldAccountModels(sess *xorm.Session, transaction
}
}
if transaction.DestinationAccountId == oldTransaction.DestinationAccountId {
if transaction.RelatedAccountId == oldTransaction.RelatedAccountId {
oldDestinationAccount = destinationAccount
} else {
has, err := sess.ID(oldTransaction.DestinationAccountId).Where("uid=? AND deleted=?", transaction.Uid, false).Get(oldDestinationAccount)
has, err := sess.ID(oldTransaction.RelatedAccountId).Where("uid=? AND deleted=?", transaction.Uid, false).Get(oldDestinationAccount)
if err != nil {
return nil, nil, err
@@ -800,8 +976,8 @@ func (s *TransactionService) getOldAccountModels(sess *xorm.Session, transaction
}
func (s *TransactionService) isCategoryValid(sess *xorm.Session, transaction *models.Transaction) error {
if transaction.Type == models.TRANSACTION_TYPE_MODIFY_BALANCE {
if transaction.CategoryId > 0 {
if transaction.Type == models.TRANSACTION_DB_TYPE_MODIFY_BALANCE {
if transaction.CategoryId != 0 {
return errs.ErrBalanceModificationTransactionCannotSetCategory
}
} else {
@@ -818,9 +994,9 @@ func (s *TransactionService) isCategoryValid(sess *xorm.Session, transaction *mo
return errs.ErrCannotUsePrimaryCategoryForTransaction
}
if (transaction.Type == models.TRANSACTION_TYPE_INCOME && category.Type != models.CATEGORY_TYPE_INCOME) ||
(transaction.Type == models.TRANSACTION_TYPE_EXPENSE && category.Type != models.CATEGORY_TYPE_EXPENSE) ||
(transaction.Type == models.TRANSACTION_TYPE_TRANSFER && category.Type != models.CATEGORY_TYPE_TRANSFER) {
if (transaction.Type == models.TRANSACTION_DB_TYPE_INCOME && category.Type != models.CATEGORY_TYPE_INCOME) ||
(transaction.Type == models.TRANSACTION_DB_TYPE_EXPENSE && category.Type != models.CATEGORY_TYPE_EXPENSE) ||
((transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN) && category.Type != models.CATEGORY_TYPE_TRANSFER) {
return errs.ErrTransactionCategoryTypeInvalid
}
}
+2 -1
View File
@@ -337,9 +337,10 @@ export default {
'transaction id is invalid': 'Transaction ID is invalid',
'transaction not found': 'Transaction is not found',
'transaction type is invalid': 'Transaction type is invalid',
'transaction source and destination account id not equal': 'Source account ID and destination account ID do not equal',
'transaction source and destination account id cannot be equal': 'Source account ID and destination account ID cannot be equal',
'transaction source and destination amount not equal': 'Source amount and destination source do not equal',
'transaction destination account cannot be set': 'Cannot set destination account',
'transaction destination amount cannot be set': 'Cannot set destination amount',
'too much transaction in one second': 'There are too much transaction in one second, please choose another time',
'balance modification transaction cannot set category': 'You cannot set category for balance modification transaction',
'balance modification transaction cannot change account id': 'You cannot change account ID for balance modification transaction',
+3 -2
View File
@@ -335,11 +335,12 @@ export default {
'destination account not found': '目标账户不存在',
'account is in use and cannot be deleted': '账户正在被使用,无法删除',
'transaction id is invalid': '交易ID无效',
'transaction not found': '交易不存',
'transaction not found': '交易不存',
'transaction type is invalid': '交易类型无效',
'transaction source and destination account id not equal': '来源账户和目标账户不一致',
'transaction source and destination account id cannot be equal': '来源账户和目标账户不能相同',
'transaction source and destination amount not equal': '源金额和目标金额不一致',
'transaction destination account cannot be set': '不能设置目标账户',
'transaction destination amount cannot be set': '不能设置目标金额',
'too much transaction in one second': '一秒钟内交易太多,请选择其他时间',
'balance modification transaction cannot set category': '您无法对修改余额的交易设置分类',
'balance modification transaction cannot change account id': '您无法对修改余额的交易修改账户ID',
+2 -2
View File
@@ -532,9 +532,9 @@ export default {
type: self.transaction.type,
time: self.transaction.unixTime,
sourceAccountId: self.transaction.sourceAccountId,
destinationAccountId: self.transaction.sourceAccountId,
sourceAmount: self.transaction.sourceAmount,
destinationAmount: self.transaction.sourceAmount,
destinationAccountId: '0',
destinationAmount: 0,
tagIds: self.transaction.tagIds,
comment: self.transaction.comment
};