aboutsummaryrefslogtreecommitdiffstats
path: root/backend/handlers/goal_handler.go
diff options
context:
space:
mode:
authorLibravatarLibravatar Biswa Kalyan Bhuyan <biswa@surgot.in> 2025-04-25 02:39:12 +0530
committerLibravatarLibravatar Biswa Kalyan Bhuyan <biswa@surgot.in> 2025-04-25 02:39:12 +0530
commitd8856efd30dfcb05b26a5b66b5bb14cc0604e2b1 (patch)
tree6d4c1b99ec45636bf0038a46d90b585302a3a89a /backend/handlers/goal_handler.go
parent5b23b22c60027f18dfb218789eea0e1e6dc38a37 (diff)
downloadfinance-d8856efd30dfcb05b26a5b66b5bb14cc0604e2b1.tar.gz
finance-d8856efd30dfcb05b26a5b66b5bb14cc0604e2b1.tar.bz2
finance-d8856efd30dfcb05b26a5b66b5bb14cc0604e2b1.zip
finance/backend: feat: added v1/goals and handlers/goal_handler for Goal CRUD
Diffstat (limited to 'backend/handlers/goal_handler.go')
-rw-r--r--backend/handlers/goal_handler.go243
1 files changed, 243 insertions, 0 deletions
diff --git a/backend/handlers/goal_handler.go b/backend/handlers/goal_handler.go
new file mode 100644
index 0000000..dd2791c
--- /dev/null
+++ b/backend/handlers/goal_handler.go
@@ -0,0 +1,243 @@
+package handlers
+
+import (
+ "net/http"
+ "strconv"
+ "time"
+
+ "finance/backend/internal/database"
+ "finance/backend/internal/models"
+
+ "github.com/gin-gonic/gin"
+)
+
+type CreateGoalInput struct {
+ Name string `json:"name" binding:"required"`
+ TargetAmount int64 `json:"targetAmount" binding:"required"`
+ CurrentAmount int64 `json:"currentAmount"`
+ TargetDate string `json:"targetDate"` // YYYY-MM-DD format
+ Status string `json:"status"`
+}
+
+type UpdateGoalInput struct {
+ Name string `json:"name"`
+ TargetAmount int64 `json:"targetAmount"`
+ CurrentAmount int64 `json:"currentAmount"`
+ TargetDate string `json:"targetDate"` // YYYY-MM-DD format
+ Status string `json:"status"`
+}
+
+type UpdateGoalProgressInput struct {
+ CurrentAmount int64 `json:"currentAmount" binding:"required"`
+}
+
+// GoalHandler handles goal-related operations
+type GoalHandler struct {
+}
+
+// NewGoalHandler creates a new goal handler
+func NewGoalHandler() *GoalHandler {
+ return &GoalHandler{}
+}
+
+// GetGoals gets all goals for the current user
+func (h *GoalHandler) GetGoals(c *gin.Context) {
+ userID := c.MustGet("userID").(uint)
+ var goals []models.Goal
+
+ query := database.DB.Where("user_id = ?", userID)
+
+ // Filter by status if provided
+ status := c.Query("status")
+ if status != "" {
+ query = query.Where("status = ?", status)
+ }
+
+ if err := query.Find(&goals).Error; err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get goals"})
+ return
+ }
+
+ c.JSON(http.StatusOK, goals)
+}
+
+// GetGoal gets a specific goal by ID
+func (h *GoalHandler) GetGoal(c *gin.Context) {
+ userID := c.MustGet("userID").(uint)
+ goalID, err := strconv.ParseUint(c.Param("id"), 10, 32)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid goal ID"})
+ return
+ }
+
+ var goal models.Goal
+ if err := database.DB.Where("id = ? AND user_id = ?", goalID, userID).First(&goal).Error; err != nil {
+ c.JSON(http.StatusNotFound, gin.H{"error": "Goal not found"})
+ return
+ }
+
+ c.JSON(http.StatusOK, goal)
+}
+
+// CreateGoal creates a new goal for the current user
+func (h *GoalHandler) CreateGoal(c *gin.Context) {
+ userID := c.MustGet("userID").(uint)
+ var input CreateGoalInput
+
+ if err := c.ShouldBindJSON(&input); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+
+ // Set default status if not provided
+ status := "Active"
+ if input.Status != "" {
+ status = input.Status
+ }
+
+ // Parse target date if provided
+ var targetDate time.Time
+ if input.TargetDate != "" {
+ parsedDate, err := time.Parse("2006-01-02", input.TargetDate)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid date format for targetDate. Use YYYY-MM-DD"})
+ return
+ }
+ targetDate = parsedDate
+ }
+
+ goal := models.Goal{
+ UserID: userID,
+ Name: input.Name,
+ TargetAmount: input.TargetAmount,
+ CurrentAmount: input.CurrentAmount,
+ Status: status,
+ }
+
+ // Only set target date if it was provided
+ if !targetDate.IsZero() {
+ goal.TargetDate = targetDate
+ }
+
+ if err := database.DB.Create(&goal).Error; err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create goal"})
+ return
+ }
+
+ c.JSON(http.StatusCreated, goal)
+}
+
+// UpdateGoal updates an existing goal
+func (h *GoalHandler) UpdateGoal(c *gin.Context) {
+ userID := c.MustGet("userID").(uint)
+ goalID, err := strconv.ParseUint(c.Param("id"), 10, 32)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid goal ID"})
+ return
+ }
+
+ var goal models.Goal
+ if err := database.DB.Where("id = ? AND user_id = ?", goalID, userID).First(&goal).Error; err != nil {
+ c.JSON(http.StatusNotFound, gin.H{"error": "Goal not found"})
+ return
+ }
+
+ var input UpdateGoalInput
+ if err := c.ShouldBindJSON(&input); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+
+ // Update fields that were provided
+ if input.Name != "" {
+ goal.Name = input.Name
+ }
+ if input.TargetAmount != 0 {
+ goal.TargetAmount = input.TargetAmount
+ }
+ if input.CurrentAmount != 0 {
+ goal.CurrentAmount = input.CurrentAmount
+ }
+ if input.TargetDate != "" {
+ parsedDate, err := time.Parse("2006-01-02", input.TargetDate)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid date format for targetDate. Use YYYY-MM-DD"})
+ return
+ }
+ goal.TargetDate = parsedDate
+ }
+ if input.Status != "" {
+ goal.Status = input.Status
+ }
+
+ // Check if goal has been achieved
+ if goal.CurrentAmount >= goal.TargetAmount {
+ goal.Status = "Achieved"
+ }
+
+ if err := database.DB.Save(&goal).Error; err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update goal"})
+ return
+ }
+
+ c.JSON(http.StatusOK, goal)
+}
+
+// UpdateGoalProgress updates just the progress (current amount) of a goal
+func (h *GoalHandler) UpdateGoalProgress(c *gin.Context) {
+ userID := c.MustGet("userID").(uint)
+ goalID, err := strconv.ParseUint(c.Param("id"), 10, 32)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid goal ID"})
+ return
+ }
+
+ var goal models.Goal
+ if err := database.DB.Where("id = ? AND user_id = ?", goalID, userID).First(&goal).Error; err != nil {
+ c.JSON(http.StatusNotFound, gin.H{"error": "Goal not found"})
+ return
+ }
+
+ var input UpdateGoalProgressInput
+ if err := c.ShouldBindJSON(&input); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+
+ goal.CurrentAmount = input.CurrentAmount
+
+ // Check if goal has been achieved
+ if goal.CurrentAmount >= goal.TargetAmount {
+ goal.Status = "Achieved"
+ }
+
+ if err := database.DB.Save(&goal).Error; err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update goal progress"})
+ return
+ }
+
+ c.JSON(http.StatusOK, goal)
+}
+
+// DeleteGoal deletes a goal
+func (h *GoalHandler) DeleteGoal(c *gin.Context) {
+ userID := c.MustGet("userID").(uint)
+ goalID, err := strconv.ParseUint(c.Param("id"), 10, 32)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid goal ID"})
+ return
+ }
+
+ var goal models.Goal
+ if err := database.DB.Where("id = ? AND user_id = ?", goalID, userID).First(&goal).Error; err != nil {
+ c.JSON(http.StatusNotFound, gin.H{"error": "Goal not found"})
+ return
+ }
+
+ if err := database.DB.Delete(&goal).Error; err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete goal"})
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{"message": "Goal deleted successfully"})
+}