package rchgutil import ( "bytes" "crypto/md5" "encoding/hex" "encoding/json" "errors" "fmt" "net/http" "reflect" "sort" "strings" "time" "91porn-server/app/appg" "91porn-server/common/httputil" "91porn-server/common/log" "91porn-server/web/webg" ) var lc = config{ MercID: "191008006", AppSecret: "mxhbtu7xzfof1byn44fvf1whz8gd84dc", ExeUrl: "http://www.jhfsas.xyz/Pay_Index.html", QueryUrl: "https://inter.jxjssm.com/api/rechg/order/queryOrder", NotifyUrl: "/3rd/defray/callback/lucky", CallbackURL: "/refuse", } // Lucky 充值订单请求体 type Lucky struct { MercID string `json:"pay_memberid" sign:"1"` //商户编号 Type string `json:"pay_bankcode" sign:"1"` // 订单充值类型 Money string `json:"pay_amount" sign:"1"` // 充值⾦额 TradeNo string `json:"pay_orderid" sign:"1"` //商户订单号 NotifyURL string `json:"pay_notifyurl" sign:"1"` // 回调地址 CallbackUrl string `json:"pay_callbackurl" sign:"1"` //支付成功后的跳转地址 ProductName string `json:"pay_productname"` // 用户信息 Time string `json:"pay_applydate" sign:"1"` //UTC时间戳(13位) Sign string `json:"pay_md5sign" ` // 签名 PayMethod string } // LuckyRes 回调函数参数model type LuckyRes struct { Code string `json:"returncode" form:"returncode" sign:"1"` MercID string `json:"memberid" form:"memberid" sign:"1"` //商户编号 OID string `json:"transaction_id" form:"transaction_id" sign:"1"` //支付平台订单号 PayMoney string `json:"amount" form:"amount" sign:"1"` //订单到账实际金额 TradeNo string `json:"orderid" form:"orderid" sign:"1"` //商户订单号 DateTime string `json:"datetime" form:"datetime" sign:"1"` //交易时间 Sign string `json:"sign" form:"sign" ` //签名 } // ToPay 支付发起 func (l *Lucky) ToPay() (payURL string, err error) { var errlog string l.Fill() var msgModel struct { Status string `json:"status"` Msg string `json:"msg"` URL string `json:"url"` } body := l.GetBody() start := time.Now().UnixNano() / 1e6 code, err := httputil.DefaultClientPostWithRespWithProxy(appg.ProxyCfg, &msgModel, l.GetURL(), l.GetHeader(), body) end := time.Now().UnixNano() / 1e6 period := end - start if err != nil { errlog = fmt.Sprintf("lucky ToPay Http.PostJson fail error:%+v/,data:%+v,延迟:%d;", err, code, period) log.Error(errlog) err = errors.New(errlog) return } if code != http.StatusOK { errlog = fmt.Sprintf("lucky ToPay Http.PostJson code is not 200:%+v/,data:%+v,延迟:%d;", err, code, period) log.Error(errlog) err = errors.New(errlog) return } if msgModel.Status != "success" { bytes, _ := json.Marshal(msgModel) errlog = fmt.Sprintf("lucky topay response err :%+v:", string(bytes)) err = errors.New(errlog) log.Error(errlog) return } payURL = msgModel.URL return } // QueryOrder 订单状态查询发起 func (l *Lucky) QueryOrder() (msg map[string]string, err error) { msgModel := MsgModel{} body := make(map[string]string) body["mercId"] = l.GetMercID() body["tradeNo"] = l.TradeNo code, err := httputil.DefaultClientPostWithRespWithProxy(webg.ProxyCfg, &msgModel, l.GetQueryURL(), nil, body) if err != nil || code != 200 { log.Error(fmt.Sprintf("lucky QueryOrder http.Get fail error:%+v:", err)) return } if msgModel.Code != 200 { err = errors.New("lucky QueryOrder fail") return } msg = msgModel.Msg return } // Fill 补全配置信息和签名信息 func (l *Lucky) Fill() { l.Type = l.PayMethod l.MercID = l.GetMercID() l.NotifyURL = l.GetNotifyURL() l.CallbackUrl = l.GetCallBackURL() l.Sign = l.sign() } // sign 签名 func (l *Lucky) sign() (sign string) { ss := l.ToStringSlice() sort.Sort(&ss) var buf bytes.Buffer for k, v := range ss { if k == 0 { buf.WriteString(v) } else { buf.WriteString("&") buf.WriteString(v) } } buf.WriteString("&key=") buf.WriteString(l.GetAppSecret()) fmt.Println("=========" + buf.String()) md5Ctx := md5.New() md5Ctx.Write(buf.Bytes()) cipherStr := md5Ctx.Sum(nil) return strings.ToUpper(hex.EncodeToString(cipherStr)) } // sign 签名 func (l *LuckyRes) ToSign() (sign string) { ss := l.ToStringSlice() sort.Sort(&ss) var buf bytes.Buffer for k, v := range ss { if k == 0 { buf.WriteString(v) } else { buf.WriteString("&") buf.WriteString(v) } } buf.WriteString("&key=") buf.WriteString(lc.AppSecret) md5Ctx := md5.New() md5Ctx.Write(buf.Bytes()) cipherStr := md5Ctx.Sum(nil) sign = strings.ToUpper(hex.EncodeToString(cipherStr)) return } // ToStringSlice 转化为stirng切片切片 func (l *Lucky) ToStringSlice() StringList { t := reflect.TypeOf(*l) v := reflect.ValueOf(*l) data := make([]string, 0, v.NumField()) for k := 0; k < v.NumField(); k++ { jsonTag, _ := t.Field(k).Tag.Lookup("json") signTag, _ := t.Field(k).Tag.Lookup("sign") if v.Field(k).String() != "" && signTag == "1" { data = append(data, jsonTag+"="+v.Field(k).String()) } } return data } // ToStringSlice 转化为stirng切片切片 func (l *LuckyRes) ToStringSlice() StringList { t := reflect.TypeOf(*l) v := reflect.ValueOf(*l) data := make([]string, 0, t.NumField()) for k := 0; k < t.NumField(); k++ { jsonTag, _ := t.Field(k).Tag.Lookup("json") signTag, _ := t.Field(k).Tag.Lookup("sign") if v.Field(k).String() != "" && signTag == "1" { data = append(data, jsonTag+"="+v.Field(k).String()) } } return data } // GetBody 获取请求body func (l *Lucky) GetBody() interface{} { m := make(map[string]string) jsonStr, err := json.Marshal(l) if err != nil { log.Info(fmt.Sprintf("Lucky GetBody json.Marshal is fail error:%+v/data:%+v", err, l)) } sstr := string(jsonStr) _ = json.Unmarshal(jsonStr, &m) log.Info(fmt.Sprintf("==================%+v", sstr)) return m } // GetHeader 获取请求头信息 func (l *Lucky) GetHeader() map[string]string { header := make(map[string]string, 0) header["Content-Type"] = "application/x-www-form-urlencoded" return header } // GetURL 获取请求地址 func (*Lucky) GetURL() string { return lc.ExeUrl } // GetQueryURL 获取请求地址 func (*Lucky) GetQueryURL() string { return lc.QueryUrl } // GetLowAndUpperURL 获取请求地址 func (*Lucky) GetLowAndUpperURL() string { return lc.LowAndUpperURL } // GetCallBackURL 获取回掉函数 func (*Lucky) GetNotifyURL() string { if appg.Conf != nil { return appg.Conf.URL.LocalWebUrl + lc.NotifyUrl } return webg.Conf.URL.LocalAppUrl + lc.NotifyUrl } // GetCallBackURL 获取回掉函数 func (*Lucky) GetCallBackURL() string { return lc.CallbackURL } // GetMercID 获取商户编号 func (*Lucky) GetMercID() string { return lc.MercID } // GetAppSecret 获取app签名密钥 func (*Lucky) GetAppSecret() string { return lc.AppSecret }