Переглянути джерело

add 第三方支付

tags/v1.1.5
DengBiao 2 роки тому
джерело
коміт
42e019d19f
7 змінених файлів з 440 додано та 1 видалено
  1. +6
    -0
      md/basic.go
  2. +58
    -0
      md/kudian.go
  3. +122
    -0
      pay/pay_by_kudian.go
  4. +0
    -1
      pay/pay_config.go
  5. +209
    -0
      utils/curl.go
  6. +22
    -0
      utils/file.go
  7. +23
    -0
      utils/serialize.go

+ 6
- 0
md/basic.go Переглянути файл

@@ -0,0 +1,6 @@
package md

const (
ZHIOS_PAY_URL_PRD = "http://pay.zhios.cn"
ZHIOS_PAY_URL_DEV = "http://pay.izhyin.com"
)

+ 58
- 0
md/kudian.go Переглянути файл

@@ -0,0 +1,58 @@
package md

type KuDianWxPayParams struct {
AppId string `json:"app_id"`
OpenId string `json:"open_id"`
OutTradeNo string `json:"out_trade_no"`
Description string `json:"description"`
NotifyUrl string `json:"notify_url"`
TotalAmount string `json:"total_amount" binding:"required"`
Attach string `json:"attach" binding:"required"`
MustParams struct {
ShopId string `json:"shop_id"`
KuDianMchId string `json:"ku_dian_mch_id"`
KuDianSecretKey string `json:"ku_dian_secret_key"`
} `json:"must_params"`
}

type KuDianAliAppPayParams struct {
OutTradeNo string `json:"out_trade_no"`
Description string `json:"description"`
NotifyUrl string `json:"notify_url"`
UserId string `json:"user_id"`
TotalAmount string `json:"total_amount" binding:"required"`
Attach string `json:"attach" binding:"required"`
TradeType string `json:"trade_type"`
SenceInfo struct {
WapUrl string `json:"wap_url"`
WapName string `json:"wap_name"`
ReturnUrl string `json:"return_url"`
} `json:"sence_info"`
MustParams struct {
ShopId string `json:"shop_id"`
KuDianMchId string `json:"ku_dian_mch_id"`
KuDianSecretKey string `json:"ku_dian_secret_key"`
} `json:"must_params"`
}

// ########################################### 酷点支付 - 回调结构体 ###############################################

type KuDianPayCallback struct {
Code int `json:"code"`
Msg string `json:"msg"`
Result string `json:"result"`
}

type KuDianPayCallbackResp struct {
MchId string `json:"mch_id"` //商户id
PayNo string `json:"pay_no"` //聚合支付订单号
OutTradeNo string `json:"out_trade_no"` //业务系统订单号
TransactionId string `json:"transaction_id"` //支付平台交易流水号。微信、支付宝、云闪付等用户支付使用的平台返回流水号
Fee int `json:"fee"` //交易总额,单位:分
ReceivedFee int `json:"received_fee"` //商户实收金额,单位:分
PayTime string `json:"pay_time"` //支付时间,格式"yyyy-MM-dd HH:mm:ss"
Payment string `json:"payment"` //支付方式
Body string `json:"body"` //支付简要描述
Status int `json:"status"` //支付状态
Attach string `json:"attach"` //附加信息
}

+ 122
- 0
pay/pay_by_kudian.go Переглянути файл

@@ -0,0 +1,122 @@
package pay

import (
"code.fnuoos.com/go_rely_warehouse/zyos_go_pay.git/md"
zhios_pay_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_pay.git/utils"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
)

