package yeepaycli import ( "context" "encoding/json" "fmt" "github.com/yop-platform/yop-go-sdk/yop/client" "github.com/yop-platform/yop-go-sdk/yop/constants" "github.com/yop-platform/yop-go-sdk/yop/request" yoputils "github.com/yop-platform/yop-go-sdk/yop/utils" "net/http" "service/bizcommon/util" "service/library/configcenter" "service/library/idgenerator" "service/library/logger" "time" ) const ( YeepayWayH5 = "H5_PAY" // h5支付 ) const ( YeepayChannelWxpay = "WECHAT" // 易宝支付微信 YeepayChannelAlipay = "ALIPAY" // 易宝支付支付宝 ) const ( DefaultOrderTimeoutSeconds = 900 // 默认订单超时时间,单位: s ) var defaultYeepayClient *YeepayClient type YeepayClient struct { client *client.YopClient AppId string ParentMerchantNo string // 父商编 系统商或平台商场景下为主商户商户编号,否则为收单商户编号 MerchantNo string // 子商编 收单商户商编 NotifyUrl string // 回调通知 PrivateKey string // 私钥 } func GetDefaultYeepayClient() *YeepayClient { return defaultYeepayClient } func Init(cfg *configcenter.YeepayClientConfig) { cli := &client.YopClient{ Client: &http.Client{ Transport: http.DefaultTransport, }, } defaultYeepayClient = &YeepayClient{ client: cli, AppId: cfg.Appid, ParentMerchantNo: cfg.ParentMerchantNo, MerchantNo: cfg.MerchantNo, NotifyUrl: cfg.NotifyUrl, PrivateKey: cfg.PrivateKey, } } // 验签 type YeepayNotify struct { ChannelOrderId string `json:"channelOrderId"` OrderId string `json:"orderId"` BankOrderId string `json:"bankOrderId"` PaySuccessDate string `json:"paySuccessDate"` Channel string `json:"channel"` PayWay string `json:"payWay"` UniqueOrderNo string `json:"uniqueOrderNo"` OrderAmount string `json:"orderAmount"` PayAmount string `json:"payAmount"` PayerInfo string `json:"payerInfo"` RealPayAmount string `json:"realPayAmount"` ParentMerchantNo string `json:"parentMerchantNo"` MerchantNo string `json:"merchantNo"` Status string `json:"status"` } func (c *YeepayClient) ParseNotify(req *http.Request) (*YeepayNotify, error) { if err := req.ParseForm(); err != nil { logger.Error("Yeepay ParseForm fail, err: %v", err) return nil, err } var ( response = req.Form.Get("response") appKey = req.Form.Get("customerIdentification") ) logger.Info("YeepayCallback notify, response: %v, appKey: %v", response, appKey) content, err := yoputils.DecryptCallback(request.YOP_PLATFORM_PUBLIC_KEY, c.PrivateKey, response) if err != nil { logger.Error("Yeepay DecryptCallback fail, form: %v, err: %v", req.Form.Encode(), err) return nil, err } notify := new(YeepayNotify) err = json.Unmarshal([]byte(content), notify) if err != nil { logger.Error("Yeepay unmarshal fail, form: %v, content: %v, err: %v", req.Form.Encode(), util.ToJson(content), err) return nil, err } logger.Info("Yeepay ParseNotify, %v", util.ToJson(notify)) return notify, nil } // 易宝支付 聚合支付 type AggPayParam struct { Description string OutTradeNo string // 商家订单id,我们自己的订单id TotalAmount int64 // 金额,单位:分 RedirectUrl string // 页面通知地址 支付成功后页面回调地址 如不指定页面回调地址,支付完成后会停留在易宝的支付成功页 PayWay string PayChannel string Ip string } type AggPayResp struct { Code string `json:"code"` Message string `json:"message"` OrderId string `json:"orderId"` UniqueOrderNo string `json:"uniqueOrderNo"` BankOrderId string `json:"bankOrderId"` PrePayTn string `json:"prePayTn"` } func (c *YeepayClient) AggPay(ctx context.Context, param *AggPayParam) (resp *AggPayResp, err error) { req := request.NewYopRequest(constants.POST_HTTP_METHOD, "/rest/v1.0/aggpay/tutelage/pre-pay") req.AppId = c.AppId req.IsvPriKey = request.IsvPriKey{Value: c.PrivateKey, CertType: request.RSA2048} req.AddParam("parentMerchantNo", c.ParentMerchantNo) req.AddParam("merchantNo", c.MerchantNo) req.AddParam("orderId", param.OutTradeNo) req.AddParam("orderAmount", float64(param.TotalAmount)/100.0) req.AddParam("expiredTime", time.Unix(time.Now().Unix()+DefaultOrderTimeoutSeconds, 0).Format("2006-01-02 15:04:05")) req.AddParam("goodsName", param.Description) req.AddParam("notifyUrl", c.NotifyUrl) req.AddParam("payWay", param.PayWay) req.AddParam("channel", param.PayChannel) req.AddParam("scene", "OFFLINE") req.AddParam("userIp", param.Ip) if len(param.RedirectUrl) > 0 { req.AddParam("redirectUrl", param.RedirectUrl) } respMeta, err := c.client.Request(req) if err != nil { logger.Error("yeepay AggPay fail, param: %v, respMeta: %v, err: %v", util.ToJson(req.Params), util.ToJson(respMeta), err) return } resp = new(AggPayResp) b, _ := json.Marshal(respMeta.Result) _ = json.Unmarshal(b, resp) logger.Info("yeepay AggPay param: %v, resp: %v", util.ToJson(req.Params), util.ToJson(resp)) return } // 退款 type RefundOneParam struct { OutTradeNo string // 商家订单id,我们自己的订单id RefundAmount int64 // 退款金额,单位:分 RefundReason string // 退款理由 } type RefundOneResp struct { Code string `json:"code"` Message string `json:"message"` ParentMerchantNo string `json:"parentMerchantNo"` MerchantNo string `json:"merchantNo"` OrderId string `json:"orderId"` RefundRequestId string `json:"refundRequestId"` UniqueRefundNo string `json:"uniqueRefundNo"` Status string `json:"status"` RefundAmount string `json:"refundAmount"` RefundRequestDate string `json:"refundRequestDate"` RefundMerchantFee string `json:"refundMerchantFee"` RefundAccountDetail string `json:"refundAccountDetail"` RefundCsFinishDate string `json:"refundCsFinishDate"` } func (c *YeepayClient) RefundOne(ctx context.Context, param *RefundOneParam) (resp *RefundOneResp, refundRequestId string, err error) { refundRequestId = idgenerator.GenYeepayRefundId() req := request.NewYopRequest(constants.POST_HTTP_METHOD, "/rest/v1.0/trade/refund") req.AppId = c.AppId req.IsvPriKey = request.IsvPriKey{Value: c.PrivateKey, CertType: request.RSA2048} req.AddParam("parentMerchantNo", c.ParentMerchantNo) req.AddParam("merchantNo", c.MerchantNo) req.AddParam("orderId", param.OutTradeNo) req.AddParam("refundRequestId", refundRequestId) req.AddParam("refundAmount", fmt.Sprintf("%.2f", float64(param.RefundAmount)/100.0)) respMeta, err := c.client.Request(req) if err != nil { logger.Error("yeepay RefundOne fail, param: %v, respMeta: %v, err: %v", util.ToJson(req.Params), util.ToJson(respMeta), err) return } resp = new(RefundOneResp) b, _ := json.Marshal(respMeta.Result) _ = json.Unmarshal(b, resp) logger.Info("yeepay RefundOne param: %v, resp: %v", util.ToJson(req.Params), util.ToJson(resp)) return } // 查询退款 type QueryRefundParam struct { OutTradeNo string // 商家订单id,我们自己的订单id RefundRequestId string } type QueryRefundResp struct { Code string `json:"code"` Message string `json:"message"` ParentMerchantNo string `json:"parentMerchantNo"` MerchantNo string `json:"merchantNo"` OrderId string `json:"orderId"` RefundRequestId string `json:"refundRequestId"` UniqueRefundNo string `json:"uniqueRefundNo"` Status string `json:"status"` RefundAmount string `json:"refundAmount"` RefundRequestDate string `json:"refundRequestDate"` RefundMerchantFee string `json:"refundMerchantFee"` RefundAccountDetail string `json:"refundAccountDetail"` RefundCsFinishDate string `json:"refundCsFinishDate"` } func (c *YeepayClient) QueryRefund(ctx context.Context, param *QueryRefundParam) (resp *QueryRefundResp, err error) { req := request.NewYopRequest(constants.GET_HTTP_METHOD, "/rest/v1.0/trade/refund/query") req.AppId = c.AppId req.ServerRoot = request.SERVER_ROOT req.IsvPriKey = request.IsvPriKey{Value: c.PrivateKey, CertType: request.RSA2048} req.AddParam("parentMerchantNo", c.ParentMerchantNo) req.AddParam("merchantNo", c.MerchantNo) req.AddParam("orderId", param.OutTradeNo) req.AddParam("refundRequestId", param.RefundRequestId) respMeta, err := c.client.Request(req) if err != nil { logger.Error("yeepay RefundOne fail, param: %v, respMeta: %v, err: %v", util.ToJson(req.Params), util.ToJson(respMeta), err) return } resp = new(QueryRefundResp) b, _ := json.Marshal(respMeta.Result) _ = json.Unmarshal(b, resp) logger.Info("yeepay QueryRefund param: %v, resp: %v", util.ToJson(req.Params), util.ToJson(resp)) return }