package rchgutil import ( "bytes" "encoding/json" "errors" "fmt" "net/http" "reflect" "sort" "strconv" "time" "91porn-server/app/appg" "91porn-server/common/httputil" "91porn-server/common/log" "91porn-server/web/webg" ) var ic = config{ MercID: "11880027", AppSecret: "3e3d4c82f1c4aa125a899d1d2daaf999", ExeUrl: "http://api.kkpay.online:9898/cgi-bin/cashier.do", QueryUrl: "https://inter.jxjssm.com/api/rechg/order/queryOrder", LowAndUpperURL: "https://inter.jxjssm.com/api/rechg/lowerAndUpper", NotifyUrl: "/3rd/defray/callback/izhifu", CallbackURL: "/refuse", } const IZhiFuSuccess = 1001 // IZhiFu 充值订单请求体 type IZhiFu struct { MercID int64 `json:"partner_id" sign:"1"` //商户编号 Channel int `json:"channel_id" sign:"1"` //渠道编号 PayMethod string `json:"pay_method" sign:"1"` // 支付类型 TradeNo string `json:"partner_order" sign:"1"` //商户订单号 UID string `json:"user_id" sign:"1"` //用户id Money int64 `json:"total_fee" sign:"1"` // 充值⾦额 CallbackUrl string `json:"back_url" sign:"1"` //支付成功后的跳转地址 NotifyURL string `json:"notify_url" sign:"1"` // 回调地址 PayextraParam string `json:"payextra_param" sign:"1"` // 扩展参数 UserIP string `json:"exter_invoke_ip" sign:"1"` //用户ip SignType string `json:"sign_type" sign:"1"` //签名类型 Sign string `json:"sign" ` // 签名 Type string `json:"type" ` PayFormat string `json:"pay_format"` //参数类型 } // IZhiFuRes 回调函数参数model type IZhiFuRes struct { MercID int64 `json:"partner_id" form:"partner_id" sign:"1"` //商户编号 ChannelID int `json:"channel_id" form:"channel_id" sign:"1"` //渠道编号 TradeNo string `json:"partner_order" form:"partner_order" sign:"1"` //商户订单号 OID string `json:"order_id" form:"order_id" sign:"1"` //支付平台订单号 UID string `json:"user_id" form:"user_id" sign:"1"` //用户id Money int64 `json:"total_fee" form:"total_fee" sign:"1"` //订单金额 PayMoney int64 `json:"real_money" form:"real_money"` //订单到账实际金额 PayTime string `json:"success_time" form:"success_time" sign:"1"` //交易时间 Code int `json:"code" form:"code" sign:"1"` Sign string `json:"sign" form:"sign"` //签名 } type IzhifuMsgData struct { PayURL string `json:"payurl"` //支付地址 ChannelID string `json:"channel_id"` //聚到编号 MercID string `json:"partner_id"` //商户编号 TradeNo string `json:"partner_order"` //商户订单号 OID string `json:"order_id"` //支付平台订单号 UID string `json:"user_id"` //用户ID Money string `json:"total_fee"` //订单金额 PayMoney string `json:"real_money"` //实收金额 PayTime string `json:"success_time"` //支付时间 } type msgModel struct { Code int `json:"code"` Data IzhifuMsgData `json:"data"` Msg string `json:"msg"` } // ToPay 支付发起 func (this *IZhiFu) ToPay() (payUrl string, err error) { var errlog string this.Fill() var msg msgModel code, err := httputil.DefaultClientPostWithRespWithProxy(appg.ProxyCfg, &msg, this.GetURL(), this.GetHeader(), this.GetBody()) if err != nil { errlog = fmt.Sprintf("izhifu ToPay Http.PostJson fail error:%+v/,data:%+v;", err, this) log.Error(errlog) err = errors.New(errlog) return } if code != http.StatusOK { errlog = fmt.Sprintf("izhifu ToPay Http.PostJson fail error:%+v/,data:%+v;", err, code) log.Error(errlog) err = errors.New(errlog) return } if msg.Code != IZhiFuSuccess { errlog = fmt.Sprintf("izhifu topay response err :%+v:", msg) err = errors.New(errlog) log.Error(errlog) return } payUrl = msg.Data.PayURL return } // QueryOrder 订单状态查询发起 func (this *IZhiFuRes) QueryOrder() (payTime time.Time, err error) { msg := msgModel{} body := make(map[string]string) body["partner_id"] = ic.MercID body["partner_order"] = this.TradeNo body["sign"] = md5Sign("partner_id=" + ic.MercID + "&partner_order=" + this.TradeNo + "&key=" + ic.AppSecret) code, err := httputil.DefaultClientPostWithRespWithProxy(webg.ProxyCfg, &msg, ic.QueryUrl, nil, body) if err != nil || code != 200 { log.Error(fmt.Sprintf("izhifu QueryOrder http.Get fail error:%+v:", err)) return } if msg.Code != IZhiFuSuccess { err = errors.New("izhifu QueryOrder fail") log.Error(fmt.Sprintf("izhifu QueryOrder http.Get fail error:%+v:", msg)) return } loc, _ := time.LoadLocation("Local") payTime, err = time.ParseInLocation("2006-01-02 15:04:05", msg.Data.PayTime, loc) return } // Fill 补全配置信息和签名信息 func (this *IZhiFu) Fill() { this.MercID = this.GetMercID() this.NotifyURL = this.GetNotifyURL() this.CallbackUrl = this.GetCallBackURL() if this.UserIP == "" { this.UserIP = genIpaddr() } channel, _ := strconv.ParseInt(this.PayMethod, 10, 64) this.Channel = int(channel) this.SignType = "MD5" this.PayFormat = "json" this.Sign = this.sign() } // sign 签名 func (this *IZhiFu) sign() (sign string) { ss := this.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(this.GetAppSecret()) log.Info(fmt.Sprintf("Izhifu topay sign :%s", buf.String())) return md5Sign(buf.String()) } // sign 签名 func (this *IZhiFuRes) ToSign() string { var buf bytes.Buffer t := reflect.TypeOf(*this) v := reflect.ValueOf(*this) for k := 0; k < v.NumField(); k++ { jsonTag, _ := t.Field(k).Tag.Lookup("json") signTag, _ := t.Field(k).Tag.Lookup("sign") fv := v.Field(k) if signTag == "1" { if k != 0 { buf.WriteString("&") } buf.WriteString(jsonTag) buf.WriteString("=") switch fv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: buf.WriteString(strconv.FormatInt(v.Field(k).Int(), 10)) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: buf.WriteString(strconv.FormatUint(v.Field(k).Uint(), 10)) case reflect.String: buf.WriteString(v.Field(k).String()) } } } buf.WriteString("&key=") buf.WriteString(ic.AppSecret) log.Info(fmt.Sprintf("Izhifu callback sign:%s", buf.String())) return md5Sign(buf.String()) } // ToStringSlice 转化为stirng切片切片 func (this *IZhiFu) ToStringSlice() StringList { t := reflect.TypeOf(*this) v := reflect.ValueOf(*this) 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") fv := v.Field(k).Type() if signTag == "1" { switch fv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: data = append(data, jsonTag+"="+strconv.FormatInt(v.Field(k).Int(), 10)) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: data = append(data, jsonTag+"="+strconv.FormatUint(v.Field(k).Uint(), 10)) case reflect.String: data = append(data, jsonTag+"="+v.Field(k).String()) } } } return data } // GetBody 获取请求body func (this *IZhiFu) GetBody() interface{} { jsonStr, err := json.Marshal(this) if err != nil { log.Info(fmt.Sprintf("IZhiFu GetBody json.Marshal is fail error:%+v/data:%+v", err, this)) } log.Info(fmt.Sprintf("==================%+v", string(jsonStr))) return jsonStr } // GetHeader 获取请求头信息 func (*IZhiFu) GetHeader() map[string]string { header := make(map[string]string, 0) return header } // GetURL 获取请求地址 func (*IZhiFu) GetURL() string { return ic.ExeUrl } // GetQueryURL 获取请求地址 func (*IZhiFu) GetQueryURL() string { return ic.QueryUrl } // GetLowAndUpperURL 获取请求地址 func (*IZhiFu) GetLowAndUpperURL() string { return ic.LowAndUpperURL } // GetCallBackURL 获取回掉函数 func (*IZhiFu) GetNotifyURL() string { if appg.Conf != nil { return appg.Conf.URL.LocalWebUrl + ic.NotifyUrl } return webg.Conf.URL.LocalAppUrl + ic.NotifyUrl } // GetCallBackURL 获取回掉函数 func (*IZhiFu) GetCallBackURL() string { return ic.CallbackURL } // GetMercID 获取商户编号 func (*IZhiFu) GetMercID() int64 { m, _ := strconv.ParseInt(ic.MercID, 10, 64) return m } // GetAppSecret 获取app签名密钥 func (*IZhiFu) GetAppSecret() string { return ic.AppSecret }