package app import ( "fmt" "time" "verification-platform-backend/internal/database" "verification-platform-backend/internal/model" "verification-platform-backend/internal/service" "verification-platform-backend/pkg/response" "github.com/gin-gonic/gin" ) func SetupPaymentRoutes(r *gin.RouterGroup) { r.POST("/recharge", handleAppRecharge) r.POST("/trial", handleAppTrial) } func handleAppRecharge(c *gin.Context) { appKey := c.Param("appKey") var app model.Application if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil { response.Error(c, 404, "应用不存在") return } if service.GetApplicationDisabledStatus(app.ID) { response.Error(c, 403, "该应用已被禁用") return } var req struct { Username string `json:"username"` CardKey string `json:"card_key"` DeviceID string `json:"device_id"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误") return } if blocked, reason := checkRiskControl(c, app.ID, req.DeviceID, req.Username); blocked { response.Error(c, 403, reason) return } var card model.Card if err := database.DB.Preload("CardType").Where("card_key = ?", req.CardKey).First(&card).Error; err != nil { service.LogVerification(c, &app.ID, nil, "recharge_failed", fmt.Sprintf("充值失败: 卡密不存在 - %s", req.CardKey), "", fmt.Errorf("卡密不存在")) response.Error(c, 404, "卡密不存在") return } fmt.Printf("[DEBUG] 卡密信息: ID=%d, CardKey=%s, Status=%s, CardTypeID=%d\n", card.ID, card.CardKey, card.Status, card.CardTypeID) fmt.Printf("[DEBUG] 卡类信息: ID=%d, Name=%s, Value=%f, Price=%f\n", card.CardType.ID, card.CardType.Name, card.CardType.Value, card.CardType.Price) if card.Status != "unused" { service.LogVerification(c, &app.ID, nil, "recharge_failed", fmt.Sprintf("充值失败: 卡密已使用 - %s", req.CardKey), "", fmt.Errorf("卡密已使用")) response.Error(c, 400, "卡密已使用") return } var user model.AppUser if err := database.DB.Where("username = ? AND application_id = ?", req.Username, app.ID).First(&user).Error; err != nil { service.LogVerification(c, &app.ID, nil, "recharge_failed", fmt.Sprintf("充值失败: 用户不存在 - %s", req.Username), "", fmt.Errorf("用户不存在")) response.Error(c, 404, "用户不存在") return } if user.Balance == -1 { service.LogVerification(c, &app.ID, &user.ID, "recharge_failed", fmt.Sprintf("充值失败: 用户已是永久会员 - %s", user.Username), "", fmt.Errorf("该用户已是永久会员,无法再次充值")) response.Error(c, 400, "该用户已是永久会员,无法再次充值") return } fmt.Printf("[DEBUG] 充值前用户信息: ID=%d, Username=%s, Balance=%f, ExpiryAt=%v\n", user.ID, user.Username, user.Balance, user.ExpiryAt) tx := database.DB.Begin() card.Status = "used" card.AppUserID = &user.ID now := time.Now() card.UsedAt = &now if err := tx.Save(&card).Error; err != nil { tx.Rollback() response.Error(c, 500, "充值失败") return } user.IsTrialUser = false if card.CardType.Value == -1 { if card.CardType.RechargeType == "subscription" { permanentExpiry := time.Date(9999, 12, 31, 23, 59, 59, 0, time.UTC) user.ExpiryAt = &permanentExpiry user.Balance = -1 } else { user.Balance = -1 user.ExpiryAt = nil } } else { switch card.CardType.RechargeType { case "subscription": var baseTime time.Time if user.ExpiryAt != nil && user.ExpiryAt.After(now) { baseTime = *user.ExpiryAt } else { baseTime = now } var duration time.Duration switch card.CardType.ValueUnit { case "minute": duration = time.Duration(card.CardType.Value) * time.Minute case "hour": duration = time.Duration(card.CardType.Value) * time.Hour case "day": duration = time.Duration(card.CardType.Value) * 24 * time.Hour case "month": duration = time.Duration(card.CardType.Value) * 30 * 24 * time.Hour case "year": duration = time.Duration(card.CardType.Value) * 365 * 24 * time.Hour default: duration = time.Duration(card.CardType.Value) * time.Second } newExpiry := baseTime.Add(duration) user.ExpiryAt = &newExpiry case "balance": fallthrough default: user.Balance += card.CardType.Value } } fmt.Printf("[DEBUG] 充值后用户信息: Balance=%f, ExpiryAt=%v (CardType.Value=%f, BillingType=%s)\n", user.Balance, user.ExpiryAt, card.CardType.Value, app.BillingType) if err := tx.Save(&user).Error; err != nil { tx.Rollback() response.Error(c, 500, "更新用户信息失败") return } rechargeRecord := model.RechargeRecord{ UserID: user.ID, OrderNo: generateOrderNo("R"), CardID: &card.ID, CardCode: card.CardKey, Amount: card.CardType.Price, Status: "success", PaymentType: "card", Remark: "卡密充值 - " + card.CardType.Name, } if err := tx.Create(&rechargeRecord).Error; err != nil { tx.Rollback() response.Error(c, 500, "创建充值记录失败") return } if err := tx.Commit().Error; err != nil { response.Error(c, 500, "充值失败") return } service.LogVerification(c, &app.ID, &user.ID, "recharge", fmt.Sprintf("用户充值: %s, 卡密: %s, 金额: %.2f", user.Username, card.CardKey, card.CardType.Price), "", nil) response.SuccessWithMessage(c, "充值成功", gin.H{ "message": "充值成功", "value": card.CardType.Value, }) } func handleAppTrial(c *gin.Context) { appKey := c.Param("appKey") var app model.Application if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil { response.Error(c, 404, "应用不存在") return } if service.GetApplicationDisabledStatus(app.ID) { response.Error(c, 403, "该应用已被禁用") return } if !app.EnableTrial { response.Error(c, 400, "该应用不支持试用") return } var req struct { UserID uint `json:"user_id"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误") return } var user model.AppUser if err := database.DB.First(&user, req.UserID).Error; err != nil { response.Error(c, 404, "用户不存在") return } response.SuccessWithMessage(c, "试用成功", gin.H{ "message": "试用成功", "trial_balance": app.TrialBalance, }) } func generateOrderNo(prefix string) string { return prefix + time.Now().Format("20060102150405") + randomString(6) } func randomString(length int) string { const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" b := make([]byte, length) for i := range b { b[i] = charset[time.Now().Nanosecond()%len(charset)] time.Sleep(1 * time.Nanosecond) } return string(b) }