|
- 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
- }
|