package model import ( "errors" "fmt" "github.com/QuantumNous/new-api/common" "github.com/QuantumNous/new-api/logger" "github.com/shopspring/decimal" "gorm.io/gorm" ) // RechargeWechat 微信支付充值完成(由回调触发) func RechargeWechat(tradeNo string) error { return rechargeByQRCodePayment(tradeNo, "微信支付") } // RechargeAlipay 支付宝充值完成(由回调触发) func RechargeAlipay(tradeNo string) error { return rechargeByQRCodePayment(tradeNo, "支付宝") } // rechargeByQRCodePayment 扫码支付充值完成(微信/支付宝通用) // 使用事务+行锁保证幂等 func rechargeByQRCodePayment(tradeNo string, paymentMethod string) error { if tradeNo == "" { return errors.New("未提供支付单号") } var quotaToAdd int64 var payMoney float64 var userId int refCol := "`trade_no`" if common.UsingPostgreSQL { refCol = `"trade_no"` } err := DB.Transaction(func(tx *gorm.DB) error { topUp := &TopUp{} if err := tx.Set("gorm:query_option", "FOR UPDATE").Where(refCol+" = ?", tradeNo).First(topUp).Error; err != nil { return errors.New("充值订单不存在") } if topUp.Status == common.TopUpStatusSuccess { return nil } if topUp.Status != common.TopUpStatusPending { return errors.New("充值订单状态错误") } topUp.CompleteTime = common.GetTimestamp() topUp.Status = common.TopUpStatusSuccess if err := tx.Save(topUp).Error; err != nil { return err } dMoney := decimal.NewFromFloat(topUp.Money) dQuotaPerUnit := decimal.NewFromFloat(common.QuotaPerUnit) quotaToAdd = dMoney.Mul(dQuotaPerUnit).IntPart() if quotaToAdd <= 0 { return errors.New("无效的充值额度") } if err := tx.Model(&User{}).Where("id = ?", topUp.UserId).Update("quota", gorm.Expr("quota + ?", quotaToAdd)).Error; err != nil { return err } userId = topUp.UserId payMoney = topUp.Money return nil }) if err != nil { return err } if quotaToAdd > 0 { RecordLog(userId, LogTypeTopup, fmt.Sprintf("使用%s充值成功,充值金额: %v,支付金额:%.2f", paymentMethod, logger.FormatQuota(int(quotaToAdd)), payMoney)) } return nil }