qnc-server-old/api/pay.go

763 lines
26 KiB
Go
Raw Normal View History

2024-09-14 10:48:09 +08:00
package api
import (
"context"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"github.com/redis/go-redis/v9"
"github.com/smartwalle/alipay/v3"
wxcore "github.com/wechatpay-apiv3/wechatpay-go/core"
"github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers"
"github.com/wechatpay-apiv3/wechatpay-go/core/downloader"
"github.com/wechatpay-apiv3/wechatpay-go/core/notify"
"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
wxutils "github.com/wechatpay-apiv3/wechatpay-go/utils"
"gorm.io/gorm"
"log"
2024-12-25 11:59:33 +08:00
"math"
2024-09-14 10:48:09 +08:00
"net/http"
"qnc-server/config"
"qnc-server/db"
"qnc-server/global"
"qnc-server/model/model"
"qnc-server/model/request"
"qnc-server/model/response"
"qnc-server/service"
"qnc-server/utils"
"strconv"
"time"
)
type Pay struct {
}
var ctx = context.Background()
var productService service.ProductService
// 注册路由
func InitPay(group *gin.RouterGroup) {
var p Pay
{
payPublicGroup := group.Group("pay")
payPublicGroup.POST("callback/:platform", p.Callback) // 微信支付支付回调
payPublicGroup.GET("refund_details/:id", p.RefundDetailsHTML) // 内部退款订单详情页面
payPublicGroup.POST("refund/:id", p.Refund) // 内部退款按钮
payPublicGroup.POST("refund_callback/:platform", p.RefundCallback) // 微信退款回调
2024-12-25 11:59:33 +08:00
payPublicGroup.POST("ali_callback", p.AlipayCallback) // 阿里回调
2024-09-14 10:48:09 +08:00
payPublicGroup.POST("complaint_callback/:platform", p.WxPayComplaintCallback)
}
{
payPrivateGroup := group.Group("pay")
payPrivateGroup.Use(JWTAuth())
2024-12-25 11:59:33 +08:00
payPrivateGroup.POST("prepay", p.Prepay) // 创建微信支付订单
payPrivateGroup.GET("order_list", p.GetOrderList) // 获取订单列表
payPrivateGroup.GET("promotion_list", p.GetPromotionList) // 获取订单列表
payPrivateGroup.POST("ali_prepay", p.AliPrepay) // 创建支付宝支付订单
payPrivateGroup.GET("get_query_cache", p.GetQueryCache) // 获取网页的查询缓存
2024-09-14 10:48:09 +08:00
}
}
func (p *Pay) GetOrderList(c *gin.Context) {
// 从查询参数中获取分页参数
pageSizeStr := c.DefaultQuery("page_size", "10")
pageNumStr := c.DefaultQuery("page_num", "1")
userId := utils.GetUserID(c)
pageSize, err := strconv.Atoi(pageSizeStr)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
pageNum, err := strconv.Atoi(pageNumStr)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, err := orderService.GetList(pageSize, pageNum, userId)
if err != nil {
log.Println("get order list error:", err)
response.FailWithMessage(err.Error(), c)
return
}
response.OkWithData(list, c)
}
2024-12-25 11:59:33 +08:00
func (p *Pay) GetPromotionList(c *gin.Context) {
userId := utils.GetUserID(c)
user, err := userService.GetUserByUserid(userId)
if err != nil {
log.Println("get user info error:", err)
response.FailWithMessage("系统开小差啦, 请稍后再试~", c)
return
}
if user.Promotion == "" {
response.FailWithMessage("您不是代理推广人哦", c)
return
}
// 从查询参数中获取分页参数
pageSizeStr := c.DefaultQuery("page_size", "10")
pageNumStr := c.DefaultQuery("page_num", "1")
pageSize, err := strconv.Atoi(pageSizeStr)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
pageNum, err := strconv.Atoi(pageNumStr)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
list, err := orderService.GetListByPromotion(pageSize, pageNum, user.Promotion)
if err != nil {
log.Println("get order list error:", err)
response.FailWithMessage(err.Error(), c)
return
}
// 获取总单数和总金额
totalCount, totalAmount, err := orderService.GetSummaryByPromotion(user.Promotion)
if err != nil {
log.Println("get order summary error:", err)
response.FailWithMessage(err.Error(), c)
return
}
// 计算总金额的 30%,并保留两位小数
totalAmount30 := math.Round((totalAmount/30.0)*100) / 100
response.OkWithData(gin.H{
"list": list,
"points": 30,
"total_count": totalCount,
"total_amount": totalAmount30, // 总金额的30%
}, c)
}
2024-09-14 10:48:09 +08:00
func (p *Pay) Prepay(c *gin.Context) {
Claims, err := utils.GetClaims(c)
if err != nil {
log.Println("get claims error:", err)
response.FailWithMessage(err.Error(), c)
return
}
var reqBody request.PrepayReq
err = c.ShouldBindJSON(&reqBody)
if err != nil {
response.FailWithMessage("Failed to read request body, need product", c)
return
}
var (
userid = Claims.Userid
openid string
appid string
mchID string
)
2024-12-25 11:59:33 +08:00
log.Printf("Claims, %+v", Claims)
log.Printf("reqBody, %+v", reqBody)
2024-09-14 10:48:09 +08:00
// 获取用户ip
clientIP := c.ClientIP()
switch reqBody.Platform {
case model.PlatformMPWEIXIN:
openid = Claims.AuthIdentifiers.OpenID
appid = config.ConfigData.System.WxAppId
mchID = config.ConfigData.WxPay.MchID
case model.PlatformMPH5:
openid = Claims.AuthIdentifiers.OpenID
appid = config.ConfigData.System.WxH5AppId
mchID = config.ConfigData.WxPay.MchH5ID
case model.PlatformH5:
appid = config.ConfigData.System.WxH5AppId
mchID = config.ConfigData.WxPay.MchH5ID
2024-12-25 11:59:33 +08:00
case model.PlatformTYDATA:
openid = Claims.AuthIdentifiers.OpenID
appid = config.ConfigData.System.WxTyDataAppId
mchID = config.ConfigData.WxPay.MchH5ID
2024-09-14 10:48:09 +08:00
default:
response.FailWithMessage("ProductName Must be wx or mp-h5 or h5", c)
return
}
product, err := productService.GetProduct(reqBody.ProductName)
if err != nil {
log.Println(err)
response.FailWithMessage(err.Error(), c)
return
}
// 查看用户是否内部号
user, err := userService.GetUserByUserid(Claims.Userid)
if err != nil {
log.Println(err)
response.FailWithMessage(err.Error(), c)
return
}
var amount int64
if user.Inside {
amount = int64(1)
} else {
amount = int64(product.SellPrice)
}
var outTradeNo = fmt.Sprintf("wx_%s", utils.GenerateOrderNumber())
var resp interface{}
if reqBody.Platform == model.PlatformMPWEIXIN {
resp, err = orderService.WechatJSAPIPrepay(appid, mchID, product, outTradeNo, amount, openid, model.PlatformMPWEIXIN, global.GlobalData.PayClient)
if err != nil {
log.Printf("【创建微信支付订单】创建支付失败,系统错误: %v", err)
response.FailWithMessage("创建支付失败,系统错误", c)
return
}
} else if reqBody.Platform == model.PlatformMPH5 {
2024-12-25 11:59:33 +08:00
resp, err = orderService.WechatJSAPIPrepay(appid, mchID, product, outTradeNo, amount, openid, model.PlatformMPH5, global.GlobalData.PayH5Client)
if err != nil {
log.Printf("【创建微信支付订单】创建支付失败,系统错误: %v", err)
response.FailWithMessage("创建支付失败,系统错误", c)
return
}
} else if reqBody.Platform == model.PlatformTYDATA {
resp, err = orderService.WechatJSAPIPrepay(appid, mchID, product, outTradeNo, amount, openid, model.PlatformTYDATA, global.GlobalData.PayH5Client)
2024-09-14 10:48:09 +08:00
if err != nil {
log.Printf("【创建微信支付订单】创建支付失败,系统错误: %v", err)
response.FailWithMessage("创建支付失败,系统错误", c)
return
}
} else {
resp, err = orderService.WechatH5Prepay(appid, mchID, product, outTradeNo, amount, clientIP, global.GlobalData.PayH5Client)
if err != nil {
log.Printf("【创建微信支付订单】创建支付失败,系统错误: %v", err)
response.FailWithMessage("创建支付失败,系统错误", c)
return
}
}
var payOrder = model.PayOrder{
OutTradeNo: outTradeNo,
Amount: amount,
Userid: userid,
PayStatus: model.PayStatusNotPay,
ProductID: product.ID,
Product: &product,
Platform: reqBody.Platform,
PaymentMethod: model.PaymentMethod_WECHAT,
2024-12-25 11:59:33 +08:00
Promotion: reqBody.Promotion,
2024-09-14 10:48:09 +08:00
}
err = db.DB.Create(&payOrder).Error
if err != nil {
log.Printf("create payOrder error%v", err)
}
response.OkWithData(resp, c)
}
func (p *Pay) Callback(c *gin.Context) {
ctx := c //这个参数是context.Background()
cRequest := c.Request //这个值是*http.Request
platform := c.Param("platform")
var mchID string
var mchCertificateSerialNumber string
var mchAPIv3Key string
var privateKeyPath string
switch platform {
case model.PlatformMPWEIXIN:
mchID = config.ConfigData.WxPay.MchID
mchCertificateSerialNumber = config.ConfigData.WxPay.MchCertificateSerialNumber
mchAPIv3Key = config.ConfigData.WxPay.MchAPIv3Key
privateKeyPath = "merchant/mp/apiclient_key.pem"
2024-12-25 11:59:33 +08:00
case model.PlatformH5, model.PlatformMPH5, model.PlatformTYDATA:
2024-09-14 10:48:09 +08:00
mchID = config.ConfigData.WxPay.MchH5ID
mchCertificateSerialNumber = config.ConfigData.WxPay.MchH5CertificateSerialNumber
mchAPIv3Key = config.ConfigData.WxPay.MchH5APIv3Key
privateKeyPath = "merchant/mph5/apiclient_key.pem"
}
mchPrivateKey, err := wxutils.LoadPrivateKeyWithPath(privateKeyPath)
if err != nil {
log.Printf("load merchant private key error")
return
}
// 1. 使用 `RegisterDownloaderWithPrivateKey` 注册下载器
err = downloader.MgrInstance().RegisterDownloaderWithPrivateKey(ctx, mchPrivateKey, mchCertificateSerialNumber, mchID, mchAPIv3Key)
if err != nil {
log.Printf("register downloader with private key error")
return
}
// 2. 获取商户号对应的微信支付平台证书访问器
certificateVisitor := downloader.MgrInstance().GetCertificateVisitor(mchID)
// 3. 使用证书访问器初始化 `notify.Handler`
handler := notify.NewNotifyHandler(mchAPIv3Key, verifiers.NewSHA256WithRSAVerifier(certificateVisitor))
transaction := new(payments.Transaction)
notifyReq, err := handler.ParseNotifyRequest(context.Background(), cRequest, transaction)
// 如果验签未通过,或者解密失败
if err != nil {
log.Printf("parse notify request error")
return
}
log.Printf("微信支付回调响应: %+v", notifyReq)
var status string
if notifyReq.Summary == "支付成功" {
status = model.PayStatusSuccess
} else {
status = model.PayStatusPayError
}
err = db.DB.Model(&model.PayOrder{}).Where("out_trade_no = ?", transaction.OutTradeNo).Updates(model.PayOrder{PayStatus: status, TransactionId: *transaction.TransactionId}).Error
if err != nil {
log.Printf("订单回调处理错误%v", err)
}
c.String(http.StatusOK, "success")
}
func (p *Pay) RefundDetailsHTML(c *gin.Context) {
encryptedOrderID := c.Param("id")
// 解密订单ID
decryptedOrderID, err := utils.IDDecrypt(encryptedOrderID, "njbh287yfbuyh18suygbhd98")
if err != nil {
log.Printf("解密订单ID(%s)失败:%v", decryptedOrderID, err)
c.String(http.StatusNotFound, "")
return
}
// 将字符串转换为 uint64
u64, err := strconv.ParseUint(decryptedOrderID, 10, 64)
if err != nil {
log.Printf("uint64转换失败: %v", err)
c.String(http.StatusNotFound, "")
return
}
// 将 uint64 转换为 uint
orderID := uint(u64)
order, err := orderService.GetOrderByid(orderID)
if err != nil {
log.Printf("订单(%d)获取失败:%v", orderID, err)
c.String(http.StatusNotFound, "")
return
}
type RenderOrder struct {
ID string
OutTradeNo string
TransactionId string
Userid uint
CreatedAt string
Product string
Amount float64
PayStatus string
}
renderOrder := RenderOrder{
ID: encryptedOrderID,
OutTradeNo: order.OutTradeNo,
TransactionId: order.TransactionId,
Userid: order.Userid,
CreatedAt: order.CreatedAt.Format("2006-01-02 15:04:05"),
Product: order.Product.ProductName,
Amount: float64(order.Amount) / 100,
PayStatus: order.PayStatus,
}
c.HTML(http.StatusOK, "refund.html", renderOrder)
}
func (p *Pay) Refund(c *gin.Context) {
encryptedOrderID := c.Param("id")
// 解密订单ID
decryptedOrderID, err := utils.IDDecrypt(encryptedOrderID, "njbh287yfbuyh18suygbhd98")
if err != nil {
log.Printf("解密订单ID(%s)失败:%v", decryptedOrderID, err)
c.String(http.StatusNotFound, "")
return
}
// 将字符串转换为 uint64
u64, err := strconv.ParseUint(decryptedOrderID, 10, 64)
if err != nil {
log.Printf("uint64转换失败: %v", err)
c.String(http.StatusNotFound, "")
return
}
// 将 uint64 转换为 uint
orderID := uint(u64)
order, err := orderService.GetOrderByid(orderID)
if err != nil {
log.Printf("订单(%d)获取失败:%v", orderID, err)
c.String(http.StatusNotFound, "")
return
}
var payClient *wxcore.Client
switch order.Platform {
case model.PlatformMPWEIXIN:
payClient = global.GlobalData.PayClient
2024-12-25 11:59:33 +08:00
case model.PlatformH5, model.PlatformMPH5, model.PlatformTYDATA:
2024-09-14 10:48:09 +08:00
payClient = global.GlobalData.PayH5Client
}
outRefundNo := utils.GenerateOrderRefundNumber()
svc := refunddomestic.RefundsApiService{Client: payClient}
resp, result, err := svc.Create(ctx,
refunddomestic.CreateRequest{
OutTradeNo: wxcore.String(order.OutTradeNo),
OutRefundNo: wxcore.String(outRefundNo), //退款单号
NotifyUrl: wxcore.String(fmt.Sprintf("%s/%s", config.ConfigData.WxPay.RefundNotifyURL, order.Platform)),
Amount: &refunddomestic.AmountReq{
Currency: wxcore.String("CNY"),
Refund: wxcore.Int64(order.Amount),
Total: wxcore.Int64(order.Amount),
},
},
)
if err != nil {
// 处理错误
log.Printf("微信订单申请退款错误:%s", err)
response.Fail(c)
} else {
// 处理返回结果
log.Printf("微信订单申请退款 response status=%d resp=%s", result.Response.StatusCode, resp)
order.PayStatus = model.PayStatusUnderRefund
err = db.DB.Save(order).Error
if err != nil {
log.Printf("微信订单退款状态修改失败 underRefund Error:%v", err)
}
response.Ok(c)
}
}
func (p *Pay) RefundCallback(c *gin.Context) {
ctx := c //这个参数是context.Background()
cRequest := c.Request //这个值是*http.Request
platform := c.Param("platform")
var mchID string
var mchCertificateSerialNumber string
var mchAPIv3Key string
var privateKeyPath string
switch platform {
case model.PlatformMPWEIXIN:
mchID = config.ConfigData.WxPay.MchID
mchCertificateSerialNumber = config.ConfigData.WxPay.MchCertificateSerialNumber
mchAPIv3Key = config.ConfigData.WxPay.MchAPIv3Key
privateKeyPath = "merchant/mp/apiclient_key.pem"
2024-12-25 11:59:33 +08:00
case model.PlatformH5, model.PlatformMPH5, model.PlatformTYDATA:
2024-09-14 10:48:09 +08:00
mchID = config.ConfigData.WxPay.MchH5ID
mchCertificateSerialNumber = config.ConfigData.WxPay.MchH5CertificateSerialNumber
mchAPIv3Key = config.ConfigData.WxPay.MchH5APIv3Key
privateKeyPath = "merchant/mph5/apiclient_key.pem"
}
mchPrivateKey, err := wxutils.LoadPrivateKeyWithPath(privateKeyPath)
if err != nil {
log.Printf("load merchant private key error")
return
}
// 1. 使用 `RegisterDownloaderWithPrivateKey` 注册下载器
err = downloader.MgrInstance().RegisterDownloaderWithPrivateKey(ctx, mchPrivateKey, mchCertificateSerialNumber, mchID, mchAPIv3Key)
if err != nil {
log.Printf("register downloader with private key error")
return
}
// 2. 获取商户号对应的微信支付平台证书访问器
certificateVisitor := downloader.MgrInstance().GetCertificateVisitor(mchID)
// 3. 使用证书访问器初始化 `notify.Handler`
handler := notify.NewNotifyHandler(mchAPIv3Key, verifiers.NewSHA256WithRSAVerifier(certificateVisitor))
transaction := new(payments.Transaction)
notifyReq, err := handler.ParseNotifyRequest(context.Background(), cRequest, transaction)
// 如果验签未通过,或者解密失败
if err != nil {
log.Printf("parse notify request error")
return
}
log.Printf("微信退款回调响应 notifyReq: %+v", notifyReq)
log.Printf("微信退款回调响应 transaction: %+v", transaction)
order := model.PayOrder{}
err = db.DB.Preload("Product").Where("out_trade_no = ?", transaction.OutTradeNo).First(&order).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
log.Printf("【微信退款回调响应】找不到回调相关的订单。OutTradeNo%s", transaction.OutTradeNo)
return
} else {
log.Printf("退款回调处理错误%v", err)
}
}
if notifyReq.EventType == "REFUND.SUCCESS" {
order.PayStatus = model.PayStatusRefund
err = db.DB.Save(&order).Error
if err != nil {
log.Printf("退款回调处理错误%v", err)
} else {
notifyService.SendNotification("退款成功", order.Product.ProductName, order.Userid, order.ID)
}
} else if notifyReq.EventType == "REFUND.ABNORMAL" {
order.PayStatus = model.PayStatusRefundError
err = db.DB.Save(&order).Error
if err != nil {
log.Printf("退款回调处理错误%v", err)
} else {
notifyService.SendNotification("退款异常,请及时处理", order.Product.ProductName, order.Userid, order.ID)
}
}
//log.Printf("微信退款回调响应: %+v", transaction)
c.String(http.StatusOK, "success")
}
// AliPrepay 阿里支付
func (p *Pay) AliPrepay(c *gin.Context) {
var reqBody request.H5PrepayReq
err := c.ShouldBindJSON(&reqBody)
if err != nil {
response.FailWithMessage("Failed to read request body, need product", c)
return
}
Claims, err := utils.GetClaims(c)
if err != nil {
log.Println("get claims error:", err)
response.FailWithMessage(err.Error(), c)
return
}
// 获取商品信息
product, err := productService.GetProduct(reqBody.ProductName)
if err != nil {
log.Println(err)
response.FailWithMessage(err.Error(), c)
return
}
// 生成单号
outTradeNo := fmt.Sprintf("ali_%s", utils.GenerateOrderNumber())
// 查看用户是否内部号
user, err := userService.GetUserByUserid(Claims.Userid)
if err != nil {
log.Println(err)
response.FailWithMessage(err.Error(), c)
return
}
var amount string
var orderAmount int64
log.Printf("is inside%+v,is %t", user, user.Inside)
if user.Inside {
amount = "0.01"
orderAmount = 1
} else {
amount = utils.ConvertCentsToYuan(product.SellPrice)
orderAmount = int64(product.SellPrice)
}
pay := alipay.TradeWapPay{}
pay.NotifyURL = config.ConfigData.AliPay.NotifyURL // 替换为您的回调地址
pay.ReturnURL = fmt.Sprintf("%s%s?callback=true", config.ConfigData.Server.Domain, reqBody.Href) // 支付成功后跳转的地址
pay.Subject = product.ProductName // 订单标题
pay.OutTradeNo = outTradeNo // 生成的唯一订单号
pay.TotalAmount = amount // 支付金额,单位元
2024-12-25 11:59:33 +08:00
pay.ProductCode = "QUICK_WAP_PAY" // WAP支付的产品代码w
2024-09-14 10:48:09 +08:00
payURL, err := global.GlobalData.AliPayClient.TradeWapPay(pay)
if err != nil {
log.Printf("【阿里支付创建】创建订单错误:%v", err)
response.Fail(c)
return
}
ctx := context.Background()
expiration := 5 * time.Minute // 5分钟超时
err = db.RedisClient.Set(ctx, fmt.Sprintf("alipay_%s", outTradeNo), reqBody.QueryData, expiration).Err()
if err != nil {
log.Printf("【阿里支付创建】前端请求数据缓存错误:%v", err)
response.Fail(c)
return
}
var payOrder = model.PayOrder{
OutTradeNo: outTradeNo,
Amount: orderAmount,
Userid: Claims.Userid,
PayStatus: model.PayStatusNotPay,
ProductID: product.ID,
Product: &product,
Platform: reqBody.Platform,
PaymentMethod: model.PaymentMethod_ALIPAY,
}
err = db.DB.Create(&payOrder).Error
if err != nil {
log.Printf("【阿里支付创建】订单保存错误:%v", err)
response.Fail(c)
return
}
response.OkWithData(gin.H{
"PayUrl": payURL.String(),
}, c)
}
// AlipayCallback 阿里支付回调
func (p *Pay) AlipayCallback(c *gin.Context) {
// 解析表单
err := c.Request.ParseForm()
if err != nil {
log.Printf("ali pay callback解析请求表单失败%v", err)
return
}
// DecodeNotification 内部已调用 VerifySign 方法验证签名
noti, err := global.GlobalData.AliPayClient.DecodeNotification(c.Request.Form)
if err != nil {
log.Printf("【阿里支付回调】通知解码失败失败:%v", err)
return
}
log.Printf("【阿里支付回调】接收到支付宝回调,商户订单号:%s", noti.OutTradeNo)
log.Printf("【阿里支付回调】接收到支付宝回调,支付宝订单号:%s", noti.OutTradeNo)
log.Printf("【阿里支付回调】交易状态:%s", noti.TradeStatus)
if noti.TradeStatus == alipay.TradeStatusSuccess {
log.Printf("【阿里支付回调】交易成功")
err = db.DB.Model(&model.PayOrder{}).Where("out_trade_no = ?", noti.OutTradeNo).Updates(model.PayOrder{PayStatus: model.PayStatusSuccess, AliTradeNo: noti.TradeNo}).Error
if err != nil {
log.Printf("【阿里支付回调】订单回调处理错误%v", err)
}
// 确认收到通知消息,不然支付宝后续会继续推送相同的消息
alipay.ACKNotification(c.Writer)
}
}
func (p *Pay) GetQueryCache(c *gin.Context) {
var reqBody request.QueryDataReq
err := c.ShouldBindQuery(&reqBody)
if err != nil {
response.FailWithMessage("Failed to read request body, need out_trade_no", c)
return
}
ctx := context.Background()
key := fmt.Sprintf("alipay_%s", reqBody.OutTradeNo)
result, err := db.RedisClient.Get(ctx, key).Result()
if errors.Is(err, redis.Nil) {
response.FailWithMessage("超时,请重新手动输入数据查询", c)
return
} else if err != nil {
log.Printf("【阿里支付】获取缓存表单数据错误%v", err)
response.FailWithMessage("请重新手动输入数据", c)
return
}
response.OkWithData(result, c)
}
func (p *Pay) WxPayComplaintCallback(c *gin.Context) {
ctx := context.Background()
cRequest := c.Request
platform := c.Param("platform")
var mchID string
var mchCertificateSerialNumber string
var mchAPIv3Key string
var privateKeyPath string
var platformString string
switch platform {
case model.PlatformMPWEIXIN:
platformString = "微信小程序"
mchID = config.ConfigData.WxPay.MchID
mchCertificateSerialNumber = config.ConfigData.WxPay.MchCertificateSerialNumber
mchAPIv3Key = config.ConfigData.WxPay.MchAPIv3Key
privateKeyPath = "merchant/mp/apiclient_key.pem"
2024-12-25 11:59:33 +08:00
case model.PlatformH5, model.PlatformMPH5, model.PlatformTYDATA:
2024-09-14 10:48:09 +08:00
platformString = "公众号"
mchID = config.ConfigData.WxPay.MchH5ID
mchCertificateSerialNumber = config.ConfigData.WxPay.MchH5CertificateSerialNumber
mchAPIv3Key = config.ConfigData.WxPay.MchH5APIv3Key
privateKeyPath = "merchant/mph5/apiclient_key.pem"
}
notifyService.SendComplaintNotification(fmt.Sprintf("%s投诉", platformString), "", platformString, "")
mchPrivateKey, err := wxutils.LoadPrivateKeyWithPath(privateKeyPath)
if err != nil {
log.Printf("【%s投诉通知回调】加载商户私钥失败: %v", platformString, err)
return
}
// 注册下载器
err = downloader.MgrInstance().RegisterDownloaderWithPrivateKey(ctx, mchPrivateKey, mchCertificateSerialNumber, mchID, mchAPIv3Key)
if err != nil {
log.Printf("【%s投诉通知回调】注册下载器失败: %v", platformString, err)
return
}
// 获取微信支付平台证书访问器
certificateVisitor := downloader.MgrInstance().GetCertificateVisitor(mchID)
// 初始化 notify.Handler
handler := notify.NewNotifyHandler(mchAPIv3Key, verifiers.NewSHA256WithRSAVerifier(certificateVisitor))
// 解析并验证通知请求
content := make(map[string]interface{})
notifyReq, err := handler.ParseNotifyRequest(ctx, cRequest, &content)
if err != nil {
log.Printf("【%s投诉通知回调】解析通知请求失败: %v", platformString, err)
return
}
// 打印通知摘要和解析后的内容
log.Printf("【%s投诉通知回调】通知信息: %s", platformString, notifyReq.Summary)
log.Printf("【%s投诉通知回调】通知数据: %s", platformString, content)
// 根据解析后的数据处理通知
actionType, ok := content["action_type"].(string)
if !ok {
log.Printf("【%s投诉通知回调】通知内容中缺少action_type字段", platformString)
return
}
complaintID, ok := content["complaint_id"].(string)
if !ok {
log.Printf("【%s投诉通知回调】通知内容中缺少complaint_id字段", platformString)
return
}
switch actionType {
case "CREATE_COMPLAINT":
message := "用户提交了新的投诉"
notifyService.SendComplaintNotification(message, "新投诉", platformString, complaintID)
case "CONTINUE_COMPLAINT":
message := "用户继续投诉"
notifyService.SendComplaintNotification(message, "继续投诉", platformString, complaintID)
case "USER_RESPONSE":
message := "用户在投诉单中添加了新留言"
notifyService.SendComplaintNotification(message, "用户留言", platformString, complaintID)
case "RESPONSE_BY_PLATFORM":
message := "平台在投诉单中添加了新留言"
notifyService.SendComplaintNotification(message, "平台留言", platformString, complaintID)
case "SELLER_REFUND":
message := "商户发起了全额退款"
notifyService.SendComplaintNotification(message, "全额退款", platformString, complaintID)
case "MERCHANT_RESPONSE":
message := "商户对投诉进行了回复"
notifyService.SendComplaintNotification(message, "商户回复", platformString, complaintID)
case "MERCHANT_CONFIRM_COMPLETE":
message := "商户标记投诉处理完成"
notifyService.SendComplaintNotification(message, "投诉处理完成", platformString, complaintID)
case "MERCHANT_APPROVE_REFUND":
message := "商户同意了退款"
notifyService.SendComplaintNotification(message, "同意退款", platformString, complaintID)
case "MERCHANT_REJECT_REFUND":
message := "商户拒绝了退款"
notifyService.SendComplaintNotification(message, "拒绝退款", platformString, complaintID)
case "REFUND_SUCCESS":
message := "退款已成功到账"
notifyService.SendComplaintNotification(message, "退款到账", platformString, complaintID)
default:
message := "未知投诉类型"
notifyService.SendComplaintNotification(message, "未知投诉类型", platformString, complaintID)
log.Printf("【%s投诉通知回调】收到未知类型的投诉通知: %s", platformString, actionType)
}
// 返回成功响应
c.String(http.StatusOK, "success")
}