service/library/payclients/alipaycli/client.go

262 lines
7.2 KiB
Go
Raw Normal View History

2023-12-21 22:17:40 +08:00
package alipaycli
import (
"context"
2024-02-18 23:24:52 +08:00
"errors"
2023-12-21 22:17:40 +08:00
"fmt"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/alipay"
2024-07-11 10:03:25 +08:00
"math/rand"
2023-12-29 14:16:37 +08:00
"net/http"
2023-12-21 22:17:40 +08:00
"service/bizcommon/util"
"service/library/configcenter"
"service/library/logger"
"time"
)
const (
DefaultOrderTimeoutSeconds = 900 // 默认订单超时时间,单位: s
)
2024-02-18 23:24:52 +08:00
const (
AppIdXinYiDaoLe = "2021004115647165" // 心意到了
AppIdMiYuanTianShi = "2021004135664261" // 觅缘天使
2024-07-03 16:05:46 +08:00
AppIdLanXing01 = "2021004153681591" // 揽星01
2024-02-18 23:24:52 +08:00
)
2023-12-21 22:17:40 +08:00
2024-02-18 23:24:52 +08:00
var allAlipayClients = map[string]*AlipayClient{}
2024-02-18 23:47:58 +08:00
func GetDefaultAlipayClient() *AlipayClient {
2024-07-11 15:14:27 +08:00
rate := rand.Intn(1000)
if rate < 995 {
2024-07-11 10:03:25 +08:00
return allAlipayClients[AppIdMiYuanTianShi]
}
2024-07-03 16:05:46 +08:00
return allAlipayClients[AppIdLanXing01]
2023-12-21 22:17:40 +08:00
}
2024-02-18 23:47:58 +08:00
func GetAlipayClientByAppId(appId string) *AlipayClient {
return allAlipayClients[appId]
}
2023-12-21 22:17:40 +08:00
type AlipayClient struct {
*alipay.Client
2024-02-18 23:24:52 +08:00
alipayPublicCertPath string
}
2024-02-18 23:47:58 +08:00
func InitMulti(cfgList ...*configcenter.AlipayClientConfig) (err error) {
2024-02-18 23:24:52 +08:00
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
2023-12-21 22:17:40 +08:00
}
2024-02-18 23:24:52 +08:00
func NewAlipayClient(cfg *configcenter.AlipayClientConfig) (ret *AlipayClient, err error) {
2023-12-21 22:17:40 +08:00
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)
2024-01-08 14:25:27 +08:00
err = alipayCli.SetCertSnByPath(
2024-02-12 23:41:41 +08:00
cfg.AppCertPath,
cfg.AlipayRootCertPath,
cfg.AlipayPublicCertPath,
2024-01-08 14:25:27 +08:00
)
if err != nil {
logger.Error("SetCertSnByPath fail, cfg: %v, err: %v", util.ToJson(cfg), err)
return
}
2024-02-18 23:24:52 +08:00
ret = &AlipayClient{
Client: alipayCli,
alipayPublicCertPath: cfg.AlipayPublicCertPath,
2023-12-21 22:17:40 +08:00
}
return
}
2024-07-04 11:39:10 +08:00
//// 解析回调参数
//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
//}
2023-12-29 14:16:37 +08:00
// 解析回调参数
2024-07-04 11:39:10 +08:00
func ParseNotify(req *http.Request) (notify gopay.BodyMap, err error) {
2023-12-29 14:16:37 +08:00
// 解析参数
notifyTmp, err := alipay.ParseNotifyToBodyMap(req)
if err != nil {
logger.Error("ParseNotifyToBodyMap fail, req: %v, err: %v", util.ToJson(req), err)
return
}
2023-12-29 20:47:34 +08:00
logger.Info("Alipay ParseNotify, %v", util.ToJson(notifyTmp))
2024-01-08 21:24:45 +08:00
2024-07-04 11:39:10 +08:00
// 获取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
}
2023-12-29 14:16:37 +08:00
// 验签
2024-02-18 23:24:52 +08:00
ok, err := alipay.VerifySignWithCert(c.alipayPublicCertPath, notifyTmp)
2023-12-29 14:16:37 +08:00
if !ok {
logger.Error("VerifySign fail, not ok, bm: %v", util.ToJson(notifyTmp))
return
}
notify = notifyTmp
return
}
2023-12-21 22:17:40 +08:00
// 支付宝 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"),
2023-12-29 15:03:50 +08:00
"notify_url": c.NotifyUrl,
2023-12-21 22:17:40 +08:00
}
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 // 订单有效时间,单位:秒
2023-12-29 20:47:34 +08:00
ReturnUrl string // 支付宝return_url
2023-12-21 22:17:40 +08:00
}
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"),
2023-12-29 15:03:50 +08:00
"notify_url": c.NotifyUrl,
2023-12-21 22:17:40 +08:00
}
2023-12-29 20:47:34 +08:00
if len(param.ReturnUrl) > 0 {
bm["return_url"] = param.ReturnUrl
}
2023-12-21 22:17:40 +08:00
alipayWapParamStr, err = c.TradeWapPay(ctx, bm)
if err != nil {
return
}
logger.Info("alipay TradeWapPay param: %v", alipayWapParamStr)
return
}
2024-01-08 11:49:16 +08:00
// 支付宝单笔转账
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
}
2024-02-03 17:23:08 +08:00
// 订单查询
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
}
2024-02-18 23:47:58 +08:00
// 退款申请
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)
if err != nil {
return
}
return
}