feat: 添加预算管理功能,包括其handler、service和repository层。
This commit is contained in:
@@ -98,6 +98,7 @@ func (h *BudgetHandler) GetBudget(c *gin.Context) {
|
||||
}
|
||||
|
||||
// GetAllBudgets handles GET /api/v1/budgets
|
||||
// Returns budgets with calculated spent and progress fields
|
||||
func (h *BudgetHandler) GetAllBudgets(c *gin.Context) {
|
||||
// Get user ID from context
|
||||
userID, exists := c.Get("user_id")
|
||||
@@ -106,7 +107,8 @@ func (h *BudgetHandler) GetAllBudgets(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
budgets, err := h.service.GetAllBudgets(userID.(uint))
|
||||
// Use GetAllBudgetsWithProgress to return budgets with spent and progress calculated
|
||||
budgets, err := h.service.GetAllBudgetsWithProgress(userID.(uint))
|
||||
if err != nil {
|
||||
api.InternalError(c, "Failed to get budgets")
|
||||
return
|
||||
|
||||
@@ -66,8 +66,19 @@ func (r *BudgetRepository) Update(budget *models.Budget) error {
|
||||
return fmt.Errorf("failed to check budget existence: %w", err)
|
||||
}
|
||||
|
||||
// Update the budget
|
||||
if err := r.db.Save(budget).Error; err != nil {
|
||||
// Update the budget using Select to explicitly specify fields to update
|
||||
// This ensures that nil/NULL values for CategoryID and AccountID are properly saved
|
||||
if err := r.db.Model(budget).Select(
|
||||
"name",
|
||||
"amount",
|
||||
"period_type",
|
||||
"category_id", // Explicitly include to allow setting to NULL
|
||||
"account_id", // Explicitly include to allow setting to NULL
|
||||
"is_rolling",
|
||||
"start_date",
|
||||
"end_date",
|
||||
"updated_at",
|
||||
).Updates(budget).Error; err != nil {
|
||||
return fmt.Errorf("failed to update budget: %w", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -126,6 +126,65 @@ func (s *BudgetService) GetAllBudgets(userID uint) ([]models.Budget, error) {
|
||||
return budgets, nil
|
||||
}
|
||||
|
||||
// BudgetWithProgress represents a budget with calculated progress fields
|
||||
type BudgetWithProgress struct {
|
||||
models.Budget
|
||||
Spent float64 `json:"spent"`
|
||||
Progress float64 `json:"progress"`
|
||||
}
|
||||
|
||||
// GetAllBudgetsWithProgress retrieves all budgets with calculated spent and progress for a user
|
||||
func (s *BudgetService) GetAllBudgetsWithProgress(userID uint) ([]BudgetWithProgress, error) {
|
||||
budgets, err := s.repo.GetAll(userID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get budgets: %w", err)
|
||||
}
|
||||
|
||||
result := make([]BudgetWithProgress, len(budgets))
|
||||
now := time.Now()
|
||||
|
||||
for i, budget := range budgets {
|
||||
// Calculate current period
|
||||
startDate, endDate := s.calculateCurrentPeriod(&budget, now)
|
||||
|
||||
// Get spent amount for current period
|
||||
spent, err := s.repo.GetSpentAmount(&budget, startDate, endDate)
|
||||
if err != nil {
|
||||
// Log error but continue with 0 spent
|
||||
spent = 0
|
||||
}
|
||||
|
||||
// Calculate effective amount and progress
|
||||
effectiveAmount := budget.Amount
|
||||
|
||||
if budget.IsRolling {
|
||||
// For rolling budgets, calculate effective amount
|
||||
periodsElapsed := s.calculatePeriodsElapsed(&budget, startDate)
|
||||
totalBudget := budget.Amount * float64(periodsElapsed+1)
|
||||
|
||||
historyEnd := startDate.Add(-time.Second)
|
||||
historySpent := 0.0
|
||||
if historyEnd.After(budget.StartDate) {
|
||||
historySpent, _ = s.repo.GetSpentAmount(&budget, budget.StartDate, historyEnd)
|
||||
}
|
||||
effectiveAmount = totalBudget - historySpent
|
||||
}
|
||||
|
||||
progress := 0.0
|
||||
if effectiveAmount > 0 {
|
||||
progress = (spent / effectiveAmount) * 100
|
||||
}
|
||||
|
||||
result[i] = BudgetWithProgress{
|
||||
Budget: budget,
|
||||
Spent: spent,
|
||||
Progress: progress,
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// UpdateBudget updates an existing budget after verifying ownership
|
||||
func (s *BudgetService) UpdateBudget(userID, id uint, input BudgetInput) (*models.Budget, error) {
|
||||
// Get existing budget
|
||||
|
||||
Reference in New Issue
Block a user