package platformPay import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "fmt" "github.com/sirupsen/logrus" "leafstalk/log" "os" "sort" "strconv" "strings" "time" ) var ( //appId string //appSecret string // //offerId string //midasSecret string // wxAccessToken string wxAccessTokenExpires = time.Now().Unix() getBalanceUri = "/cgi-bin/midas/getbalance" payUri = "/cgi-bin/midas/pay" cancelPayUri = "/cgi-bin/midas/cancelpay" presentUri = "/cgi-bin/midas/present" ) func CreateOutTradeNo(id int64) string { n := time.Now().Unix() return fmt.Sprintf("%v%vS%vU%d", time.Now().Format("20060102150405"), 999, id, n%65536) } func hmacSha256(msg string, secret string) string { k := []byte(secret) h := hmac.New(sha256.New, k) h.Write([]byte(msg)) sha := hex.EncodeToString(h.Sum(nil)) return sha //base64.StdEncoding.EncodeToString([]byte(sha)) } func MakeGetBalanceSig(md map[string]interface{}, uri string) string { var str string var ms []string for k, v := range md { switch v := v.(type) { case string: str = k + "=" + v ms = append(ms, str) case int: str = k + "=" + strconv.FormatInt(int64(v), 10) ms = append(ms, str) case int64: str = k + "=" + strconv.FormatInt(v, 10) ms = append(ms, str) } } sort.Strings(ms) str = "org_loc=" + uri ms = append(ms, str) str = "method=POST" ms = append(ms, str) str = "secret=" + os.Getenv("WXPAY_MIDASSECRET") ms = append(ms, str) var nstr string = strings.Join(ms, "&") r := hmacSha256(nstr, os.Getenv("WXPAY_MIDASSECRET")) return r } //SIG //requestData := make(map[string]interface{}) // requestData["openid"] = "odkx20ENSNa2w5y3g_qOkOvBNM1g" // requestData["appid"] = "wx1234567" // requestData["offer_id"] = "12345678" // requestData["ts"] = int64(1507530737) // requestData["zone_id"] = "1" // requestData["pf"] = "android" // midasSecret = "zNLgAGgqsEWJOg1nFVaO5r7fAlIQxr1u" //result: "1ad64e8dcb2ec1dc486b7fdf01f4a15159fc623dc3422470e51cf6870734726b" func GetAccessToken(platform int) string { if platform == int(WxPlat) { return wxAccessToken } else { return dyAccessToken } } type ResponseGetBalance struct { ErrCode int `json:"errcode"` ErrMsg string `json:"errmsg"` Balance int `json:"balance"` //游戏币个数(包含赠送) GenBalance int `json:"gen_balance"` //赠送游戏币数量(赠送游戏币数量) FirstSave int `json:"first_save"` //是否满足历史首次充值 SaveAmt int `json:"save_amt"` //累计充值金额的游戏币数量 SaveSum int `json:"save_sum"` //历史总游戏币金额 CostSum int `json:"cost_sum"` //历史总消费游戏币金额 PresentSum int `json:"present_sum"` //历史累计收到赠送金额 } // 查询余额 func WxQueryBalance(openid string) (*ResponseGetBalance, error) { req := NewHttpRequest() requestData := make(map[string]interface{}) requestData["openid"] = openid //"oNEBv5CU3aOz7FcWp5ZDlhCNc3-U" requestData["appid"] = os.Getenv("WXPAY_APPID") //"wx831355257c862ac2" requestData["offer_id"] = os.Getenv("WXPAY_OFFERID") //"1450030892" requestData["ts"] = time.Now().Unix() requestData["zone_id"] = "1" requestData["pf"] = "android" requestData["sig"] = MakeGetBalanceSig(requestData, getBalanceUri) requestData["access_token "] = wxAccessToken url := "https://api.weixin.qq.com" + getBalanceUri + "?access_token=" + wxAccessToken logrus.Warnf("url:%+v, requestData%+v", url, requestData) resp, err := req.JSON(requestData).Post(url) if err != nil { //log.Warnln(err) return nil, err } defer func() { if resp.GetBody() != nil { resp.GetBody().Close() } }() if resp.GetStatusCode() == 200 { res := new(ResponseGetBalance) err := resp.UnmarshalBody(res) if err != nil { return nil, err } //log.Warnf("%#v", res) return res, nil } logrus.Warnf("resp.GetStatusCode():%v", resp.GetStatusCode()) return nil, nil } func WxQueryBalanceAndCheck(openid string) (*ResponseGetBalance, error) { rgb, err := WxQueryBalance(openid) if err != nil { return rgb, err } if rgb.ErrCode == 40001 || rgb.ErrCode == 41001 || rgb.ErrCode == 42001 { token, expired, err := QueryAccessToken(int(WxPlat), wxAccessTokenExpires) if err == nil { wxAccessToken = token wxAccessTokenExpires = expired return WxQueryBalance(openid) } } return rgb, err } type ResponsePay struct { ErrCode int `json:"errcode"` ErrMsg string `json:"errmsg"` BillNo string `json:"bill_no"` Balance int `json:"balance"` //预扣后的余额 UsedGenAmt int `json:"used_gen_amt"` //本次扣的赠送币的金额 } // 支付 func WxPay(openid string, billNo string, amt int) (*ResponsePay, error) { req := NewHttpRequest() requestData := make(map[string]interface{}) requestData["openid"] = openid //"oNEBv5CU3aOz7FcWp5ZDlhCNc3-U" requestData["appid"] = os.Getenv("WXPAY_APPID") //"wx831355257c862ac2" requestData["offer_id"] = os.Getenv("WXPAY_OFFERID") //"1450030892" requestData["ts"] = time.Now().Unix() requestData["zone_id"] = "1" requestData["pf"] = "android" requestData["amt"] = amt //123 requestData["bill_no"] = billNo //requestData["pay_item"] = "钻石" requestData["sig"] = MakeGetBalanceSig(requestData, payUri) requestData["access_token "] = wxAccessToken url := "https://api.weixin.qq.com" + payUri + "?access_token=" + wxAccessToken //url := "https://api.weixin.qq.com/cgi-bin/midas/sandbox/pay?access_token=" + accessToken resp, err := req.JSON(requestData).Post(url) if err != nil { //log.Warnln(err) return nil, err } defer func() { if resp.GetBody() != nil { resp.GetBody().Close() } }() if resp.GetStatusCode() == 200 { res := new(ResponsePay) err := resp.UnmarshalBody(res) if err != nil { return nil, err } //log.Warnf("%#v", res) return res, nil } return nil, nil } func WxPayAndCheck(openid string, billNo string, amt int) (*ResponsePay, error) { var rp *ResponsePay var err error for i := 0; i < 3; i++ { rp, err = WxPay(openid, billNo, amt) if err != nil { log.Warnf("PayAndCheck error: %v", err) time.Sleep(time.Millisecond * 10) continue } if rp.ErrCode == 0 { return rp, err } if rp.ErrCode == 40001 || rp.ErrCode == 41001 || rp.ErrCode == 42001 { token, expired, err := QueryAccessToken(int(WxPlat), wxAccessTokenExpires) if err != nil { return rp, err } wxAccessToken = token wxAccessTokenExpires = expired continue } if rp.ErrCode < 0 { time.Sleep(time.Millisecond * 10) continue } return rp, err } return rp, err } type ResponseCancelPay struct { ErrCode int `json:"errcode"` ErrMsg string `json:"errmsg"` BillNo string `json:"bill_no"` } // 取消支付 func CancelPay(openid string, billNo string) (*ResponseCancelPay, error) { req := NewHttpRequest() requestData := make(map[string]interface{}) requestData["openid"] = openid //"oNEBv5CU3aOz7FcWp5ZDlhCNc3-U" requestData["appid"] = os.Getenv("WXPAY_APPID") //"wx831355257c862ac2" requestData["offer_id"] = os.Getenv("WXPAY_OFFERID") //"1450030892" requestData["ts"] = time.Now().Unix() requestData["zone_id"] = "1" requestData["pf"] = "android" requestData["bill_no"] = billNo //requestData["pay_item"] = "钻石" requestData["sig"] = MakeGetBalanceSig(requestData, cancelPayUri) requestData["access_token "] = wxAccessToken url := "https://api.weixin.qq.com" + cancelPayUri + "?access_token=" + wxAccessToken //url := "https://api.weixin.qq.com/cgi-bin/midas/sandbox/cancelpay?access_token=" + accessToken resp, err := req.JSON(requestData).Post(url) if err != nil { //log.Warnln(err) return nil, err } defer func() { if resp.GetBody() != nil { resp.GetBody().Close() } }() if resp.GetStatusCode() == 200 { res := new(ResponseCancelPay) resp.UnmarshalBody(res) //log.Warnf("%#v", res) return res, nil } return nil, nil } type ResponsePresent struct { ErrCode int `json:"errcode"` ErrMsg string `json:"errmsg"` Balance int `json:"balance"` BillNo string `json:"bill_no"` } // 赠送 func Present(openid string, billNo string, presendCount int) (*ResponsePresent, error) { req := NewHttpRequest() requestData := make(map[string]interface{}) requestData["openid"] = openid //"oNEBv5CU3aOz7FcWp5ZDlhCNc3-U" requestData["appid"] = os.Getenv("WXPAY_APPID") //"wx831355257c862ac2" requestData["offer_id"] = os.Getenv("WXPAY_OFFERID") //"1450030892" requestData["ts"] = time.Now().Unix() requestData["zone_id"] = "1" requestData["pf"] = "android" requestData["bill_no"] = billNo requestData["present_counts"] = presendCount requestData["sig"] = MakeGetBalanceSig(requestData, presentUri) requestData["access_token "] = wxAccessToken url := "https://api.weixin.qq.com" + presentUri + "?access_token=" + wxAccessToken //url := "https://api.weixin.qq.com/cgi-bin/midas/sandbox/present?access_token=" + accessToken resp, err := req.JSON(requestData).Post(url) if err != nil { //log.Warnln(err) return nil, err } defer func() { if resp.GetBody() != nil { resp.GetBody().Close() } }() if resp.GetStatusCode() == 200 { res := new(ResponsePresent) resp.UnmarshalBody(res) //log.Warnf("%#v", res) return res, nil } return nil, nil }