| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | package service | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import ( | 
					
						
							|  |  |  |  | 	"context" | 
					
						
							|  |  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2025-05-11 01:22:25 +08:00
										 |  |  |  | 	"net/http" | 
					
						
							|  |  |  |  | 	"strconv" | 
					
						
							|  |  |  |  | 	"time" | 
					
						
							|  |  |  |  | 	"tydata-server/app/user/cmd/api/internal/config" | 
					
						
							|  |  |  |  | 	"tydata-server/app/user/model" | 
					
						
							|  |  |  |  | 	"tydata-server/common/ctxdata" | 
					
						
							|  |  |  |  | 	"tydata-server/pkg/lzkit/lzUtils" | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | 	"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/core/option" | 
					
						
							|  |  |  |  | 	"github.com/wechatpay-apiv3/wechatpay-go/services/payments" | 
					
						
							|  |  |  |  | 	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/app" | 
					
						
							|  |  |  |  | 	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi" | 
					
						
							|  |  |  |  | 	"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic" | 
					
						
							|  |  |  |  | 	"github.com/wechatpay-apiv3/wechatpay-go/utils" | 
					
						
							|  |  |  |  | 	"github.com/zeromicro/go-zero/core/logx" | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | const ( | 
					
						
							|  |  |  |  | 	TradeStateSuccess    = "SUCCESS"    // 支付成功 | 
					
						
							|  |  |  |  | 	TradeStateRefund     = "REFUND"     // 转入退款 | 
					
						
							|  |  |  |  | 	TradeStateNotPay     = "NOTPAY"     // 未支付 | 
					
						
							|  |  |  |  | 	TradeStateClosed     = "CLOSED"     // 已关闭 | 
					
						
							|  |  |  |  | 	TradeStateRevoked    = "REVOKED"    // 已撤销(付款码支付) | 
					
						
							|  |  |  |  | 	TradeStateUserPaying = "USERPAYING" // 用户支付中(付款码支付) | 
					
						
							|  |  |  |  | 	TradeStatePayError   = "PAYERROR"   // 支付失败(其他原因,如银行返回失败) | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-11 01:22:25 +08:00
										 |  |  |  | // InitType 初始化类型 | 
					
						
							|  |  |  |  | type InitType string | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | const ( | 
					
						
							|  |  |  |  | 	InitTypePlatformCert InitType = "platform_cert" // 平台证书初始化 | 
					
						
							|  |  |  |  | 	InitTypeWxPayPubKey  InitType = "wxpay_pubkey"  // 微信支付公钥初始化 | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | type WechatPayService struct { | 
					
						
							|  |  |  |  | 	config        config.WxpayConfig | 
					
						
							|  |  |  |  | 	wechatClient  *core.Client | 
					
						
							|  |  |  |  | 	notifyHandler *notify.Handler | 
					
						
							| 
									
										
										
										
											2025-01-21 20:00:18 +08:00
										 |  |  |  | 	userAuthModel model.UserAuthModel | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-11 01:22:25 +08:00
										 |  |  |  | // NewWechatPayService 创建微信支付服务实例 | 
					
						
							|  |  |  |  | func NewWechatPayService(c config.Config, userAuthModel model.UserAuthModel, initType InitType) *WechatPayService { | 
					
						
							|  |  |  |  | 	switch initType { | 
					
						
							|  |  |  |  | 	case InitTypePlatformCert: | 
					
						
							|  |  |  |  | 		return newWechatPayServiceWithPlatformCert(c, userAuthModel) | 
					
						
							|  |  |  |  | 	case InitTypeWxPayPubKey: | 
					
						
							|  |  |  |  | 		return newWechatPayServiceWithWxPayPubKey(c, userAuthModel) | 
					
						
							|  |  |  |  | 	default: | 
					
						
							|  |  |  |  | 		logx.Errorf("不支持的初始化类型: %s", initType) | 
					
						
							|  |  |  |  | 		panic(fmt.Sprintf("初始化失败,服务停止: %s", initType)) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // newWechatPayServiceWithPlatformCert 使用平台证书初始化微信支付服务 | 
					
						
							|  |  |  |  | func newWechatPayServiceWithPlatformCert(c config.Config, userAuthModel model.UserAuthModel) *WechatPayService { | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | 	// 从配置中加载商户信息 | 
					
						
							|  |  |  |  | 	mchID := c.Wxpay.MchID | 
					
						
							|  |  |  |  | 	mchCertificateSerialNumber := c.Wxpay.MchCertificateSerialNumber | 
					
						
							|  |  |  |  | 	mchAPIv3Key := c.Wxpay.MchApiv3Key | 
					
						
							| 
									
										
										
										
											2025-05-11 01:22:25 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | 	// 从文件中加载商户私钥 | 
					
						
							|  |  |  |  | 	mchPrivateKey, err := utils.LoadPrivateKeyWithPath(c.Wxpay.MchPrivateKeyPath) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		logx.Errorf("加载商户私钥失败: %v", err) | 
					
						
							|  |  |  |  | 		panic(fmt.Sprintf("初始化失败,服务停止: %v", err)) // 记录错误并停止程序 | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-05-11 01:22:25 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 使用商户私钥和其他参数初始化微信支付客户端 | 
					
						
							|  |  |  |  | 	opts := []core.ClientOption{ | 
					
						
							|  |  |  |  | 		option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key), | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	client, err := core.NewClient(context.Background(), opts...) | 
					
						
							| 
									
										
										
										
											2025-01-21 20:00:18 +08:00
										 |  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2025-05-11 01:22:25 +08:00
										 |  |  |  | 		logx.Errorf("创建微信支付客户端失败: %v", err) | 
					
						
							| 
									
										
										
										
											2025-01-21 20:00:18 +08:00
										 |  |  |  | 		panic(fmt.Sprintf("初始化失败,服务停止: %v", err)) // 记录错误并停止程序 | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-05-11 01:22:25 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 在初始化时获取证书访问器并创建 notifyHandler | 
					
						
							|  |  |  |  | 	certificateVisitor := downloader.MgrInstance().GetCertificateVisitor(mchID) | 
					
						
							|  |  |  |  | 	notifyHandler, err := notify.NewRSANotifyHandler(mchAPIv3Key, verifiers.NewSHA256WithRSAVerifier(certificateVisitor)) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		logx.Errorf("获取证书访问器失败: %v", err) | 
					
						
							|  |  |  |  | 		panic(fmt.Sprintf("初始化失败,服务停止: %v", err)) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	logx.Infof("微信支付客户端初始化成功(平台证书方式)") | 
					
						
							|  |  |  |  | 	return &WechatPayService{ | 
					
						
							|  |  |  |  | 		config:        c.Wxpay, | 
					
						
							|  |  |  |  | 		wechatClient:  client, | 
					
						
							|  |  |  |  | 		notifyHandler: notifyHandler, | 
					
						
							|  |  |  |  | 		userAuthModel: userAuthModel, | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // newWechatPayServiceWithWxPayPubKey 使用微信支付公钥初始化微信支付服务 | 
					
						
							|  |  |  |  | func newWechatPayServiceWithWxPayPubKey(c config.Config, userAuthModel model.UserAuthModel) *WechatPayService { | 
					
						
							|  |  |  |  | 	// 从配置中加载商户信息 | 
					
						
							|  |  |  |  | 	mchID := c.Wxpay.MchID | 
					
						
							|  |  |  |  | 	mchCertificateSerialNumber := c.Wxpay.MchCertificateSerialNumber | 
					
						
							|  |  |  |  | 	mchAPIv3Key := c.Wxpay.MchApiv3Key | 
					
						
							|  |  |  |  | 	mchPrivateKeyPath := c.Wxpay.MchPrivateKeyPath | 
					
						
							|  |  |  |  | 	mchPublicKeyID := c.Wxpay.MchPublicKeyID | 
					
						
							|  |  |  |  | 	mchPublicKeyPath := c.Wxpay.MchPublicKeyPath | 
					
						
							|  |  |  |  | 	// 从文件中加载商户私钥 | 
					
						
							|  |  |  |  | 	mchPrivateKey, err := utils.LoadPrivateKeyWithPath(mchPrivateKeyPath) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		logx.Errorf("加载商户私钥失败: %v", err) | 
					
						
							|  |  |  |  | 		panic(fmt.Sprintf("初始化失败,服务停止: %v", err)) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 从文件中加载微信支付平台证书 | 
					
						
							|  |  |  |  | 	mchPublicKey, err := utils.LoadPublicKeyWithPath(mchPublicKeyPath) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		logx.Errorf("加载微信支付平台证书失败: %v", err) | 
					
						
							|  |  |  |  | 		panic(fmt.Sprintf("初始化失败,服务停止: %v", err)) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | 	// 使用商户私钥和其他参数初始化微信支付客户端 | 
					
						
							|  |  |  |  | 	opts := []core.ClientOption{ | 
					
						
							| 
									
										
										
										
											2025-01-21 20:00:18 +08:00
										 |  |  |  | 		option.WithWechatPayPublicKeyAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchPublicKeyID, mchPublicKey), | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 	client, err := core.NewClient(context.Background(), opts...) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		logx.Errorf("创建微信支付客户端失败: %v", err) | 
					
						
							| 
									
										
										
										
											2025-05-11 01:22:25 +08:00
										 |  |  |  | 		panic(fmt.Sprintf("初始化失败,服务停止: %v", err)) | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-05-11 01:22:25 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 初始化 notify.Handler | 
					
						
							| 
									
										
										
										
											2025-05-11 12:04:54 +08:00
										 |  |  |  | 	certificateVisitor := downloader.MgrInstance().GetCertificateVisitor(mchID) | 
					
						
							| 
									
										
										
										
											2025-01-21 21:14:27 +08:00
										 |  |  |  | 	notifyHandler := notify.NewNotifyHandler( | 
					
						
							|  |  |  |  | 		mchAPIv3Key, | 
					
						
							| 
									
										
										
										
											2025-05-11 12:04:54 +08:00
										 |  |  |  | 		verifiers.NewSHA256WithRSACombinedVerifier(certificateVisitor, mchPublicKeyID, *mchPublicKey)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-11 01:22:25 +08:00
										 |  |  |  | 	logx.Infof("微信支付客户端初始化成功(微信支付公钥方式)") | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | 	return &WechatPayService{ | 
					
						
							|  |  |  |  | 		config:        c.Wxpay, | 
					
						
							|  |  |  |  | 		wechatClient:  client, | 
					
						
							|  |  |  |  | 		notifyHandler: notifyHandler, | 
					
						
							| 
									
										
										
										
											2025-01-21 20:00:18 +08:00
										 |  |  |  | 		userAuthModel: userAuthModel, | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // CreateWechatAppOrder 创建微信APP支付订单 | 
					
						
							|  |  |  |  | func (w *WechatPayService) CreateWechatAppOrder(ctx context.Context, amount float64, description string, outTradeNo string) (string, error) { | 
					
						
							|  |  |  |  | 	totalAmount := lzUtils.ToWechatAmount(amount) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 构建支付请求参数 | 
					
						
							|  |  |  |  | 	payRequest := app.PrepayRequest{ | 
					
						
							|  |  |  |  | 		Appid:       core.String(w.config.AppID), | 
					
						
							|  |  |  |  | 		Mchid:       core.String(w.config.MchID), | 
					
						
							|  |  |  |  | 		Description: core.String(description), | 
					
						
							|  |  |  |  | 		OutTradeNo:  core.String(outTradeNo), | 
					
						
							|  |  |  |  | 		NotifyUrl:   core.String(w.config.NotifyUrl), | 
					
						
							|  |  |  |  | 		Amount: &app.Amount{ | 
					
						
							|  |  |  |  | 			Total: core.Int64(totalAmount), | 
					
						
							|  |  |  |  | 		}, | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 初始化 AppApiService | 
					
						
							|  |  |  |  | 	svc := app.AppApiService{Client: w.wechatClient} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 发起预支付请求 | 
					
						
							|  |  |  |  | 	resp, result, err := svc.Prepay(ctx, payRequest) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, result.Response.StatusCode) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 返回预支付交易会话标识 | 
					
						
							|  |  |  |  | 	return *resp.PrepayId, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // CreateWechatMiniProgramOrder 创建微信小程序支付订单 | 
					
						
							| 
									
										
										
										
											2025-01-21 20:00:18 +08:00
										 |  |  |  | func (w *WechatPayService) CreateWechatMiniProgramOrder(ctx context.Context, amount float64, description string, outTradeNo string, openid string) (interface{}, error) { | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | 	totalAmount := lzUtils.ToWechatAmount(amount) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 构建支付请求参数 | 
					
						
							|  |  |  |  | 	payRequest := jsapi.PrepayRequest{ | 
					
						
							|  |  |  |  | 		Appid:       core.String(w.config.AppID), | 
					
						
							|  |  |  |  | 		Mchid:       core.String(w.config.MchID), | 
					
						
							|  |  |  |  | 		Description: core.String(description), | 
					
						
							|  |  |  |  | 		OutTradeNo:  core.String(outTradeNo), | 
					
						
							|  |  |  |  | 		NotifyUrl:   core.String(w.config.NotifyUrl), | 
					
						
							|  |  |  |  | 		Amount: &jsapi.Amount{ | 
					
						
							|  |  |  |  | 			Total: core.Int64(totalAmount), | 
					
						
							|  |  |  |  | 		}, | 
					
						
							|  |  |  |  | 		Payer: &jsapi.Payer{ | 
					
						
							|  |  |  |  | 			Openid: core.String(openid), // 用户的 OpenID,通过前端传入 | 
					
						
							|  |  |  |  | 		}} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 初始化 AppApiService | 
					
						
							|  |  |  |  | 	svc := jsapi.JsapiApiService{Client: w.wechatClient} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 发起预支付请求 | 
					
						
							|  |  |  |  | 	resp, result, err := svc.PrepayWithRequestPayment(ctx, payRequest) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, result.Response.StatusCode) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	// 返回预支付交易会话标识 | 
					
						
							| 
									
										
										
										
											2025-01-21 20:00:18 +08:00
										 |  |  |  | 	return resp, nil | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // CreateWechatOrder 创建微信支付订单(集成 APP、H5、小程序) | 
					
						
							| 
									
										
										
										
											2025-01-21 20:00:18 +08:00
										 |  |  |  | func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64, description string, outTradeNo string) (interface{}, error) { | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | 	// 根据 ctx 中的 platform 判断平台 | 
					
						
							|  |  |  |  | 	platform := ctx.Value("platform").(string) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-21 20:00:18 +08:00
										 |  |  |  | 	var prepayData interface{} | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | 	var err error | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	switch platform { | 
					
						
							|  |  |  |  | 	case "mp-weixin": | 
					
						
							| 
									
										
										
										
											2025-01-21 20:00:18 +08:00
										 |  |  |  | 		userID, getUidErr := ctxdata.GetUidFromCtx(ctx) | 
					
						
							|  |  |  |  | 		if getUidErr != nil { | 
					
						
							|  |  |  |  | 			return "", getUidErr | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		userAuthModel, findAuthModelErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxMini) | 
					
						
							|  |  |  |  | 		if findAuthModelErr != nil { | 
					
						
							|  |  |  |  | 			return "", findAuthModelErr | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		prepayData, err = w.CreateWechatMiniProgramOrder(ctx, amount, description, outTradeNo, userAuthModel.AuthKey) | 
					
						
							| 
									
										
										
										
											2025-05-11 01:22:25 +08:00
										 |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			return "", err | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-01-21 20:00:18 +08:00
										 |  |  |  | 	case "h5-weixin": | 
					
						
							|  |  |  |  | 		userID, getUidErr := ctxdata.GetUidFromCtx(ctx) | 
					
						
							|  |  |  |  | 		if getUidErr != nil { | 
					
						
							|  |  |  |  | 			return "", getUidErr | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		userAuthModel, findAuthModelErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxh5) | 
					
						
							|  |  |  |  | 		if findAuthModelErr != nil { | 
					
						
							|  |  |  |  | 			return "", findAuthModelErr | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		prepayData, err = w.CreateWechatMiniProgramOrder(ctx, amount, description, outTradeNo, userAuthModel.AuthKey) | 
					
						
							| 
									
										
										
										
											2025-05-11 01:22:25 +08:00
										 |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			return "", err | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | 	case "app": | 
					
						
							|  |  |  |  | 		// 如果是 APP 平台,调用 APP 支付订单创建 | 
					
						
							| 
									
										
										
										
											2025-01-21 20:00:18 +08:00
										 |  |  |  | 		prepayData, err = w.CreateWechatAppOrder(ctx, amount, description, outTradeNo) | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | 	default: | 
					
						
							|  |  |  |  | 		return "", fmt.Errorf("不支持的支付平台: %s", platform) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 如果创建支付订单失败,返回错误 | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return "", fmt.Errorf("支付订单创建失败: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 返回预支付ID | 
					
						
							| 
									
										
										
										
											2025-01-21 20:00:18 +08:00
										 |  |  |  | 	return prepayData, nil | 
					
						
							| 
									
										
										
										
											2025-01-10 00:09:25 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // HandleWechatPayNotification 处理微信支付回调 | 
					
						
							|  |  |  |  | func (w *WechatPayService) HandleWechatPayNotification(ctx context.Context, req *http.Request) (*payments.Transaction, error) { | 
					
						
							|  |  |  |  | 	transaction := new(payments.Transaction) | 
					
						
							|  |  |  |  | 	_, err := w.notifyHandler.ParseNotifyRequest(ctx, req, transaction) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("微信支付通知处理失败: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	// 返回交易信息 | 
					
						
							|  |  |  |  | 	return transaction, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // HandleRefundNotification 处理微信退款回调 | 
					
						
							|  |  |  |  | func (w *WechatPayService) HandleRefundNotification(ctx context.Context, req *http.Request) (*refunddomestic.Refund, error) { | 
					
						
							|  |  |  |  | 	refund := new(refunddomestic.Refund) | 
					
						
							|  |  |  |  | 	_, err := w.notifyHandler.ParseNotifyRequest(ctx, req, refund) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("微信退款回调通知处理失败: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return refund, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // QueryOrderStatus 主动查询订单状态 | 
					
						
							|  |  |  |  | func (w *WechatPayService) QueryOrderStatus(ctx context.Context, transactionID string) (*payments.Transaction, error) { | 
					
						
							|  |  |  |  | 	svc := jsapi.JsapiApiService{Client: w.wechatClient} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 调用 QueryOrderById 方法查询订单状态 | 
					
						
							|  |  |  |  | 	resp, result, err := svc.QueryOrderById(ctx, jsapi.QueryOrderByIdRequest{ | 
					
						
							|  |  |  |  | 		TransactionId: core.String(transactionID), | 
					
						
							|  |  |  |  | 		Mchid:         core.String(w.config.MchID), | 
					
						
							|  |  |  |  | 	}) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("订单查询失败: %v, 状态码: %d", err, result.Response.StatusCode) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return resp, nil | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // WeChatRefund 申请微信退款 | 
					
						
							|  |  |  |  | func (w *WechatPayService) WeChatRefund(ctx context.Context, outTradeNo string, refundAmount float64, totalAmount float64) error { | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 生成唯一的退款单号 | 
					
						
							|  |  |  |  | 	outRefundNo := fmt.Sprintf("%s-refund", outTradeNo) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 初始化退款服务 | 
					
						
							|  |  |  |  | 	svc := refunddomestic.RefundsApiService{Client: w.wechatClient} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 创建退款请求 | 
					
						
							|  |  |  |  | 	resp, result, err := svc.Create(ctx, refunddomestic.CreateRequest{ | 
					
						
							|  |  |  |  | 		OutTradeNo:  core.String(outTradeNo), | 
					
						
							|  |  |  |  | 		OutRefundNo: core.String(outRefundNo), | 
					
						
							|  |  |  |  | 		NotifyUrl:   core.String(w.config.RefundNotifyUrl), | 
					
						
							|  |  |  |  | 		Amount: &refunddomestic.AmountReq{ | 
					
						
							|  |  |  |  | 			Currency: core.String("CNY"), | 
					
						
							|  |  |  |  | 			Refund:   core.Int64(lzUtils.ToWechatAmount(refundAmount)), | 
					
						
							|  |  |  |  | 			Total:    core.Int64(lzUtils.ToWechatAmount(totalAmount)), | 
					
						
							|  |  |  |  | 		}, | 
					
						
							|  |  |  |  | 	}) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return fmt.Errorf("微信订单申请退款错误: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	// 打印退款结果 | 
					
						
							|  |  |  |  | 	logx.Infof("退款申请成功,状态码=%d,退款单号=%s,微信退款单号=%s", result.Response.StatusCode, *resp.OutRefundNo, *resp.RefundId) | 
					
						
							|  |  |  |  | 	return nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // GenerateOutTradeNo 生成唯一订单号 | 
					
						
							|  |  |  |  | func (w *WechatPayService) GenerateOutTradeNo() string { | 
					
						
							|  |  |  |  | 	length := 16 | 
					
						
							|  |  |  |  | 	timestamp := time.Now().UnixNano() | 
					
						
							|  |  |  |  | 	timeStr := strconv.FormatInt(timestamp, 10) | 
					
						
							|  |  |  |  | 	randomPart := strconv.Itoa(int(timestamp % 1e6)) | 
					
						
							|  |  |  |  | 	combined := timeStr + randomPart | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if len(combined) >= length { | 
					
						
							|  |  |  |  | 		return combined[:length] | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for len(combined) < length { | 
					
						
							|  |  |  |  | 		combined += strconv.Itoa(int(timestamp % 10)) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return combined | 
					
						
							|  |  |  |  | } |