//酷点 - 支付宝APP支付
func AliAppPayByKuDian(payParams *md.KuDianAliAppPayParams, isPrd bool) (string, error) {
var url string
if isPrd == true {
url = md.ZHIOS_PAY_URL_PRD + "/kuDianPay/Pay/aliAppPay"
} else {
url = md.ZHIOS_PAY_URL_DEV + "/kuDianPay/Pay/aliAppPay"
}
zhios_pay_utils.FilePutContents("AliAppPayByKuDian", zhios_pay_utils.SerializeStr(map[string]interface{}{
"data": payParams,
}))
bytes, err := zhios_pay_utils.CurlPost(url, zhios_pay_utils.Serialize(payParams), nil)
if err != nil {
return "", err
}
var result struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data map[string]string `json:"data"`
}
zhios_pay_utils.FilePutContents("AliAppPayByKuDian", zhios_pay_utils.SerializeStr(result))
err = json.Unmarshal(bytes, &result)
if err != nil {
return "", err
}
if result.Code != 0 {
return "", errors.New(result.Msg)
}
zhios_pay_utils.FilePutContents("AliAppPayByKuDian", zhios_pay_utils.SerializeStr(result.Data["data"]))
return result.Data["url"], nil
}

// 酷点 - 支付宝JsAPi支付
func AliJsApiPayByKuDian(payParams *md.KuDianAliAppPayParams, isPrd bool) (string, error) {
var url string
if isPrd == true {
url = md.ZHIOS_PAY_URL_PRD + "/kuDianPay/Pay/aliJsApiPay"
} else {
url = md.ZHIOS_PAY_URL_DEV + "/kuDianPay/Pay/aliJsApiPay"
}
zhios_pay_utils.FilePutContents("AliAppPayByKuDian", zhios_pay_utils.SerializeStr(map[string]interface{}{
"data": payParams,
}))
bytes, err := zhios_pay_utils.CurlPost(url, zhios_pay_utils.Serialize(payParams), nil)
if err != nil {
return "", err
}
var result struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data map[string]string `json:"data"`
}
zhios_pay_utils.FilePutContents("AliAppPayByKuDian", zhios_pay_utils.SerializeStr(result))
err = json.Unmarshal(bytes, &result)
if err != nil {
return "", err
}
if result.Code != 0 {
return "", errors.New(result.Msg)
}
zhios_pay_utils.FilePutContents("AliAppPayByKuDian", zhios_pay_utils.SerializeStr(result.Data["data"]))
return result.Data["trade_no"], nil
}

// 酷点 - 微信小程序支付
func WxAppletPayByKuDian(payParams *md.KuDianWxPayParams, isPrd bool) (interface{}, error) {
var url string
if isPrd == true {
url = md.ZHIOS_PAY_URL_PRD + "/kuDianPay/Pay/wxJsAPi"
} else {
url = md.ZHIOS_PAY_URL_DEV + "/kuDianPay/Pay/wxJsAPi"
}
zhios_pay_utils.FilePutContents("WxAppletPayByKuDian", zhios_pay_utils.SerializeStr(map[string]interface{}{
"data": payParams,
}))
bytes, err := zhios_pay_utils.CurlPost(url, zhios_pay_utils.Serialize(payParams), nil)
if err != nil {
return nil, err
}
var result struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data map[string]interface{} `json:"data"`
}
zhios_pay_utils.FilePutContents("WxAppletPayByKuDian", zhios_pay_utils.SerializeStr(result))
err = json.Unmarshal(bytes, &result)
if err != nil {
return nil, err
}
if result.Code != 0 {
return nil, errors.New(result.Msg)
}
zhios_pay_utils.FilePutContents("WxAppletPayByKuDian", zhios_pay_utils.SerializeStr(result.Data["data"]))
return result.Data["data"], nil
}

// 酷点 - 检查返回参数
func CheckAllCallbackParamsByKuDian(c *gin.Context) (interface{}, error) {
var dataWx md.KuDianPayCallback
if err := c.ShouldBindJSON(&dataWx); err != nil {
fmt.Println(">>>>>>>>>CheckAllCallbackParamsByKuDian>>>>>>>>>>>>>>", err)
return nil, err
}
var dataPay md.KuDianPayCallbackResp
if err := json.Unmarshal([]byte(dataWx.Result), &dataPay); err != nil {
fmt.Println(">>>>>>>>>CheckAllCallbackParamsByKuDian>>>>>>>>>>>>>>", err)
return nil, err
}
zhios_pay_utils.FilePutContents("CheckAllCallbackParamsByKuDian", zhios_pay_utils.SerializeStr(dataPay))
return dataPay, nil
}

