99 lines
2.9 KiB
Go
99 lines
2.9 KiB
Go
package service
|
|
|
|
import (
|
|
"time"
|
|
|
|
"git.juancwu.dev/juancwu/budgit/internal/model"
|
|
"git.juancwu.dev/juancwu/budgit/internal/repository"
|
|
)
|
|
|
|
type ReportService struct {
|
|
expenseRepo repository.ExpenseRepository
|
|
}
|
|
|
|
func NewReportService(expenseRepo repository.ExpenseRepository) *ReportService {
|
|
return &ReportService{expenseRepo: expenseRepo}
|
|
}
|
|
|
|
type DateRange struct {
|
|
Label string
|
|
Key string
|
|
From time.Time
|
|
To time.Time
|
|
}
|
|
|
|
func (s *ReportService) GetSpendingReport(spaceID string, from, to time.Time) (*model.SpendingReport, error) {
|
|
byTag, err := s.expenseRepo.GetExpensesByTag(spaceID, from, to)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
daily, err := s.expenseRepo.GetDailySpending(spaceID, from, to)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
monthly, err := s.expenseRepo.GetMonthlySpending(spaceID, from, to)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
topExpenses, err := s.expenseRepo.GetTopExpenses(spaceID, from, to, 10)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Get tags and payment methods for top expenses
|
|
ids := make([]string, len(topExpenses))
|
|
for i, e := range topExpenses {
|
|
ids[i] = e.ID
|
|
}
|
|
|
|
tagsMap, _ := s.expenseRepo.GetTagsByExpenseIDs(ids)
|
|
methodsMap, _ := s.expenseRepo.GetPaymentMethodsByExpenseIDs(ids)
|
|
|
|
topWithTags := make([]*model.ExpenseWithTagsAndMethod, len(topExpenses))
|
|
for i, e := range topExpenses {
|
|
topWithTags[i] = &model.ExpenseWithTagsAndMethod{
|
|
Expense: *e,
|
|
Tags: tagsMap[e.ID],
|
|
PaymentMethod: methodsMap[e.ID],
|
|
}
|
|
}
|
|
|
|
totalIncome, totalExpenses, err := s.expenseRepo.GetIncomeVsExpenseSummary(spaceID, from, to)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &model.SpendingReport{
|
|
ByTag: byTag,
|
|
DailySpending: daily,
|
|
MonthlySpending: monthly,
|
|
TopExpenses: topWithTags,
|
|
TotalIncome: totalIncome,
|
|
TotalExpenses: totalExpenses,
|
|
NetBalance: totalIncome.Sub(totalExpenses),
|
|
}, nil
|
|
}
|
|
|
|
func GetPresetDateRanges(now time.Time) []DateRange {
|
|
thisMonthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
|
|
thisMonthEnd := thisMonthStart.AddDate(0, 1, -1)
|
|
thisMonthEnd = time.Date(thisMonthEnd.Year(), thisMonthEnd.Month(), thisMonthEnd.Day(), 23, 59, 59, 0, now.Location())
|
|
|
|
lastMonthStart := thisMonthStart.AddDate(0, -1, 0)
|
|
lastMonthEnd := thisMonthStart.AddDate(0, 0, -1)
|
|
lastMonthEnd = time.Date(lastMonthEnd.Year(), lastMonthEnd.Month(), lastMonthEnd.Day(), 23, 59, 59, 0, now.Location())
|
|
|
|
last3MonthsStart := thisMonthStart.AddDate(0, -2, 0)
|
|
|
|
yearStart := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location())
|
|
|
|
return []DateRange{
|
|
{Label: "This Month", Key: "this_month", From: thisMonthStart, To: thisMonthEnd},
|
|
{Label: "Last Month", Key: "last_month", From: lastMonthStart, To: lastMonthEnd},
|
|
{Label: "Last 3 Months", Key: "last_3_months", From: last3MonthsStart, To: thisMonthEnd},
|
|
{Label: "This Year", Key: "this_year", From: yearStart, To: thisMonthEnd},
|
|
}
|
|
}
|