package api
import (
"encoding/json"
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"strings"
"time"
"zhoujinhui/model"
"zhoujinhui/util"
"github.com/globalsign/mgo/bson"
)
const APPID, SECRET = "wxxxxxxxxxx86", "06xxxxxxxxxxx08"
const WX_LOGIN_API = "https://api.weixin.qq.com/sns/jscode2session?grant_type=authorization_code&appid=" + APPID + "&secret=" + SECRET
const MCH_ID, MCH_KEY, TRADE_TYPE = "1xxxxxx2", "34xxxxxxxxx87", "JSAPI"
const NOTIFY_URL, WX_PAY_API = "https://admin.qhx-xhx.com/api/notifyRrl", "https://api.mch.weixin.qq.com/pay/unifiedorder"
func GetOpenId(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
resp, err := http.Get(WX_LOGIN_API + "&js_code=" + r.Form.Get("res_code"))
defer resp.Body.Close()
if err == nil {
body, _ := ioutil.ReadAll(resp.Body)
var respStr = string(body)
var jm map[string]string
json.Unmarshal([]byte(respStr), &jm)
if jm["openid"] != "" {
if model.IsExistsWxUserByOpenId(jm["openid"]) {
model.EditWxUser(jm["openid"])
} else {
model.InsertWxUser(jm["openid"])
}
}
fmt.Fprint(w, respStr)
}
}
func UpdateUserInfo(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
openId := r.Form.Get("open_id")
if openId != "" {
var wxUser model.WU
json.Unmarshal([]byte(r.Form.Get("user_info")), &wxUser)
model.UpdateWxUserInfo(openId, wxUser)
}
}
// fmt.Fprint(w, wxPay(wxPayRequest{"JSAPI pay test", util.Krand(16, 3),
// openId, outTradeNo, controller.GetRemoteIp(r), 1}))
//支付输入信息
type wxPayRequest struct {
Body string //商品描述
Nonce_str string //随机数
Openid string //商户唯一标识 openid
Out_trade_no string //订单号
Spbill_create_ip string //用户端ip //订单生成的机器 IP
Total_fee int //订单总金额,单位为分
}
//支付反馈信息
type wxPayResponse struct {
Return_code string `xml:"return_code"`
Return_msg string `xml:"return_msg"`
Nonce_str string `xml:"nonce_str"`
Prepay_id string `xml:"prepay_id"`
}
//支付
func wxPay(payRequest wxPayRequest) string {
reqStr := getReqStr(payRequest) //通过签名算法计算得出的xml
client := &http.Client{}
// 调用支付统一下单API
req, err := http.NewRequest("POST", WX_PAY_API, strings.NewReader(reqStr))
if err != nil {
fmt.Println("访问预支付交易地址:https://api.mch.weixin.qq.com/pay/unifiedorder 失败!")
return "{\"msg\":\"err\",\"info\":\"访问预支付交易地址失败:" + err.Error() + "\"}"
}
req.Header.Set("Content-Type", "text/xml;charset=utf-8")
resp, err := client.Do(req)
defer resp.Body.Close()
body2, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("解析响应内容失败:", err)
return "{\"msg\":\"err\",\"info\":\"解析响应内容失败:" + err.Error() + "\"}"
}
var payResponse wxPayResponse
err = xml.Unmarshal(body2, &payResponse)
if err != nil {
panic(err)
return "{\"msg\":\"err\",\"info\":\"" + err.Error() + "\"}"
}
// 返回预付单信息
if strings.ToUpper(payResponse.Return_code) == "SUCCESS" {
// 再次签名
return getRepStr(payResponse)
} else {
return "{\"msg\":\"err\",\"info\":\"" + payResponse.Return_msg + "\"}"
}
}
//通过签名算法计算得出的xml
func getReqStr(payRequest wxPayRequest) string {
feeStr := strconv.Itoa(payRequest.Total_fee)
stringSign := "appid=" + APPID +
"&body=" + payRequest.Body +
"&mch_id=" + MCH_ID +
"&nonce_str=" + payRequest.Nonce_str +
"¬ify_url=" + NOTIFY_URL +
"&openid=" + payRequest.Openid +
"&out_trade_no=" + payRequest.Out_trade_no +
"&spbill_create_ip=" + payRequest.Spbill_create_ip +
"&total_fee=" + feeStr +
"&trade_type=" + TRADE_TYPE +
"&key=" + MCH_KEY
//进行MD5签名并且将所有字符转为大写.
sign := strings.ToUpper(util.GetMd5String(stringSign))
reqStr := "<xml>" +
"<appid>" + APPID + "</appid>" +
"<body>" + payRequest.Body + "</body>" +
"<mch_id>" + MCH_ID + "</mch_id>" +
"<nonce_str>" + payRequest.Nonce_str + "</nonce_str>" +
"<notify_url>" + NOTIFY_URL + "</notify_url>" +
"<openid>" + payRequest.Openid + "</openid>" +
"<out_trade_no>" + payRequest.Out_trade_no + "</out_trade_no>" +
"<spbill_create_ip>" + payRequest.Spbill_create_ip + "</spbill_create_ip>" +
"<total_fee>" + feeStr + "</total_fee>" +
"<trade_type>" + TRADE_TYPE + "</trade_type>" +
"<sign>" + sign + "</sign></xml>"
return reqStr
}
//再次签名算法计算得出的json
func getRepStr(payResponse wxPayResponse) string {
//当前时间戳
timeStamp := strconv.FormatInt(time.Now().Unix(), 10)
stringSign := "appId=" + APPID +
"&nonceStr=" + payResponse.Nonce_str +
"&package=prepay_id=" + payResponse.Prepay_id +
"&signType=MD5&timeStamp=" + timeStamp +
"&key=" + MCH_KEY
// 进行MD5签名并且将所有字符转为大写.
paySign := strings.ToUpper(util.GetMd5String(stringSign))
repStr := "{\"msg\":\"ok\",\"timeStamp\":\"" + timeStamp +
"\",\"nonceStr\":\"" + payResponse.Nonce_str +
"\",\"package\":\"prepay_id=" + payResponse.Prepay_id +
"\",\"signType\":\"MD5\",\"paySign\":\"" + paySign + "\"}"
return repStr
}
//商户处理后同步返回给微信参数
func NotifyRrl(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
// fmt.Println("读取http body失败,原因!", err)
http.Error(w.(http.ResponseWriter), http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
defer r.Body.Close()
type payNotifyReq struct {
Appid string `xml:"appid"`
Bank_type string `xml:"bank_type"`
Cash_fee float64 `xml:"cash_fee"`
Fee_type string `xml:"fee_type"`
Is_subscribe string `xml:"is_subscribe"`
Mch_id string `xml:"mch_id"`
Nonce_str string `xml:"nonce_str"`
Openid string `xml:"openid"`
Out_trade_no string `xml:"out_trade_no"`
Result_code string `xml:"result_code"`
Return_code string `xml:"return_code"`
Sign string `xml:"sign"`
Time_end string `xml:"time_end"`
Total_fee float64 `xml:"total_fee"`
Trade_type string `xml:"trade_type"`
Transaction_id string `xml:"transaction_id"`
}
var mr payNotifyReq
err = xml.Unmarshal(body, &mr)
if err != nil {
// fmt.Println("解析HTTP Body格式到xml失败,原因!", err)
http.Error(w.(http.ResponseWriter), http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
if orderIdStr := mr.Out_trade_no; orderIdStr != "" && bson.IsObjectIdHex(orderIdStr) {
// model.UpdateOrderSta(bson.ObjectIdHex(orderIdStr), util.ORDER_PAYED)
fmt.Fprint(w, "<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>")
} else {
fmt.Fprint(w, "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[订单号格式校验错误]]></return_msg></xml>")
}
}