| 
									
										
										
										
											2025-05-27 18:35:01 +08:00
										 |  |  |  | package service | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import ( | 
					
						
							|  |  |  |  | 	"context" | 
					
						
							|  |  |  |  | 	"database/sql" | 
					
						
							|  |  |  |  | 	"fmt" | 
					
						
							|  |  |  |  | 	"net/http" | 
					
						
							|  |  |  |  | 	"time" | 
					
						
							|  |  |  |  | 	"tyc-server/app/main/api/internal/config" | 
					
						
							|  |  |  |  | 	"tyc-server/app/main/model" | 
					
						
							|  |  |  |  | 	"tyc-server/common/ctxdata" | 
					
						
							|  |  |  |  | 	"tyc-server/pkg/core/payment" | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-03 21:39:36 +08:00
										 |  |  |  | 	"github.com/zeromicro/go-zero/core/logx" | 
					
						
							| 
									
										
										
										
											2025-05-27 18:35:01 +08:00
										 |  |  |  | 	"github.com/zeromicro/go-zero/core/stores/sqlx" | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // PayService 支付服务 | 
					
						
							|  |  |  |  | type PayService struct { | 
					
						
							|  |  |  |  | 	config           config.Config | 
					
						
							|  |  |  |  | 	orderModel       model.OrderModel | 
					
						
							|  |  |  |  | 	orderRefundModel model.OrderRefundModel | 
					
						
							|  |  |  |  | 	productModel     model.ProductModel | 
					
						
							|  |  |  |  | 	userAuthModel    model.UserAuthModel | 
					
						
							|  |  |  |  | 	userModel        model.UserModel | 
					
						
							| 
									
										
										
										
											2025-06-03 21:39:36 +08:00
										 |  |  |  | 	asyncService     *AsynqService | 
					
						
							| 
									
										
										
										
											2025-05-27 18:35:01 +08:00
										 |  |  |  | 	alipayService    *payment.AliPayService | 
					
						
							|  |  |  |  | 	wechatService    *payment.WechatPayService | 
					
						
							|  |  |  |  | 	appleService     *payment.ApplePayService | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // NewPayService 创建支付服务 | 
					
						
							| 
									
										
										
										
											2025-06-03 21:39:36 +08:00
										 |  |  |  | func NewPayService(c config.Config, orderModel model.OrderModel, orderRefundModel model.OrderRefundModel, productModel model.ProductModel, userAuthModel model.UserAuthModel, userModel model.UserModel, asyncService *AsynqService) *PayService { | 
					
						
							| 
									
										
										
										
											2025-05-27 18:35:01 +08:00
										 |  |  |  | 	ps := &PayService{ | 
					
						
							|  |  |  |  | 		config:           c, | 
					
						
							|  |  |  |  | 		orderModel:       orderModel, | 
					
						
							|  |  |  |  | 		orderRefundModel: orderRefundModel, | 
					
						
							|  |  |  |  | 		productModel:     productModel, | 
					
						
							|  |  |  |  | 		userAuthModel:    userAuthModel, | 
					
						
							| 
									
										
										
										
											2025-06-03 20:59:26 +08:00
										 |  |  |  | 		userModel:        userModel, | 
					
						
							| 
									
										
										
										
											2025-06-03 21:39:36 +08:00
										 |  |  |  | 		asyncService:     asyncService, | 
					
						
							| 
									
										
										
										
											2025-05-27 18:35:01 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 根据配置选择性初始化支付服务 | 
					
						
							|  |  |  |  | 	if c.Alipay.Enabled { | 
					
						
							|  |  |  |  | 		// 初始化支付宝服务 | 
					
						
							|  |  |  |  | 		alipayConfig := payment.AlipayConfig{ | 
					
						
							|  |  |  |  | 			AppID:           c.Alipay.AppID, | 
					
						
							|  |  |  |  | 			PrivateKey:      c.Alipay.PrivateKey, | 
					
						
							|  |  |  |  | 			AlipayPublicKey: c.Alipay.AlipayPublicKey, | 
					
						
							|  |  |  |  | 			IsProduction:    c.Alipay.IsProduction, | 
					
						
							|  |  |  |  | 			NotifyURL:       c.Alipay.NotifyUrl, | 
					
						
							|  |  |  |  | 			ReturnURL:       c.Alipay.ReturnURL, | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		alipayService, err := payment.NewAliPayService(alipayConfig) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			panic(fmt.Sprintf("初始化支付宝服务失败: %v", err)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		ps.alipayService = alipayService | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if c.Wxpay.Enabled { | 
					
						
							|  |  |  |  | 		// 初始化微信支付服务 | 
					
						
							|  |  |  |  | 		wechatConfig := &payment.WechatPayConfig{ | 
					
						
							|  |  |  |  | 			AppID:       c.Wxpay.AppID, | 
					
						
							|  |  |  |  | 			MchID:       c.Wxpay.MchID, | 
					
						
							|  |  |  |  | 			SerialNo:    c.Wxpay.MchCertificateSerialNumber, | 
					
						
							|  |  |  |  | 			MchAPIv3Key: c.Wxpay.MchApiv3Key, | 
					
						
							|  |  |  |  | 			PrivateKey:  c.Wxpay.MchPrivateKeyPath, | 
					
						
							|  |  |  |  | 			NotifyURL:   c.Wxpay.NotifyUrl, | 
					
						
							|  |  |  |  | 			RefundURL:   c.Wxpay.RefundNotifyUrl, | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		wechatService, err := payment.NewWechatPayService(wechatConfig) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			panic(fmt.Sprintf("初始化微信支付服务失败: %v", err)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		ps.wechatService = wechatService | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if c.Applepay.Enabled { | 
					
						
							|  |  |  |  | 		// 初始化苹果支付服务 | 
					
						
							|  |  |  |  | 		appleConfig := payment.ApplePayConfig{ | 
					
						
							|  |  |  |  | 			BundleID:        c.Applepay.BundleID, | 
					
						
							|  |  |  |  | 			KeyID:           c.Applepay.KeyID, | 
					
						
							|  |  |  |  | 			TeamID:          c.Applepay.IssuerID, | 
					
						
							|  |  |  |  | 			PrivateKey:      c.Applepay.LoadPrivateKeyPath, | 
					
						
							|  |  |  |  | 			IsProduction:    !c.Applepay.Sandbox, | 
					
						
							|  |  |  |  | 			NotifyURL:       c.Applepay.ProductionVerifyURL, | 
					
						
							|  |  |  |  | 			RefundNotifyURL: c.Applepay.SandboxVerifyURL, | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		appleService, err := payment.NewApplePayService(appleConfig) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			panic(fmt.Sprintf("初始化苹果支付服务失败: %v", err)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		ps.appleService = appleService | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return ps | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // CreateOrder 创建支付订单 | 
					
						
							|  |  |  |  | func (p *PayService) CreateOrder(ctx context.Context, req *CreateOrderRequest) (*CreateOrderResponse, error) { | 
					
						
							|  |  |  |  | 	platform, ok := ctx.Value("platform").(string) | 
					
						
							|  |  |  |  | 	if !ok { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("获取平台失败") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	userID, err := ctxdata.GetUidFromCtx(ctx) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("获取用户信息失败: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	product, err := p.productModel.FindOneByProductEn(ctx, req.ProductEn) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("获取商品失败: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	user, err := p.userModel.FindOne(ctx, userID) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("获取用户失败: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-06-03 21:50:29 +08:00
										 |  |  |  | 	outTradeNo := req.OrderNo | 
					
						
							| 
									
										
										
										
											2025-05-27 18:35:01 +08:00
										 |  |  |  | 	var orderID int64 | 
					
						
							|  |  |  |  | 	amount := product.SellPrice | 
					
						
							|  |  |  |  | 	if user.Inside == 1 { | 
					
						
							|  |  |  |  | 		amount = 0.01 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	// 使用事务创建订单 | 
					
						
							|  |  |  |  | 	var payData interface{} | 
					
						
							|  |  |  |  | 	err = p.orderModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error { | 
					
						
							|  |  |  |  | 		// 根据支付方式创建支付订单 | 
					
						
							|  |  |  |  | 		switch req.PayMethod { | 
					
						
							|  |  |  |  | 		case "alipay": | 
					
						
							|  |  |  |  | 			orderReq := &payment.AlipayCreateOrderRequest{ | 
					
						
							| 
									
										
										
										
											2025-06-03 21:50:29 +08:00
										 |  |  |  | 				Amount:     amount, | 
					
						
							|  |  |  |  | 				Subject:    product.ProductName, | 
					
						
							|  |  |  |  | 				Platform:   payment.PlatformH5, | 
					
						
							|  |  |  |  | 				OutTradeNo: outTradeNo, | 
					
						
							| 
									
										
										
										
											2025-05-27 18:35:01 +08:00
										 |  |  |  | 			} | 
					
						
							|  |  |  |  | 			resp, err := p.alipayService.CreateOrder(ctx, orderReq) | 
					
						
							|  |  |  |  | 			if err != nil { | 
					
						
							|  |  |  |  | 				return fmt.Errorf("创建支付宝订单失败: %v", err) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			payData = resp.PayParams | 
					
						
							|  |  |  |  | 		case "wechat": | 
					
						
							|  |  |  |  | 			orderReq := &payment.Order{ | 
					
						
							|  |  |  |  | 				OutTradeNo: outTradeNo, | 
					
						
							|  |  |  |  | 				Subject:    product.ProductName, | 
					
						
							|  |  |  |  | 				Amount:     amount, | 
					
						
							|  |  |  |  | 				Platform:   payment.PlatformApp, | 
					
						
							|  |  |  |  | 				NotifyURL:  p.config.Wxpay.NotifyUrl, | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			// 如果是小程序支付,需要获取用户的 OpenID | 
					
						
							|  |  |  |  | 			if platform == "mp-weixin" { | 
					
						
							|  |  |  |  | 				userAuth, err := p.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWechatMiniOpenID) | 
					
						
							|  |  |  |  | 				if err != nil { | 
					
						
							|  |  |  |  | 					return fmt.Errorf("获取用户认证信息失败: %v", err) | 
					
						
							|  |  |  |  | 				} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 				orderReq.OpenID = userAuth.AuthKey | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			resp, err := p.wechatService.CreateOrder(orderReq) | 
					
						
							|  |  |  |  | 			if err != nil { | 
					
						
							|  |  |  |  | 				return fmt.Errorf("创建微信支付订单失败: %v", err) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			payData = resp.PayParams | 
					
						
							|  |  |  |  | 			outTradeNo = resp.OrderNo | 
					
						
							|  |  |  |  | 		// case "apple": | 
					
						
							|  |  |  |  | 		// 	orderReq := &payment.AppleCreateOrderRequest{ | 
					
						
							|  |  |  |  | 		// 		Amount:     amount, | 
					
						
							|  |  |  |  | 		// 		Subject:    product.ProductName, | 
					
						
							|  |  |  |  | 		// 		OutTradeNo: outTradeNo, | 
					
						
							|  |  |  |  | 		// 		Platform:   payment.PlatformApp, | 
					
						
							|  |  |  |  | 		// 		NotifyURL:  p.config.Applepay.ProductionVerifyURL, | 
					
						
							|  |  |  |  | 		// 	} | 
					
						
							|  |  |  |  | 		// 	resp, err := p.appleService.CreateOrder(ctx, orderReq) | 
					
						
							|  |  |  |  | 		// 	if err != nil { | 
					
						
							|  |  |  |  | 		// 		return fmt.Errorf("创建苹果支付订单失败: %v", err) | 
					
						
							|  |  |  |  | 		// 	} | 
					
						
							|  |  |  |  | 		// 	payData = resp.PayParams | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			return fmt.Errorf("不支持的支付方式: %s", req.PayMethod) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		// 创建订单记录 | 
					
						
							|  |  |  |  | 		order := &model.Order{ | 
					
						
							|  |  |  |  | 			OrderNo:         outTradeNo, | 
					
						
							|  |  |  |  | 			UserId:          userID, | 
					
						
							|  |  |  |  | 			ProductId:       product.Id, | 
					
						
							|  |  |  |  | 			PaymentPlatform: string(req.PayMethod), | 
					
						
							|  |  |  |  | 			PaymentScene:    platform, | 
					
						
							|  |  |  |  | 			Amount:          amount, | 
					
						
							|  |  |  |  | 			Status:          model.OrderStatusPending, | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		result, err := p.orderModel.Insert(ctx, session, order) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			return fmt.Errorf("创建订单记录失败: %v", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		orderID, err = result.LastInsertId() | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			return fmt.Errorf("获取订单ID失败: %v", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return nil | 
					
						
							|  |  |  |  | 	}) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, err | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return &CreateOrderResponse{ | 
					
						
							|  |  |  |  | 		OrderNo:   outTradeNo, | 
					
						
							|  |  |  |  | 		PayData:   payData, | 
					
						
							|  |  |  |  | 		PayMethod: req.PayMethod, | 
					
						
							|  |  |  |  | 		OrderID:   orderID, | 
					
						
							|  |  |  |  | 	}, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // HandlePaymentCallback 处理支付回调 | 
					
						
							|  |  |  |  | func (p *PayService) HandlePaymentCallback(ctx context.Context, payType string, req *http.Request) error { | 
					
						
							|  |  |  |  | 	return p.orderModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error { | 
					
						
							|  |  |  |  | 		var payOrder *payment.QueryOrderResponse | 
					
						
							|  |  |  |  | 		var err error | 
					
						
							|  |  |  |  | 		switch payType { | 
					
						
							|  |  |  |  | 		case "alipay": | 
					
						
							|  |  |  |  | 			payOrder, err = p.handleAlipayCallback(ctx, req, session) | 
					
						
							|  |  |  |  | 		case "wechat": | 
					
						
							|  |  |  |  | 			payOrder, err = p.handleWechatCallback(ctx, req, session) | 
					
						
							|  |  |  |  | 		case "apple": | 
					
						
							|  |  |  |  | 			payOrder, err = p.handleAppleCallback(ctx, req, session) | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			return fmt.Errorf("不支持的支付类型: %s", payType) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			return err | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if payOrder == nil { | 
					
						
							|  |  |  |  | 			return fmt.Errorf("支付订单信息为空") | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		// 查询订单 | 
					
						
							|  |  |  |  | 		order, err := p.orderModel.FindOneByOrderNo(ctx, payOrder.OrderNo) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			return fmt.Errorf("查询订单失败: %v", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		// 验证订单金额 | 
					
						
							|  |  |  |  | 		if payOrder.Amount != order.Amount { | 
					
						
							|  |  |  |  | 			return fmt.Errorf("订单金额不匹配") | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		// 根据支付状态更新订单状态 | 
					
						
							|  |  |  |  | 		switch payOrder.Status { | 
					
						
							|  |  |  |  | 		case payment.StatusSuccess: | 
					
						
							|  |  |  |  | 			order.Status = model.OrderStatusPaid | 
					
						
							|  |  |  |  | 		case payment.StatusFailed: | 
					
						
							|  |  |  |  | 			order.Status = model.OrderStatusFailed | 
					
						
							|  |  |  |  | 		case payment.StatusClosed: | 
					
						
							|  |  |  |  | 			order.Status = model.OrderStatusClosed | 
					
						
							|  |  |  |  | 		case payment.StatusRefunded: | 
					
						
							| 
									
										
										
										
											2025-06-30 01:09:33 +08:00
										 |  |  |  | 			order.Status = model.OrderStatusRefund | 
					
						
							| 
									
										
										
										
											2025-05-27 18:35:01 +08:00
										 |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			return fmt.Errorf("不支持的支付状态: %s", payOrder.Status) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		// 更新订单状态 | 
					
						
							|  |  |  |  | 		order.PlatformOrderId = sql.NullString{String: payOrder.TransactionID, Valid: true} | 
					
						
							|  |  |  |  | 		_, err = p.orderModel.Update(ctx, session, order) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			return fmt.Errorf("更新订单状态失败: %v", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-06-03 21:39:36 +08:00
										 |  |  |  | 		if asyncErr := p.asyncService.SendQueryTask(order.Id); asyncErr != nil { | 
					
						
							|  |  |  |  | 			logx.Errorf("异步任务调度失败: %v", asyncErr) | 
					
						
							|  |  |  |  | 			return asyncErr | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-05-27 18:35:01 +08:00
										 |  |  |  | 		return nil | 
					
						
							|  |  |  |  | 	}) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // handleAlipayCallback 处理支付宝回调 | 
					
						
							|  |  |  |  | func (p *PayService) handleAlipayCallback(ctx context.Context, req *http.Request, session sqlx.Session) (*payment.QueryOrderResponse, error) { | 
					
						
							|  |  |  |  | 	return p.alipayService.HandlePaymentNotification(req) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // handleWechatCallback 处理微信支付回调 | 
					
						
							|  |  |  |  | func (p *PayService) handleWechatCallback(ctx context.Context, req *http.Request, session sqlx.Session) (*payment.QueryOrderResponse, error) { | 
					
						
							|  |  |  |  | 	notification, err := p.wechatService.HandlePaymentNotification(req) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("处理微信支付回调失败: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 将微信支付通知转换为统一的查询订单响应格式 | 
					
						
							|  |  |  |  | 	return &payment.QueryOrderResponse{ | 
					
						
							|  |  |  |  | 		OrderNo:       notification.OrderNo, | 
					
						
							|  |  |  |  | 		TransactionID: notification.TransactionID, | 
					
						
							|  |  |  |  | 		Status:        notification.Status, | 
					
						
							|  |  |  |  | 		Amount:        notification.Amount, | 
					
						
							|  |  |  |  | 		PayTime:       notification.PayTime, | 
					
						
							|  |  |  |  | 		PayMethod:     payment.MethodWechat, | 
					
						
							|  |  |  |  | 	}, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // handleAppleCallback 处理苹果支付回调 | 
					
						
							|  |  |  |  | func (p *PayService) handleAppleCallback(ctx context.Context, req *http.Request, session sqlx.Session) (*payment.QueryOrderResponse, error) { | 
					
						
							|  |  |  |  | 	receipt := req.FormValue("receipt-data") | 
					
						
							|  |  |  |  | 	if receipt == "" { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("无效的苹果支付收据") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	verifyResp, err := p.appleService.VerifyReceipt(ctx, receipt) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("验证苹果支付收据失败: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if verifyResp.Status != payment.StatusSuccess { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("苹果支付验证失败,状态码: %s", verifyResp.Status) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 将苹果支付验证响应转换为统一的查询订单响应格式 | 
					
						
							|  |  |  |  | 	return &payment.QueryOrderResponse{ | 
					
						
							|  |  |  |  | 		OrderNo:       verifyResp.OrderNo, | 
					
						
							|  |  |  |  | 		TransactionID: verifyResp.TransactionID, | 
					
						
							|  |  |  |  | 		Status:        verifyResp.Status, | 
					
						
							|  |  |  |  | 		Amount:        verifyResp.Amount, | 
					
						
							|  |  |  |  | 		PayTime:       time.Now(), | 
					
						
							|  |  |  |  | 		PayMethod:     payment.MethodApple, | 
					
						
							|  |  |  |  | 	}, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Refund 申请退款 | 
					
						
							|  |  |  |  | func (p *PayService) Refund(ctx context.Context, req *RefundRequest) (*RefundResponse, error) { | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 查询订单信息 | 
					
						
							|  |  |  |  | 	order, err := p.orderModel.FindOne(ctx, req.OrderId) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("查询订单失败: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 验证订单状态 | 
					
						
							|  |  |  |  | 	if order.Status != model.OrderStatusPaid { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("订单状态为 %s,无法退款", order.Status) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if req.RefundAmount > order.Amount { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("退款金额 %.2f 不能大于订单金额 %.2f", req.RefundAmount, order.Amount) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	var result refundResult | 
					
						
							|  |  |  |  | 	result.status = model.OrderRefundStatusPending | 
					
						
							|  |  |  |  | 	order.Status = model.OrderStatusRefunding | 
					
						
							|  |  |  |  | 	// 使用事务处理退款流程 | 
					
						
							|  |  |  |  | 	err = p.orderModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error { | 
					
						
							|  |  |  |  | 		// 根据支付方式申请退款 | 
					
						
							|  |  |  |  | 		switch order.PaymentPlatform { | 
					
						
							|  |  |  |  | 		case string(PayMethodAlipay): | 
					
						
							|  |  |  |  | 			refundReq := &payment.AlipayRefundRequest{ | 
					
						
							|  |  |  |  | 				OrderNo:      order.OrderNo, | 
					
						
							|  |  |  |  | 				RefundAmount: req.RefundAmount, | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			resp, err := p.alipayService.Refund(ctx, refundReq) | 
					
						
							|  |  |  |  | 			if err != nil { | 
					
						
							|  |  |  |  | 				return fmt.Errorf("支付宝退款申请失败: %v", err) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			result = refundResult{ | 
					
						
							|  |  |  |  | 				refundNo:         resp.RefundNo, | 
					
						
							|  |  |  |  | 				status:           model.OrderRefundStatusSuccess, | 
					
						
							|  |  |  |  | 				refundTime:       resp.RefundTime, | 
					
						
							|  |  |  |  | 				refundAmount:     resp.RefundAmount, | 
					
						
							|  |  |  |  | 				platformRefundId: sql.NullString{String: resp.RefundID, Valid: true}, | 
					
						
							|  |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2025-06-20 15:11:38 +08:00
										 |  |  |  | 			order.Status = model.OrderStatusRefund | 
					
						
							| 
									
										
										
										
											2025-05-27 18:35:01 +08:00
										 |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			return fmt.Errorf("不支持的支付平台退款: %s", order.PaymentPlatform) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		// 创建退款记录 | 
					
						
							|  |  |  |  | 		refund := &model.OrderRefund{ | 
					
						
							|  |  |  |  | 			RefundNo:         result.refundNo, | 
					
						
							|  |  |  |  | 			PlatformRefundId: result.platformRefundId, | 
					
						
							|  |  |  |  | 			OrderId:          order.Id, | 
					
						
							|  |  |  |  | 			UserId:           order.UserId, | 
					
						
							|  |  |  |  | 			ProductId:        order.ProductId, | 
					
						
							|  |  |  |  | 			RefundAmount:     result.refundAmount, | 
					
						
							|  |  |  |  | 			RefundReason:     sql.NullString{String: req.Reason, Valid: true}, | 
					
						
							|  |  |  |  | 			Status:           result.status, | 
					
						
							|  |  |  |  | 			RefundTime:       sql.NullTime{Time: result.refundTime, Valid: !result.refundTime.IsZero()}, | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if _, err := p.orderRefundModel.Insert(ctx, session, refund); err != nil { | 
					
						
							|  |  |  |  | 			return fmt.Errorf("创建退款记录失败: %v", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		// 更新订单状态 | 
					
						
							| 
									
										
										
										
											2025-06-20 15:11:38 +08:00
										 |  |  |  | 		order.Status = model.OrderStatusRefund | 
					
						
							| 
									
										
										
										
											2025-05-27 18:35:01 +08:00
										 |  |  |  | 		order.RefundTime = sql.NullTime{Time: result.refundTime, Valid: !result.refundTime.IsZero()} | 
					
						
							|  |  |  |  | 		if _, err := p.orderModel.Update(ctx, session, order); err != nil { | 
					
						
							|  |  |  |  | 			return fmt.Errorf("更新订单状态失败: %v", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		return nil | 
					
						
							|  |  |  |  | 	}) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, err | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return &RefundResponse{ | 
					
						
							|  |  |  |  | 		RefundNo: result.refundNo, | 
					
						
							|  |  |  |  | 		Amount:   result.refundAmount, | 
					
						
							|  |  |  |  | 		Status:   result.status, | 
					
						
							|  |  |  |  | 	}, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // QueryOrderStatus 查询订单状态 | 
					
						
							|  |  |  |  | func (p *PayService) QueryOrderStatus(ctx context.Context, orderNo string) (*OrderStatusResponse, error) { | 
					
						
							|  |  |  |  | 	// 查询订单信息 | 
					
						
							|  |  |  |  | 	order, err := p.orderModel.FindOneByOrderNo(ctx, orderNo) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("查询订单失败: %v", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 根据支付方式查询支付状态 | 
					
						
							|  |  |  |  | 	var payStatus payment.PaymentStatus | 
					
						
							|  |  |  |  | 	switch order.PaymentPlatform { | 
					
						
							|  |  |  |  | 	case "alipay": | 
					
						
							|  |  |  |  | 		queryReq := &payment.QueryOrderRequest{ | 
					
						
							|  |  |  |  | 			OrderNo: orderNo, | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		resp, err := p.alipayService.QueryOrder(ctx, queryReq) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			return nil, fmt.Errorf("查询支付宝订单状态失败: %v", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		payStatus = resp.Status | 
					
						
							|  |  |  |  | 	// case "wechat": | 
					
						
							|  |  |  |  | 	// 	queryReq := &payment.OrderQuery{ | 
					
						
							|  |  |  |  | 	// 		OrderNo: orderNo, | 
					
						
							|  |  |  |  | 	// 	} | 
					
						
							|  |  |  |  | 	// 	resp, err := p.wechatService.QueryOrder(queryReq) | 
					
						
							|  |  |  |  | 	// 	if err != nil { | 
					
						
							|  |  |  |  | 	// 		return nil, fmt.Errorf("查询微信支付订单状态失败: %v", err) | 
					
						
							|  |  |  |  | 	// 	} | 
					
						
							|  |  |  |  | 	// 	payStatus = resp.Status | 
					
						
							|  |  |  |  | 	// case "apple": | 
					
						
							|  |  |  |  | 	// 	return nil, fmt.Errorf("苹果支付暂不支持主动查询订单状态") | 
					
						
							|  |  |  |  | 	default: | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("不支持的支付方式: %s", order.PaymentPlatform) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return &OrderStatusResponse{ | 
					
						
							|  |  |  |  | 		OrderNo:     orderNo, | 
					
						
							|  |  |  |  | 		PayMethod:   PayMethod(order.PaymentPlatform), | 
					
						
							|  |  |  |  | 		PayStatus:   string(payStatus), | 
					
						
							|  |  |  |  | 		OrderStatus: order.Status, | 
					
						
							|  |  |  |  | 		Amount:      order.Amount, | 
					
						
							|  |  |  |  | 	}, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | type PayMethod string | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | const ( | 
					
						
							|  |  |  |  | 	PayMethodAlipay PayMethod = "alipay" | 
					
						
							|  |  |  |  | 	PayMethodWechat PayMethod = "wechat" | 
					
						
							|  |  |  |  | 	PayMethodApple  PayMethod = "apple" | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 请求和响应结构体定义 | 
					
						
							|  |  |  |  | type CreateOrderRequest struct { | 
					
						
							|  |  |  |  | 	PayMethod PayMethod `json:"pay_method"` // 支付方式:alipay, wechat, apple | 
					
						
							|  |  |  |  | 	ProductEn string    `json:"product_en"` // 商品英文名 | 
					
						
							| 
									
										
										
										
											2025-06-03 21:50:29 +08:00
										 |  |  |  | 	OrderNo   string    `json:"order_no"`   // 订单号 | 
					
						
							| 
									
										
										
										
											2025-05-27 18:35:01 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | type CreateOrderResponse struct { | 
					
						
							|  |  |  |  | 	OrderNo   string      `json:"order_no"` // 订单号 | 
					
						
							|  |  |  |  | 	PayData   interface{} `json:"pay_data"` // 支付数据 | 
					
						
							|  |  |  |  | 	PayMethod PayMethod   `json:"pay_type"` // 支付方式 | 
					
						
							|  |  |  |  | 	OrderID   int64       `json:"order_id"` // 订单ID | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | type RefundRequest struct { | 
					
						
							|  |  |  |  | 	OrderId      int64   `json:"order_id"`      // 订单ID | 
					
						
							|  |  |  |  | 	RefundAmount float64 `json:"refund_amount"` // 退款金额 | 
					
						
							|  |  |  |  | 	Reason       string  `json:"reason"`        // 退款原因 | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // 定义退款结果结构 | 
					
						
							|  |  |  |  | type refundResult struct { | 
					
						
							|  |  |  |  | 	refundNo         string | 
					
						
							|  |  |  |  | 	status           string | 
					
						
							|  |  |  |  | 	refundTime       time.Time | 
					
						
							|  |  |  |  | 	refundAmount     float64 | 
					
						
							|  |  |  |  | 	platformRefundId sql.NullString | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | type RefundResponse struct { | 
					
						
							|  |  |  |  | 	RefundNo string  `json:"refund_no"` // 退款单号 | 
					
						
							|  |  |  |  | 	Amount   float64 `json:"amount"`    // 退款金额 | 
					
						
							|  |  |  |  | 	Status   string  `json:"status"`    // 退款状态 | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | type OrderStatusResponse struct { | 
					
						
							|  |  |  |  | 	OrderNo     string    `json:"order_no"`     // 订单号 | 
					
						
							|  |  |  |  | 	PayMethod   PayMethod `json:"pay_type"`     // 支付方式 | 
					
						
							|  |  |  |  | 	PayStatus   string    `json:"pay_status"`   // 支付状态 | 
					
						
							|  |  |  |  | 	OrderStatus string    `json:"order_status"` // 订单状态 | 
					
						
							|  |  |  |  | 	Amount      float64   `json:"amount"`       // 订单金额 | 
					
						
							|  |  |  |  | } |