From 42e019d19f07963a17aceb2e23750c5d583182a1 Mon Sep 17 00:00:00 2001 From: DengBiao <2319963317@qq.com> Date: Mon, 30 May 2022 18:47:50 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E7=AC=AC=E4=B8=89=E6=96=B9=E6=94=AF?= =?UTF-8?q?=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- md/basic.go | 6 ++ md/kudian.go | 58 ++++++++++++ pay/pay_by_kudian.go | 122 +++++++++++++++++++++++++ pay/pay_config.go | 1 - utils/curl.go | 209 +++++++++++++++++++++++++++++++++++++++++++ utils/file.go | 22 +++++ utils/serialize.go | 23 +++++ 7 files changed, 440 insertions(+), 1 deletion(-) create mode 100644 md/basic.go create mode 100644 md/kudian.go create mode 100644 pay/pay_by_kudian.go create mode 100644 utils/curl.go create mode 100644 utils/file.go create mode 100644 utils/serialize.go diff --git a/md/basic.go b/md/basic.go new file mode 100644 index 0000000..8551066 --- /dev/null +++ b/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" +) diff --git a/md/kudian.go b/md/kudian.go new file mode 100644 index 0000000..614dc20 --- /dev/null +++ b/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"` //附加信息 +} diff --git a/pay/pay_by_kudian.go b/pay/pay_by_kudian.go new file mode 100644 index 0000000..1f578ff --- /dev/null +++ b/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 +} diff --git a/pay/pay_config.go b/pay/pay_config.go index b1e57ba..b3ebef0 100644 --- a/pay/pay_config.go +++ b/pay/pay_config.go @@ -32,6 +32,5 @@ func JudgePayChannelPayType(channelId string) (model.PayChannel, error) { if !res { return payChannel, errors.New("查询数据失败") } - return payChannel, nil } diff --git a/utils/curl.go b/utils/curl.go new file mode 100644 index 0000000..fb081a0 --- /dev/null +++ b/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) +} diff --git a/utils/file.go b/utils/file.go new file mode 100644 index 0000000..0d08244 --- /dev/null +++ b/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() +} diff --git a/utils/serialize.go b/utils/serialize.go new file mode 100644 index 0000000..edd84ed --- /dev/null +++ b/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)) +}