aboutsummaryrefslogtreecommitdiffstats
path: root/backend/internal/api/v1/loans
diff options
context:
space:
mode:
Diffstat (limited to 'backend/internal/api/v1/loans')
-rw-r--r--backend/internal/api/v1/loans/loans.go248
1 files changed, 248 insertions, 0 deletions
diff --git a/backend/internal/api/v1/loans/loans.go b/backend/internal/api/v1/loans/loans.go
new file mode 100644
index 0000000..06d96b0
--- /dev/null
+++ b/backend/internal/api/v1/loans/loans.go
@@ -0,0 +1,248 @@
+package loans
+
+import (
+ "net/http"
+ "strconv"
+ "time"
+
+ "finance/backend/internal/database"
+ "finance/backend/internal/models"
+
+ "github.com/gin-gonic/gin"
+ "gorm.io/gorm"
+)
+
+// GetLoans returns all loans for the authenticated user
+func GetLoans() gin.HandlerFunc {
+ return func(c *gin.Context) {
+ // Get user from context (set by auth middleware)
+ user, exists := c.Get("user")
+ if !exists {
+ c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
+ return
+ }
+
+ userObj := user.(*models.User)
+ var loans []models.Loan
+
+ // Fetch all loans for the user
+ if err := database.DB.Where("user_id = ?", userObj.ID).Find(&loans).Error; err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch loans"})
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{"loans": loans})
+ }
+}
+
+// GetLoanByID returns a specific loan by ID
+func GetLoanByID() gin.HandlerFunc {
+ return func(c *gin.Context) {
+ // Get user from context (set by auth middleware)
+ user, exists := c.Get("user")
+ if !exists {
+ c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
+ return
+ }
+ userObj := user.(*models.User)
+
+ // Get loan ID from URL parameter
+ loanID, err := strconv.ParseUint(c.Param("id"), 10, 32)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid loan ID format"})
+ return
+ }
+
+ var loan models.Loan
+
+ // Fetch the loan and ensure it belongs to the authenticated user
+ if err := database.DB.Where("id = ? AND user_id = ?", loanID, userObj.ID).First(&loan).Error; err != nil {
+ if err == gorm.ErrRecordNotFound {
+ c.JSON(http.StatusNotFound, gin.H{"error": "Loan not found"})
+ } else {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch loan"})
+ }
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{"loan": loan})
+ }
+}
+
+// CreateLoan creates a new loan
+func CreateLoan() gin.HandlerFunc {
+ return func(c *gin.Context) {
+ // Get user from context (set by auth middleware)
+ user, exists := c.Get("user")
+ if !exists {
+ c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
+ return
+ }
+ userObj := user.(*models.User)
+
+ // Define a struct to bind the request JSON
+ var input struct {
+ Name string `json:"name" binding:"required"`
+ OriginalAmount int64 `json:"originalAmount" binding:"required"`
+ CurrentBalance int64 `json:"currentBalance" binding:"required"`
+ InterestRate float64 `json:"interestRate"`
+ StartDate string `json:"startDate" binding:"required"`
+ EndDate string `json:"endDate" binding:"required"`
+ AccountID *uint `json:"accountId"`
+ }
+
+ // Bind JSON to struct
+ if err := c.ShouldBindJSON(&input); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+
+ // Parse dates
+ startDate, err := time.Parse("2006-01-02", input.StartDate)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid start date format"})
+ return
+ }
+
+ endDate, err := time.Parse("2006-01-02", input.EndDate)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid end date format"})
+ return
+ }
+
+ // Create loan object
+ loan := models.Loan{
+ UserID: userObj.ID,
+ Name: input.Name,
+ OriginalAmount: input.OriginalAmount,
+ CurrentBalance: input.CurrentBalance,
+ InterestRate: input.InterestRate,
+ StartDate: startDate,
+ EndDate: endDate,
+ AccountID: input.AccountID,
+ }
+
+ // Save to database
+ if err := database.DB.Create(&loan).Error; err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create loan"})
+ return
+ }
+
+ c.JSON(http.StatusCreated, gin.H{"loan": loan})
+ }
+}
+
+// UpdateLoan updates an existing loan
+func UpdateLoan() gin.HandlerFunc {
+ return func(c *gin.Context) {
+ // Get user from context (set by auth middleware)
+ user, exists := c.Get("user")
+ if !exists {
+ c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
+ return
+ }
+ userObj := user.(*models.User)
+
+ // Get loan ID from URL parameter
+ loanID, err := strconv.ParseUint(c.Param("id"), 10, 32)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid loan ID format"})
+ return
+ }
+
+ // Check if the loan exists and belongs to the user
+ var loan models.Loan
+ if err := database.DB.Where("id = ? AND user_id = ?", loanID, userObj.ID).First(&loan).Error; err != nil {
+ if err == gorm.ErrRecordNotFound {
+ c.JSON(http.StatusNotFound, gin.H{"error": "Loan not found"})
+ } else {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch loan"})
+ }
+ return
+ }
+
+ // Define a struct to bind the request JSON
+ var input struct {
+ Name string `json:"name"`
+ CurrentBalance int64 `json:"currentBalance"`
+ InterestRate float64 `json:"interestRate"`
+ EndDate string `json:"endDate"`
+ AccountID *uint `json:"accountId"`
+ }
+
+ // Bind JSON to struct
+ if err := c.ShouldBindJSON(&input); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+
+ // Update fields if provided
+ if input.Name != "" {
+ loan.Name = input.Name
+ }
+ if input.CurrentBalance != 0 {
+ loan.CurrentBalance = input.CurrentBalance
+ }
+ if input.InterestRate != 0 {
+ loan.InterestRate = input.InterestRate
+ }
+ if input.EndDate != "" {
+ endDate, err := time.Parse("2006-01-02", input.EndDate)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid end date format"})
+ return
+ }
+ loan.EndDate = endDate
+ }
+ if input.AccountID != nil {
+ loan.AccountID = input.AccountID
+ }
+
+ // Save updates to database
+ if err := database.DB.Save(&loan).Error; err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update loan"})
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{"loan": loan})
+ }
+}
+
+// DeleteLoan deletes a loan
+func DeleteLoan() gin.HandlerFunc {
+ return func(c *gin.Context) {
+ // Get user from context (set by auth middleware)
+ user, exists := c.Get("user")
+ if !exists {
+ c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
+ return
+ }
+ userObj := user.(*models.User)
+
+ // Get loan ID from URL parameter
+ loanID, err := strconv.ParseUint(c.Param("id"), 10, 32)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid loan ID format"})
+ return
+ }
+
+ // Check if the loan exists and belongs to the user
+ var loan models.Loan
+ if err := database.DB.Where("id = ? AND user_id = ?", loanID, userObj.ID).First(&loan).Error; err != nil {
+ if err == gorm.ErrRecordNotFound {
+ c.JSON(http.StatusNotFound, gin.H{"error": "Loan not found"})
+ } else {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch loan"})
+ }
+ return
+ }
+
+ // Delete the loan
+ if err := database.DB.Delete(&loan).Error; err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete loan"})
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{"message": "Loan deleted successfully"})
+ }
+}