@@ -0,0 +1,6 @@ | |||||
package md | |||||
const ( | |||||
ZHIOS_PAY_URL_PRD = "http://pay.zhios.cn" | |||||
ZHIOS_PAY_URL_DEV = "http://pay.izhyin.com" | |||||
) |
@@ -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"` //附加信息 | |||||
} |
@@ -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 | |||||
} |
@@ -32,6 +32,5 @@ func JudgePayChannelPayType(channelId string) (model.PayChannel, error) { | |||||
if !res { | if !res { | ||||
return payChannel, errors.New("查询数据失败") | return payChannel, errors.New("查询数据失败") | ||||
} | } | ||||
return payChannel, nil | return payChannel, nil | ||||
} | } |
@@ -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) | |||||
} |
@@ -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() | |||||
} |
@@ -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)) | |||||
} |