add outflows / inflows / net cash flow in statistics & analysis

This commit is contained in:
MaysWind
2025-10-27 00:52:41 +08:00
parent 9a2f682379
commit 5cb7eca340
26 changed files with 226 additions and 49 deletions
+35 -15
View File
@@ -1796,8 +1796,8 @@ func (s *TransactionService) GetAccountsTotalIncomeAndExpense(c core.Context, ui
return incomeAmounts, expenseAmounts, 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, tagIds []int64, noTags bool, tagFilterType models.TransactionTagFilterType, keyword string, utcOffset int16, useTransactionTimezone bool) ([]*models.Transaction, error) {
// GetAccountsAndCategoriesTotalInflowAndOutflow returns the every accounts and categories total inflows and outflows amount by specific date range
func (s *TransactionService) GetAccountsAndCategoriesTotalInflowAndOutflow(c core.Context, uid int64, startUnixTime int64, endUnixTime int64, tagIds []int64, noTags bool, tagFilterType models.TransactionTagFilterType, keyword string, utcOffset int16, useTransactionTimezone bool) ([]*models.Transaction, error) {
if uid <= 0 {
return nil, errs.ErrUserIdInvalid
}
@@ -1817,12 +1817,14 @@ func (s *TransactionService) GetAccountsAndCategoriesTotalIncomeAndExpense(c cor
endTransactionTime = utils.GetMaxTransactionTimeFromUnixTime(endUnixTime)
}
condition := "uid=? AND deleted=? AND (type=? OR type=?)"
conditionParams := make([]any, 0, 4)
condition := "uid=? AND deleted=? AND (type=? OR type=? OR type=? OR type=?)"
conditionParams := make([]any, 0, 6)
conditionParams = append(conditionParams, uid)
conditionParams = append(conditionParams, false)
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)
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_TRANSFER_IN)
minTransactionTime := startTransactionTime
maxTransactionTime := endTransactionTime
@@ -1850,7 +1852,7 @@ func (s *TransactionService) GetAccountsAndCategoriesTotalIncomeAndExpense(c cor
finalConditionParams = append(finalConditionParams, "%%"+keyword+"%%")
}
sess := s.UserDataDB(uid).NewSession(c).Select("category_id, account_id, transaction_time, timezone_utc_offset, amount").Where(finalCondition, finalConditionParams...)
sess := s.UserDataDB(uid).NewSession(c).Select("type, category_id, account_id, related_account_id, transaction_time, timezone_utc_offset, amount").Where(finalCondition, finalConditionParams...)
sess = s.appendFilterTagIdsConditionToQuery(sess, uid, maxTransactionTime, minTransactionTime, tagIds, noTags, tagFilterType)
err := sess.Limit(pageCountForLoadTransactionAmounts, 0).OrderBy("transaction_time desc").Find(&transactions)
@@ -1886,13 +1888,20 @@ func (s *TransactionService) GetAccountsAndCategoriesTotalIncomeAndExpense(c cor
}
groupKey := fmt.Sprintf("%d_%d", transaction.CategoryId, transaction.AccountId)
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
groupKey = fmt.Sprintf("%d_%d_%d_%d", transaction.CategoryId, transaction.AccountId, transaction.RelatedAccountId, transaction.Type)
}
totalAmounts, exists := transactionTotalAmountsMap[groupKey]
if !exists {
totalAmounts = &models.Transaction{
CategoryId: transaction.CategoryId,
AccountId: transaction.AccountId,
Amount: 0,
Type: transaction.Type,
CategoryId: transaction.CategoryId,
AccountId: transaction.AccountId,
RelatedAccountId: transaction.RelatedAccountId,
Amount: 0,
}
transactionTotalAmountsMap[groupKey] = totalAmounts
@@ -1910,8 +1919,8 @@ func (s *TransactionService) GetAccountsAndCategoriesTotalIncomeAndExpense(c cor
return transactionTotalAmounts, nil
}
// GetAccountsAndCategoriesMonthlyIncomeAndExpense returns the every accounts monthly income and expense amount by specific date range
func (s *TransactionService) GetAccountsAndCategoriesMonthlyIncomeAndExpense(c core.Context, uid int64, startYear int32, startMonth int32, endYear int32, endMonth int32, tagIds []int64, noTags bool, tagFilterType models.TransactionTagFilterType, keyword string, utcOffset int16, useTransactionTimezone bool) (map[int32][]*models.Transaction, error) {
// GetAccountsAndCategoriesMonthlyInflowAndOutflow returns the every accounts monthly inflows and outflows amount by specific date range
func (s *TransactionService) GetAccountsAndCategoriesMonthlyInflowAndOutflow(c core.Context, uid int64, startYear int32, startMonth int32, endYear int32, endMonth int32, tagIds []int64, noTags bool, tagFilterType models.TransactionTagFilterType, keyword string, utcOffset int16, useTransactionTimezone bool) (map[int32][]*models.Transaction, error) {
if uid <= 0 {
return nil, errs.ErrUserIdInvalid
}
@@ -1936,12 +1945,14 @@ func (s *TransactionService) GetAccountsAndCategoriesMonthlyIncomeAndExpense(c c
}
}
condition := "uid=? AND deleted=? AND (type=? OR type=?)"
conditionParams := make([]any, 0, 4)
condition := "uid=? AND deleted=? AND (type=? OR type=? OR type=? OR type=?)"
conditionParams := make([]any, 0, 6)
conditionParams = append(conditionParams, uid)
conditionParams = append(conditionParams, false)
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)
conditionParams = append(conditionParams, models.TRANSACTION_DB_TYPE_TRANSFER_IN)
minTransactionTime := startTransactionTime
maxTransactionTime := endTransactionTime
@@ -1969,7 +1980,7 @@ func (s *TransactionService) GetAccountsAndCategoriesMonthlyIncomeAndExpense(c c
finalConditionParams = append(finalConditionParams, "%%"+keyword+"%%")
}
sess := s.UserDataDB(uid).NewSession(c).Select("category_id, account_id, transaction_time, timezone_utc_offset, amount").Where(finalCondition, finalConditionParams...)
sess := s.UserDataDB(uid).NewSession(c).Select("type, category_id, account_id, related_account_id, transaction_time, timezone_utc_offset, amount").Where(finalCondition, finalConditionParams...)
sess = s.appendFilterTagIdsConditionToQuery(sess, uid, maxTransactionTime, minTransactionTime, tagIds, noTags, tagFilterType)
err := sess.Limit(pageCountForLoadTransactionAmounts, 0).OrderBy("transaction_time desc").Find(&transactions)
@@ -2008,13 +2019,22 @@ func (s *TransactionService) GetAccountsAndCategoriesMonthlyIncomeAndExpense(c c
}
groupKey := fmt.Sprintf("%d_%d_%d", yearMonth, transaction.CategoryId, transaction.AccountId)
if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN {
groupKey = fmt.Sprintf("%d_%d_%d_%d_%d", yearMonth, transaction.CategoryId, transaction.AccountId, transaction.RelatedAccountId, transaction.Type)
}
transactionAmounts, exists := transactionsMonthlyAmountsMap[groupKey]
if !exists {
transactionAmounts = &models.Transaction{
CategoryId: transaction.CategoryId,
AccountId: transaction.AccountId,
Type: transaction.Type,
CategoryId: transaction.CategoryId,
AccountId: transaction.AccountId,
RelatedAccountId: transaction.RelatedAccountId,
Amount: 0,
}
transactionsMonthlyAmountsMap[groupKey] = transactionAmounts
}