service/library/payclients/alipaycli/client.go

264 lines
7.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package alipaycli
import (
"context"
"errors"
"fmt"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/alipay"
"math/rand"
"net/http"
"service/bizcommon/util"
"service/library/configcenter"
"service/library/logger"
"time"
)
const (
DefaultOrderTimeoutSeconds = 900 // 默认订单超时时间,单位: s
)
const (
AppIdXinYiDaoLe = "2021004115647165" // 心意到了
AppIdMiYuanTianShi = "2021004135664261" // 觅缘天使
AppIdLanXing01 = "2021004153681591" // 揽星01
AppIdLanXing02 = "2021004153620449" // 揽星02
)
var allAlipayClients = map[string]*AlipayClient{}
func GetDefaultAlipayClient() *AlipayClient {
rate := rand.Intn(100)
if rate < 75 {
return allAlipayClients[AppIdMiYuanTianShi]
}
return allAlipayClients[AppIdLanXing01]
}
func GetAlipayClientByAppId(appId string) *AlipayClient {
return allAlipayClients[appId]
}
type AlipayClient struct {
*alipay.Client
alipayPublicCertPath string
}
func InitMulti(cfgList ...*configcenter.AlipayClientConfig) (err error) {
for _, cfg := range cfgList {
var cli *AlipayClient
cli, err = NewAlipayClient(cfg)
if err != nil {
return
}
if cli == nil {
err = errors.New("NewAlipayClient fail")
return
}
allAlipayClients[cli.AppId] = cli
}
return
}
func NewAlipayClient(cfg *configcenter.AlipayClientConfig) (ret *AlipayClient, err error) {
alipayCli, err := alipay.NewClient(cfg.Appid, cfg.PrivateKey, true)
if err != nil {
logger.Error("NewClient fail, cfg: %v, err: %v", util.ToJson(cfg), err)
return
}
alipayCli.SetNotifyUrl(cfg.NotifyUrl)
err = alipayCli.SetCertSnByPath(
cfg.AppCertPath,
cfg.AlipayRootCertPath,
cfg.AlipayPublicCertPath,
)
if err != nil {
logger.Error("SetCertSnByPath fail, cfg: %v, err: %v", util.ToJson(cfg), err)
return
}
ret = &AlipayClient{
Client: alipayCli,
alipayPublicCertPath: cfg.AlipayPublicCertPath,
}
return
}
//// 解析回调参数
//func (c *AlipayClient) ParseNotify(req *http.Request) (notify gopay.BodyMap, err error) {
// // 解析参数
// notifyTmp, err := alipay.ParseNotifyToBodyMap(req)
// if err != nil {
// logger.Error("ParseNotifyToBodyMap fail, req: %v, err: %v", util.ToJson(req), err)
// return
// }
// logger.Info("Alipay ParseNotify, %v", util.ToJson(notifyTmp))
//
// // 验签
// ok, err := alipay.VerifySignWithCert(c.alipayPublicCertPath, notifyTmp)
// if !ok {
// logger.Error("VerifySign fail, not ok, bm: %v", util.ToJson(notifyTmp))
// return
// }
// notify = notifyTmp
// return
//}
// 解析回调参数
func ParseNotify(req *http.Request) (notify gopay.BodyMap, err error) {
// 解析参数
notifyTmp, err := alipay.ParseNotifyToBodyMap(req)
if err != nil {
logger.Error("ParseNotifyToBodyMap fail, req: %v, err: %v", util.ToJson(req), err)
return
}
logger.Info("Alipay ParseNotify, %v", util.ToJson(notifyTmp))
// 获取appId
appId := notifyTmp.Get("app_id")
c := GetAlipayClientByAppId(appId)
if c == nil {
err = fmt.Errorf("GetAlipayClientByAppId fail, appId: %v", appId)
logger.Error("GetAlipayClientByAppId fail, appId: %v", appId)
return
}
// 验签
ok, err := alipay.VerifySignWithCert(c.alipayPublicCertPath, notifyTmp)
if !ok {
logger.Error("VerifySign fail, not ok, bm: %v", util.ToJson(notifyTmp))
return
}
notify = notifyTmp
return
}
// 支付宝 app支付
type AppPayParam struct {
OutTradeNo string // 商家订单id我们自己的订单id
Subject string // 主题
TotalAmount int64 // 金额,单位:分
TimeOutSeconds int // 订单有效时间,单位:秒
}
func (c *AlipayClient) AppPay(ctx context.Context, param *AppPayParam) (alipayAppParamStr string, err error) {
if param.TimeOutSeconds <= 0 {
param.TimeOutSeconds = DefaultOrderTimeoutSeconds
}
bm := gopay.BodyMap{
"out_trade_no": param.OutTradeNo,
"subject": param.Subject,
"total_amount": fmt.Sprintf("%.2f", float64(param.TotalAmount)/100.0),
"time_expire": time.Now().Add(time.Second * time.Duration(param.TimeOutSeconds)).Format("2006-01-02 15:04:05"),
"notify_url": c.NotifyUrl,
}
alipayAppParamStr, err = c.TradeAppPay(ctx, bm)
if err != nil {
return
}
logger.Info("alipay TradeAppPay param: %v", alipayAppParamStr)
return
}
// 支付宝 手机web支付
type WapPayParam struct {
OutTradeNo string // 商家订单id我们自己的订单id
Subject string // 主题
TotalAmount int64 // 金额,单位:分
TimeOutSeconds int // 订单有效时间,单位:秒
ReturnUrl string // 支付宝return_url
}
func (c *AlipayClient) WapPay(ctx context.Context, param *WapPayParam) (alipayWapParamStr string, err error) {
if param.TimeOutSeconds <= 0 {
param.TimeOutSeconds = DefaultOrderTimeoutSeconds
}
bm := gopay.BodyMap{
"out_trade_no": param.OutTradeNo,
"subject": param.Subject,
"total_amount": fmt.Sprintf("%.2f", float64(param.TotalAmount)/100.0),
"time_expire": time.Now().Add(time.Second * time.Duration(param.TimeOutSeconds)).Format("2006-01-02 15:04:05"),
"notify_url": c.NotifyUrl,
}
if len(param.ReturnUrl) > 0 {
bm["return_url"] = param.ReturnUrl
}
alipayWapParamStr, err = c.TradeWapPay(ctx, bm)
if err != nil {
return
}
logger.Info("alipay TradeWapPay param: %v", alipayWapParamStr)
return
}
// 支付宝单笔转账
type UniTransferParam struct {
OutBizNo string // 商家订单id我们自己的订单id
Amount int64 // 金额,单位:分
Title string // 转账业务的标题,用于在支付宝用户的账单里显示。
AlipayLoginId string // 支付宝登录账号
AlipayName string // 支付宝真实姓名
}
func (c *AlipayClient) UniTransfer(ctx context.Context, param *UniTransferParam) (resp *alipay.FundTransUniTransferResponse, err error) {
bm := gopay.BodyMap{
"out_biz_no": param.OutBizNo,
"trans_amount": fmt.Sprintf("%.2f", float64(param.Amount)/100.0),
"biz_scene": "DIRECT_TRANSFER",
"product_code": "TRANS_ACCOUNT_NO_PWD",
"order_title": param.Title,
"payee_info": map[string]interface{}{
"identity": param.AlipayLoginId,
"identity_type": "ALIPAY_LOGON_ID",
"name": param.AlipayName,
},
}
resp, err = c.FundTransUniTransfer(ctx, bm)
if err != nil {
return
}
logger.Info("alipay UniTransfer param: %v, resp: %v", bm.JsonBody(), util.ToJson(resp))
return
}
// 订单查询
type QueryOrderParam struct {
OutTradeNo string // 商家订单id我们自己的订单id
}
func (c *AlipayClient) QueryOrder(ctx context.Context, param *QueryOrderParam) (resp *alipay.TradeQueryResponse, err error) {
bm := gopay.BodyMap{
"out_trade_no": param.OutTradeNo,
}
resp, err = c.TradeQuery(ctx, bm)
if err != nil {
return
}
return
}
// 退款申请
type RefundOneParam struct {
OutTradeNo string // 商家订单id我们自己的订单id
RefundAmount int64 // 退款金额,单位:分
RefundReason string // 退款理由
}
func (c *AlipayClient) RefundOne(ctx context.Context, param *RefundOneParam) (resp *alipay.TradeRefundResponse, err error) {
if len(param.RefundReason) <= 0 {
param.RefundReason = "退款"
}
bm := gopay.BodyMap{
"out_trade_no": param.OutTradeNo,
"refund_amount": fmt.Sprintf("%.2f", float64(param.RefundAmount)/100.0),
"refund_reason": param.RefundReason,
}
resp, err = c.TradeRefund(ctx, bm)
logger.Info("RefundOne bm: %v, resp: %v", util.ToJson(bm), util.ToJson(resp))
if err != nil {
return
}
return
}