+ 0
- 1
pay/pay_config.go Переглянути файл

@@ -32,6 +32,5 @@ func JudgePayChannelPayType(channelId string) (model.PayChannel, error) {
if !res {
return payChannel, errors.New("查询数据失败")
}

return payChannel, nil
}

+ 209
- 0
utils/curl.go Переглянути файл

@@ -0,0 +1,209 @@
package zhios_pay_utils

import (
"bytes"
"crypto/tls"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"sort"
"strings"
"time"
)

var CurlDebug bool

func CurlGet(router string, header map[string]string) ([]byte, error) {
return curl(http.MethodGet, router, nil, header)
}
func CurlGetJson(router string, body interface{}, header map[string]string) ([]byte, error) {
return curl_new(http.MethodGet, router, body, header)
}

// 只支持form 与json 提交, 请留意body的类型, 支持string, []byte, map[string]string
func CurlPost(router string, body interface{}, header map[string]string) ([]byte, error) {
return curl(http.MethodPost, router, body, header)
}

func CurlPut(router string, body interface{}, header map[string]string) ([]byte, error) {
return curl(http.MethodPut, router, body, header)
}

// 只支持form 与json 提交, 请留意body的类型, 支持string, []byte, map[string]string
func CurlPatch(router string, body interface{}, header map[string]string) ([]byte, error) {
return curl(http.MethodPatch, router, body, header)
}

// CurlDelete is curl delete
func CurlDelete(router string, body interface{}, header map[string]string) ([]byte, error) {
return curl(http.MethodDelete, router, body, header)
}

func curl(method, router string, body interface{}, header map[string]string) ([]byte, error) {
var reqBody io.Reader
contentType := "application/json"
switch v := body.(type) {
case string:
reqBody = strings.NewReader(v)
case []byte:
reqBody = bytes.NewReader(v)
case map[string]string:
val := url.Values{}
for k, v := range v {
val.Set(k, v)
}
reqBody = strings.NewReader(val.Encode())
contentType = "application/x-www-form-urlencoded"
case map[string]interface{}:
val := url.Values{}
for k, v := range v {
val.Set(k, v.(string))
}
reqBody = strings.NewReader(val.Encode())
contentType = "application/x-www-form-urlencoded"
}
if header == nil {
header = map[string]string{"Content-Type": contentType}
}
if _, ok := header["Content-Type"]; !ok {
header["Content-Type"] = contentType
}
resp, er := CurlReq(method, router, reqBody, header)
if er != nil {
return nil, er
}
res, err := ioutil.ReadAll(resp.Body)
if CurlDebug {
blob := SerializeStr(body)
if contentType != "application/json" {
blob = HttpBuild(body)
}
fmt.Printf("\n\n=====================\n[url]: %s\n[time]: %s\n[method]: %s\n[content-type]: %v\n[req_header]: %s\n[req_body]: %#v\n[resp_err]: %v\n[resp_header]: %v\n[resp_body]: %v\n=====================\n\n",
router,
time.Now().Format("2006-01-02 15:04:05.000"),
method,
contentType,
HttpBuildQuery(header),
blob,
err,
SerializeStr(resp.Header),
string(res),
)
}
resp.Body.Close()
return res, err
}

