@@ -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 { | |||
return payChannel, errors.New("查询数据失败") | |||
} | |||
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)) | |||
} |