package service import ( "context" "fmt" "github.com/smartwalle/alipay/v3" mathrand "math/rand" "net/http" "strconv" "time" "tydata-server/app/user/cmd/api/internal/config" "tydata-server/pkg/lzkit/lzUtils" ) type AliPayService struct { config config.AlipayConfig AlipayClient *alipay.Client } // NewAliPayService 是一个构造函数,用于初始化 AliPayService func NewAliPayService(c config.Config) *AliPayService { client, err := alipay.New(c.Alipay.AppID, c.Alipay.PrivateKey, c.Alipay.IsProduction) if err != nil { panic(fmt.Sprintf("创建支付宝客户端失败: %v", err)) } //// 加载支付宝公钥 //err = client.LoadAliPayPublicKey(c.Alipay.AlipayPublicKey) //if err != nil { // panic(fmt.Sprintf("加载支付宝公钥失败: %v", err)) //} // 加载证书 if err = client.LoadAppCertPublicKeyFromFile(c.Alipay.AppCertPath); err != nil { panic(fmt.Sprintf("加载应用公钥证书失败: %v", err)) } if err = client.LoadAlipayCertPublicKeyFromFile(c.Alipay.AlipayCertPath); err != nil { panic(fmt.Sprintf("加载支付宝公钥证书失败: %v", err)) } if err = client.LoadAliPayRootCertFromFile(c.Alipay.AlipayRootCertPath); err != nil { panic(fmt.Sprintf("加载根证书失败: %v", err)) } return &AliPayService{ config: c.Alipay, AlipayClient: client, } } func (a *AliPayService) CreateAlipayAppOrder(amount float64, subject string, outTradeNo string) (string, error) { client := a.AlipayClient totalAmount := lzUtils.ToAlipayAmount(amount) // 构造移动支付请求 p := alipay.TradeAppPay{ Trade: alipay.Trade{ Subject: subject, OutTradeNo: outTradeNo, TotalAmount: totalAmount, ProductCode: "QUICK_MSECURITY_PAY", // 移动端支付专用代码 NotifyURL: a.config.NotifyUrl, // 异步回调通知地址 }, } // 获取APP支付字符串,这里会签名 payStr, err := client.TradeAppPay(p) if err != nil { return "", fmt.Errorf("创建支付宝订单失败: %v", err) } return payStr, nil } // CreateAlipayH5Order 创建支付宝H5支付订单 func (a *AliPayService) CreateAlipayH5Order(amount float64, subject string, outTradeNo string, brand string) (string, error) { var returnURL string if brand == "tyc" { returnURL = "https://www.tianyuancha.com/report" } else if brand == "qnc" { returnURL = "https://www.quannengcha.com/report" } else { returnURL = a.config.ReturnURL } client := a.AlipayClient totalAmount := lzUtils.ToAlipayAmount(amount) // 构造H5支付请求 p := alipay.TradeWapPay{ Trade: alipay.Trade{ Subject: subject, OutTradeNo: outTradeNo, TotalAmount: totalAmount, ProductCode: "QUICK_WAP_PAY", // H5支付专用产品码 NotifyURL: a.config.NotifyUrl, // 异步回调通知地址 ReturnURL: returnURL, }, } // 获取H5支付请求字符串,这里会签名 payUrl, err := client.TradeWapPay(p) if err != nil { return "", fmt.Errorf("创建支付宝H5订单失败: %v", err) } return payUrl.String(), nil } // CreateAlipayOrder 根据平台类型创建支付宝支付订单 func (a *AliPayService) CreateAlipayOrder(ctx context.Context, amount float64, subject string, outTradeNo string, brand string) (string, error) { // 根据 ctx 中的 platform 判断平台 platform, platformOk := ctx.Value("platform").(string) if !platformOk { return "", fmt.Errorf("无的支付平台: %s", platform) } switch platform { case "app": // 调用App支付的创建方法 return a.CreateAlipayAppOrder(amount, subject, outTradeNo) case "h5": // 调用H5支付的创建方法,并传入 returnUrl return a.CreateAlipayH5Order(amount, subject, outTradeNo, brand) default: return "", fmt.Errorf("不支持的支付平台: %s", platform) } } // AliRefund 发起支付宝退款 func (a *AliPayService) AliRefund(ctx context.Context, outTradeNo string, refundAmount float64) (*alipay.TradeRefundRsp, error) { refund := alipay.TradeRefund{ OutTradeNo: outTradeNo, RefundAmount: lzUtils.ToAlipayAmount(refundAmount), OutRequestNo: fmt.Sprintf("%s-refund", outTradeNo), } // 发起退款请求 refundResp, err := a.AlipayClient.TradeRefund(ctx, refund) if err != nil { return nil, fmt.Errorf("支付宝退款请求错误:%v", err) } return refundResp, nil } // HandleAliPaymentNotification 支付宝支付回调 func (a *AliPayService) HandleAliPaymentNotification(r *http.Request) (*alipay.Notification, error) { // 解析表单 err := r.ParseForm() if err != nil { return nil, fmt.Errorf("解析请求表单失败:%v", err) } // 解析并验证通知,DecodeNotification 会自动验证签名 notification, err := a.AlipayClient.DecodeNotification(r.Form) if err != nil { return nil, fmt.Errorf("验证签名失败: %v", err) } return notification, nil } func (a *AliPayService) QueryOrderStatus(ctx context.Context, outTradeNo string) (*alipay.TradeQueryRsp, error) { queryRequest := alipay.TradeQuery{ OutTradeNo: outTradeNo, } // 发起查询请求 resp, err := a.AlipayClient.TradeQuery(ctx, queryRequest) if err != nil { return nil, fmt.Errorf("查询支付宝订单失败: %v", err) } // 返回交易状态 if resp.IsSuccess() { return resp, nil } return nil, fmt.Errorf("查询支付宝订单失败: %v", resp.SubMsg) } // GenerateOutTradeNo 生成唯一订单号的函数 func (a *AliPayService) GenerateOutTradeNo() string { length := 16 // 获取当前时间戳 timestamp := time.Now().UnixNano() // 转换为字符串 timeStr := strconv.FormatInt(timestamp, 10) // 生成随机数 mathrand.Seed(time.Now().UnixNano()) randomPart := strconv.Itoa(mathrand.Intn(1000000)) // 组合时间戳和随机数 combined := timeStr + randomPart // 如果长度超出指定值,则截断;如果不够,则填充随机字符 if len(combined) >= length { return combined[:length] } // 如果长度不够,填充0 for len(combined) < length { combined += strconv.Itoa(mathrand.Intn(10)) // 填充随机数 } return combined } // AliTransfer 支付宝单笔转账到支付宝账户(提现功能) func (a *AliPayService) AliTransfer( ctx context.Context, payeeAccount string, // 收款方支付宝账户 payeeName string, // 收款方姓名 amount float64, // 转账金额 remark string, // 转账备注 outBizNo string, // 商户转账唯一订单号(可使用GenerateOutTradeNo生成) ) (*alipay.FundTransUniTransferRsp, error) { // 参数校验 if payeeAccount == "" { return nil, fmt.Errorf("收款账户不能为空") } if amount <= 0 { return nil, fmt.Errorf("转账金额必须大于0") } // 构造转账请求 req := alipay.FundTransUniTransfer{ OutBizNo: outBizNo, TransAmount: lzUtils.ToAlipayAmount(amount), // 金额格式转换 ProductCode: "TRANS_ACCOUNT_NO_PWD", // 单笔无密转账到支付宝账户 BizScene: "DIRECT_TRANSFER", // 单笔转账 OrderTitle: "账户提现", // 转账标题 Remark: remark, PayeeInfo: &alipay.PayeeInfo{ Identity: payeeAccount, IdentityType: "ALIPAY_LOGON_ID", // 根据账户类型选择: Name: payeeName, // ALIPAY_USER_ID/ALIPAY_LOGON_ID }, } // 执行转账请求 transferRsp, err := a.AlipayClient.FundTransUniTransfer(ctx, req) if err != nil { return nil, fmt.Errorf("支付宝转账请求失败: %v", err) } return transferRsp, nil } func (a *AliPayService) QueryTransferStatus( ctx context.Context, outBizNo string, ) (*alipay.FundTransOrderQueryRsp, error) { req := alipay.FundTransOrderQuery{ OutBizNo: outBizNo, } response, err := a.AlipayClient.FundTransOrderQuery(ctx, req) if err != nil { return nil, fmt.Errorf("支付宝接口调用失败: %v", err) } // 处理响应 if response.Code.IsFailure() { return nil, fmt.Errorf("支付宝返回错误: %s-%s", response.Code, response.Msg) } return response, nil }