diff options
author | 2025-04-27 23:02:42 +0530 | |
---|---|---|
committer | 2025-04-27 23:02:42 +0530 | |
commit | 538d933baef56d7ee76f78617b553d63713efa24 (patch) | |
tree | 3fcbc4208849dfa0e5dc8fe5761e103a3591c283 /backend/internal/api | |
parent | 3941d80ff120238b973451325b834ebd8377281e (diff) | |
download | finance-master.tar.gz finance-master.tar.bz2 finance-master.zip |
Diffstat (limited to 'backend/internal/api')
-rw-r--r-- | backend/internal/api/handlers/goal_handler.go | 128 | ||||
-rw-r--r-- | backend/internal/api/v1/goals/goals.go | 26 |
2 files changed, 152 insertions, 2 deletions
diff --git a/backend/internal/api/handlers/goal_handler.go b/backend/internal/api/handlers/goal_handler.go index 09bea74..efbe7f9 100644 --- a/backend/internal/api/handlers/goal_handler.go +++ b/backend/internal/api/handlers/goal_handler.go @@ -6,6 +6,7 @@ import ( "strconv" "time" + "finance/backend/internal/core" "finance/backend/internal/database" "finance/backend/internal/models" @@ -35,13 +36,21 @@ type UpdateGoalProgressInput struct { CurrentAmount int64 `json:"currentAmount" binding:"required"` } +// LinkTransactionInput defines the structure for linking a transaction to a goal +type LinkTransactionInput struct { + TransactionID uint `json:"transactionId" binding:"required"` +} + // GoalHandler handles all goal-related operations in the API type GoalHandler struct { + goalService *core.GoalService } // NewGoalHandler creates and returns a new GoalHandler instance func NewGoalHandler() *GoalHandler { - return &GoalHandler{} + return &GoalHandler{ + goalService: core.NewGoalService(), + } } // GetGoals retrieves all goals for the authenticated user @@ -270,3 +279,120 @@ func (h *GoalHandler) DeleteGoal(c *gin.Context) { log.Printf("Goal ID %d deleted successfully for user %d", goalID, userID) c.JSON(http.StatusOK, gin.H{"message": "Goal deleted successfully"}) } + +// GetGoalProgressDetails retrieves a goal with detailed progress information +func (h *GoalHandler) GetGoalProgressDetails(c *gin.Context) { + userID := c.MustGet("userID").(uint) + goalID, err := strconv.ParseUint(c.Param("id"), 10, 32) + if err != nil { + log.Printf("Error parsing goal ID: %v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid goal ID"}) + return + } + + progress, err := h.goalService.GetGoalProgress(userID, uint(goalID)) + if err != nil { + log.Printf("Error fetching goal progress for ID %d, user %d: %v", goalID, userID, err) + c.JSON(http.StatusNotFound, gin.H{"error": "Goal not found"}) + return + } + + c.JSON(http.StatusOK, progress) +} + +// GetAllGoalsProgressDetails retrieves all goals with enhanced progress details +func (h *GoalHandler) GetAllGoalsProgressDetails(c *gin.Context) { + userID := c.MustGet("userID").(uint) + + // Filter by status if provided + status := c.Query("status") + + progress, err := h.goalService.GetAllGoalsProgress(userID, status) + if err != nil { + log.Printf("Error fetching all goals progress for user %d: %v", userID, err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get goal progress"}) + return + } + + c.JSON(http.StatusOK, progress) +} + +// LinkTransactionToGoal links a transaction to a specific goal +func (h *GoalHandler) LinkTransactionToGoal(c *gin.Context) { + userID := c.MustGet("userID").(uint) + goalID, err := strconv.ParseUint(c.Param("id"), 10, 32) + if err != nil { + log.Printf("Error parsing goal ID: %v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid goal ID"}) + return + } + + var input LinkTransactionInput + if err := c.ShouldBindJSON(&input); err != nil { + log.Printf("Error binding JSON for linking transaction: %v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + // Verify the goal belongs to the user + var goal models.Goal + if err := database.DB.Where("id = ? AND user_id = ?", goalID, userID).First(&goal).Error; err != nil { + log.Printf("Error fetching goal ID %d for user %d: %v", goalID, userID, err) + c.JSON(http.StatusNotFound, gin.H{"error": "Goal not found"}) + return + } + + // Verify the transaction belongs to the user + var transaction models.Transaction + if err := database.DB.Where("id = ? AND user_id = ?", input.TransactionID, userID).First(&transaction).Error; err != nil { + log.Printf("Error fetching transaction ID %d for user %d: %v", input.TransactionID, userID, err) + c.JSON(http.StatusNotFound, gin.H{"error": "Transaction not found"}) + return + } + + // Link the transaction to the goal + if err := h.goalService.LinkTransactionToGoal(input.TransactionID, uint(goalID)); err != nil { + log.Printf("Error linking transaction %d to goal %d: %v", input.TransactionID, goalID, err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to link transaction to goal"}) + return + } + + log.Printf("Transaction ID %d successfully linked to goal ID %d for user %d", input.TransactionID, goalID, userID) + c.JSON(http.StatusOK, gin.H{"message": "Transaction linked to goal successfully"}) +} + +// RecalculateGoalProgress recalculates a goal's progress based on linked transactions +func (h *GoalHandler) RecalculateGoalProgress(c *gin.Context) { + userID := c.MustGet("userID").(uint) + goalID, err := strconv.ParseUint(c.Param("id"), 10, 32) + if err != nil { + log.Printf("Error parsing goal ID: %v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid goal ID"}) + return + } + + // Verify the goal belongs to the user + var goal models.Goal + if err := database.DB.Where("id = ? AND user_id = ?", goalID, userID).First(&goal).Error; err != nil { + log.Printf("Error fetching goal ID %d for user %d: %v", goalID, userID, err) + c.JSON(http.StatusNotFound, gin.H{"error": "Goal not found"}) + return + } + + // Recalculate the goal progress + if err := h.goalService.UpdateGoalFromTransactions(uint(goalID)); err != nil { + log.Printf("Error recalculating goal progress for ID %d: %v", goalID, err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to recalculate goal progress"}) + return + } + + // Fetch the updated goal to return in response + if err := database.DB.First(&goal, goalID).Error; err != nil { + log.Printf("Error fetching updated goal after recalculation: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch updated goal"}) + return + } + + log.Printf("Goal ID %d progress recalculated successfully for user %d", goalID, userID) + c.JSON(http.StatusOK, goal) +} diff --git a/backend/internal/api/v1/goals/goals.go b/backend/internal/api/v1/goals/goals.go index 1d2cd6f..4f99468 100644 --- a/backend/internal/api/v1/goals/goals.go +++ b/backend/internal/api/v1/goals/goals.go @@ -1,7 +1,7 @@ package goals import ( - "finance/backend/handlers" + "finance/backend/internal/api/handlers" "github.com/gin-gonic/gin" ) @@ -41,3 +41,27 @@ func UpdateGoalProgress() gin.HandlerFunc { handler := handlers.NewGoalHandler() return handler.UpdateGoalProgress } + +// GetGoalProgressDetails returns goal with enhanced progress tracking details +func GetGoalProgressDetails() gin.HandlerFunc { + handler := handlers.NewGoalHandler() + return handler.GetGoalProgressDetails +} + +// GetAllGoalsProgressDetails returns all goals with enhanced progress tracking details +func GetAllGoalsProgressDetails() gin.HandlerFunc { + handler := handlers.NewGoalHandler() + return handler.GetAllGoalsProgressDetails +} + +// LinkTransactionToGoal links a transaction to a goal for progress tracking +func LinkTransactionToGoal() gin.HandlerFunc { + handler := handlers.NewGoalHandler() + return handler.LinkTransactionToGoal +} + +// RecalculateGoalProgress recalculates the progress of a goal based on its transactions +func RecalculateGoalProgress() gin.HandlerFunc { + handler := handlers.NewGoalHandler() + return handler.RecalculateGoalProgress +} |