@@ -107,8 +107,8 @@ func (s *TransactionService) GetAllSpecifiedTransactions(c core.Context, uid int
107107 return allTransactions , nil
108108}
109109
110- // GetAllTransactionsWithAccountBalanceByMaxTime returns account statement within time range
111- func (s * TransactionService ) GetAllTransactionsWithAccountBalanceByMaxTime (c core.Context , uid int64 , pageCount int32 , maxTransactionTime int64 , minTransactionTime int64 , accountId int64 , accountCategory models.AccountCategory ) ([]* models.TransactionWithAccountBalance , int64 , int64 , int64 , int64 , error ) {
110+ // GetAllTransactionsInOneAccountWithAccountBalanceByMaxTime returns account statement within time range
111+ func (s * TransactionService ) GetAllTransactionsInOneAccountWithAccountBalanceByMaxTime (c core.Context , uid int64 , pageCount int32 , maxTransactionTime int64 , minTransactionTime int64 , accountId int64 , accountCategory models.AccountCategory ) ([]* models.TransactionWithAccountBalance , int64 , int64 , int64 , int64 , error ) {
112112 if maxTransactionTime <= 0 {
113113 maxTransactionTime = utils .GetMaxTransactionTimeFromUnixTime (time .Now ().Unix ())
114114 }
@@ -158,7 +158,7 @@ func (s *TransactionService) GetAllTransactionsWithAccountBalanceByMaxTime(c cor
158158 } else if transaction .Type == models .TRANSACTION_DB_TYPE_TRANSFER_IN {
159159 accumulatedBalance = accumulatedBalance + transaction .Amount
160160 } else {
161- log .Errorf (c , "[transactions.GetAllTransactionsWithAccountBalanceByMaxTime ] trasaction type (%d) is invalid (id:%d)" , transaction .TransactionId , transaction .Type )
161+ log .Errorf (c , "[transactions.GetAllTransactionsInOneAccountWithAccountBalanceByMaxTime ] trasaction type (%d) is invalid (id:%d)" , transaction .TransactionId , transaction .Type )
162162 return nil , 0 , 0 , 0 , 0 , errs .ErrTransactionTypeInvalid
163163 }
164164
@@ -197,6 +197,132 @@ func (s *TransactionService) GetAllTransactionsWithAccountBalanceByMaxTime(c cor
197197 return allTransactionsAndAccountBalance , totalInflows , totalOutflows , openingBalance , accumulatedBalance , nil
198198}
199199
200+ // GetAllAccountsDailyOpeningAndClosingBalance returns daily opening and closing balance of all accounts within time range
201+ func (s * TransactionService ) GetAllAccountsDailyOpeningAndClosingBalance (c core.Context , uid int64 , maxTransactionTime int64 , minTransactionTime int64 , utcOffset int16 ) (map [int32 ][]* models.TransactionWithAccountBalance , error ) {
202+ if maxTransactionTime <= 0 {
203+ maxTransactionTime = utils .GetMaxTransactionTimeFromUnixTime (time .Now ().Unix ())
204+ }
205+
206+ clientLocation := time .FixedZone ("Client Timezone" , int (utcOffset )* 60 )
207+ var allTransactions []* models.Transaction
208+
209+ for maxTransactionTime > 0 {
210+ transactions , err := s .GetTransactionsByMaxTime (c , uid , maxTransactionTime , 0 , 0 , nil , nil , nil , false , models .TRANSACTION_TAG_FILTER_HAS_ANY , "" , "" , 1 , pageCountForLoadTransactionAmounts , false , false )
211+
212+ if err != nil {
213+ return nil , err
214+ }
215+
216+ allTransactions = append (allTransactions , transactions ... )
217+
218+ if len (transactions ) < pageCountForLoadTransactionAmounts {
219+ maxTransactionTime = 0
220+ break
221+ }
222+
223+ maxTransactionTime = transactions [len (transactions )- 1 ].TransactionTime - 1
224+ }
225+
226+ accountDailyLastBalances := make (map [string ]* models.TransactionWithAccountBalance )
227+ accountDailyBalances := make (map [int32 ][]* models.TransactionWithAccountBalance )
228+
229+ if len (allTransactions ) < 1 {
230+ return accountDailyBalances , nil
231+ }
232+
233+ accumulatedBalances := make (map [int64 ]int64 )
234+ accumulatedBalancesBeforeStartTime := make (map [int64 ]int64 )
235+
236+ for i := len (allTransactions ) - 1 ; i >= 0 ; i -- {
237+ transaction := allTransactions [i ]
238+ accumulatedBalance := accumulatedBalances [transaction .AccountId ]
239+ lastAccumulatedBalance := accumulatedBalances [transaction .AccountId ]
240+
241+ if transaction .Type == models .TRANSACTION_DB_TYPE_MODIFY_BALANCE {
242+ accumulatedBalance = accumulatedBalance + transaction .RelatedAccountAmount
243+ } else if transaction .Type == models .TRANSACTION_DB_TYPE_INCOME {
244+ accumulatedBalance = accumulatedBalance + transaction .Amount
245+ } else if transaction .Type == models .TRANSACTION_DB_TYPE_EXPENSE {
246+ accumulatedBalance = accumulatedBalance - transaction .Amount
247+ } else if transaction .Type == models .TRANSACTION_DB_TYPE_TRANSFER_OUT {
248+ accumulatedBalance = accumulatedBalance - transaction .Amount
249+ } else if transaction .Type == models .TRANSACTION_DB_TYPE_TRANSFER_IN {
250+ accumulatedBalance = accumulatedBalance + transaction .Amount
251+ } else {
252+ log .Errorf (c , "[transactions.GetAllTransactionsWithAccountBalanceByMaxTime] trasaction type (%d) is invalid (id:%d)" , transaction .TransactionId , transaction .Type )
253+ return nil , errs .ErrTransactionTypeInvalid
254+ }
255+
256+ accumulatedBalances [transaction .AccountId ] = accumulatedBalance
257+
258+ if transaction .TransactionTime < minTransactionTime {
259+ accumulatedBalancesBeforeStartTime [transaction .AccountId ] = accumulatedBalance
260+ continue
261+ }
262+
263+ yearMonthDay := utils .FormatUnixTimeToNumericYearMonthDay (utils .GetUnixTimeFromTransactionTime (transaction .TransactionTime ), clientLocation )
264+ groupKey := fmt .Sprintf ("%d_%d" , yearMonthDay , transaction .AccountId )
265+ dailyAccountBalance , exists := accountDailyLastBalances [groupKey ]
266+
267+ if exists {
268+ dailyAccountBalance .AccountClosingBalance = accumulatedBalance
269+ } else {
270+ dailyAccountBalance = & models.TransactionWithAccountBalance {
271+ Transaction : & models.Transaction {
272+ AccountId : transaction .AccountId ,
273+ },
274+ AccountOpeningBalance : lastAccumulatedBalance ,
275+ AccountClosingBalance : accumulatedBalance ,
276+ }
277+ accountDailyLastBalances [groupKey ] = dailyAccountBalance
278+ }
279+ }
280+
281+ firstTransactionTime := allTransactions [len (allTransactions )- 1 ].TransactionTime
282+
283+ if minTransactionTime > firstTransactionTime {
284+ firstTransactionTime = minTransactionTime
285+ }
286+
287+ firstYearMonthDay := utils .FormatUnixTimeToNumericYearMonthDay (utils .GetUnixTimeFromTransactionTime (firstTransactionTime ), clientLocation )
288+
289+ // fill in the opening balance for accounts that do not have transactions on the first day
290+ for accountId , accumulatedBalance := range accumulatedBalancesBeforeStartTime {
291+ if accumulatedBalance == 0 {
292+ continue
293+ }
294+
295+ groupKey := fmt .Sprintf ("%d_%d" , firstYearMonthDay , accountId )
296+
297+ if _ , exists := accountDailyLastBalances [groupKey ]; exists {
298+ continue
299+ }
300+
301+ accountDailyLastBalances [groupKey ] = & models.TransactionWithAccountBalance {
302+ Transaction : & models.Transaction {
303+ AccountId : accountId ,
304+ },
305+ AccountOpeningBalance : accumulatedBalance ,
306+ AccountClosingBalance : accumulatedBalance ,
307+ }
308+ }
309+
310+ for groupKey , transactionWithAccountBalance := range accountDailyLastBalances {
311+ groupKeyParts := strings .Split (groupKey , "_" )
312+ yearMonthDay , _ := utils .StringToInt32 (groupKeyParts [0 ])
313+ dailyAccountBalances , exists := accountDailyBalances [yearMonthDay ]
314+
315+ if ! exists {
316+ dailyAccountBalances = make ([]* models.TransactionWithAccountBalance , 0 )
317+ }
318+
319+ dailyAccountBalances = append (dailyAccountBalances , transactionWithAccountBalance )
320+ accountDailyBalances [yearMonthDay ] = dailyAccountBalances
321+ }
322+
323+ return accountDailyBalances , nil
324+ }
325+
200326// GetTransactionsByMaxTime returns transactions before given time
201327func (s * TransactionService ) GetTransactionsByMaxTime (c core.Context , uid int64 , maxTransactionTime int64 , minTransactionTime int64 , transactionType models.TransactionType , categoryIds []int64 , accountIds []int64 , tagIds []int64 , noTags bool , tagFilterType models.TransactionTagFilterType , amountFilter string , keyword string , page int32 , count int32 , needOneMoreItem bool , noDuplicated bool ) ([]* models.Transaction , error ) {
202328 if uid <= 0 {
0 commit comments