package paymentService import ( "PaymentCenter/app/constants/common" "PaymentCenter/app/constants/errorcode" "PaymentCenter/app/services/thirdpay/thirdpay_notify" "PaymentCenter/app/third/paymentService/payCommon" "PaymentCenter/config" "context" "encoding/json" "errors" "fmt" "github.com/go-pay/gopay" "github.com/go-pay/gopay/alipay" "github.com/qit-team/snow-core/log/logger" "strconv" ) // AliInitClient 使用提供的支付请求参数初始化支付宝客户端 func AliInitClient(aliConfig AliPay) (*alipay.Client, error) { envConfig := config.GetConf() // 初始化支付宝客户端 // appid:应用ID // privateKey:应用私钥,支持PKCS1和PKCS8 // isProd:是否是正式环境,沙箱环境请选择新版沙箱应用。 aliClient, aliClientErr := alipay.NewClient(aliConfig.AppId, aliConfig.PrivateKey, envConfig.PayService.IsProd) // 自定义配置http请求接收返回结果body大小,默认 10MB aliClient.SetBodySize(10) // 没有特殊需求,可忽略此配置 // 打开Debug开关,输出日志,默认关闭 aliClient.DebugSwitch = gopay.DebugOn // 设置支付宝请求 公共参数 // 注意:具体设置哪些参数,根据不同的方法而不同,此处列举出所有设置参数 aliClient.SetLocation(alipay.LocationShanghai). // 设置时区,不设置或出错均为默认服务器时间 SetCharset(alipay.UTF8). // 设置字符编码,不设置默认 utf-8 SetSignType(alipay.RSA2) // 设置签名类型,不设置默认 RSA2 // 自动同步验签(只支持证书模式) // 传入 alipayPublicCert.crt 内容 aliClient.AutoVerifySign([]byte(aliConfig.AlipayPublicCert)) // 证书内容 aliClientErr = aliClient.SetCertSnByContent([]byte(aliConfig.AppPublicCert), []byte(aliConfig.AlipayRootCert), []byte(aliConfig.AlipayPublicCert)) if aliClient == nil { return nil, errors.New("client not initialized") } if aliClientErr != nil { return nil, aliClientErr } return aliClient, nil } // ALiH5PayInfo 支付宝手机网站支付 func ALiH5PayInfo(c context.Context, payOrderRequest PayOrderRequest) (string, error) { // 初始化支付宝客户端 aliClient, err := AliInitClient(payOrderRequest.Ali) if err != nil { return "", err } // 初始化 BodyMap amount := float64(payOrderRequest.Amount) / 100.0 envConfig := config.GetConf() bm := make(gopay.BodyMap) bm.Set("out_trade_no", payOrderRequest.OrderId). Set("total_amount", amount). Set("subject", payOrderRequest.Description). Set("notify_url", fmt.Sprintf(envConfig.PayService.Host+payCommon.ALI_NOTIFY_URL_TEST+"%d", payOrderRequest.PayChannelId)) if payOrderRequest.ReturnUrl != "" { bm.Set("return_url", payOrderRequest.ReturnUrl) } aliRsp, err := aliClient.TradeWapPay(c, bm) if err != nil { logger.Error(c, "ALiH5PayInfo 发生错误", fmt.Sprintf("错误信息:%s", err.Error())) if bizErr, ok := alipay.IsBizError(err); ok { return "", bizErr } return "", err } return aliRsp, nil } // ALiPCPayInfo 支付宝 支付宝PC网站支付 func ALiPCPayInfo(c context.Context, payOrderRequest PayOrderRequest) (string, error) { // 初始化支付宝客户端 aliClient, err := AliInitClient(payOrderRequest.Ali) if err != nil { return "", err } // 初始化 BodyMap amount := float64(payOrderRequest.Amount) / 100.0 envConfig := config.GetConf() bm := make(gopay.BodyMap) bm.Set("out_trade_no", payOrderRequest.OrderId). Set("total_amount", amount). Set("subject", payOrderRequest.Description). Set("qr_pay_mode", 1). Set("notify_url", fmt.Sprintf(envConfig.PayService.Host+payCommon.ALI_NOTIFY_URL_TEST+"%d", payOrderRequest.PayChannelId)) if payOrderRequest.ReturnUrl != "" { bm.Set("return_url", payOrderRequest.ReturnUrl) } aliRsp, err := aliClient.TradePagePay(c, bm) if err != nil { logger.Error(c, "ALiH5PayInfo 发生错误", fmt.Sprintf("错误信息:%s", err.Error())) if bizErr, ok := alipay.IsBizError(err); ok { return "", bizErr } return "", err } return aliRsp, nil } // ALiQrCodeTradePrecreate 支付宝 订单码支付 func ALiQrCodeTradePrecreate(c context.Context, payOrderRequest PayOrderRequest) (string, error) { // 初始化支付宝客户端 aliClient, err := AliInitClient(payOrderRequest.Ali) if err != nil { return "", err } // 初始化 BodyMap amount := float64(payOrderRequest.Amount) / 100.0 envConfig := config.GetConf() bm := make(gopay.BodyMap) bm.Set("out_trade_no", payOrderRequest.OrderId). Set("total_amount", amount). Set("subject", payOrderRequest.Description). Set("notify_url", fmt.Sprintf(envConfig.PayService.Host+payCommon.ALI_NOTIFY_URL_TEST+"%d", payOrderRequest.PayChannelId)) if payOrderRequest.ReturnUrl != "" { bm.Set("return_url", payOrderRequest.ReturnUrl) } aliRsp, err := aliClient.TradePrecreate(c, bm) if err != nil { logger.Error(c, "ALiH5PayInfo 发生错误", fmt.Sprintf("错误信息:%s", err.Error())) if bizErr, ok := alipay.IsBizError(err); ok { return "", bizErr } return "", err } return aliRsp.Response.QrCode, nil } // ALiCallBack 支付宝支付回调 func ALiCallBack(notifyReq gopay.BodyMap, aliConfig AliPay) error { var orderStatus int ok, err := alipay.VerifySignWithCert([]byte(aliConfig.AlipayPublicCert), notifyReq) if !ok || err != nil { return err } // 拼装数据触发下游回调,触发下游回调 orderId, _ := strconv.Atoi(notifyReq.Get("out_trade_no")) payerTotal, _ := strconv.Atoi(notifyReq.Get("buyer_pay_amount")) // 订单状态 tradeStatus := notifyReq.Get("trade_status") errCode := 0 msg := "" switch tradeStatus { case "TRADE_CLOSED": errCode = errorcode.ParamError orderStatus = common.ORDER_STATUS_CLOSE msg = "未付款交易超时关闭,或支付完成后全额退款。" case "TRADE_SUCCESS": errCode = errorcode.Success orderStatus = common.ORDER_STATUS_PAYED msg = "交易支付成功。" case "TRADE_FINISHED": errCode = errorcode.Success orderStatus = common.ORDER_STATUS_CLOSE msg = "交易结束,不可退款。" } if errCode == 0 { // 等待买家付款,不走后续回调 return errors.New("订单状态异常,无法进行后续回调") } res := thirdpay_notify.NewOrderNotifyWithHandle(int64(orderId), orderStatus, errCode, payerTotal, msg) merchantCallback, _ := json.Marshal(res) // 记录日志 go func() { payCallback, _ := json.Marshal(notifyReq) payParam := "{}" status := common.THIRD_ORDER_LOG_STATUS_SUCCESS SaveLog(int64(orderId), common.THIRD_ORDER_TYPE_CALL_BACK, string(payCallback), payParam, "{}", status) }() if res.ErrCode != errorcode.Success { logger.Error(context.Background(), "ALiCallBack 发生错误", fmt.Sprintf("回调时,下游处理订单失败,返回数据为:%s", string(merchantCallback))) return errors.New("回调时,下游处理订单失败") } return nil } // ALiOrderQuery 查询支付宝订单 func ALiOrderQuery(ctx context.Context, aliConfig AliPay, OrderNo string) (PayOrderQueryInfo, error) { // 初始化支付宝客户端 aliClient, err := AliInitClient(aliConfig) if err != nil { return PayOrderQueryInfo{}, err } // 请求参数 bm := make(gopay.BodyMap) bm.Set("out_trade_no", OrderNo) // 查询订单 aliRsp, err := aliClient.TradeQuery(ctx, bm) if err != nil { if bizErr, ok := alipay.IsBizError(err); ok { return PayOrderQueryInfo{}, bizErr } return PayOrderQueryInfo{}, err } // 同步返回验签 ok, err := alipay.VerifySyncSignWithCert([]byte(aliConfig.AlipayPublicCert), aliRsp.SignData, aliRsp.Sign) if err != nil || !ok { return PayOrderQueryInfo{}, errors.New(fmt.Sprintf("验签失败,失败原因:%s", err.Error())) } // 映射交易状态 tradeState := "" tradeStateDesc := "" switch aliRsp.Response.TradeStatus { case "TRADE_SUCCESS": tradeState = "SUCCESS" tradeStateDesc = "交易支付成功" case "REFUND": tradeState = "REFUND" tradeStateDesc = "转入退款" case "WAIT_BUYER_PAY": tradeState = "NOTPAY" tradeStateDesc = "交易创建,等待买家付款" case "TRADE_CLOSED": tradeState = "CLOSED" tradeStateDesc = "未付款交易超时关闭,或支付完成后全额退款" } amountTotal, _ := strconv.ParseFloat(aliRsp.Response.TotalAmount, 64) payerTotal, _ := strconv.ParseFloat(aliRsp.Response.BuyerPayAmount, 64) // 构建数据 outTradeNo, _ := strconv.Atoi(aliRsp.Response.OutTradeNo) return PayOrderQueryInfo{ AppId: aliConfig.AppId, OutTradeNo: int64(outTradeNo), TransactionId: aliRsp.Response.TradeNo, TradeState: tradeState, TradeStateDesc: tradeStateDesc, SuccessTime: aliRsp.Response.SendPayDate, AmountTotal: int64(amountTotal * 100), PayerTotal: int64(payerTotal * 100), }, nil } // AliRefundOrder 支付宝退款申请 func AliRefundOrder(ctx context.Context, orderRefundRequest OrderRefundRequest) (OrderRefundInfo, error) { // 初始化支付宝客户端 aliClient, err := AliInitClient(orderRefundRequest.Ali) if err != nil { return OrderRefundInfo{}, err } // 请求参数 refundAmount := float64(orderRefundRequest.RefundAmount) / 100.0 bm := make(gopay.BodyMap) bm.Set("out_trade_no", orderRefundRequest.OrderId). Set("refund_amount", refundAmount). Set("refund_reason", orderRefundRequest.RefundReason). Set("out_request_no", orderRefundRequest.RefundOrderId) // 发起退款请求 aliRsp, err := aliClient.TradeRefund(ctx, bm) if err != nil { logger.Error(ctx, "AliRefundOrder 发生错误", fmt.Sprintf("申请退款接口失败,错误信息:%s", err.Error())) if bizErr, ok := alipay.IsBizError(err); ok { return OrderRefundInfo{}, bizErr } return OrderRefundInfo{}, err } refundFee, _ := strconv.ParseFloat(aliRsp.Response.RefundFee, 64) outTradeNo, _ := strconv.ParseFloat(aliRsp.Response.OutTradeNo, 64) return OrderRefundInfo{ OutTradeNo: int64(outTradeNo), TransactionId: aliRsp.Response.TradeNo, RefundFee: int64(refundFee * 100), RefundOrderId: orderRefundRequest.RefundOrderId, RefundStatus: payCommon.PAY_REFUND_STATU_SUCCESS, RefundSuccessTime: aliRsp.Response.GmtRefundPay, }, nil } // AliRefundOrderQuery 支付宝订单退款查询 func AliRefundOrderQuery(ctx context.Context, orderRefundQueryRequest OrderRefundQueryRequest) (OrderRefundInfo, error) { // 初始化支付宝客户端 aliClient, err := AliInitClient(orderRefundQueryRequest.Ali) if err != nil { return OrderRefundInfo{}, err } // 请求参数 bm := make(gopay.BodyMap) bm.Set("out_trade_no", orderRefundQueryRequest.OrderId). Set("out_request_no", orderRefundQueryRequest.RefundOrderId). Set("query_options", []string{"gmt_refund_pay"}) // 发起退款查询请求 aliRsp, err := aliClient.TradeFastPayRefundQuery(ctx, bm) if err != nil { if bizErr, ok := alipay.IsBizError(err); ok { return OrderRefundInfo{}, bizErr } return OrderRefundInfo{}, err } refundFee, _ := strconv.ParseFloat(aliRsp.Response.RefundAmount, 64) outTradeNo, _ := strconv.Atoi(aliRsp.Response.OutTradeNo) refundOrderId, _ := strconv.Atoi(aliRsp.Response.OutRequestNo) return OrderRefundInfo{ OutTradeNo: int64(outTradeNo), TransactionId: aliRsp.Response.TradeNo, RefundFee: int64(refundFee * 100), RefundOrderId: int64(refundOrderId), RefundStatus: payCommon.PAY_REFUND_STATU_SUCCESS, RefundSuccessTime: aliRsp.Response.GmtRefundPay, }, nil } // AliCloseOrder 支付宝订单关闭 func AliCloseOrder(ctx context.Context, orderCloseRequest OrderCloseRequest) (OrderCloseInfo, error) { // 初始化支付宝客户端 aliClient, err := AliInitClient(orderCloseRequest.Ali) if err != nil { return OrderCloseInfo{}, err } // 请求参数 bm := make(gopay.BodyMap) bm.Set("out_trade_no", orderCloseRequest.OrderId) // 关闭订单 aliRsp, err := aliClient.TradeClose(ctx, bm) if err != nil { logger.Error(ctx, "AliCloseOrder 发生错误", fmt.Sprintf("申请退款接口失败,错误信息:%s", err.Error())) if bizErr, ok := alipay.IsBizError(err); ok { return OrderCloseInfo{}, bizErr } return OrderCloseInfo{}, err } outTradeNo, _ := strconv.Atoi(aliRsp.Response.OutTradeNo) return OrderCloseInfo{ OutTradeNo: int64(outTradeNo), }, nil }