| package controllers |
|
|
| import ( |
| "fmt" |
| "net/http" |
| "service-warungpos-go/config" |
| "service-warungpos-go/models" |
| "service-warungpos-go/services" |
|
|
| "github.com/gin-gonic/gin" |
| ) |
|
|
| |
|
|
| |
| func GetWalletDetail(c *gin.Context) { |
| userVal, _ := c.Get("user") |
| user := userVal.(*models.User) |
|
|
| var company models.Company |
| if err := config.DB.First(&company, *user.CompanyID).Error; err != nil { |
| c.JSON(http.StatusNotFound, gin.H{"detail": "Company tidak ditemukan"}) |
| return |
| } |
|
|
| var history []models.WalletTransaction |
| if err := config.DB.Where("company_id = ?", company.ID).Order("created_at desc").Limit(50).Find(&history).Error; err != nil { |
| c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal mengambil riwayat dompet"}) |
| return |
| } |
|
|
| c.JSON(http.StatusOK, gin.H{ |
| "balance": company.WalletBalance, |
| "limit": company.WalletLimit, |
| "history": history, |
| }) |
| } |
|
|
| type TopupManualRequest struct { |
| Amount float64 `json:"amount" binding:"required,gt=0"` |
| ProofURL string `json:"proof_url" binding:"required"` |
| } |
|
|
| type TopupQrisRequest struct { |
| Amount float64 `json:"amount" binding:"required,gt=0"` |
| } |
|
|
| |
| func RequestTopupManual(c *gin.Context) { |
| userVal, _ := c.Get("user") |
| user := userVal.(*models.User) |
|
|
| var req TopupManualRequest |
| if err := c.ShouldBindJSON(&req); err != nil { |
| c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()}) |
| return |
| } |
|
|
| topup := models.TopupRequest{ |
| CompanyID: *user.CompanyID, |
| Amount: req.Amount, |
| ProofURL: req.ProofURL, |
| Status: "pending", |
| } |
|
|
| if err := config.DB.Create(&topup).Error; err != nil { |
| c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal mengajukan top-up"}) |
| return |
| } |
|
|
| c.JSON(http.StatusCreated, gin.H{"message": "Pengajuan top-up berhasil dibuat, menunggu persetujuan admin", "data": topup}) |
| } |
|
|
| |
| func RequestTopupQris(c *gin.Context) { |
| userVal, _ := c.Get("user") |
| user := userVal.(*models.User) |
|
|
| var req TopupQrisRequest |
| if err := c.ShouldBindJSON(&req); err != nil { |
| c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()}) |
| return |
| } |
|
|
| |
| topup := models.TopupRequest{ |
| CompanyID: *user.CompanyID, |
| Amount: req.Amount, |
| ProofURL: "QRIS TRIPAY", |
| Status: "pending", |
| } |
|
|
| if err := config.DB.Create(&topup).Error; err != nil { |
| c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal membuat request topup"}) |
| return |
| } |
|
|
| merchantRef := fmt.Sprintf("TOPUP-%d", topup.ID) |
|
|
| var company models.Company |
| config.DB.First(&company, *user.CompanyID) |
|
|
| tripayItems := []services.TripayItem{ |
| { |
| SKU: "TOPUP", |
| Name: "Top-up Saldo Dompet", |
| Price: int(req.Amount), |
| Quantity: 1, |
| }, |
| } |
|
|
| |
| tripayRes, err := services.CreateTripayTransaction( |
| merchantRef, |
| int(req.Amount), |
| "QRIS", |
| user.Name, |
| user.Email, |
| user.Phone, |
| tripayItems, |
| *user.CompanyID, |
| ) |
|
|
| if err != nil { |
| |
| topup.Status = "rejected" |
| config.DB.Save(&topup) |
| c.JSON(http.StatusBadRequest, gin.H{"detail": fmt.Sprintf("Gagal generate QRIS Tripay: %v", err)}) |
| return |
| } |
|
|
| c.JSON(http.StatusOK, gin.H{ |
| "message": "Berhasil generate QRIS Top-up", |
| "topup_id": topup.ID, |
| "qr_url": tripayRes.Data.QrURL, |
| "checkout_url": tripayRes.Data.CheckoutURL, |
| "amount": tripayRes.Data.Amount, |
| "expired_time": tripayRes.Data.ExpiredTime, |
| }) |
| } |
|
|
| |
|
|
| |
| func AdminGetPendingTopups(c *gin.Context) { |
| var topups []models.TopupRequest |
| if err := config.DB.Preload("Company").Where("status = ? AND proof_url != ?", "pending", "QRIS TRIPAY").Order("created_at asc").Find(&topups).Error; err != nil { |
| c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal mengambil data top-up"}) |
| return |
| } |
| c.JSON(http.StatusOK, topups) |
| } |
|
|
| |
| func AdminApproveTopup(c *gin.Context) { |
| topupID := c.Param("id") |
|
|
| tx := config.DB.Begin() |
| defer func() { |
| if r := recover(); r != nil { |
| tx.Rollback() |
| } |
| }() |
|
|
| var topup models.TopupRequest |
| if err := tx.First(&topup, topupID).Error; err != nil { |
| tx.Rollback() |
| c.JSON(http.StatusNotFound, gin.H{"detail": "Request Top-up tidak ditemukan"}) |
| return |
| } |
|
|
| if topup.Status != "pending" { |
| tx.Rollback() |
| c.JSON(http.StatusBadRequest, gin.H{"detail": "Status top-up sudah diproses sebelumnya"}) |
| return |
| } |
|
|
| topup.Status = "approved" |
| if err := tx.Save(&topup).Error; err != nil { |
| tx.Rollback() |
| c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal update status topup"}) |
| return |
| } |
|
|
| |
| var company models.Company |
| if err := tx.First(&company, topup.CompanyID).Error; err != nil { |
| tx.Rollback() |
| c.JSON(http.StatusNotFound, gin.H{"detail": "Company tidak ditemukan"}) |
| return |
| } |
|
|
| company.WalletBalance += topup.Amount |
| if err := tx.Save(&company).Error; err != nil { |
| tx.Rollback() |
| c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal update saldo perusahaan"}) |
| return |
| } |
|
|
| |
| walletTx := models.WalletTransaction{ |
| CompanyID: company.ID, |
| Amount: topup.Amount, |
| Type: "topup_manual", |
| RefID: fmt.Sprintf("TOPUP-%d", topup.ID), |
| Desc: "Top-up Saldo Manual (Disetujui Admin)", |
| } |
| if err := tx.Create(&walletTx).Error; err != nil { |
| tx.Rollback() |
| c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal mencatat log dompet"}) |
| return |
| } |
|
|
| if err := tx.Commit().Error; err != nil { |
| tx.Rollback() |
| c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal menyimpan perubahan"}) |
| return |
| } |
|
|
| c.JSON(http.StatusOK, gin.H{"message": "Top-up berhasil disetujui", "new_balance": company.WalletBalance}) |
| } |
|
|
| |
| func AdminRejectTopup(c *gin.Context) { |
| topupID := c.Param("id") |
|
|
| var topup models.TopupRequest |
| if err := config.DB.First(&topup, topupID).Error; err != nil { |
| c.JSON(http.StatusNotFound, gin.H{"detail": "Request Top-up tidak ditemukan"}) |
| return |
| } |
|
|
| if topup.Status != "pending" { |
| c.JSON(http.StatusBadRequest, gin.H{"detail": "Status top-up sudah diproses sebelumnya"}) |
| return |
| } |
|
|
| topup.Status = "rejected" |
| if err := config.DB.Save(&topup).Error; err != nil { |
| c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal menolak topup"}) |
| return |
| } |
|
|
| c.JSON(http.StatusOK, gin.H{"message": "Top-up berhasil ditolak"}) |
| } |
|
|
| type AdminAdjustWalletRequest struct { |
| Amount float64 `json:"amount" binding:"required"` |
| } |
|
|
| |
| func AdminAdjustWallet(c *gin.Context) { |
| companyID := c.Param("id") |
|
|
| var req AdminAdjustWalletRequest |
| if err := c.ShouldBindJSON(&req); err != nil { |
| c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()}) |
| return |
| } |
|
|
| tx := config.DB.Begin() |
| defer func() { |
| if r := recover(); r != nil { |
| tx.Rollback() |
| } |
| }() |
|
|
| var company models.Company |
| if err := tx.First(&company, companyID).Error; err != nil { |
| tx.Rollback() |
| c.JSON(http.StatusNotFound, gin.H{"detail": "Company tidak ditemukan"}) |
| return |
| } |
|
|
| company.WalletBalance += req.Amount |
| if err := tx.Save(&company).Error; err != nil { |
| tx.Rollback() |
| c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal update saldo perusahaan"}) |
| return |
| } |
|
|
| walletTx := models.WalletTransaction{ |
| CompanyID: company.ID, |
| Amount: req.Amount, |
| Type: "admin_adjustment", |
| RefID: "ADMIN", |
| Desc: "Penyesuaian saldo manual oleh admin", |
| } |
| if err := tx.Create(&walletTx).Error; err != nil { |
| tx.Rollback() |
| c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal mencatat log dompet"}) |
| return |
| } |
|
|
| if err := tx.Commit().Error; err != nil { |
| tx.Rollback() |
| c.JSON(http.StatusInternalServerError, gin.H{"detail": "Gagal menyimpan perubahan"}) |
| return |
| } |
|
|
| c.JSON(http.StatusOK, gin.H{"message": "Saldo berhasil disesuaikan", "new_balance": company.WalletBalance}) |
| } |
|
|