diff --git a/cmd/webserver.go b/cmd/webserver.go index e2e863d1..eca68661 100644 --- a/cmd/webserver.go +++ b/cmd/webserver.go @@ -275,7 +275,6 @@ func startWebServer(c *cli.Context) error { apiV1Route.GET("/transactions/list/by_month.json", bindApi(api.Transactions.TransactionMonthListHandler)) apiV1Route.GET("/transactions/statistics.json", bindApi(api.Transactions.TransactionStatisticsHandler)) apiV1Route.GET("/transactions/amounts.json", bindApi(api.Transactions.TransactionAmountsHandler)) - apiV1Route.GET("/transactions/amounts/by_month.json", bindApi(api.Transactions.TransactionMonthAmountsHandler)) apiV1Route.GET("/transactions/get.json", bindApi(api.Transactions.TransactionGetHandler)) apiV1Route.POST("/transactions/add.json", bindApi(api.Transactions.TransactionCreateHandler)) apiV1Route.POST("/transactions/modify.json", bindApi(api.Transactions.TransactionModifyHandler)) diff --git a/pkg/api/transactions.go b/pkg/api/transactions.go index 283ab9e7..4383f284 100644 --- a/pkg/api/transactions.go +++ b/pkg/api/transactions.go @@ -2,7 +2,6 @@ package api import ( "sort" - "strings" orderedmap "github.com/wk8/go-ordered-map/v2" @@ -14,8 +13,6 @@ import ( "github.com/mayswind/ezbookkeeping/pkg/utils" ) -const pageCountForLoadTransactionAmounts = 1000 - // TransactionsApi represents transaction api type TransactionsApi struct { transactions *services.TransactionService @@ -381,120 +378,6 @@ func (a *TransactionsApi) TransactionAmountsHandler(c *core.Context) (any, *errs return amountsResp, nil } -// TransactionMonthAmountsHandler returns every month transaction amounts of current user -func (a *TransactionsApi) TransactionMonthAmountsHandler(c *core.Context) (any, *errs.Error) { - var transactionAmountsReq models.TransactionMonthAmountsRequest - err := c.ShouldBindQuery(&transactionAmountsReq) - - if err != nil { - log.WarnfWithRequestId(c, "[transactions.TransactionMonthAmountsHandler] parse request failed, because %s", err.Error()) - return nil, errs.NewIncompleteOrIncorrectSubmissionError(err) - } - - utcOffset, err := c.GetClientTimezoneOffset() - - if err != nil { - log.WarnfWithRequestId(c, "[transactions.TransactionMonthAmountsHandler] cannot get client timezone offset, because %s", err.Error()) - return nil, errs.ErrClientTimezoneOffsetInvalid - } - - startTime, endTime, err := transactionAmountsReq.GetStartTimeAndEndTime(utcOffset) - - if err != nil { - log.WarnfWithRequestId(c, "[transactions.TransactionMonthAmountsHandler] parse request start or end date failed, because %s", err.Error()) - return nil, errs.ErrParameterInvalid - } - - uid := c.GetCurrentUid() - - accounts, err := a.accounts.GetAllAccountsByUid(c, uid) - accountMap := a.accounts.GetAccountMapByList(accounts) - - if err != nil { - log.ErrorfWithRequestId(c, "[transactions.TransactionMonthAmountsHandler] failed to get all accounts for user \"uid:%d\", because %s", uid, err.Error()) - return nil, errs.Or(err, errs.ErrOperationFailed) - } - - totalAmounts, err := a.transactions.GetAccountsMonthTotalIncomeAndExpense(c, uid, startTime, endTime, pageCountForLoadTransactionAmounts) - - if err != nil { - log.ErrorfWithRequestId(c, "[transactions.TransactionMonthAmountsHandler] failed to get accounts month total income and expense for user \"uid:%d\", because %s", uid, err.Error()) - return nil, errs.Or(err, errs.ErrOperationFailed) - } - - amountsMap := make(map[string]map[string]*models.TransactionAmountsResponseItemAmountInfo) - - for yearMonth, monthAccountsAmounts := range totalAmounts { - for accountId, monthAccountAmounts := range monthAccountsAmounts { - account, exists := accountMap[accountId] - - if !exists { - log.WarnfWithRequestId(c, "[transactions.TransactionMonthAmountsHandler] cannot find account for account \"id:%d\" of user \"uid:%d\"", accountId, uid) - continue - } - - monthTotalAmounts, exists := amountsMap[yearMonth] - - if !exists { - monthTotalAmounts = make(map[string]*models.TransactionAmountsResponseItemAmountInfo) - amountsMap[yearMonth] = monthTotalAmounts - } - - monthTotalAmount, exists := monthTotalAmounts[account.Currency] - - if !exists { - monthTotalAmount = &models.TransactionAmountsResponseItemAmountInfo{ - Currency: account.Currency, - IncomeAmount: 0, - ExpenseAmount: 0, - } - } - - monthTotalAmount.IncomeAmount += monthAccountAmounts.TotalIncomeAmount - monthTotalAmount.ExpenseAmount += monthAccountAmounts.TotalExpenseAmount - - monthTotalAmounts[account.Currency] = monthTotalAmount - } - } - - amountsResp := make(models.TransactionMonthAmountsResponseItemSlice, 0) - - for yearMonth, monthTotalAmounts := range amountsMap { - yearMonthItems := strings.Split(yearMonth, "-") - year, err := utils.StringToInt32(yearMonthItems[0]) - - if err != nil { - log.WarnfWithRequestId(c, "[transactions.TransactionMonthAmountsHandler] cannot get year from year-month item \"%s\" for user \"uid:%d\"", yearMonth, uid) - continue - } - - month, err := utils.StringToInt32(yearMonthItems[1]) - - if err != nil { - log.WarnfWithRequestId(c, "[transactions.TransactionMonthAmountsHandler] cannot get month from year-month item \"%s\" for user \"uid:%d\"", yearMonth, uid) - continue - } - - amounts := make(models.TransactionAmountsResponseItemAmountInfoSlice, 0, len(monthTotalAmounts)) - - for _, monthTotalAmount := range monthTotalAmounts { - amounts = append(amounts, monthTotalAmount) - } - - sort.Sort(amounts) - - amountsResp = append(amountsResp, &models.TransactionMonthAmountsResponseItem{ - Year: year, - Month: month, - Amounts: amounts, - }) - } - - sort.Sort(amountsResp) - - return amountsResp, nil -} - // TransactionGetHandler returns one specific transaction of current user func (a *TransactionsApi) TransactionGetHandler(c *core.Context) (any, *errs.Error) { var transactionGetReq models.TransactionGetRequest diff --git a/pkg/models/transaction.go b/pkg/models/transaction.go index 12054c5c..0ee525fa 100644 --- a/pkg/models/transaction.go +++ b/pkg/models/transaction.go @@ -151,12 +151,6 @@ type TransactionAmountsRequestItem struct { EndTime int64 } -// TransactionMonthAmountsRequest represents all parameters of transaction month amounts request -type TransactionMonthAmountsRequest struct { - StartYearMonth string `form:"start_year_month"` - EndYearMonth string `form:"end_year_month"` -} - // TransactionGetRequest represents all parameters of transaction getting request type TransactionGetRequest struct { Id int64 `form:"id,string" binding:"required,min=1"` @@ -170,14 +164,10 @@ type TransactionDeleteRequest struct { Id int64 `json:"id,string" binding:"required,min=1"` } -// TransactionAccountsAmount represents transaction accounts amount map -type TransactionAccountsAmount map[int64]*TransactionAccountAmount - -// TransactionAccountAmount represents transaction account amount -type TransactionAccountAmount struct { - AccountId int64 - TotalIncomeAmount int64 - TotalExpenseAmount int64 +// YearMonthRangeRequest represents all parameters of a request with year and month range +type YearMonthRangeRequest struct { + StartYearMonth string `form:"start_year_month"` + EndYearMonth string `form:"end_year_month"` } // TransactionGeoLocationResponse represents a view-object of transaction geographic location info @@ -381,7 +371,7 @@ func (t *TransactionAmountsRequest) GetTransactionAmountsRequestItems() ([]*Tran } // GetStartTimeAndEndTime returns start unix time and end unix time by request parameter -func (t *TransactionMonthAmountsRequest) GetStartTimeAndEndTime(utcOffset int16) (int64, int64, error) { +func (t *YearMonthRangeRequest) GetStartTimeAndEndTime(utcOffset int16) (int64, int64, error) { startUnixTime := int64(0) endUnixTime := time.Now().Unix() @@ -431,28 +421,6 @@ func (s TransactionInfoResponseSlice) Less(i, j int) bool { return s[i].Id > s[j].Id } -// TransactionMonthAmountsResponseItemSlice represents the slice data structure of TransactionMonthAmountsResponseItem -type TransactionMonthAmountsResponseItemSlice []*TransactionMonthAmountsResponseItem - -// Len returns the count of items -func (s TransactionMonthAmountsResponseItemSlice) Len() int { - return len(s) -} - -// Swap swaps two items -func (s TransactionMonthAmountsResponseItemSlice) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Less reports whether the first item is less than the second one -func (s TransactionMonthAmountsResponseItemSlice) Less(i, j int) bool { - if s[i].Year != s[j].Year { - return s[i].Year > s[j].Year - } - - return s[i].Month > s[j].Month -} - // TransactionAmountsResponseItemAmountInfoSlice represents the slice data structure of TransactionAmountsResponseItemAmountInfo type TransactionAmountsResponseItemAmountInfoSlice []*TransactionAmountsResponseItemAmountInfo diff --git a/pkg/services/transactions.go b/pkg/services/transactions.go index 6064cdbe..98078c4d 100644 --- a/pkg/services/transactions.go +++ b/pkg/services/transactions.go @@ -1035,73 +1035,6 @@ func (s *TransactionService) GetAccountsTotalIncomeAndExpense(c *core.Context, u return incomeAmounts, expenseAmounts, nil } -// GetAccountsMonthTotalIncomeAndExpense returns the every accounts total income and expense amount in month by specific date range -func (s *TransactionService) GetAccountsMonthTotalIncomeAndExpense(c *core.Context, uid int64, startUnixTime int64, endUnixTime int64, pageCount int) (map[string]models.TransactionAccountsAmount, error) { - if uid <= 0 { - return nil, errs.ErrUserIdInvalid - } - - startTransactionTime := utils.GetMinTransactionTimeFromUnixTime(startUnixTime) - endTransactionTime := utils.GetMaxTransactionTimeFromUnixTime(endUnixTime) - - minTransactionTime := startTransactionTime - maxTransactionTime := endTransactionTime - var allTransactions []*models.Transaction - - for maxTransactionTime > 0 { - var transactions []*models.Transaction - - err := s.UserDataDB(uid).NewSession(c).Select("uid, type, account_id, transaction_time, timezone_utc_offset, amount").Where("uid=? AND deleted=? AND (type=? OR type=?) AND transaction_time>=? AND transaction_time<=?", uid, false, models.TRANSACTION_DB_TYPE_INCOME, models.TRANSACTION_DB_TYPE_EXPENSE, minTransactionTime, maxTransactionTime).Limit(pageCount, 0).OrderBy("transaction_time desc").Find(&transactions) - - if err != nil { - return nil, err - } - - allTransactions = append(allTransactions, transactions...) - - if len(transactions) < pageCount { - maxTransactionTime = 0 - break - } - - maxTransactionTime = transactions[len(transactions)-1].TransactionTime - 1 - } - - totalAmounts := make(map[string]models.TransactionAccountsAmount) - - for i := 0; i < len(allTransactions); i++ { - transaction := allTransactions[i] - transactionTimeZone := time.FixedZone("Transaction Timezone", int(transaction.TimezoneUtcOffset)*60) - yearMonth := utils.FormatUnixTimeToYearMonth(utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime), transactionTimeZone) - - monthAccountsAmounts, exists := totalAmounts[yearMonth] - - if !exists { - monthAccountsAmounts = make(models.TransactionAccountsAmount) - totalAmounts[yearMonth] = monthAccountsAmounts - } - - monthAccountAmount, exists := monthAccountsAmounts[transaction.AccountId] - - if !exists { - monthAccountAmount = &models.TransactionAccountAmount{ - AccountId: transaction.AccountId, - TotalIncomeAmount: 0, - TotalExpenseAmount: 0, - } - monthAccountsAmounts[transaction.AccountId] = monthAccountAmount - } - - if transaction.Type == models.TRANSACTION_DB_TYPE_INCOME { - monthAccountAmount.TotalIncomeAmount += transaction.Amount - } else if transaction.Type == models.TRANSACTION_DB_TYPE_EXPENSE { - monthAccountAmount.TotalExpenseAmount += transaction.Amount - } - } - - return totalAmounts, nil -} - // GetAccountsAndCategoriesTotalIncomeAndExpense returns the every accounts and categories total income and expense amount by specific date range func (s *TransactionService) GetAccountsAndCategoriesTotalIncomeAndExpense(c *core.Context, uid int64, startUnixTime int64, endUnixTime int64) ([]*models.Transaction, error) { if uid <= 0 {