func curl_new(method, router string, body interface{}, header map[string]string) ([]byte, error) {
var reqBody io.Reader
contentType := "application/json"

if header == nil {
header = map[string]string{"Content-Type": contentType}
}
if _, ok := header["Content-Type"]; !ok {
header["Content-Type"] = contentType
}
resp, er := CurlReq(method, router, reqBody, header)
if er != nil {
return nil, er
}
res, err := ioutil.ReadAll(resp.Body)
if CurlDebug {
blob := SerializeStr(body)
if contentType != "application/json" {
blob = HttpBuild(body)
}
fmt.Printf("\n\n=====================\n[url]: %s\n[time]: %s\n[method]: %s\n[content-type]: %v\n[req_header]: %s\n[req_body]: %#v\n[resp_err]: %v\n[resp_header]: %v\n[resp_body]: %v\n=====================\n\n",
router,
time.Now().Format("2006-01-02 15:04:05.000"),
method,
contentType,
HttpBuildQuery(header),
blob,
err,
SerializeStr(resp.Header),
string(res),
)
}
resp.Body.Close()
return res, err
}

func CurlReq(method, router string, reqBody io.Reader, header map[string]string) (*http.Response, error) {
req, _ := http.NewRequest(method, router, reqBody)
if header != nil {
for k, v := range header {
req.Header.Set(k, v)
}
}
// 绕过github等可能因为特征码返回503问题
// https://www.imwzk.com/posts/2021-03-14-why-i-always-get-503-with-golang/
defaultCipherSuites := []uint16{0xc02f, 0xc030, 0xc02b, 0xc02c, 0xcca8, 0xcca9, 0xc013, 0xc009,
0xc014, 0xc00a, 0x009c, 0x009d, 0x002f, 0x0035, 0xc012, 0x000a}
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
CipherSuites: append(defaultCipherSuites[8:], defaultCipherSuites[:8]...),
},
},
// 获取301重定向
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
return client.Do(req)
}

// 组建get请求参数,sortAsc true为小到大,false为大到小,nil不排序 a=123&b=321
func HttpBuildQuery(args map[string]string, sortAsc ...bool) string {
str := ""
if len(args) == 0 {
return str
}
if len(sortAsc) > 0 {
keys := make([]string, 0, len(args))
for k := range args {
keys = append(keys, k)
}
if sortAsc[0] {
sort.Strings(keys)
} else {
sort.Sort(sort.Reverse(sort.StringSlice(keys)))
}
for _, k := range keys {
str += "&" + k + "=" + args[k]
}
} else {
for k, v := range args {
str += "&" + k + "=" + v
}
}
return str[1:]
}

func HttpBuild(body interface{}, sortAsc ...bool) string {
params := map[string]string{}
if args, ok := body.(map[string]interface{}); ok {
for k, v := range args {
params[k] = AnyToString(v)
}
return HttpBuildQuery(params, sortAsc...)
}
if args, ok := body.(map[string]string); ok {
for k, v := range args {
params[k] = AnyToString(v)
}
return HttpBuildQuery(params, sortAsc...)
}
if args, ok := body.(map[string]int); ok {
for k, v := range args {
params[k] = AnyToString(v)
}
return HttpBuildQuery(params, sortAsc...)
}
return AnyToString(body)
}

+ 22
- 0
utils/file.go Переглянути файл

@@ -0,0 +1,22 @@
package zhios_pay_utils

import (
"os"
"path"
"strings"
"time"
)

// 获取文件后缀
func FileExt(fname string) string {
return strings.ToLower(strings.TrimLeft(path.Ext(fname), "."))
}

func FilePutContents(fileName string, content string) {
fd, _ := os.OpenFile("./tmp/"+fileName+".log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
fd_time := time.Now().Format("2006-01-02 15:04:05")
fd_content := strings.Join([]string{"[", fd_time, "] ", content, "\n"}, "")
buf := []byte(fd_content)
fd.Write(buf)
fd.Close()
}

+ 23
- 0
utils/serialize.go Переглянути файл

@@ -0,0 +1,23 @@
package zhios_pay_utils

import (
"encoding/json"
)

func Serialize(data interface{}) []byte {
res, err := json.Marshal(data)
if err != nil {
return []byte{}
}
return res
}

func Unserialize(b []byte, dst interface{}) {
if err := json.Unmarshal(b, dst); err != nil {
dst = nil
}
}

func SerializeStr(data interface{}, arg ...interface{}) string {
return string(Serialize(data))
}

Завантаження…
Відмінити
Зберегти