@@ -0,0 +1,188 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
)
|
||||
|
||||
var asc = config{
|
||||
MercID: "10005",
|
||||
AppSecret: "176486f9d7c14189717fb88f12d6626a",
|
||||
ExeUrl: "http://106.55.92.30:8081/api/pay",
|
||||
NotifyUrl: "/3rd/defray/callback/rchg/asen",
|
||||
}
|
||||
|
||||
// ASen 充值订单请求体
|
||||
type ASen struct {
|
||||
MercID string `json:"merchant_no" sign:"1"` //商户编号
|
||||
TradeNo string `json:"out_order_no" sign:"1"` //商户订单号
|
||||
Money string `json:"amount" sign:"1"` // 支付金额:元
|
||||
Type string `json:"pay_type" sign:"1"` // 订单充值类型
|
||||
NotifyURL string `json:"notify_url" sign:"1"` // 回调地址
|
||||
Sign string `json:"sign"` // 签名
|
||||
PayMethod string `json:"-"`
|
||||
}
|
||||
|
||||
type ASenMsgData struct {
|
||||
MercID string `json:"merchant_no"` //商户编号
|
||||
OID string `json:"order_no"`
|
||||
TradeNo string `json:"out_order_no"` //商户订单号
|
||||
Money string `json:"amount"`
|
||||
PayWay string `json:"pay_type"`
|
||||
PayUrl string `json:"pay_url"`
|
||||
}
|
||||
|
||||
type ASenMsg struct {
|
||||
Code int `json:"code" sign:"1"` //交易返回码,返回SUCCESS 表示交易成功(不代表最终结果),
|
||||
Data interface{} `json:"data"`
|
||||
Msg string `json:"msg"` //签名
|
||||
}
|
||||
|
||||
// RYRes 回调函数参数model
|
||||
type ASenBack struct {
|
||||
OID string `json:"order_no" form:"order_no" sign:"1"` //订单号
|
||||
MercID string `json:"merchant_no" form:"merchant_no" sign:"1" ` //商户编号
|
||||
TradeNo string `json:"out_order_no" form:"out_order_no" sign:"1"` //商户订单号
|
||||
PayMoney string `json:"amount" form:"amount" sign:"1"` //订单到账实际金额
|
||||
Type string `json:"pay_type" form:"pay_type" sign:"1"` // 订单充值类型
|
||||
Status string `json:"code" form:"code" sign:"1"` //交易结果 1(成功)
|
||||
Sign string `json:"sign" form:"sign" ` //签名
|
||||
}
|
||||
|
||||
// ToPay 支付发起
|
||||
func (this *ASen) ToPay() (res RchgMsg, err error) {
|
||||
var errlog string
|
||||
this.Fill()
|
||||
msg := ASenMsg{}
|
||||
code, err := httputil.DefaultClientPostJsonWithResp(&msg, this.GetURL(), this.GetHeader(), this.GetBody())
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("asen ToPay requset fail \nerror:%+v\n\ndata:%+v;", err, this)
|
||||
log.Error(errlog)
|
||||
err = errors.New(errlog)
|
||||
return
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
errlog = fmt.Sprintf("asen ToPay response status exception;\nstatus %+v;", code)
|
||||
log.Error(errlog)
|
||||
err = errors.New(errlog)
|
||||
return
|
||||
}
|
||||
if msg.Code != 1 {
|
||||
errlog = fmt.Sprintf("asen ToPay be rejected;\n msg:%+v:", msg)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
var data ASenMsgData
|
||||
bytes, err := json.Marshal(msg.Data)
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("asen payUrl urlDecode fail \nerror:%+v;", err)
|
||||
log.Error(errlog)
|
||||
err = errors.New(errlog)
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal(bytes, &data); err != nil {
|
||||
errlog = fmt.Sprintf("asen payUrl urlDecode fail \nerror:%+v;", err)
|
||||
log.Error(errlog)
|
||||
err = errors.New(errlog)
|
||||
return
|
||||
}
|
||||
res.PayUrl = data.PayUrl
|
||||
res.OID = data.OID
|
||||
res.Mode = "sdk"
|
||||
return
|
||||
}
|
||||
|
||||
// ASenCallBack 阿森结构回调函数
|
||||
func (this *ASenBack) Notify() (RchgBack, error) {
|
||||
now := time.Now()
|
||||
r := RchgBack{}
|
||||
if this.Sign != this.ToSign() {
|
||||
err := errors.New("check sign fail")
|
||||
log.Error(fmt.Sprintf("ASen callback sign verify fail error:%+v:", err))
|
||||
return r, err
|
||||
}
|
||||
r.Code = 200
|
||||
if this.Status != "1" {
|
||||
r.Code = 400
|
||||
}
|
||||
fPayMoney, err := strconv.ParseFloat(this.PayMoney, 64)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("ASen callback sign verify fail error:%+v:", err))
|
||||
return r, err
|
||||
}
|
||||
r.PayMoney = int64(fPayMoney * 100)
|
||||
r.PaymentAt = now
|
||||
r.TransNo = this.TradeNo
|
||||
r.OID = this.OID
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (this *ASenBack) Success() string {
|
||||
return "success"
|
||||
}
|
||||
|
||||
// Fill 补全配置信息和签名信息
|
||||
func (this *ASen) Fill() {
|
||||
this.Type = this.PayMethod
|
||||
this.PayMethod = ""
|
||||
this.MercID = this.GetMercID()
|
||||
this.NotifyURL = this.GetCallBackURL()
|
||||
this.Sign = this.sign()
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (this *ASen) sign() string {
|
||||
buf := fixedSignStrAdd(*this)
|
||||
buf.WriteString(asc.AppSecret)
|
||||
log.Info(fmt.Sprintf("--------------%s", buf.String()))
|
||||
return md5Sign(buf.String())
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (this *ASenBack) ToSign() string {
|
||||
buf := fixedSignStrAdd(*this)
|
||||
buf.WriteString(asc.AppSecret)
|
||||
return md5Sign(buf.String())
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (this *ASen) GetBody() interface{} {
|
||||
m := make(map[string]string)
|
||||
jsonStr, err := json.Marshal(this)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("ASen GetBody json.Marshal is fail error:%+v/data:%+v", err, this))
|
||||
}
|
||||
sstr := string(jsonStr)
|
||||
log.Info(fmt.Sprintf("==================%+v", sstr))
|
||||
_ = json.Unmarshal(jsonStr, &m)
|
||||
return m
|
||||
}
|
||||
|
||||
// GetHeader 获取请求头信息
|
||||
func (g *ASen) GetHeader() map[string]string {
|
||||
return map[string]string{"Content-Type": "application/x-www-form-urlencoded"}
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (*ASen) GetURL() string {
|
||||
return asc.ExeUrl
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (*ASen) GetCallBackURL() string {
|
||||
return appg.Conf.URL.LocalWebUrl + asc.NotifyUrl
|
||||
}
|
||||
|
||||
// GetMercID 获取商户编号
|
||||
func (*ASen) GetMercID() string {
|
||||
return asc.MercID
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var PAY_CHANNEL_CLOSE_ERROR = errors.New("PAY CHANNEL CLOSE")
|
||||
var PAY_CHANNEL_BAN_ERROR = errors.New("USER IS DISABLED")
|
||||
|
||||
const (
|
||||
Alipay = "alipay" //支付宝
|
||||
Wechat = "wechat" //微信支付
|
||||
|
||||
UNKNOWError = 444
|
||||
RCHG_NOTIFY_URL = "/3rd/defray/callback/rchg/"
|
||||
)
|
||||
|
||||
type Rchg struct {
|
||||
TransNo string `json:"transNo"` //订单号
|
||||
PlatformID string `json:"platformID"` //平台
|
||||
UID string `json:"uid" ` //用户id
|
||||
DevID string `json:"devID" ` //设备id
|
||||
UserIP string `json:"userIP"` //用户ip
|
||||
Name string `json:"name"` //用户名称
|
||||
Tel string `json:"tel"` //用户手机号
|
||||
DevType string `json:"devType"` //设备系统类型 ios pc android
|
||||
Money int64 `json:"money"` //充值金额 订单金额 确认
|
||||
Channel string `json:"channel"` //渠道类型 鲨鱼 金鱼
|
||||
Mode string `json:"mode,omitempty"` //式模 持支 表代则传 值定固。填选
|
||||
CreatedAt time.Time `json:"createdAt"` //创建时间
|
||||
NotifyUrl string `json:"notifyUrl"` //回调地址
|
||||
PType string `json:"pType"` //支付类型 wechat alipay
|
||||
ProductType int `json:"productType"` //支付产品类型 0 站群 1 棋牌
|
||||
UserLevel int `json:"userLevel"` //限定用户层级 (0默认无等级 1充值成功过的1等级)
|
||||
PayMethod string
|
||||
}
|
||||
|
||||
type RchgMsg struct {
|
||||
Err string `json:"err"`
|
||||
PayUrl string `json:"payUrl"`
|
||||
OID string `json:"oid"`
|
||||
Mode string `json:"mode"`
|
||||
CID string `json:"cid"`
|
||||
Rate string `json:"rate"` //渠道费率
|
||||
|
||||
}
|
||||
|
||||
type RchgBack struct {
|
||||
TransNo string `json:"transNo"` //流水id
|
||||
OID string `json:"oid"` //支付平台订单号
|
||||
PayMoney int64 `json:"payMoney"` //实际到账金额 用户实际支付金额 李秋山确认
|
||||
FailureAt time.Time `json:"failureAt"` //回调失败时间
|
||||
SuccessAt time.Time `json:"successAt"` //回调成功时间
|
||||
PaymentAt time.Time `json:"paymentAt"` //支付时间
|
||||
Code int `json:"code"` //状态码
|
||||
}
|
||||
|
||||
type RchgBackMsg struct {
|
||||
Code int `json:"code"`
|
||||
Err string `json:"err"`
|
||||
}
|
||||
|
||||
// MsgModel 返回消息结构体
|
||||
type MsgModel struct {
|
||||
Code int `json:"code"`
|
||||
Msg map[string]string `json:"msg"`
|
||||
Err interface{} `json:"err"`
|
||||
}
|
||||
|
||||
// RchgRes 返回消息结构体
|
||||
type RchgRes struct {
|
||||
Code int `json:"code"`
|
||||
OID string `json:"oid"`
|
||||
PayURL string `json:"payUrl"`
|
||||
Err error `json:"err"`
|
||||
}
|
||||
|
||||
// MsgModel 返回消息结构体
|
||||
type ExchgMsgModel struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Err string `json:"err"`
|
||||
}
|
||||
|
||||
// config
|
||||
type config struct {
|
||||
MercID string `json:"mercID"` //商户id
|
||||
AppSecret string `json:"appSecret"`
|
||||
ExeUrl string `json:"exeUrl"` //业务发起地址
|
||||
NotifyUrl string `json:"notifyUrl"` //回调地址
|
||||
QueryUrl string `json:"queryUrl"` //充值方式查询地址
|
||||
LowAndUpperURL string `json:"lowAndUpperURL"` //充值范围查询地址
|
||||
CallbackURL string `json:"callbackURL"` //充值成功请求的页面地址
|
||||
VerifySecret string //验证密钥
|
||||
}
|
||||
|
||||
// GetUTCTime 获取utc时间戳
|
||||
func GetUTCTimeMS(t time.Time) string {
|
||||
return strconv.FormatInt(t.UnixNano()/1000000, 10)
|
||||
}
|
||||
|
||||
// VerifySign 签名
|
||||
func VerifySign(sign string, buf string) bool {
|
||||
nsign := md5Sign(buf)
|
||||
return nsign == sign
|
||||
}
|
||||
|
||||
// md5签名
|
||||
func md5Sign(buf string) string {
|
||||
md5Ctx := md5.New()
|
||||
md5Ctx.Write([]byte(buf))
|
||||
cipherStr := md5Ctx.Sum(nil)
|
||||
nsign := hex.EncodeToString(cipherStr)
|
||||
return nsign
|
||||
}
|
||||
|
||||
var (
|
||||
lastNameLen = len(lastName)
|
||||
firstNameLen = len(firstName)
|
||||
|
||||
lastName = []string{
|
||||
"赵", "钱", "孙", "李", "周", "吴", "郑", "王", "冯", "陈", "褚", "卫", "蒋",
|
||||
"沈", "韩", "杨", "朱", "秦", "尤", "许", "何", "吕", "施", "张", "孔", "曹", "严", "华", "金", "魏",
|
||||
"陶", "姜", "戚", "谢", "邹", "喻", "柏", "水", "窦", "章", "云", "苏", "潘", "葛", "奚", "范", "彭",
|
||||
"郎", "鲁", "韦", "昌", "马", "苗", "凤", "花", "方", "任", "袁", "柳", "鲍", "史", "唐", "费", "薛",
|
||||
"雷", "贺", "倪", "汤", "滕", "殷", "罗", "毕", "郝", "安", "常", "傅", "卞", "齐", "元", "顾", "孟",
|
||||
"平", "黄", "穆", "萧", "尹", "姚", "邵", "湛", "汪", "祁", "毛", "狄", "米", "伏", "成", "戴", "谈",
|
||||
"宋", "茅", "庞", "熊", "纪", "舒", "屈", "项", "祝", "董", "梁", "杜", "阮", "蓝", "闵", "季", "贾",
|
||||
"路", "娄", "江", "童", "颜", "郭", "梅", "盛", "林", "钟", "徐", "邱", "骆", "高", "夏", "蔡", "田",
|
||||
"樊", "胡", "凌", "霍", "虞", "万", "支", "柯", "管", "卢", "莫", "柯", "房", "裘", "缪", "解", "应",
|
||||
"宗", "丁", "宣", "邓", "单", "杭", "洪", "包", "诸", "左", "石", "崔", "吉", "龚", "程", "嵇", "邢",
|
||||
"裴", "陆", "荣", "翁", "荀", "于", "惠", "甄", "曲", "封", "储", "仲", "伊", "宁", "仇", "甘", "武",
|
||||
"符", "刘", "景", "詹", "龙", "叶", "幸", "司", "黎", "溥", "印", "怀", "蒲", "邰", "从", "索", "赖",
|
||||
"卓", "屠", "池", "乔", "胥", "闻", "莘", "党", "翟", "谭", "贡", "劳", "逄", "姬", "申", "扶", "堵",
|
||||
"冉", "宰", "雍", "桑", "寿", "通", "燕", "浦", "尚", "农", "温", "别", "庄", "晏", "柴", "瞿", "阎",
|
||||
"连", "习", "容", "向", "古", "易", "廖", "庾", "终", "步", "都", "耿", "满", "弘", "匡", "国", "文",
|
||||
"寇", "广", "禄", "阙", "东", "欧", "利", "师", "巩", "聂", "关", "荆", "司马", "上官", "欧阳", "夏侯",
|
||||
"诸葛", "闻人", "东方", "赫连", "皇甫", "尉迟", "公羊", "澹台", "公冶", "宗政", "濮阳", "淳于", "单于",
|
||||
"太叔", "申屠", "公孙", "仲孙", "轩辕", "令狐", "徐离", "宇文", "长孙", "慕容", "司徒", "司空"}
|
||||
firstName = []string{
|
||||
"伟", "刚", "勇", "毅", "俊", "峰", "强", "军", "平", "保", "东", "文", "辉", "力", "明", "永", "健", "世", "广", "志", "义",
|
||||
"兴", "良", "海", "山", "仁", "波", "宁", "贵", "福", "生", "龙", "元", "全", "国", "胜", "学", "祥", "才", "发", "武", "新",
|
||||
"利", "清", "飞", "彬", "富", "顺", "信", "子", "杰", "涛", "昌", "成", "康", "星", "光", "天", "达", "安", "岩", "中", "茂",
|
||||
"进", "林", "有", "坚", "和", "彪", "博", "诚", "先", "敬", "震", "振", "壮", "会", "思", "群", "豪", "心", "邦", "承", "乐",
|
||||
"绍", "功", "松", "善", "厚", "庆", "磊", "民", "友", "裕", "河", "哲", "江", "超", "浩", "亮", "政", "谦", "亨", "奇", "固",
|
||||
"之", "轮", "翰", "朗", "伯", "宏", "言", "若", "鸣", "朋", "斌", "梁", "栋", "维", "启", "克", "伦", "翔", "旭", "鹏", "泽",
|
||||
"晨", "辰", "士", "以", "建", "家", "致", "树", "炎", "德", "行", "时", "泰", "盛", "雄", "琛", "钧", "冠", "策", "腾", "楠",
|
||||
"榕", "风", "航", "弘", "秀", "娟", "英", "华", "慧", "巧", "美", "娜", "静", "淑", "惠", "珠", "翠", "雅", "芝", "玉", "萍",
|
||||
"红", "娥", "玲", "芬", "芳", "燕", "彩", "春", "菊", "兰", "凤", "洁", "梅", "琳", "素", "云", "莲", "真", "环", "雪", "荣",
|
||||
"爱", "妹", "霞", "香", "月", "莺", "媛", "艳", "瑞", "凡", "佳", "嘉", "琼", "勤", "珍", "贞", "莉", "桂", "娣", "叶", "璧",
|
||||
"璐", "娅", "琦", "晶", "妍", "茜", "秋", "珊", "莎", "锦", "黛", "青", "倩", "婷", "姣", "婉", "娴", "瑾", "颖", "露", "瑶",
|
||||
"怡", "婵", "雁", "蓓", "纨", "仪", "荷", "丹", "蓉", "眉", "君", "琴", "蕊", "薇", "菁", "梦", "岚", "苑", "婕", "馨", "瑗",
|
||||
"琰", "韵", "融", "园", "艺", "咏", "卿", "聪", "澜", "纯", "毓", "悦", "昭", "冰", "爽", "琬", "茗", "羽", "希", "欣", "飘",
|
||||
"育", "滢", "馥", "筠", "柔", "竹", "霭", "凝", "晓", "欢", "霄", "枫", "芸", "菲", "寒", "伊", "亚", "宜", "可", "姬", "舒",
|
||||
"影", "荔", "枝", "丽", "阳", "妮", "宝", "贝", "初", "程", "梵", "罡", "恒", "鸿", "桦", "骅", "剑", "娇", "纪", "宽", "苛",
|
||||
"灵", "玛", "媚", "琪", "晴", "容", "睿", "烁", "堂", "唯", "威", "韦", "雯", "苇", "萱", "阅", "彦", "宇", "雨", "洋", "忠",
|
||||
"宗", "曼", "紫", "逸", "贤", "蝶", "菡", "绿", "蓝", "儿", "翠", "烟", "小", "轩"}
|
||||
)
|
||||
|
||||
// 获取随机姓名
|
||||
func GetFullName() string {
|
||||
var first string //名
|
||||
for i := 0; i <= rand.Intn(2); i++ { //随机产生2位或者3位的名
|
||||
first = fmt.Sprint(firstName[rand.Intn(firstNameLen-1)])
|
||||
}
|
||||
//返回姓名
|
||||
return fmt.Sprintf("%s%s", fmt.Sprint(lastName[rand.Intn(lastNameLen-1)]), first)
|
||||
}
|
||||
|
||||
func genIpaddr() string {
|
||||
ip := fmt.Sprintf("%d.%d.%d.%d", rand.Intn(255), rand.Intn(255), rand.Intn(255), rand.Intn(255))
|
||||
return ip
|
||||
}
|
||||
|
||||
type StringList []string
|
||||
|
||||
func (sl *StringList) Len() int {
|
||||
return len(*sl)
|
||||
}
|
||||
|
||||
func (sl *StringList) Less(i, j int) bool {
|
||||
s := strings.Split((*sl)[i], "=")[0]
|
||||
e := strings.Split((*sl)[j], "=")[0]
|
||||
ib := []byte(s)
|
||||
jb := []byte(e)
|
||||
for k := range ib {
|
||||
if ib[k] == jb[k] {
|
||||
continue
|
||||
} else {
|
||||
return ib[k] < jb[k]
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (sl *StringList) Swap(i, j int) {
|
||||
b := (*sl)[i]
|
||||
(*sl)[i] = (*sl)[j]
|
||||
(*sl)[j] = b
|
||||
}
|
||||
|
||||
const (
|
||||
letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
letterIdxBits = 6 // 6 bits to represent a letter index
|
||||
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
||||
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
||||
)
|
||||
|
||||
func RandStringBytesMaskImpr(n int) string {
|
||||
b := make([]byte, n)
|
||||
// A rand.Int63() generates 63 random bits, enough for letterIdxMax letters!
|
||||
for i, cache, remain := n-1, rand.Int63(), letterIdxMax; i >= 0; {
|
||||
if remain == 0 {
|
||||
cache, remain = rand.Int63(), letterIdxMax
|
||||
}
|
||||
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
||||
b[i] = letterBytes[idx]
|
||||
i--
|
||||
}
|
||||
cache >>= letterIdxBits
|
||||
remain--
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func RChgIDAssemble(id string) string {
|
||||
return "CZ-91PO-" + id
|
||||
}
|
||||
|
||||
func RChgIDDisassemble(transNo string) string {
|
||||
temp := strings.Split(transNo, "-")
|
||||
return temp[len(temp)-1]
|
||||
}
|
||||
|
||||
func RChgWLIDAssemble(id string) string {
|
||||
return "CZ-91POW-" + id
|
||||
}
|
||||
|
||||
func EChgIDAssemble(id string) string {
|
||||
return "TX-91PO-" + id
|
||||
}
|
||||
|
||||
func EChgWLIDAssemble(id string) string {
|
||||
return "TX-91POW-" + id
|
||||
}
|
||||
|
||||
func EChgIDDisassemble(transNo string) string {
|
||||
temp := strings.Split(transNo, "-")
|
||||
return temp[len(temp)-1]
|
||||
}
|
||||
|
||||
// sign 结构体固定顺序签名
|
||||
func fixedSignStrAdd(obj interface{}) bytes.Buffer {
|
||||
var buf bytes.Buffer
|
||||
t := reflect.TypeOf(obj)
|
||||
v := reflect.ValueOf(obj)
|
||||
for k := 0; k < v.NumField(); k++ {
|
||||
signTag, _ := t.Field(k).Tag.Lookup("sign")
|
||||
fv := v.Field(k)
|
||||
if signTag == "1" {
|
||||
var value string
|
||||
switch fv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
value = strconv.FormatInt(v.Field(k).Int(), 10)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
value = strconv.FormatUint(v.Field(k).Uint(), 10)
|
||||
case reflect.String:
|
||||
value = v.Field(k).String()
|
||||
}
|
||||
buf.WriteString(value)
|
||||
}
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
type Notify interface {
|
||||
Notify() (RchgBack, error)
|
||||
Success() string
|
||||
}
|
||||
|
||||
func GetNotifyBack(name string) Notify {
|
||||
switch name {
|
||||
case YongLiName:
|
||||
return (&YongLiBack{})
|
||||
case DaBaiShaName:
|
||||
return (&DaBaiShaRes{})
|
||||
case ASenName:
|
||||
return (&ASenBack{})
|
||||
case "bill":
|
||||
return (&RchgBack{})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToStringSlice 转化为stirng切片切片
|
||||
func ToStringSlice(obj interface{}) StringList {
|
||||
t := reflect.TypeOf(obj)
|
||||
v := reflect.ValueOf(obj)
|
||||
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())
|
||||
case reflect.Float64, reflect.Float32:
|
||||
data = append(data, jsonTag+"="+strconv.FormatFloat(v.Field(k).Float(), 'f', 2, 64))
|
||||
}
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
var (
|
||||
DaBaiShaName = "dabaisha"
|
||||
ASenName = "asen"
|
||||
YongLiName = "yongli"
|
||||
YongLiWanShun = "ylws"
|
||||
)
|
||||
|
||||
const ProductName = "充值"
|
||||
|
||||
func (this *Rchg) ToPay() (res RchgMsg, err error) {
|
||||
strMoney := strconv.FormatFloat(float64(this.Money)/100, 'f', 2, 64)
|
||||
//充值统一前缀
|
||||
this.TransNo = RChgIDAssemble(this.TransNo)
|
||||
switch this.Channel {
|
||||
case DaBaiShaName:
|
||||
dbs := DaBaiSha{
|
||||
Money: strMoney,
|
||||
TradeNo: this.TransNo,
|
||||
Info: DaBaiShaInfo{
|
||||
PlayerID: this.UID,
|
||||
PlayerIP: this.UserIP,
|
||||
DeviceID: this.DevID,
|
||||
DeviceType: this.DevType,
|
||||
Name: ProductName,
|
||||
},
|
||||
Mode: this.Mode,
|
||||
Time: GetUTCTimeMS(this.CreatedAt),
|
||||
PayMethod: this.PayMethod,
|
||||
}
|
||||
res, err = dbs.ToPay()
|
||||
case ASenName:
|
||||
strIntMoney := strconv.FormatInt(int64(float64(this.Money)/100), 10)
|
||||
res, err = (&ASen{
|
||||
TradeNo: this.TransNo,
|
||||
Money: strIntMoney,
|
||||
PayMethod: this.PayMethod,
|
||||
}).ToPay()
|
||||
case YongLiName:
|
||||
res, err = (&YongLi{
|
||||
TradeNo: this.TransNo,
|
||||
Money: strMoney,
|
||||
PayMethod: this.PayMethod,
|
||||
Time: strconv.FormatInt(this.CreatedAt.UTC().Unix(), 10),
|
||||
}).ToPay()
|
||||
case YongLiWanShun:
|
||||
res, err = (&WsylInfo{
|
||||
OutTradeNo: this.TransNo,
|
||||
Amount: strMoney,
|
||||
}).toPay()
|
||||
default:
|
||||
err = errors.New("invalid pay channel")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
)
|
||||
|
||||
type PayTypeParam struct {
|
||||
Moneys []int64 `json:"moneys"`
|
||||
DevType string `json:"devType"`
|
||||
ProductType int `json:"productType"` //产品类型 0站群 1棋牌
|
||||
UserLevel int `json:"userLevel"` //限定用户层级 (0默认无等级 1充值成功过的1等级)
|
||||
PlatformID string `json:"platformID"` //平台
|
||||
}
|
||||
|
||||
type RchgType struct {
|
||||
Money int64 `json:"money"` //金额 单位 分
|
||||
Alipay bool `json:"alipay"` //是否支持支付宝
|
||||
Wechat bool `json:"wechat"` //是否支持微信
|
||||
Union bool `json:"union"` //是否支持银联
|
||||
DaiChong bool `json:"daichong"` //是否支持代充
|
||||
USDT bool `json:"usdt"` //是否支持代充
|
||||
QuickUnion bool `json:"quickUnion"` //是否支持快速银联
|
||||
}
|
||||
|
||||
type StdMsg struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data interface{} `json:"data"`
|
||||
Tip string `json:"tip"`
|
||||
}
|
||||
|
||||
// GetPayType 从支付中心获取充值金额对应的充值方式
|
||||
func GetPayType(ctx context.Context, moneys []int64, devType string, productType, userLevel int) ([]RchgType, error) {
|
||||
var errlog string
|
||||
p := PayTypeParam{
|
||||
moneys,
|
||||
devType,
|
||||
productType,
|
||||
userLevel,
|
||||
"91PORN",
|
||||
}
|
||||
res := StdMsg{}
|
||||
code, err := httputil.DefaultClientPostJsonWithResp(&res, p.GetURL(), nil, p.GetBody())
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("bill GetPayType requset fail \nerror:%+v\n\ndata:%+v;", err, p)
|
||||
log.ErrorX(ctx, "get pay type in bill center failed", log.Any("param", p), log.Any("url", p.GetURL()),
|
||||
log.E(err))
|
||||
return nil, errors.New(errlog)
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
errlog = fmt.Sprintf("bill GetPayType response status exception;\nstatus %+v;", code)
|
||||
log.ErrorX(ctx, errlog, log.Any("code", code))
|
||||
return nil, errors.New(errlog)
|
||||
}
|
||||
if res.Code != 200 {
|
||||
errlog = fmt.Sprintf("bill GetPayType be rejected;\n err:%+v:", res)
|
||||
log.ErrorX(ctx, errlog, log.Any("res", res))
|
||||
return nil, errors.New(errlog)
|
||||
}
|
||||
bytes, err := json.Marshal(res.Data)
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("bill payUrl urlDecode fail \nerror:%+v;", err)
|
||||
log.Error(errlog)
|
||||
return nil, errors.New(errlog)
|
||||
}
|
||||
var payTypes []RchgType
|
||||
if err = json.Unmarshal(bytes, &payTypes); err != nil {
|
||||
errlog = fmt.Sprintf("bill payUrl urlDecode fail \nerror:%+v;", err)
|
||||
log.ErrorX(ctx, errlog, log.E(err))
|
||||
return nil, errors.New(errlog)
|
||||
}
|
||||
log.InfoX(ctx, "bill GetPayType data", log.Any("res", res))
|
||||
return payTypes, nil
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (this *PayTypeParam) GetBody() []byte {
|
||||
data, err := json.Marshal(this)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("bill GetBody json.Marshal is fail error:%+v/data:%+v", err, this))
|
||||
return nil
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (*PayTypeParam) GetURL() string {
|
||||
return appg.Conf.URL.TransactionUrl + "/api/recharge/payType"
|
||||
}
|
||||
|
||||
var (
|
||||
PayErrPostFailure = errors.New("recharge http post failure")
|
||||
PayErrResponseCode = errors.New("recharge http code isn't 200")
|
||||
PayErrBeRejected = errors.New("recharge has been rejected")
|
||||
)
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (this *Rchg) ToPayNew(ctx context.Context) (res RchgMsg, err error) {
|
||||
defer func() {
|
||||
log.InfoX(ctx, "bill ToPayNew request info end 2", log.Any("transNo", this.TransNo), log.Any("res", res))
|
||||
if err := recover(); err != nil {
|
||||
log.ErrorX(ctx, "bill ToPayNew recover", log.Any("Rchg", this), log.Any("panic", err))
|
||||
}
|
||||
}()
|
||||
this.fill()
|
||||
param, err := json.Marshal(this)
|
||||
if err != nil {
|
||||
log.ErrorX(ctx, "bill ToPayNew json.Marshal failed,", log.Any("transNo", this.TransNo), log.E(err))
|
||||
return
|
||||
}
|
||||
log.InfoX(ctx, "ToPayNew request info start", log.Any("transNo", this.TransNo), log.Any("param", string(param)))
|
||||
startS := time.Now().UnixNano()
|
||||
code, err := httputil.DefaultClientPostJsonWithResp(&res, this.GetURL(), nil, param)
|
||||
log.InfoX(ctx, "ToPayNew POST resp ", log.Any("code", code), log.Any("transNo", this.TransNo),
|
||||
log.Any("param", string(param)), log.Any("topay-bill-time cost", time.Now().UnixNano()-startS))
|
||||
if err != nil {
|
||||
log.ErrorX(ctx, "bill ToPayNew post failed", log.Any("transNo", this.TransNo), log.E(err))
|
||||
err = PayErrPostFailure
|
||||
return
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
log.ErrorX(ctx, "bill ToPayNew bad http statusCode", log.Any("transNo", this.TransNo), log.Any("statusCode", code))
|
||||
err = PayErrResponseCode
|
||||
return
|
||||
}
|
||||
if res.Err != "" {
|
||||
log.ErrorX(ctx, "bill ToPayNew has been rejected", log.Any("transNo", this.TransNo), log.Any("res err", res.Err))
|
||||
err = PayErrBeRejected
|
||||
return
|
||||
}
|
||||
log.InfoX(ctx, "bill ToPayNew request info end", log.Any("transNo", this.TransNo), log.Any("res", res))
|
||||
return
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (this *Rchg) fill() {
|
||||
this.PlatformID = "91PORN"
|
||||
if this.ProductType == 0 {
|
||||
this.TransNo = RChgIDAssemble(this.TransNo)
|
||||
}
|
||||
if this.ProductType == 1 {
|
||||
this.TransNo = RChgWLIDAssemble(this.TransNo)
|
||||
}
|
||||
this.NotifyUrl = appg.Conf.URL.LocalWebUrl + RCHG_NOTIFY_URL + "bill"
|
||||
this.PType = this.PayMethod
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (*Rchg) GetURL() string {
|
||||
return appg.Conf.URL.TransactionUrl + "/api/recharge/recharge"
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (this *RchgBack) Notify() (RchgBack, error) {
|
||||
return *this, nil
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (this *RchgBack) Success() string {
|
||||
return "success"
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/models/v/wdordmod"
|
||||
"91porn-server/web/webg"
|
||||
)
|
||||
|
||||
type Exchg struct {
|
||||
TransNo string `json:"transNo" bson:"transNo"` //订单号
|
||||
UID string `json:"uid" bson:"uid"` //用户id
|
||||
Name string `json:"name" bson:"name"` //用户名
|
||||
PayMoney int64 `json:"payMoney" bson:"payMoney"` //实际到账
|
||||
PayType string `json:"payType" bson:"payType" binding:"required"` //提现方式,alipay,bankcard
|
||||
ActName string `json:"actName" bson:"actName"` //交易账户持有人
|
||||
Act string `json:"act" bson:"act"` //交易账户
|
||||
UserIP string `json:"userIp" bson:"userIp"` //用户ip
|
||||
DeviceType string `json:"deviceType" bson:"deviceType"` //设备类型
|
||||
DevID string `json:"devID" bson:"devID"` //设备id
|
||||
CheckedAt time.Time `json:"checkedAt" bson:"checkedAt"` //审核时间
|
||||
NotifyUrl string `json:"notifyUrl"` //回调地址
|
||||
ProductType int `json:"productType"` //支付产品类型 0 站群 1 棋牌
|
||||
Rate float64 `json:"rate"` //费率
|
||||
PlatformID string `json:"platformID"`
|
||||
BankCode string `json:"bankCode" bson:"bankCode"` //银行编码
|
||||
}
|
||||
|
||||
type ExchgBack struct {
|
||||
OID string `json:"oid" ` //支付平台订单号
|
||||
Money int64 `json:"money"` //兑换金额
|
||||
TradeNo string `json:"tradeNo"` //商户订单号
|
||||
Status string `json:"status"`
|
||||
Mark string `json:"mark"` //拒绝兑换理由
|
||||
}
|
||||
|
||||
type ExchgBackMsg struct {
|
||||
Code int `json:"code"`
|
||||
Err string `json:"err"`
|
||||
}
|
||||
|
||||
type ExchgMsg struct {
|
||||
OID string `json:"oid"`
|
||||
Code int `json:"code"`
|
||||
Err string `json:"err"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
// ToPay 支付发起
|
||||
func (this *Exchg) ToPay() ExchgMsg {
|
||||
var msg ExchgMsg
|
||||
var errlog string
|
||||
this.fill()
|
||||
code, err := httputil.DefaultClientPostJsonWithResp(&msg, this.GetURL(), this.GetHeader(), this.GetBody())
|
||||
if err != nil {
|
||||
msg.Code = UNKNOWError
|
||||
errlog = fmt.Sprintf("recharge ToPay Http.PostJson fail error:%+v/,data:%+v;", err, this)
|
||||
msg.Err = errlog
|
||||
log.Error(errlog)
|
||||
return msg
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
msg.Code = UNKNOWError
|
||||
errlog = fmt.Sprintf("recharge ToPay Http.PostJson fail error:%+v/,data:%+v;", err, code)
|
||||
msg.Err = errlog
|
||||
log.Error(errlog)
|
||||
return msg
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
func (this *Exchg) fill() {
|
||||
this.PlatformID = "91PO"
|
||||
this.NotifyUrl = webg.Conf.URL.LocalAppUrl + "/3rd/defray/callback/echg/bill"
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (this *Exchg) GetBody() interface{} {
|
||||
jsonStr, err := json.Marshal(this)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("excharge json.Marshal is fail error:%+v/data:%+v", err, this))
|
||||
}
|
||||
sstr := string(jsonStr)
|
||||
log.Info(fmt.Sprintf("recharg topay json data :%+v", sstr))
|
||||
return jsonStr
|
||||
}
|
||||
|
||||
// GetHeader 获取请求头信息
|
||||
func (this *Exchg) GetHeader() map[string]string {
|
||||
header := make(map[string]string, 0)
|
||||
return header
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (*Exchg) GetURL() string {
|
||||
return webg.Conf.URL.TransactionUrl + "/api/recharge/withdraw"
|
||||
}
|
||||
|
||||
// 防洗钱校验
|
||||
// 提现防洗钱限制, 防止用户用usdt充值, 其它方式提现洗钱
|
||||
// 例如: 用户usdt充值1000, 则用户只能用usdt提现1000,
|
||||
//
|
||||
// 且, 用户usdt充值1000未提现时, 此时用其它方式提现,
|
||||
// 则, 余额 - 提现金额 >= 1000
|
||||
//
|
||||
// eType: 提现方式
|
||||
// allMoney: 可提现总金额
|
||||
// money: 提现金额
|
||||
// usdtAmount: usdt可提现额度
|
||||
// uid: 提现用户id
|
||||
func CheckMoney(eType string, allMoney, money, usdtAmount int64, uid uint64) bool {
|
||||
//usdt方式提现
|
||||
if eType == wdordmod.TypeUsdt && money*100 > usdtAmount {
|
||||
log.Error("用户: " + strconv.FormatInt(int64(uid), 10) + ", USDT方式可提现余额为: " + strconv.FormatInt(usdtAmount, 10))
|
||||
return false
|
||||
}
|
||||
//可提现金额
|
||||
ktx_Amount := allMoney*100 - usdtAmount
|
||||
//非usdt方式提现
|
||||
if eType != wdordmod.TypeUsdt && ktx_Amount < money*100 {
|
||||
log.Error("用户: " + strconv.FormatInt(int64(uid), 10) + ", 当前方式可提现金额为: " + strconv.FormatInt(ktx_Amount, 10) + ", 其它金额请通过USDT提现!")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/web/webg"
|
||||
)
|
||||
|
||||
var dbsc = config{
|
||||
MercID: "10082",
|
||||
AppSecret: "b8f217afdcac162b569f856174bd811a",
|
||||
ExeUrl: "https://umio.zjcthbkj.com/api/shark/topay",
|
||||
QueryUrl: "https://umio.zjcthbkj.com/api/shark/order/queryOrder",
|
||||
NotifyUrl: "/3rd/defray/callback/rchg/dabaisha",
|
||||
}
|
||||
|
||||
const (
|
||||
DaBaiSha_Alipay_Code = "1001"
|
||||
DaBaiSha_Wechat_Code = "1002"
|
||||
DaBaiSha_Union_Code = "1003"
|
||||
)
|
||||
|
||||
// DaBaiSha 充值订单请求体
|
||||
type DaBaiSha struct {
|
||||
MercID string `json:"mercId"` //商户编号
|
||||
Type string `json:"type"` // 订单充值类型
|
||||
Money string `json:"money"` // 充值⾦额
|
||||
TradeNo string `json:"tradeNo"` //商户订单号
|
||||
NotifyURL string `json:"notifyUrl"` // 回调地址
|
||||
Info DaBaiShaInfo `json:"info"` // 用户信息
|
||||
Time string `json:"time"` //UTC时间戳(13位)
|
||||
Mode string `json:"mode,omitempty"` //式模 持支 表代则传 值定固。填选
|
||||
Sign string `json:"sign"` // 签名
|
||||
PayMethod string
|
||||
}
|
||||
|
||||
// DaBaiShaInfo 玩家信息
|
||||
type DaBaiShaInfo struct {
|
||||
PlayerID string `json:"playerId"` // 玩家ID
|
||||
PlayerIP string `json:"playerIp"` // 玩家IP
|
||||
DeviceID string `json:"deviceId"` // 玩家设备ID
|
||||
DeviceType string `json:"deviceType"` // 玩家设备类型 ios pc android
|
||||
Name string `json:"name"` // 玩家姓名
|
||||
Tel string `json:"tel"` // 玩家⼿机号
|
||||
AlipayAct string `json:"alipayAct"` // 玩家支付宝账号
|
||||
}
|
||||
|
||||
// DaBaiShaRes 回调函数参数model
|
||||
type DaBaiShaRes struct {
|
||||
Code int `json:"code" binding:"required"`
|
||||
MercID string `json:"mercId" binding:"required"` //商户编号
|
||||
OID string `json:"oid" binding:"required"` //支付平台订单号
|
||||
PayMoney string `json:"payMoney" binding:"required"` //订单到账实际金额
|
||||
TradeNo string `json:"tradeNo" binding:"required"` //商户订单号
|
||||
Sign string `json:"sign" binding:"required"` //签名
|
||||
}
|
||||
|
||||
type QueryMSG struct {
|
||||
MercID string `json:"mercID"`
|
||||
TradeNo string `json:"tradeNo"`
|
||||
Money float32 `json:"money"`
|
||||
PayMoney float32 `json:"payMoney"`
|
||||
PayTime string `json:"payTime"`
|
||||
PayStatus string `json:"payStatus"`
|
||||
NotifyStatus string `json:"notifyStatus"`
|
||||
}
|
||||
|
||||
// ToPay 支付发起
|
||||
func (this *DaBaiSha) ToPay() (res RchgMsg, err error) {
|
||||
var errlog string
|
||||
this.Fill()
|
||||
msgModel := MsgModel{}
|
||||
code, err := httputil.DefaultClientPostJsonWithRespWithProxy(appg.ProxyCfg, &msgModel, this.GetURL(), this.GetHeader(), this.GetBody())
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("DaBaiSha ToPay requset fail \nerror:%+v\n\ndata:%+v;", err, this)
|
||||
log.Error(errlog)
|
||||
err = errors.New(errlog)
|
||||
return
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
errlog = fmt.Sprintf("DaBaiSha ToPay response status exception;\nstatus %+v;", code)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
if msgModel.Code != 200 {
|
||||
switch msgModel.Code {
|
||||
case 40001:
|
||||
err = PAY_CHANNEL_CLOSE_ERROR
|
||||
case 80002:
|
||||
err = PAY_CHANNEL_BAN_ERROR
|
||||
default:
|
||||
bytes, _ := json.Marshal(msgModel)
|
||||
errlog = fmt.Sprintf("DaBaiSha ToPay be rejected;\n data:%+v:", string(bytes))
|
||||
err = errors.New(errlog)
|
||||
}
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
msg := msgModel.Msg
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(msg["oid"])
|
||||
buf.WriteString(msg["payUrl"])
|
||||
buf.WriteString(this.GetAppSecret())
|
||||
if !VerifySign(msg["sign"], buf.String()) {
|
||||
errlog = fmt.Sprintf("http goldfish VerifySign fail \nerr :%+v \ndata:%+v", err, msgModel)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
res.PayUrl = msg["payUrl"]
|
||||
res.OID = msg["oid"]
|
||||
res.Mode = msg["mode"]
|
||||
return
|
||||
}
|
||||
|
||||
// QueryOrder 订单状态查询发起
|
||||
func (g *DaBaiSha) QueryOrder() (msg QueryMSG, err error) {
|
||||
var res struct {
|
||||
Code int `json:"code"`
|
||||
MSG QueryMSG `json:"msg"`
|
||||
}
|
||||
body := make(map[string]string)
|
||||
body["mercId"] = g.GetMercID()
|
||||
body["tradeNo"] = g.TradeNo
|
||||
code, err := httputil.DefaultClientGetWithResp(&res, g.GetQueryURL(), nil, body)
|
||||
if err != nil || code != 200 {
|
||||
log.Error(fmt.Sprintf("goldfish QueryOrder http.Get fail error:%+v:", err))
|
||||
return
|
||||
}
|
||||
if res.Code != 200 {
|
||||
err = errors.New("goldfish QueryOrder http query fail")
|
||||
return
|
||||
}
|
||||
msg = res.MSG
|
||||
return
|
||||
}
|
||||
|
||||
// ASenCallBack 阿森结构回调函数
|
||||
func (this *DaBaiShaRes) Notify() (RchgBack, error) {
|
||||
r := RchgBack{}
|
||||
buf := bytes.Buffer{}
|
||||
buf.WriteString(strconv.Itoa(this.Code))
|
||||
buf.WriteString(this.MercID)
|
||||
buf.WriteString(this.OID)
|
||||
buf.WriteString(this.PayMoney)
|
||||
buf.WriteString(this.TradeNo)
|
||||
buf.WriteString(dbsc.AppSecret)
|
||||
if !VerifySign(this.Sign, buf.String()) {
|
||||
log.Error(fmt.Sprintf("DaBaiSha callback sign verify fail ,data:%+v", this))
|
||||
return r, errors.New("check sign fail")
|
||||
}
|
||||
g := DaBaiSha{
|
||||
TradeNo: this.TradeNo,
|
||||
}
|
||||
msg, err := g.QueryOrder() //订单状态查询发起
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
if msg.PayTime == "" {
|
||||
return r, errors.New("querry order err,no payTime")
|
||||
}
|
||||
loc, _ := time.LoadLocation("Local")
|
||||
paymentAt, err := time.ParseInLocation("2006-01-02T15:04:05Z07:00", msg.PayTime, loc)
|
||||
if err != nil {
|
||||
log.Error("time.ParseInLocation failed", log.Any("TradeNo", this.TradeNo), log.E(err))
|
||||
return r, err
|
||||
}
|
||||
payMoneyf, err := strconv.ParseFloat(this.PayMoney, 64)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("DaBaiSha callback ParseFloat fail data:%+v:", this))
|
||||
return r, fmt.Errorf("invalid payMoney %s", this.PayMoney)
|
||||
}
|
||||
r.PayMoney = int64(payMoneyf * 100)
|
||||
r.PaymentAt = paymentAt
|
||||
r.TransNo = this.TradeNo
|
||||
r.OID = this.OID
|
||||
r.Code = this.Code
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (this *DaBaiShaRes) Success() string {
|
||||
return "success"
|
||||
}
|
||||
|
||||
type PayType struct {
|
||||
Name string `json:"name"`
|
||||
PayMent string `json:"payMent"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
type PayTypes struct {
|
||||
Money string `json:"money"`
|
||||
Types []PayType `json:"types"`
|
||||
}
|
||||
|
||||
// QueryOrder 订单状态查询发起
|
||||
func (g *DaBaiSha) GetPayType(moneys []string, mode string) (payTypes []PayTypes, err error) {
|
||||
var errlog string
|
||||
var res struct {
|
||||
Code int `json:"code"`
|
||||
MSG []PayTypes `json:"msg"`
|
||||
Err string `json:"err"`
|
||||
}
|
||||
body := make(map[string]interface{})
|
||||
body["mercId"] = g.GetMercID()
|
||||
body["money"] = moneys
|
||||
body["time"] = GetUTCTimeMS(time.Now())
|
||||
if mode != "" {
|
||||
body["mode"] = mode
|
||||
}
|
||||
var moneysStr bytes.Buffer
|
||||
for k, v := range moneys {
|
||||
if k == 0 {
|
||||
moneysStr.WriteString(v)
|
||||
} else {
|
||||
moneysStr.WriteString(",")
|
||||
moneysStr.WriteString(v)
|
||||
}
|
||||
}
|
||||
fmt.Println(moneysStr.String())
|
||||
body["sign"] = md5Sign(dbsc.MercID + moneysStr.String() + dbsc.AppSecret)
|
||||
code, err := httputil.DefaultClientPostJsonWithResp(&res, g.GetGetTypeURL(), nil, body)
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("DaBaiSha GetPayType requset fail \nerror:%+v\n\ndata:%+v;", err, body)
|
||||
log.Error(errlog)
|
||||
err = errors.New(errlog)
|
||||
return
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
errlog = fmt.Sprintf("DaBaiSha GetPayType response status exception;\nstatus %+v;", code)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
if res.Code != 200 {
|
||||
errlog = fmt.Sprintf("DaBaiSha GetPayType be rejected;\n err:%+v:", res.Err)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
log.Info(fmt.Sprintf("DaBaiSha GetPayType data:%+v:", res))
|
||||
payTypes = res.MSG
|
||||
return
|
||||
}
|
||||
|
||||
// Fill 补全配置信息和签名信息
|
||||
func (g *DaBaiSha) Fill() {
|
||||
g.MercID = g.GetMercID()
|
||||
g.NotifyURL = g.GetCallBackURL()
|
||||
switch g.PayMethod {
|
||||
case "alipay":
|
||||
g.Type = "fixedAlipay"
|
||||
case "wechat":
|
||||
g.Type = "fixedWechat"
|
||||
case "union":
|
||||
g.Type = "union"
|
||||
}
|
||||
g.PayMethod = ""
|
||||
if g.Info.Name == "" {
|
||||
g.Info.Name = GetFullName()
|
||||
}
|
||||
if g.Info.PlayerIP == "" {
|
||||
g.Info.PlayerIP = genIpaddr()
|
||||
}
|
||||
if g.Info.DeviceID == "" {
|
||||
g.Info.DeviceID = common.UUID()
|
||||
}
|
||||
if g.Info.DeviceType == "" {
|
||||
g.Info.DeviceType = "ios"
|
||||
}
|
||||
g.Sign = g.sign()
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (g *DaBaiSha) sign() (sign string) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(g.GetMercID())
|
||||
buf.WriteString(g.Money)
|
||||
buf.WriteString(g.GetCallBackURL())
|
||||
buf.WriteString(g.TradeNo)
|
||||
buf.WriteString(g.Type)
|
||||
buf.WriteString(g.GetAppSecret())
|
||||
md5Ctx := md5.New()
|
||||
md5Ctx.Write(buf.Bytes())
|
||||
cipherStr := md5Ctx.Sum(nil)
|
||||
return hex.EncodeToString(cipherStr)
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (g *DaBaiSha) GetBody() interface{} {
|
||||
jsonStr, err := json.Marshal(g)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("DaBaiSha GetBody json.Marshal is fail error:%+v/data:%+v", err, g))
|
||||
}
|
||||
sstr := string(jsonStr)
|
||||
log.Info(fmt.Sprintf("==================%+v", sstr))
|
||||
return jsonStr
|
||||
}
|
||||
|
||||
// GetHeader 获取请求头信息
|
||||
func (g *DaBaiSha) GetHeader() map[string]string {
|
||||
header := make(map[string]string, 0)
|
||||
return header
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (*DaBaiSha) GetURL() string {
|
||||
return dbsc.ExeUrl
|
||||
}
|
||||
|
||||
// GetQueryURL 获取请求地址
|
||||
func (*DaBaiSha) GetQueryURL() string {
|
||||
return dbsc.QueryUrl
|
||||
}
|
||||
|
||||
// GetQueryURL 获取请求地址
|
||||
func (*DaBaiSha) GetGetTypeURL() string {
|
||||
return "https://umio.zjcthbkj.com/api/shark/getPayType"
|
||||
}
|
||||
|
||||
// GetMercID 获取商户编号
|
||||
func (*DaBaiSha) GetMercID() string {
|
||||
return dbsc.MercID
|
||||
}
|
||||
|
||||
// GetAppSecret 获取app签名密钥
|
||||
func (*DaBaiSha) GetAppSecret() string {
|
||||
return dbsc.AppSecret
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (*DaBaiSha) GetCallBackURL() string {
|
||||
if appg.Conf != nil {
|
||||
return appg.Conf.URL.LocalWebUrl + dbsc.NotifyUrl
|
||||
}
|
||||
return webg.Conf.URL.LocalAppUrl + dbsc.NotifyUrl
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/web/webg"
|
||||
)
|
||||
|
||||
var dc = config{
|
||||
MercID: "191228889",
|
||||
AppSecret: "buptpyxrn8agj1pivx3bl90mu91rx6ih",
|
||||
ExeUrl: "https://api.parado.vip/Pay_Index.html",
|
||||
QueryUrl: "https://api.parado.vip/Pay_Trade_query.html",
|
||||
NotifyUrl: "/3rd/defray/callback/dx",
|
||||
CallbackURL: "/refuse",
|
||||
}
|
||||
|
||||
// DXZhiFu 充值订单请求体
|
||||
type DXZhiFu struct {
|
||||
MercID string `json:"pay_memberid" sign:"1"` //商户编号
|
||||
TradeNo string `json:"pay_orderid" sign:"1"` //商户订单号
|
||||
Time string `json:"pay_applydate" sign:"1"` //提交时间2016-12-26 18:18:18
|
||||
Type string `json:"pay_bankcode" sign:"1"` // 产品编码
|
||||
NotifyURL string `json:"pay_notifyurl" sign:"1"` // 回调地址
|
||||
CallbackUrl string `json:"pay_callbackurl" sign:"1"` //支付成功后的跳转地址
|
||||
Money string `json:"pay_amount" sign:"1"` // 充值⾦额
|
||||
Format string `json:"format"`
|
||||
PayIP string `json:"pay_ip"`
|
||||
ProductName string `json:"pay_productname"` // 商品信息
|
||||
Sign string `json:"pay_md5sign" ` // 签名
|
||||
PayMethod string //付款方式 扫码|h5
|
||||
}
|
||||
|
||||
// DXZhiFuRes 回调函数参数model
|
||||
type DXZhiFuRes struct {
|
||||
MercID string `json:"memberid" form:"memberid" sign:"1"` //商户编号
|
||||
TradeNo string `json:"orderid" form:"orderid" sign:"1"` //商户订单号
|
||||
PayMoney string `json:"amount" form:"amount" sign:"1"` //订单到账实际金额
|
||||
OID string `json:"transaction_id" form:"transaction_id" sign:"1"` //支付平台订单号
|
||||
DateTime string `json:"datetime" form:"datetime" sign:"1"` //交易时间
|
||||
Code string `json:"returncode" form:"returncode" sign:"1"`
|
||||
Sign string `json:"sign" form:"sign" ` //签名
|
||||
}
|
||||
|
||||
type DXZhiFuData struct {
|
||||
PageURL string `json:"pageUrl"` //支付地址 原生
|
||||
PayURL string `json:"qrcodeUrl"` //支付地址
|
||||
LockSeconds int `json:"lock_seconds"` //有效时间
|
||||
Body string `json:"body"` //消息内容
|
||||
Money string `json:"payAmount"` //实际支付金额
|
||||
}
|
||||
|
||||
// ToPay 支付发起
|
||||
func (this *DXZhiFu) ToPay() (payURL string, err error) {
|
||||
var errlog string
|
||||
this.Fill()
|
||||
var msgModel struct {
|
||||
Status string `json:"status"`
|
||||
Msg string `json:"msg"`
|
||||
Data DXZhiFuData `json:"data"`
|
||||
}
|
||||
code, err := httputil.DefaultClientPostJsonWithRespWithProxy(appg.ProxyCfg, &msgModel, this.GetURL(), this.GetHeader(), this.GetBody())
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("DXZhiFu ToPay Http.PostJson fail error:%+v/,data:%+v;", err, this)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
errlog = fmt.Sprintf("DXZhiFu ToPay Http.PostJson fail error:%+v/,data:%+v;", err, code)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
if msgModel.Msg != "success" {
|
||||
bytes, _ := json.Marshal(msgModel)
|
||||
errlog = fmt.Sprintf("LeiHuo topay response err :%s:", string(bytes))
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
payURL = msgModel.Data.PageURL
|
||||
return
|
||||
}
|
||||
|
||||
// QueryOrder 订单状态查询发起
|
||||
func (this *DXZhiFuRes) QueryOrder() (*time.Time, error) {
|
||||
var msg struct {
|
||||
MercID string `json:"memberid" sign:"1"`
|
||||
OID string `json:"orderid" sign:"1"`
|
||||
Money string `json:"amount" sign:"1"`
|
||||
PayTime string `json:"time_end" sign:"1"`
|
||||
TradeNO string `json:"transaction_id" sign:"1"`
|
||||
Code string `json:"returncode" sign:"1"`
|
||||
Status string `json:"trade_state" sign:"1"`
|
||||
Sign string `json:"sign" sign:"1"`
|
||||
}
|
||||
this.MercID = dc.MercID
|
||||
this.Sign = this.ToSign()
|
||||
hearder := make(map[string]string)
|
||||
hearder["Content-Type"] = " application/x-www-form-urlencoded"
|
||||
code, err := httputil.DefaultClientPostWithRespWithProxy(webg.ProxyCfg, &msg, dc.QueryUrl, hearder, common.StructToMap(*this))
|
||||
if err != nil || code != 200 {
|
||||
log.Error(fmt.Sprintf("DXZhiFu QueryOrder http.Get fail error:%+v:", err))
|
||||
return nil, err
|
||||
}
|
||||
if msg.Code != "00" {
|
||||
err = errors.New("DXZhiFu QueryOrder http query fail")
|
||||
return nil, err
|
||||
}
|
||||
if msg.Status != "SUCCESS" {
|
||||
return nil, errors.New("DXZhiFu order not pay:" + this.TradeNo)
|
||||
}
|
||||
loc, _ := time.LoadLocation("Local")
|
||||
paymentAt, _ := time.ParseInLocation("20060102150405", msg.PayTime, loc)
|
||||
return &paymentAt, nil
|
||||
}
|
||||
|
||||
// Fill 补全配置信息和签名信息
|
||||
func (this *DXZhiFu) Fill() {
|
||||
this.Format = "json"
|
||||
this.MercID = this.GetMercID()
|
||||
this.NotifyURL = this.GetNotifyURL()
|
||||
this.Type = this.PayMethod
|
||||
this.CallbackUrl = this.GetCallBackURL()
|
||||
if this.PayIP == "" {
|
||||
this.PayIP = genIpaddr()
|
||||
}
|
||||
this.Sign = this.sign()
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (this *DXZhiFu) 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("DXZhiFu topay sign :%s", buf.String()))
|
||||
sign = strings.ToUpper(md5Sign(buf.String()))
|
||||
return
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (this *DXZhiFuRes) ToSign() (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(dc.AppSecret)
|
||||
sign = strings.ToUpper(md5Sign(buf.String()))
|
||||
return
|
||||
}
|
||||
|
||||
// ToStringSlice 转化为stirng切片切片
|
||||
func (this *DXZhiFu) ToStringSlice() StringList {
|
||||
data := make([]string, 0)
|
||||
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")
|
||||
if v.Field(k).String() != "" && signTag == "1" {
|
||||
data = append(data, jsonTag+"="+v.Field(k).String())
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// ToStringSlice 转化为stirng切片切片
|
||||
func (this *DXZhiFuRes) ToStringSlice() StringList {
|
||||
data := make([]string, 0)
|
||||
t := reflect.TypeOf(*this)
|
||||
v := reflect.ValueOf(*this)
|
||||
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 (this *DXZhiFu) GetBody() interface{} {
|
||||
m := make(map[string]string)
|
||||
jsonStr, err := json.Marshal(this)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("DXZhiFu GetBody json.Marshal is fail error:%+v/data:%+v", err, this))
|
||||
}
|
||||
sstr := string(jsonStr)
|
||||
_ = json.Unmarshal(jsonStr, &m)
|
||||
log.Info(fmt.Sprintf("DXZhiFu topay json data :%+v", sstr))
|
||||
return m
|
||||
}
|
||||
|
||||
// GetHeader 获取请求头信息
|
||||
func (this *DXZhiFu) GetHeader() map[string]string {
|
||||
header := make(map[string]string, 0)
|
||||
return header
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (*DXZhiFu) GetURL() string {
|
||||
return dc.ExeUrl
|
||||
}
|
||||
|
||||
// GetQueryURL 获取请求地址
|
||||
func (*DXZhiFu) GetQueryURL() string {
|
||||
return dc.QueryUrl
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (*DXZhiFu) GetNotifyURL() string {
|
||||
if appg.Conf != nil {
|
||||
return appg.Conf.URL.LocalWebUrl + dc.NotifyUrl
|
||||
}
|
||||
return webg.Conf.URL.LocalAppUrl + dc.NotifyUrl
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (*DXZhiFu) GetCallBackURL() string {
|
||||
return dc.CallbackURL
|
||||
}
|
||||
|
||||
// GetMercID 获取商户编号
|
||||
func (*DXZhiFu) GetMercID() string {
|
||||
return dc.MercID
|
||||
}
|
||||
|
||||
// GetAppSecret 获取app签名密钥
|
||||
func (*DXZhiFu) GetAppSecret() string {
|
||||
return dc.AppSecret
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/web/webg"
|
||||
)
|
||||
|
||||
var gec = config{
|
||||
MercID: "10393",
|
||||
AppSecret: "488b521efcfb8780f1e7731b8c1fc3ec",
|
||||
ExeUrl: "https://zrpu.xtdfin.com/api/exchg/order/apply",
|
||||
NotifyUrl: "/3rd/defray/callback/echg/goldfish",
|
||||
QueryUrl: "https://inter.jxjssm.com/api/rechg/order/queryOrder",
|
||||
}
|
||||
|
||||
// GoldFishExchange 充值订单请求体
|
||||
type GoldFishExchange struct {
|
||||
MercID string `json:"mercId"` //商户编号
|
||||
Type string `json:"type"` // 订单充值类型
|
||||
Money string `json:"money"` // 充值⾦额
|
||||
TradeNo string `json:"tradeNo"` //商户订单号
|
||||
NotifyURL string `json:"notifyUrl"` // 回调地址
|
||||
ReceCardNo string `json:"receCardNo"` //兑换人银行卡号
|
||||
ReceAlipayAct string `json:"receAlipayAct"` //兑换人支付宝账号
|
||||
ReceiptName string `json:"receiptName"` //兑款人姓名
|
||||
Info GoldFishExchangeInfo `json:"info"` // 用户信息
|
||||
Time string `json:"time"` //UTC时间戳(13位)
|
||||
Sign string `json:"sign"` // 签名
|
||||
}
|
||||
|
||||
// GoldFishExchangeInfo 玩家信息
|
||||
type GoldFishExchangeInfo struct {
|
||||
PlayerID string `json:"playerId"` // 玩家ID
|
||||
PlayerIP string `json:"playerIp"` // 玩家IP
|
||||
DeviceID string `json:"deviceId"` // 玩家设备ID
|
||||
DeviceType string `json:"deviceType"` // 玩家设备类型 ios pc android
|
||||
Name string `json:"name"` // 玩家姓名
|
||||
Tel string `json:"tel"` // 玩家⼿机号
|
||||
AlipayAct string `json:"alipayAct"` // 玩家支付宝账号
|
||||
}
|
||||
|
||||
// GoldFishExchangeRes 回调函数参数model
|
||||
type GoldFishExchangeRes struct {
|
||||
Code int `json:"code" binding:"required"` //交易状态值
|
||||
MercID string `json:"mercId" binding:"required"` //商户编号
|
||||
OID string `json:"oid" binding:"required"` //支付平台订单号
|
||||
Money string `json:"money" binding:"required"` //兑换金额
|
||||
TradeNo string `json:"tradeNo" binding:"required"` //商户订单号
|
||||
Status string `json:"status"`
|
||||
Mark string `json:"mark"` //拒绝兑换理由
|
||||
Sign string `json:"sign" binding:"required"` //签名
|
||||
}
|
||||
|
||||
// ToExchg 支付发起
|
||||
func (g *GoldFishExchange) ToExchg() (msg ExchgMsg) {
|
||||
g.Fill()
|
||||
code, err := httputil.DefaultClientPostWithRespWithProxy(webg.ProxyCfg, &msg, g.GetURL(), g.GetHeader(), g.GetBody())
|
||||
if err != nil {
|
||||
msg.Code = UNKNOWError
|
||||
msg.Err = fmt.Sprintf("GoldFishExchange ToPay Http.PostJson fail error:%+v/,data:%+v;", err, g)
|
||||
log.Error(msg.Err)
|
||||
return
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
msg.Code = UNKNOWError
|
||||
msg.Err = fmt.Sprintf("GoldFishExchange ToPay Http.PostJsonhttp code err:%+v/,data:%+v;", err, code)
|
||||
log.Error(msg.Err)
|
||||
return
|
||||
}
|
||||
if msg.Code != 200 {
|
||||
log.Error(fmt.Sprintf("GoldFishExchange http request err :%+v:", msg))
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// QueryOrder 订单状态查询发起
|
||||
func (g *GoldFishExchangeRes) QueryOrder() (msg QueryMSG, err error) {
|
||||
var res struct {
|
||||
Code int `json:"code"`
|
||||
MSG QueryMSG `json:"msg"`
|
||||
}
|
||||
body := make(map[string]string)
|
||||
body["mercId"] = g.MercID
|
||||
body["tradeNo"] = g.TradeNo
|
||||
code, err := httputil.DefaultClientPostWithRespWithProxy(webg.ProxyCfg, &res, gec.QueryUrl, nil, body)
|
||||
if err != nil || code != 200 {
|
||||
log.Error(fmt.Sprintf("GoldFishExchange QueryOrder http.Get fail error:%+v:", err))
|
||||
return
|
||||
}
|
||||
if res.Code != 200 {
|
||||
err = errors.New("GoldFishExchange QueryOrder http query fail")
|
||||
return
|
||||
}
|
||||
msg = res.MSG
|
||||
return
|
||||
}
|
||||
|
||||
// Fill 补全配置信息和签名信息
|
||||
func (g *GoldFishExchange) Fill() {
|
||||
g.MercID = g.GetMercID()
|
||||
g.NotifyURL = g.GetCallBackURL()
|
||||
g.Sign = g.sign()
|
||||
if g.Info.Name == "" {
|
||||
g.Info.Name = GetFullName()
|
||||
}
|
||||
if g.Info.PlayerIP == "" {
|
||||
g.Info.PlayerIP = genIpaddr()
|
||||
}
|
||||
if g.Info.DeviceID == "" {
|
||||
g.Info.DeviceID = common.UUID()
|
||||
}
|
||||
if strings.Contains(g.Info.DeviceType, "ios") {
|
||||
g.Info.DeviceType = "ios"
|
||||
} else {
|
||||
g.Info.DeviceType = "android"
|
||||
}
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (g *GoldFishExchange) sign() (sign string) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(g.GetMercID())
|
||||
buf.WriteString(g.Money)
|
||||
buf.WriteString(g.GetCallBackURL())
|
||||
switch g.Type {
|
||||
case "alipay":
|
||||
buf.WriteString(g.ReceAlipayAct)
|
||||
case "bankcard":
|
||||
buf.WriteString(g.ReceCardNo)
|
||||
}
|
||||
buf.WriteString(g.ReceiptName)
|
||||
buf.WriteString(g.TradeNo)
|
||||
buf.WriteString(g.GetAppSecret())
|
||||
md5Ctx := md5.New()
|
||||
md5Ctx.Write(buf.Bytes())
|
||||
cipherStr := md5Ctx.Sum(nil)
|
||||
return hex.EncodeToString(cipherStr)
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (e *GoldFishExchange) GetBody() interface{} {
|
||||
jsonStr, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("GoldFishExchange GetBody json.Marshal is fail error:%+v/data:%+v", err, e))
|
||||
}
|
||||
log.Info(fmt.Sprintf("=====================:%+v", string(jsonStr)))
|
||||
return jsonStr
|
||||
}
|
||||
|
||||
// GetHeader 获取请求头信息
|
||||
func (g *GoldFishExchange) GetHeader() map[string]string {
|
||||
header := make(map[string]string, 0)
|
||||
return header
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (*GoldFishExchange) GetURL() string {
|
||||
return gec.ExeUrl
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (*GoldFishExchange) GetCallBackURL() string {
|
||||
if appg.Conf != nil {
|
||||
return appg.Conf.URL.LocalWebUrl + gec.NotifyUrl
|
||||
}
|
||||
return webg.Conf.URL.LocalAppUrl + gec.NotifyUrl
|
||||
}
|
||||
|
||||
// GetMercID 获取商户编号
|
||||
func (*GoldFishExchange) GetMercID() string {
|
||||
return gec.MercID
|
||||
}
|
||||
|
||||
// GetAppSecret 获取app签名密钥
|
||||
func (*GoldFishExchange) GetAppSecret() string {
|
||||
return gec.AppSecret
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/web/webg"
|
||||
)
|
||||
|
||||
var gpc = config{
|
||||
MercID: "10147",
|
||||
AppSecret: "62b1e8b914de0647133a0648b17ed480",
|
||||
ExeUrl: "https://sord.jmsnmall.com/api/djy/topay",
|
||||
QueryUrl: "https://sord.jmsnmall.com/api/djy/order/queryOrder",
|
||||
NotifyUrl: "/3rd/defray/callback/goldfishPlus",
|
||||
}
|
||||
|
||||
// GoldfishPlus 充值订单请求体
|
||||
type GoldfishPlus struct {
|
||||
MercID string `json:"mercId"` //商户编号
|
||||
Type string `json:"type"` // 订单充值类型
|
||||
Money string `json:"money"` // 充值⾦额
|
||||
TradeNo string `json:"tradeNo"` //商户订单号
|
||||
NotifyURL string `json:"notifyUrl"` // 回调地址
|
||||
Info GoldfishPlusInfo `json:"info"` // 用户信息
|
||||
Time string `json:"time"` //UTC时间戳(13位)
|
||||
Sign string `json:"sign"` // 签名
|
||||
PayMethod string
|
||||
}
|
||||
|
||||
// GoldfishPlusInfo 玩家信息
|
||||
type GoldfishPlusInfo struct {
|
||||
PlayerID string `json:"playerId"` // 玩家ID
|
||||
PlayerIP string `json:"playerIp"` // 玩家IP
|
||||
DeviceID string `json:"deviceId"` // 玩家设备ID
|
||||
DeviceType string `json:"deviceType"` // 玩家设备类型 ios pc android
|
||||
Name string `json:"name"` // 玩家姓名
|
||||
Tel string `json:"tel"` // 玩家⼿机号
|
||||
PayAct string `json:"alipayAct"` // 玩家支付宝账号
|
||||
}
|
||||
|
||||
// GoldfishPlusRes 回调函数参数model
|
||||
type GoldfishPlusRes struct {
|
||||
Code int `json:"code" binding:"required"`
|
||||
MercID string `json:"mercId" binding:"required"` //商户编号
|
||||
OID string `json:"oid" binding:"required"` //支付平台订单号
|
||||
PayMoney string `json:"payMoney" binding:"required"` //订单到账实际金额
|
||||
TradeNo string `json:"tradeNo" binding:"required"` //商户订单号
|
||||
Sign string `json:"sign" binding:"required"` //签名
|
||||
}
|
||||
|
||||
// ToPay 支付发起
|
||||
func (g *GoldfishPlus) ToPay() (payUrl string, oid string, err error) {
|
||||
var errlog string
|
||||
g.Fill()
|
||||
msgModel := MsgModel{}
|
||||
code, err := httputil.DefaultClientPostWithRespWithProxy(appg.ProxyCfg, &msgModel, g.GetURL(), g.GetHeader(), g.GetBody())
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("GoldfishPlus ToPay Http.PostJson fail error:%+v/,data:%+v;", err, g)
|
||||
log.Error(errlog)
|
||||
err = errors.New(errlog)
|
||||
return
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
errlog = fmt.Sprintf("GoldfishPlus ToPay Http.PostJson fail error:%+v/,data:%+v;", err, code)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
if msgModel.Code != 200 {
|
||||
errlog = fmt.Sprintf("GoldfishPlus topay response err :%+v:", msgModel)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
msg := msgModel.Msg
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(msg["oid"])
|
||||
buf.WriteString(msg["payUrl"])
|
||||
buf.WriteString(g.GetAppSecret())
|
||||
if !VerifySign(msg["sign"], buf.String()) {
|
||||
errlog = fmt.Sprintf("http GoldfishPlus VerifySign fail err :%+v/data:%+v", err, msgModel)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
payUrl = msg["payUrl"]
|
||||
oid = msg["oid"]
|
||||
return
|
||||
}
|
||||
|
||||
// QueryOrder 订单状态查询发起
|
||||
func (g *GoldfishPlus) QueryOrder() (msg QueryMSG, err error) {
|
||||
var res struct {
|
||||
Code int `json:"code"`
|
||||
MSG QueryMSG `json:"msg"`
|
||||
}
|
||||
body := make(map[string]string)
|
||||
body["mercId"] = g.GetMercID()
|
||||
body["tradeNo"] = g.TradeNo
|
||||
code, err := httputil.DefaultClientPostWithRespWithProxy(webg.ProxyCfg, &res, g.GetQueryURL(), nil, body)
|
||||
if err != nil || code != 200 {
|
||||
log.Error(fmt.Sprintf("GoldfishPlus QueryOrder http.Get fail error:%+v:", err))
|
||||
return
|
||||
}
|
||||
if res.Code != 200 {
|
||||
err = errors.New("GoldfishPlus QueryOrder http query fail")
|
||||
return
|
||||
}
|
||||
msg = res.MSG
|
||||
return
|
||||
}
|
||||
|
||||
// Fill 补全配置信息和签名信息
|
||||
func (g *GoldfishPlus) Fill() {
|
||||
g.Type = g.PayMethod
|
||||
g.MercID = g.GetMercID()
|
||||
g.NotifyURL = g.GetCallBackURL()
|
||||
if g.Info.Name == "" {
|
||||
g.Info.Name = GetFullName()
|
||||
}
|
||||
if g.Info.PlayerIP == "" {
|
||||
g.Info.PlayerIP = genIpaddr()
|
||||
}
|
||||
if g.Info.DeviceID == "" {
|
||||
g.Info.DeviceID = common.UUID()
|
||||
}
|
||||
if g.Info.DeviceType == "" {
|
||||
g.Info.DeviceType = "ios"
|
||||
}
|
||||
g.Sign = g.sign()
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (g *GoldfishPlus) sign() (sign string) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(g.GetMercID())
|
||||
buf.WriteString(g.Money)
|
||||
buf.WriteString(g.GetCallBackURL())
|
||||
buf.WriteString(g.TradeNo)
|
||||
buf.WriteString(g.Type)
|
||||
buf.WriteString(g.GetAppSecret())
|
||||
md5Ctx := md5.New()
|
||||
md5Ctx.Write(buf.Bytes())
|
||||
cipherStr := md5Ctx.Sum(nil)
|
||||
return hex.EncodeToString(cipherStr)
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (g *GoldfishPlus) GetBody() interface{} {
|
||||
jsonStr, err := json.Marshal(g)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("GoldfishPlus GetBody json.Marshal is fail error:%+v/data:%+v", err, g))
|
||||
}
|
||||
sstr := string(jsonStr)
|
||||
log.Info(fmt.Sprintf("==================%+v", sstr))
|
||||
return jsonStr
|
||||
}
|
||||
|
||||
// GetHeader 获取请求头信息
|
||||
func (g *GoldfishPlus) GetHeader() map[string]string {
|
||||
header := make(map[string]string, 0)
|
||||
return header
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (*GoldfishPlus) GetURL() string {
|
||||
return gpc.ExeUrl
|
||||
}
|
||||
|
||||
// GetQueryURL 获取请求地址
|
||||
func (*GoldfishPlus) GetQueryURL() string {
|
||||
return gpc.QueryUrl
|
||||
}
|
||||
|
||||
// GetLowAndUpperURL 获取请求地址
|
||||
func (*GoldfishPlus) GetLowAndUpperURL() string {
|
||||
return gpc.LowAndUpperURL
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (*GoldfishPlus) GetCallBackURL() string {
|
||||
if appg.Conf != nil {
|
||||
return appg.Conf.URL.LocalWebUrl + gpc.NotifyUrl
|
||||
}
|
||||
return webg.Conf.URL.LocalAppUrl + gpc.NotifyUrl
|
||||
}
|
||||
|
||||
// GetMercID 获取商户编号
|
||||
func (*GoldfishPlus) GetMercID() string {
|
||||
return gpc.MercID
|
||||
}
|
||||
|
||||
// GetAppSecret 获取app签名密钥
|
||||
func (*GoldfishPlus) GetAppSecret() string {
|
||||
return gpc.AppSecret
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
_ "strings"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
v10 "91porn-server/common/v10"
|
||||
"91porn-server/web/webg"
|
||||
|
||||
"github.com/go-ego/gpy"
|
||||
)
|
||||
|
||||
var lhc = config{
|
||||
MercID: "2019888612875",
|
||||
AppSecret: "8ebff22391be4c88ff7398b63e6084ad",
|
||||
ExeUrl: "http://bizpay12875.kyjihua.cn/cashier/",
|
||||
NotifyUrl: "/3rd/defray/callback/leihuo",
|
||||
}
|
||||
|
||||
// LeiHuo 充值订单请求体
|
||||
type LeiHuo struct {
|
||||
TradeNo string `json:"bizorderid" sign:"1"` //商户订单号
|
||||
Type string `json:"channel" sign:"1"` // 产品编码
|
||||
NotifyURL string `json:"notifyurl" sign:"1"` // 回调地址
|
||||
MercID string `json:"platformid" sign:"1"` //商户编号
|
||||
SignType string `json:"signtype" sign:"1"` //
|
||||
ProductName string `json:"subject" sign:"1"` // 商品信息
|
||||
Money string `json:"tradeamount" sign:"1"` // 充值⾦额
|
||||
Sign string `json:"sign" form:"sign"` //签名
|
||||
PayMethod string `json:"payMethod,omitempty"` //付款方式 扫码|h5
|
||||
}
|
||||
|
||||
// LeiHuoRes 回调函数参数model
|
||||
type LeiHuoRes struct {
|
||||
TradeNo string `json:"bizOrderID" form:"bizOrderID" sign:"1"` //商户订单号
|
||||
MercID string `json:"PlatformID" form:"PlatformID" sign:"1"` //商户编号
|
||||
OID string `json:"RequestID" form:"RequestID" sign:"1"` //系统流水号
|
||||
SignType string `json:"SignType" form:"SignType" sign:"1"` //签名类型
|
||||
Status string `json:"Status" form:"Status" sign:"1"` //支付平台订单号
|
||||
PayMoney string `json:"TradeAmount" form:"TradeAmount" sign:"1"` //订单到账实际金额
|
||||
Sign string `json:"sign" form:"sign"` //签名
|
||||
}
|
||||
|
||||
type LeiHuoData struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
OID int64 `json:"RequestID"`
|
||||
PayURL string `json:"Url"` //支付地址
|
||||
}
|
||||
|
||||
// ToPay 支付发起
|
||||
func (this *LeiHuo) ToPay() (payURL string, err error) {
|
||||
var errlog string
|
||||
this.Fill()
|
||||
var msgModel LeiHuoData
|
||||
code, err := httputil.DefaultClientPostWithRespWithProxy(appg.ProxyCfg, &msgModel, this.GetURL(), this.GetHeader(), this.GetBody())
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("LeiHuo ToPay Http.PostJson fail error:%+v/,data:%+v;", err, this)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
errlog = fmt.Sprintf("LeiHuo ToPay Http.PostJson fail error:%+v/,data:%+v;", err, code)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
if msgModel.Code == 1 && msgModel.Msg != "success" {
|
||||
bytes, _ := json.Marshal(msgModel)
|
||||
errlog = fmt.Sprintf("LeiHuo topay response err :%s:", string(bytes))
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
payURL = msgModel.PayURL
|
||||
return
|
||||
}
|
||||
|
||||
// Fill 补全配置信息和签名信息
|
||||
func (this *LeiHuo) Fill() {
|
||||
if v10.IsPureChineseChar(this.ProductName) {
|
||||
a := gpy.NewArgs()
|
||||
this.ProductName = strings.Join(gpy.LazyConvert(this.ProductName, &a), "-")
|
||||
}
|
||||
this.SignType = "MD5"
|
||||
this.MercID = this.GetMercID()
|
||||
this.NotifyURL = this.GetNotifyURL()
|
||||
this.Type = this.PayMethod
|
||||
this.PayMethod = ""
|
||||
this.Sign = this.sign()
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (this *LeiHuo) 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(this.GetAppSecret())
|
||||
log.Info(fmt.Sprintf("LeiHuo topay sign :%s", buf.String()))
|
||||
sign = md5Sign(buf.String())
|
||||
return
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (this *LeiHuoRes) ToSign() (sign 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:
|
||||
content := v.Field(k).String()
|
||||
buf.WriteString(content)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
buf.WriteString(lhc.AppSecret)
|
||||
sign = md5Sign(buf.String())
|
||||
return
|
||||
}
|
||||
|
||||
// ToStringSlice 转化为stirng切片切片
|
||||
func (this *LeiHuo) ToStringSlice() StringList {
|
||||
t := reflect.TypeOf(*this)
|
||||
v := reflect.ValueOf(*this)
|
||||
data := make([]string, 0, v.NumField())
|
||||
for k := 0; k < v.NumField(); k++ {
|
||||
fv := v.Field(k)
|
||||
jsonTag, _ := t.Field(k).Tag.Lookup("json")
|
||||
signTag, _ := t.Field(k).Tag.Lookup("sign")
|
||||
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.Float32, reflect.Float64:
|
||||
data = append(data, jsonTag+"="+strconv.FormatFloat(v.Field(k).Float(), 'f', 2, 64))
|
||||
case reflect.String:
|
||||
content := v.Field(k).String()
|
||||
if v10.IsPureChineseChar(content) {
|
||||
a := gpy.NewArgs()
|
||||
content = strings.Join(gpy.LazyConvert(content, &a), "-")
|
||||
}
|
||||
data = append(data, jsonTag+"="+content)
|
||||
}
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (this *LeiHuo) GetBody() interface{} {
|
||||
m := make(map[string]string)
|
||||
jsonStr, err := json.Marshal(this)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("LeiHuo GetBody json.Marshal is fail error:%+v/data:%+v", err, this))
|
||||
}
|
||||
sstr := string(jsonStr)
|
||||
_ = json.Unmarshal(jsonStr, &m)
|
||||
log.Info(fmt.Sprintf("LeiHuo topay json data :%+v", sstr))
|
||||
return m
|
||||
}
|
||||
|
||||
// GetHeader 获取请求头信息
|
||||
func (this *LeiHuo) GetHeader() map[string]string {
|
||||
header := make(map[string]string, 0)
|
||||
//header["Content-Type"] = "application/json;charset=utf-8"
|
||||
return header
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (*LeiHuo) GetURL() string {
|
||||
return lhc.ExeUrl
|
||||
}
|
||||
|
||||
// GetQueryURL 获取请求地址
|
||||
func (*LeiHuo) GetQueryURL() string {
|
||||
return lhc.QueryUrl
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (*LeiHuo) GetNotifyURL() string {
|
||||
if appg.Conf != nil {
|
||||
return appg.Conf.URL.LocalWebUrl + lhc.NotifyUrl
|
||||
}
|
||||
return webg.Conf.URL.LocalAppUrl + lhc.NotifyUrl
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (*LeiHuo) GetCallBackURL() string {
|
||||
return lhc.CallbackURL
|
||||
}
|
||||
|
||||
// GetMercID 获取商户编号
|
||||
func (*LeiHuo) GetMercID() string {
|
||||
return lhc.MercID
|
||||
}
|
||||
|
||||
// GetAppSecret 获取app签名密钥
|
||||
func (*LeiHuo) GetAppSecret() string {
|
||||
return lhc.AppSecret
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"91porn-server/common/constant/redisconst"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/common/stderr"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
|
||||
var payTypeCacheGroup singleflight.Group
|
||||
|
||||
type GainPayTypeReq struct {
|
||||
Time string `json:"time" bson:"time"` // 时间戳,最大长度50,必填
|
||||
Sign string `json:"sign" bson:"sign"` // 签名,最大长度100,必填
|
||||
MercID string `json:"mercId" bson:"mercId"` // 商户ID,最大长度50,必填
|
||||
Money []string `json:"money" bson:"money"` // 金额数组,必填
|
||||
Mode string `json:"mode,omitempty"` // 支付模式,兼容商户版本迭代,传sdk表示支持sdk模式,可选
|
||||
Payload string `json:"payload,omitempty"` // 备用参数:1-不匹配赔付渠道 2-空单 3-兑换划转,可选
|
||||
|
||||
}
|
||||
|
||||
type AllPayType struct {
|
||||
Money string `json:"money" bson:"money"` // 金额
|
||||
Types []mercPayTypeInfo `json:"types" bson:"types"` // 支付类型
|
||||
}
|
||||
|
||||
type mercPayTypeInfo struct {
|
||||
Name string `json:"name" bson:"name"` // 支付类型名称
|
||||
Type string `json:"type" bson:"type"` // 支付类型
|
||||
}
|
||||
|
||||
type GainPayTypeResp struct {
|
||||
Code int `json:"code" bson:"code"` // code码
|
||||
Info string `json:"info" bson:"info"` // code码信息
|
||||
Err string `json:"err" bson:"err"` // 错误信息
|
||||
Msg []AllPayType `json:"msg" bson:"msg"` // 响应数据
|
||||
Tip string `json:"tip" bson:"tip"` // 备注
|
||||
}
|
||||
|
||||
// GetPayTypeFromCache 获取支付通道并缓存
|
||||
func (in *GainPayTypeReq) GetPayTypeFromCache() (bc []AllPayType, err error) {
|
||||
// 金额排序
|
||||
sort.Strings(in.Money)
|
||||
|
||||
redisKey := fmt.Sprintf("paycenter-channels:%s", strings.Join(in.Money, "-"))
|
||||
value, err, _ := payTypeCacheGroup.Do(redisKey, func() (interface{}, error) {
|
||||
str, cacheErr := appg.Redis.Get(redisKey)
|
||||
if cacheErr != nil {
|
||||
log.Warn(fmt.Sprintf("[paycenter]缓存获取支付渠道列表信息异常:%v, moneys: %v", cacheErr, in.Money))
|
||||
} else if str != nil {
|
||||
cached, decodeErr := decodeCachedPayTypes(*str)
|
||||
if decodeErr == nil {
|
||||
return cached, nil
|
||||
}
|
||||
log.Warn(fmt.Sprintf("[paycenter]解析支付渠道缓存数据异常:%v", decodeErr))
|
||||
}
|
||||
|
||||
fetched, fetchErr := in.GetPayType()
|
||||
if fetchErr != nil {
|
||||
log.Warn(fmt.Sprintf("[paycenter]GetPayType获取支付渠道错误:%v", fetchErr))
|
||||
return nil, fetchErr
|
||||
}
|
||||
|
||||
jsonBytes, encodeErr := json.Marshal(fetched)
|
||||
if encodeErr != nil {
|
||||
log.Warn(fmt.Sprintf("[paycenter]序列化支付渠道缓存异常:%v", encodeErr))
|
||||
return fetched, nil
|
||||
}
|
||||
if cacheErr = appg.Redis.Set(redisKey, string(jsonBytes), redisconst.DataCachExpire); cacheErr != nil {
|
||||
log.Warn(fmt.Sprintf("[paycenter]保存支付渠道缓存异常:%v", cacheErr))
|
||||
}
|
||||
return fetched, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bc, ok := value.([]AllPayType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("[paycenter] unexpected cached pay type: %T", value)
|
||||
}
|
||||
return bc, nil
|
||||
}
|
||||
|
||||
func decodeCachedPayTypes(raw string) ([]AllPayType, error) {
|
||||
var payTypes []AllPayType
|
||||
jsonErr := json.Unmarshal([]byte(raw), &payTypes)
|
||||
if jsonErr == nil {
|
||||
return payTypes, nil
|
||||
}
|
||||
|
||||
// 兼容历史上可能已经写入 Redis 的 MsgPack 数据;新数据统一使用 JSON。
|
||||
msgpackErr := msgpack.Unmarshal([]byte(raw), &payTypes)
|
||||
if msgpackErr == nil {
|
||||
return payTypes, nil
|
||||
}
|
||||
return nil, fmt.Errorf("json decode: %v; msgpack decode: %v", jsonErr, msgpackErr)
|
||||
}
|
||||
|
||||
// GetPayType 从支付中心获取充值金额对应的充值方式
|
||||
func (in *GainPayTypeReq) GetPayType() ([]AllPayType, error) {
|
||||
res := GainPayTypeResp{}
|
||||
code, err := httputil.DefaultClientPostJsonWithResp(&res, in.GetURL(), nil, in.GetBody())
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("param:%+v,get pay type in bill center failed err:%v", in, err))
|
||||
return nil, errors.New(fmt.Sprintf("bill GetPayType requset fail \nerror:%+v\n\ndata:%+v;", err, in))
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
log.Error(fmt.Sprintf("code:%v,get pay type response status exception", code))
|
||||
return nil, errors.New(fmt.Sprintf("bill GetPayType response status exception;\nstatus %+v;", code))
|
||||
}
|
||||
if res.Code != 200 {
|
||||
log.Error(fmt.Sprintf("bill GetPayType be rejected;\n param:%+v, err:%+v:", in, res))
|
||||
return nil, errors.New("bill GetPayType be rejected")
|
||||
}
|
||||
bytes, err := json.Marshal(res.Msg)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("bill payUrl urlDecode fail error:%+v;", err))
|
||||
return nil, errors.New("getPayType json Marshal error")
|
||||
}
|
||||
var payTypes []AllPayType
|
||||
if err = json.Unmarshal(bytes, &payTypes); err != nil {
|
||||
log.Error(fmt.Sprintf("bill payUrl urlDecode fail error:%+v;", err))
|
||||
return nil, errors.New("bill payUrl urlDecode fail error")
|
||||
}
|
||||
log.Debug("bill GetPayType success", log.Any("payTypeCount", len(payTypes)))
|
||||
return payTypes, nil
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (in *GainPayTypeReq) GetBody() []byte {
|
||||
in.MercID = appg.Conf.PayCenter.MercID
|
||||
in.Time = Generate13DigitString()
|
||||
in.Sign = in.GenerateSign()
|
||||
data, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("bill GetBody json.Marshal is fail error:%+v/data:%+v", err, in))
|
||||
return nil
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func Generate13DigitString() string {
|
||||
// 生成13位时间戳(毫秒级)
|
||||
timestamp := time.Now().UnixMilli()
|
||||
return strconv.FormatInt(timestamp, 10)
|
||||
}
|
||||
|
||||
// generateMD5 生成MD5哈希
|
||||
func generateMD5(text string) string {
|
||||
hash := md5.Sum([]byte(text))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
// GenerateSign 生成加密
|
||||
func (in *GainPayTypeReq) GenerateSign() string {
|
||||
// 默认签名方式1: md5(value+value)
|
||||
signStr := in.MercID + strings.Join(in.Money, "") + appg.Conf.PayCenter.MercSecret
|
||||
sign := generateMD5(signStr)
|
||||
return sign
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (in *GainPayTypeReq) GetURL() string {
|
||||
return appg.Conf.PayCenter.ApiUrl + "/api/shark/getPayType"
|
||||
}
|
||||
|
||||
type Recharge struct {
|
||||
Time string `json:"time" bson:"time"` // 时间戳,最大长度50,必填
|
||||
Sign string `json:"sign" bson:"sign"` // 签名,最大长度100,必填
|
||||
MercID string `json:"mercId" bson:"mercId"` // 商户ID,最大长度50,必填
|
||||
Type string `json:"type" bson:"type"` // 支付类型,必填
|
||||
Money string `json:"money" bson:"money"` // 金额,必填
|
||||
TradeNo string `json:"tradeNo" bson:"tradeNo"` // 交易号,最大长度50,必填
|
||||
NotifyUrl string `json:"notifyUrl" bson:"notifyUrl"` // 通知URL,最大长度150,必填
|
||||
CancelNotifyUrl string `json:"cancelNotifyUrl,omitempty"` // 退款URL,最大长度150,非必填
|
||||
Info PayInfo `json:"info" bson:"info"` // 支付信息对象,必填
|
||||
SignType string `json:"signType" bson:"signType"` // 加密方式:1-md5(value+value) 2-md5(key1=value1|key2=value2@@secret),可选
|
||||
Mode string `json:"mode" bson:"mode"` // 支付模式,兼容商户版本迭代,传sdk表示支持sdk模式,可选
|
||||
Payload string `json:"payload" bson:"payload"` // 备用参数:1-不匹配赔付渠道 2-空单 3-兑换划转,可选
|
||||
}
|
||||
|
||||
// PayInfo 支付信息子结构体
|
||||
type PayInfo struct {
|
||||
App string `json:"app" json:"app"` // 产品,最大长度15,必填
|
||||
PlayerId string `json:"playerId" bson:"playerId"` // 玩家ID,最大长度50,必填
|
||||
PlayerIp string `json:"playerIp" bson:"playerIp"` // 玩家IP,最大长度100,必填
|
||||
DeviceType string `json:"deviceType" bson:"deviceType"` // 设备类型,必填
|
||||
DeviceId string `json:"deviceId" bson:"deviceId"` // 设备ID,最大长度100,必填
|
||||
Name string `json:"name" bson:"name"` // 玩家姓名
|
||||
Tel string `json:"tel" bson:"tel"` // 玩家⼿机号
|
||||
AlipayAct string `json:"alipayAct" bson:"alipayAct"` // 玩家支付宝账号
|
||||
}
|
||||
|
||||
type PayResp struct {
|
||||
Code stderr.Code `json:"code" bson:"code"` // 状态
|
||||
OID string `json:"oid" bson:"oid"` // 订单号
|
||||
PayUrl string `json:"payUrl" bson:"payUrl"` // 支付链接
|
||||
Mode string `json:"mode" bson:"mode"` // 模式
|
||||
Rebate string `json:"rebate" bson:"rebate"` // 通道费率
|
||||
Sign string `json:"sign" bson:"sign"` // 加密
|
||||
}
|
||||
|
||||
type RechargeResp struct {
|
||||
Code int `json:"code" bson:"code"` // code码
|
||||
Info string `json:"info" bson:"info"` // code码信息
|
||||
Err string `json:"err" bson:"err"` // 错误信息
|
||||
Msg PayResp `json:"msg" bson:"msg"` // 响应数据
|
||||
Tip string `json:"tip" bson:"tip"` // 备注
|
||||
}
|
||||
|
||||
type RechargeCallbackResp struct {
|
||||
Code int `json:"code" binding:"required"` // 编码
|
||||
MercID string `json:"mercId" binding:"required"` // 商户编号
|
||||
OID string `json:"oid" binding:"required"` // 支付平台订单号
|
||||
PayMoney string `json:"payMoney" binding:"required"` // 订单到账实际金额
|
||||
TradeNo string `json:"tradeNo" binding:"required"` // 商户订单号
|
||||
Sign string `json:"sign" binding:"required"` // 签名
|
||||
}
|
||||
|
||||
type RefundCallbackResp struct {
|
||||
Code int `json:"code" bson:"code"` // 编码
|
||||
MercID string `json:"mercId" bson:"mercId"` // 商户编号
|
||||
OID string `json:"oid" bson:"oid"` // 支付平台订单号
|
||||
TradeNo string `json:"tradeNo" bson:"tradeNo"` // 商户订单号
|
||||
Sign string `json:"sign" bson:"sign"` // 签名
|
||||
}
|
||||
|
||||
// ToPayNew 获取请求body
|
||||
func (in *Recharge) ToPayNew(ctx context.Context) (res PayResp, err error) {
|
||||
defer func() {
|
||||
log.InfoX(ctx, "bill ToPayNew request info end 2", log.Any("transNo", in.TradeNo), log.Any("res", res))
|
||||
if err := recover(); err != nil {
|
||||
log.ErrorX(ctx, "bill ToPayNew recover", log.Any("Rchg", in), log.Any("panic", err))
|
||||
}
|
||||
}()
|
||||
in.fill()
|
||||
startS := time.Now().UnixNano()
|
||||
|
||||
var rechargeResp RechargeResp
|
||||
code, err := httputil.DefaultClientPostJsonWithResp(&rechargeResp, in.GetURL(), nil, in.GetBody())
|
||||
log.InfoX(ctx, "ToPayNew POST resp ", log.Any("code", code), log.Any("transNo", in.TradeNo),
|
||||
log.Any("topay-bill-time cost", time.Now().UnixNano()-startS))
|
||||
if err != nil {
|
||||
log.ErrorX(ctx, "bill ToPayNew post failed", log.Any("transNo", in.TradeNo), log.E(err))
|
||||
err = PayErrPostFailure
|
||||
return
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
log.ErrorX(ctx, "bill ToPayNew bad http statusCode", log.Any("transNo", in.TradeNo), log.Any("statusCode", code))
|
||||
err = PayErrResponseCode
|
||||
return
|
||||
}
|
||||
if rechargeResp.Err != "" {
|
||||
log.ErrorX(ctx, "bill ToPayNew has been rejected", log.Any("transNo", in.TradeNo), log.Any("res err", rechargeResp.Err))
|
||||
err = PayErrBeRejected
|
||||
return
|
||||
}
|
||||
log.InfoX(ctx, "bill ToPayNew request info end", log.Any("transNo", in.TradeNo), log.Any("res", res))
|
||||
return rechargeResp.Msg, nil
|
||||
}
|
||||
|
||||
// fill 组装数据
|
||||
func (in *Recharge) fill() {
|
||||
in.MercID = in.GetMercID()
|
||||
in.Time = Generate13DigitString()
|
||||
in.TradeNo = RChgIDAssemble(in.TradeNo)
|
||||
in.Info.App = appg.Conf.PayCenter.AppName
|
||||
in.NotifyUrl = in.GetNotifyURL()
|
||||
in.CancelNotifyUrl = in.GetCancelNotifyURL()
|
||||
in.SignType = "1"
|
||||
in.Sign = in.sign()
|
||||
}
|
||||
|
||||
// GetNotifyURL 获取回调地址
|
||||
func (in *Recharge) GetNotifyURL() string {
|
||||
return appg.Conf.PayCenter.CallbackUrl + "/3rd/defray/callback/pay_center"
|
||||
}
|
||||
|
||||
// GetCancelNotifyURL 获取退款回调地址
|
||||
func (in *Recharge) GetCancelNotifyURL() string {
|
||||
return appg.Conf.PayCenter.CallbackUrl + "/3rd/defray/callback/refund"
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (in *Recharge) sign() (sign string) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(in.MercID)
|
||||
buf.WriteString(in.Money)
|
||||
buf.WriteString(in.NotifyUrl)
|
||||
buf.WriteString(in.TradeNo)
|
||||
buf.WriteString(in.Type)
|
||||
buf.WriteString(in.GetAppSecret())
|
||||
md5Ctx := md5.New()
|
||||
md5Ctx.Write(buf.Bytes())
|
||||
cipherStr := md5Ctx.Sum(nil)
|
||||
return hex.EncodeToString(cipherStr)
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (in *Recharge) GetBody() []byte {
|
||||
jsonStr, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("DaBaiSha GetBody json.Marshal is fail error:%+v/data:%+v", err, in))
|
||||
}
|
||||
sstr := string(jsonStr)
|
||||
log.Info(fmt.Sprintf("==================%+v", sstr))
|
||||
return jsonStr
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (in *Recharge) GetURL() string {
|
||||
return appg.Conf.PayCenter.ApiUrl + "/api/shark/topay"
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
//func (in *Recharge) Notify() (RchgBack, error) {
|
||||
// return in, nil
|
||||
//}
|
||||
|
||||
// Success 获取请求body
|
||||
func (in *Recharge) Success() string {
|
||||
return "success"
|
||||
}
|
||||
|
||||
func (in *Recharge) GetAppSecret() string {
|
||||
return appg.Conf.PayCenter.MercSecret
|
||||
}
|
||||
|
||||
// GetMercID 获取商户编号
|
||||
func (in *Recharge) GetMercID() string {
|
||||
return appg.Conf.PayCenter.MercID
|
||||
}
|
||||
|
||||
func FenToYuan(price int64) string {
|
||||
return strconv.FormatInt(price/100, 10)
|
||||
}
|
||||
|
||||
func YuanToFen(money string) int64 {
|
||||
// 去除前后空格
|
||||
money = strings.TrimSpace(money)
|
||||
if money == "" {
|
||||
return 0
|
||||
}
|
||||
|
||||
// 检查是否为负数
|
||||
isNegative := false
|
||||
if strings.HasPrefix(money, "-") {
|
||||
isNegative = true
|
||||
money = money[1:]
|
||||
}
|
||||
|
||||
// 按小数点分割
|
||||
parts := strings.Split(money, ".")
|
||||
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
// 只有整数部分,如 "123", "456"
|
||||
yuan, err := strconv.ParseInt(parts[0], 10, 64)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("invalid integer part: %v", err))
|
||||
return 0
|
||||
}
|
||||
result := yuan * 100
|
||||
if isNegative {
|
||||
result = -result
|
||||
}
|
||||
return result
|
||||
|
||||
case 2:
|
||||
// 有整数和小数部分,如 "123.45", "78.9"
|
||||
yuan, err := strconv.ParseInt(parts[0], 10, 64)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("invalid integer part: %v", err))
|
||||
return 0
|
||||
}
|
||||
|
||||
// 处理小数部分
|
||||
decimalPart := parts[1]
|
||||
if len(decimalPart) > 2 {
|
||||
// 如果小数部分超过2位,进行四舍五入或截断
|
||||
// 这里选择截断,也可以根据需要改为四舍五入
|
||||
decimalPart = decimalPart[:2]
|
||||
} else if len(decimalPart) == 1 {
|
||||
// 如果只有1位小数,补零
|
||||
decimalPart += "0"
|
||||
}
|
||||
|
||||
fen, err := strconv.ParseInt(decimalPart, 10, 64)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("invalid decimal part: %v", err))
|
||||
return 0
|
||||
}
|
||||
|
||||
result := yuan*100 + fen
|
||||
if isNegative {
|
||||
result = -result
|
||||
}
|
||||
return result
|
||||
default:
|
||||
log.Warn(fmt.Sprintf("invalid money format: %s", money))
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// GetQueryURL 获取请求地址
|
||||
func (in *Recharge) GetQueryURL() string {
|
||||
return appg.Conf.PayCenter.ApiUrl + "/api/shark/order/queryOrder"
|
||||
}
|
||||
|
||||
type RechargeQueryResp struct {
|
||||
Code int `json:"code" bson:"code"` // 响应码
|
||||
Msg QueryOrderInfo `json:"msg" bson:"msg"` // 订单信息
|
||||
}
|
||||
|
||||
type QueryOrderInfo struct {
|
||||
MercID string `json:"mercID"`
|
||||
TradeNo string `json:"tradeNo"`
|
||||
Money float32 `json:"money"`
|
||||
PayMoney float32 `json:"payMoney"`
|
||||
PayTime string `json:"payTime"`
|
||||
PayStatus string `json:"payStatus"`
|
||||
NotifyStatus string `json:"notifyStatus"`
|
||||
}
|
||||
|
||||
// QueryOrder 订单状态查询发起
|
||||
func (g *Recharge) QueryOrder() (msg QueryOrderInfo, err error) {
|
||||
var res RechargeQueryResp
|
||||
body := make(map[string]string)
|
||||
body["mercId"] = g.GetMercID()
|
||||
body["tradeNo"] = g.TradeNo
|
||||
code, err := httputil.DefaultClientGetWithResp(&res, g.GetQueryURL(), nil, body)
|
||||
if err != nil || code != 200 {
|
||||
log.Error(fmt.Sprintf("pay center QueryOrder http.Get fail error:%+v:", err))
|
||||
return
|
||||
}
|
||||
if res.Code != 200 {
|
||||
err = errors.New("pay center QueryOrder http query fail")
|
||||
return
|
||||
}
|
||||
msg = res.Msg
|
||||
return res.Msg, nil
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
func TestDecodeCachedPayTypes(t *testing.T) {
|
||||
want := []AllPayType{{
|
||||
Money: "100",
|
||||
Types: []mercPayTypeInfo{{Name: "支付宝", Type: "alipay"}},
|
||||
}}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
data func(t *testing.T) []byte
|
||||
}{
|
||||
{
|
||||
name: "json",
|
||||
data: func(t *testing.T) []byte {
|
||||
t.Helper()
|
||||
data, err := json.Marshal(want)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return data
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "legacy msgpack",
|
||||
data: func(t *testing.T) []byte {
|
||||
t.Helper()
|
||||
data, err := msgpack.Marshal(want)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return data
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := decodeCachedPayTypes(string(tt.data(t)))
|
||||
if err != nil {
|
||||
t.Fatalf("decodeCachedPayTypes() error = %v", err)
|
||||
}
|
||||
if len(got) != 1 || got[0].Money != want[0].Money || len(got[0].Types) != 1 || got[0].Types[0] != want[0].Types[0] {
|
||||
t.Fatalf("decodeCachedPayTypes() = %#v, want %#v", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeCachedPayTypesRejectsInvalidData(t *testing.T) {
|
||||
if _, err := decodeCachedPayTypes("not-json-or-msgpack"); err == nil {
|
||||
t.Fatal("decodeCachedPayTypes() error = nil, want decode error")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/web/webg"
|
||||
)
|
||||
|
||||
var sc = config{
|
||||
MercID: "10230",
|
||||
AppSecret: "9500fd843c02fe8ca2607e1295215f8b",
|
||||
ExeUrl: "https://lias.huimu311.com/api/shark/topay",
|
||||
NotifyUrl: "/3rd/defray/callback/shark",
|
||||
QueryUrl: "https://lias.huimu311.com/api/shark/order/queryOrder",
|
||||
}
|
||||
|
||||
// Shark 充值订单请求体
|
||||
type Shark struct {
|
||||
MercID string `json:"mercId"`
|
||||
Type string `json:"type"`
|
||||
Money string `json:"money"`
|
||||
TradeNo string `json:"tradeNo"`
|
||||
NotifyURL string `json:"notifyUrl"`
|
||||
Info SharkInfo `json:"info"`
|
||||
Time string `json:"time"`
|
||||
Sign string `json:"sign"`
|
||||
PayMethod string
|
||||
}
|
||||
|
||||
// SharkInfo 玩家信息
|
||||
type SharkInfo struct {
|
||||
PlayerID string `json:"playerId"`
|
||||
PlayerIP string `json:"playerIp"`
|
||||
DeviceID string `json:"deviceId"`
|
||||
DeviceType string `json:"deviceType"`
|
||||
Name string `json:"name"`
|
||||
Tel string `json:"tel"`
|
||||
PayAct string `json:"payAct"`
|
||||
}
|
||||
|
||||
// SharkRes 回调函数参数model
|
||||
type SharkRes struct {
|
||||
Code int `json:"code" binding:"required"`
|
||||
MercID string `json:"mercId" binding:"required"` //商户编号
|
||||
OID string `json:"oid" binding:"required"` //支付平台订单号
|
||||
PayMoney string `json:"payMoney" binding:"required"` //订单到账实际金额
|
||||
TradeNo string `json:"tradeNo" binding:"required"` //商户订单号
|
||||
Sign string `json:"sign" binding:"required"` //签名
|
||||
}
|
||||
|
||||
// ToPay 支付发起
|
||||
func (s *Shark) ToPay() (payUrl string, oid string, err error) {
|
||||
var errlog string
|
||||
s.Fill()
|
||||
msgModel := MsgModel{}
|
||||
code, err := httputil.DefaultClientPostWithRespWithProxy(appg.ProxyCfg, &msgModel, s.GetURL(), s.GetHeader(), s.GetBody())
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("shark ToPay Http.PostJson fail error:%+v/,data:%+v;", err, s)
|
||||
log.Error(errlog)
|
||||
err = errors.New(errlog)
|
||||
return
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
errlog = fmt.Sprintf("shark ToPay Http.PostJson fail error:%+v/,data:%+v;", err, code)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
if msgModel.Code != 200 {
|
||||
switch msgModel.Code {
|
||||
case 40001:
|
||||
err = PAY_CHANNEL_CLOSE_ERROR
|
||||
default:
|
||||
errlog = fmt.Sprintf("shark topay response err :%+v/,data:%+v;", err, msgModel)
|
||||
err = errors.New(errlog)
|
||||
}
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
msg := msgModel.Msg
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(msg["oid"])
|
||||
buf.WriteString(msg["payUrl"])
|
||||
buf.WriteString(s.GetAppSecret())
|
||||
if !VerifySign(msg["sign"], buf.String()) {
|
||||
errlog = fmt.Sprintf("http shark VerifySign fail err :%+v/data:%+v", err, msgModel)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
payUrl = msg["payUrl"]
|
||||
oid = msg["oid"]
|
||||
return
|
||||
}
|
||||
|
||||
// QueryOrder 订单状态查询发起
|
||||
func (s *Shark) QueryOrder() (msg QueryMSG, err error) {
|
||||
var res struct {
|
||||
Code int `json:"code"`
|
||||
MSG QueryMSG `json:"msg"`
|
||||
}
|
||||
body := make(map[string]string)
|
||||
body["mercId"] = s.GetMercID()
|
||||
body["tradeNo"] = s.TradeNo
|
||||
code, err := httputil.DefaultClientPostWithRespWithProxy(webg.ProxyCfg, &res, s.GetQueryURL(), nil, body)
|
||||
if err != nil || code != 200 {
|
||||
log.Error(fmt.Sprintf("shark QueryOrder http.Get fail error:%+v:", err))
|
||||
return
|
||||
}
|
||||
if res.Code != 200 {
|
||||
err = errors.New("shark QueryOrder fail")
|
||||
return
|
||||
}
|
||||
msg = res.MSG
|
||||
return
|
||||
}
|
||||
|
||||
// Fill 补全配置信息和签名信息
|
||||
func (s *Shark) Fill() {
|
||||
s.Type = s.PayMethod
|
||||
s.MercID = s.GetMercID()
|
||||
s.NotifyURL = s.GetCallBackURL()
|
||||
if s.Info.Name == "" {
|
||||
s.Info.Name = GetFullName()
|
||||
}
|
||||
if s.Info.PlayerIP == "" {
|
||||
s.Info.PlayerIP = genIpaddr()
|
||||
}
|
||||
if s.Info.DeviceID == "" {
|
||||
s.Info.DeviceID = common.UUID()
|
||||
}
|
||||
if s.Info.DeviceType == "" {
|
||||
s.Info.DeviceType = "ios"
|
||||
}
|
||||
s.Sign = s.sign()
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (s *Shark) sign() (sign string) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(s.GetMercID())
|
||||
buf.WriteString(s.Money)
|
||||
buf.WriteString(s.GetCallBackURL())
|
||||
buf.WriteString(s.TradeNo)
|
||||
buf.WriteString(s.Type)
|
||||
buf.WriteString(s.GetAppSecret())
|
||||
md5Ctx := md5.New()
|
||||
md5Ctx.Write(buf.Bytes())
|
||||
cipherStr := md5Ctx.Sum(nil)
|
||||
return hex.EncodeToString(cipherStr)
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (s *Shark) GetBody() interface{} {
|
||||
jsonStr, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("shark GetBody json.Marshal fail error:%+v/data:%+v", err, s))
|
||||
}
|
||||
log.Error(fmt.Sprintf("shark topay json body:%+v:", string(jsonStr)))
|
||||
return jsonStr
|
||||
}
|
||||
|
||||
// GetHeader 获取请求头
|
||||
func (s *Shark) GetHeader() map[string]string {
|
||||
header := make(map[string]string, 0)
|
||||
return header
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (s *Shark) GetURL() string {
|
||||
return sc.ExeUrl
|
||||
}
|
||||
|
||||
// GetQueryURL 获取查询请求地址
|
||||
func (s *Shark) GetQueryURL() string {
|
||||
return sc.QueryUrl
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (s *Shark) GetCallBackURL() string {
|
||||
if appg.Conf != nil {
|
||||
return appg.Conf.URL.LocalWebUrl + sc.NotifyUrl
|
||||
}
|
||||
return webg.Conf.URL.LocalAppUrl + sc.NotifyUrl
|
||||
}
|
||||
|
||||
// GetMercID 获取商户编号
|
||||
func (s *Shark) GetMercID() string {
|
||||
return sc.MercID
|
||||
}
|
||||
|
||||
// GetAppSecret 获取app签名密钥
|
||||
func (s *Shark) GetAppSecret() string {
|
||||
return sc.AppSecret
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/web/webg"
|
||||
)
|
||||
|
||||
var yc = config{
|
||||
MercID: "cm0020983778",
|
||||
AppSecret: "8EB5C35ED06CC6EFE8020D8B67B7E867",
|
||||
ExeUrl: "http://api.nb536.com/gateway",
|
||||
NotifyUrl: "/3rd/defray/callback/yilianfu",
|
||||
}
|
||||
|
||||
// YiLIanFu 充值订单请求体
|
||||
type YiLIanFu struct {
|
||||
Type string `sign:"1" json:"method"` // 产品编码
|
||||
Version string `sign:"1" json:"version" ` //版本
|
||||
MercID string `sign:"1" json:"mch_id"` //商户编号
|
||||
SignType string `sign:"1" json:"sign_type"` //签名类型
|
||||
Money string `sign:"1" json:"total_amount" ` // 充值⾦额
|
||||
NonceStr string `sign:"1" json:"nonce_str"` //随机字符串
|
||||
TradeNo string `sign:"1" json:"mch_order_no"` //商户订单号
|
||||
ProductName string `sign:"1" json:"body"` // 商品信息
|
||||
CurCode string `sign:"1" json:"cur_code"` //币种
|
||||
PayIP string `sign:"1" json:"spbill_create_ip"` //终端ip
|
||||
Time string `sign:"1" json:"mch_req_time"` //提交时间2016-12-26 18:18:18
|
||||
NotifyURL string `sign:"1" json:"notify_url"` // 回调地址
|
||||
Sign string `sign:"1" json:"sign" ` // 签名
|
||||
PayMethod string `json:"paymethod,omitempty"` //付款方式 扫码|h5
|
||||
}
|
||||
|
||||
// YiLIanFuRes 回调函数参数model
|
||||
type YiLIanFuRes struct {
|
||||
Type string `sign:"1" json:"method"` // 产品编码
|
||||
Version string `sign:"1" json:"version"`
|
||||
Charset string `sign:"1" json:"charset"`
|
||||
SignType string `sign:"1" json:"sign_type"`
|
||||
MercID string `sign:"1" json:"mch_id"`
|
||||
NonceStr string `sign:"1" json:"nonce_str"`
|
||||
Sign string `json:"sign"`
|
||||
ResCode string `sign:"1" json:"result_code"` //业务状态码
|
||||
ErrCode string `sign:"1" json:"err_code"` //错误码
|
||||
ErrCodeDes string `sign:"1" json:"err_code_des"` //错误原因
|
||||
CurCode string `sign:"1" json:"cur_code"` //币种
|
||||
Money string `sign:"1" json:"total_amount"` // 充值⾦额
|
||||
PayMoney string `sign:"1" json:"real_amount"` //实付金额
|
||||
BankOrderNo string `sign:"1" json:"bank_order_no"` //银行订单号
|
||||
ChannelOrderNo string `sign:"1" json:"channel_order_no"` //通道订单号
|
||||
OID string `sign:"1" json:"order_no"`
|
||||
TradeNo string `sign:"1" json:"mch_order_no"` //商户订单号
|
||||
PayTime string `sign:"1" json:"order_finish_time"` //支付时间
|
||||
}
|
||||
|
||||
type YiLIanFuData struct {
|
||||
Version string `sign:"1" json:"version"`
|
||||
Charset string `sign:"1" json:"charset"`
|
||||
SignType string `sign:"1" json:"sign_type"`
|
||||
Code string `sign:"1" json:"return_code"`
|
||||
Msg string `sign:"1" json:"return_msg"`
|
||||
NonceStr string `sign:"1" json:"nonce_str"`
|
||||
MercID string `sign:"1" json:"mch_id"`
|
||||
ResCode string `sign:"1" json:"result_code"` //业务状态码
|
||||
Sign string `json:"sign"`
|
||||
ErrCode string `sign:"1" json:"err_code"` //错误码
|
||||
ErrCodeDes string `sign:"1" json:"err_code_des"` //错误原因
|
||||
OID string `sign:"1" json:"order_no"`
|
||||
PayUrl string `sign:"1" json:"code_url"`
|
||||
TimeExpire string `sign:"1" json:"time_expire"`
|
||||
}
|
||||
|
||||
// ToPay 支付发起
|
||||
func (this *YiLIanFu) ToPay() (payURL string, err error) {
|
||||
var errlog string
|
||||
this.Fill()
|
||||
var msg YiLIanFuData
|
||||
code, err := httputil.DefaultClientPostWithRespWithProxy(appg.ProxyCfg, &msg, this.GetURL(), this.GetHeader(), this.GetBody())
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("YiLIanFu ToPay Http.PostJson fail error:%+v/,data:%+v;", err, this)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
errlog = fmt.Sprintf("YiLIanFu ToPay Http.PostJson fail error:%+v/,data:%+v;", err, code)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
if msg.ResCode != "SUCCESS" {
|
||||
bytes, _ := json.Marshal(msg)
|
||||
errlog = fmt.Sprintf("YiLIanFu topay response err :%+v:", string(bytes))
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
payURL = msg.PayUrl
|
||||
return
|
||||
}
|
||||
|
||||
// Fill 补全配置信息和签名信息
|
||||
func (this *YiLIanFu) Fill() {
|
||||
this.Version = "1.0"
|
||||
this.Type = this.PayMethod
|
||||
this.PayMethod = ""
|
||||
this.MercID = this.GetMercID()
|
||||
this.NotifyURL = this.GetNotifyURL()
|
||||
this.SignType = "MD5"
|
||||
this.NonceStr = RandStringBytesMaskImpr(10)
|
||||
this.CurCode = "CNY"
|
||||
if this.PayIP == "" {
|
||||
this.PayIP = genIpaddr()
|
||||
}
|
||||
this.Sign = this.sign()
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (this *YiLIanFu) 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(this.GetAppSecret())
|
||||
str := buf.String()
|
||||
log.Info(fmt.Sprintf("YiLIanFu topay sign :%s", str))
|
||||
return strings.ToUpper(md5Sign(buf.String()))
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (this *YiLIanFuRes) ToSign() 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(yc.AppSecret)
|
||||
return strings.ToUpper(md5Sign(buf.String()))
|
||||
}
|
||||
|
||||
// ToStringSlice 转化为stirng切片切片
|
||||
func (this *YiLIanFu) 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")
|
||||
if v.Field(k).String() != "" && signTag == "1" {
|
||||
data = append(data, jsonTag+"="+v.Field(k).String())
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// ToStringSlice 转化为stirng切片切片
|
||||
func (this *YiLIanFuRes) ToStringSlice() StringList {
|
||||
t := reflect.TypeOf(*this)
|
||||
v := reflect.ValueOf(*this)
|
||||
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
|
||||
}
|
||||
|
||||
// ToStringSlice 转化为stirng切片切片
|
||||
func (this *YiLIanFuData) ToStringSlice() StringList {
|
||||
t := reflect.TypeOf(*this)
|
||||
v := reflect.ValueOf(*this)
|
||||
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 (this *YiLIanFu) GetBody() interface{} {
|
||||
m := make(map[string]string)
|
||||
jsonStr, err := json.Marshal(this)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("YiLIanFu GetBody json.Marshal is fail error:%+v/data:%+v", err, this))
|
||||
}
|
||||
sstr := string(jsonStr)
|
||||
_ = json.Unmarshal(jsonStr, &m)
|
||||
log.Info(fmt.Sprintf("YiLIanFu topay json data :%+v", sstr))
|
||||
return m
|
||||
}
|
||||
|
||||
// GetHeader 获取请求头信息
|
||||
func (this *YiLIanFu) GetHeader() map[string]string {
|
||||
header := make(map[string]string, 0)
|
||||
return header
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (*YiLIanFu) GetURL() string {
|
||||
return yc.ExeUrl
|
||||
}
|
||||
|
||||
// GetQueryURL 获取请求地址
|
||||
func (*YiLIanFu) GetQueryURL() string {
|
||||
return yc.QueryUrl
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (*YiLIanFu) GetNotifyURL() string {
|
||||
if appg.Conf != nil {
|
||||
return appg.Conf.URL.LocalWebUrl + yc.NotifyUrl
|
||||
}
|
||||
return webg.Conf.URL.LocalAppUrl + yc.NotifyUrl
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (*YiLIanFu) GetCallBackURL() string {
|
||||
return yc.CallbackURL
|
||||
}
|
||||
|
||||
// GetMercID 获取商户编号
|
||||
func (*YiLIanFu) GetMercID() string {
|
||||
return yc.MercID
|
||||
}
|
||||
|
||||
// GetAppSecret 获取app签名密钥
|
||||
func (*YiLIanFu) GetAppSecret() string {
|
||||
return yc.AppSecret
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
)
|
||||
|
||||
var ylc = config{
|
||||
MercID: "xq032",
|
||||
AppSecret: "635379bb1abe7ed814c95e083480b09aa2d47d5a",
|
||||
ExeUrl: "https://www.hsipxix.cn/?c=Pay",
|
||||
NotifyUrl: "/3rd/defray/callback/rchg/yongli",
|
||||
}
|
||||
|
||||
// YongLi 充值订单请求体
|
||||
type YongLi struct {
|
||||
MercID string `json:"mch_id" sign:"1"` //商户编号
|
||||
Type string `json:"ptype" sign:"1"` // 订单充值类型
|
||||
TradeNo string `json:"order_sn" sign:"1"` //商户订单号
|
||||
Money string `json:"money" sign:"1"` // 支付金额:元
|
||||
NotifyURL string `json:"notify_url" sign:"1"` // 回调地址
|
||||
Time string `json:"time" sign:"1"`
|
||||
Sign string `json:"sign"` // 签名
|
||||
PayMethod string `json:"-"`
|
||||
Format string `json:"format" sign:"1"`
|
||||
Desc string `json:"goods_desc" sign:"1"`
|
||||
IP string `json:"client_ip" sign:"1"`
|
||||
}
|
||||
|
||||
type YongLiMsgData struct {
|
||||
Type string `json:"ptype" sign:"1"` // 订单充值类型
|
||||
PayTypeName string `json:"ptype_name"`
|
||||
RealNmae string `json:"realnmae"` //姓名
|
||||
Act string `json:"account"` //账户
|
||||
PayMoney string `json:"pay_money"`
|
||||
Bank string `json:"bank"` //银行
|
||||
QRcode string `json:"qrcode"` //二维码
|
||||
PayURL string `json:"pay_url"` //
|
||||
OID string `json:"order_sn"`
|
||||
}
|
||||
|
||||
type YongLiMsg struct {
|
||||
Code string `json:"code" sign:"1"` //交易返回码,返回SUCCESS 表示交易成功(不代表最终结果),
|
||||
Data interface{} `json:"data"`
|
||||
Msg string `json:"msg"` //签名
|
||||
}
|
||||
|
||||
// RYRes 回调函数参数model
|
||||
type YongLiBack struct {
|
||||
TradeNo string `json:"sh_order" form:"sh_order" sign:"1"` //商户订单号
|
||||
OID string `json:"pt_order" form:"pt_order" sign:"1"` //订单号
|
||||
PayMoney float32 `json:"money" form:"money" sign:"1"` //订单到账实际金额
|
||||
PayTime int64 `json:"time" form:"time" sign:"1"` //支付时间
|
||||
Status string `json:"status" form:"status" sign:"1"` //交易结果 1(成功)
|
||||
Sign string `json:"sign" form:"sign" ` //签名
|
||||
}
|
||||
|
||||
// ToPay 支付发起
|
||||
func (this *YongLi) ToPay() (res RchgMsg, err error) {
|
||||
var errlog string
|
||||
this.Fill()
|
||||
msg := YongLiMsg{}
|
||||
code, err := httputil.DefaultClientPostJsonWithResp(&msg, this.GetURL(), this.GetHeader(), this.GetBody())
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("yongli ToPay requset fail \nerror:%+v\n\ndata:%+v;", err, this)
|
||||
log.Error(errlog)
|
||||
err = errors.New(errlog)
|
||||
return
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
errlog = fmt.Sprintf("yongli ToPay response status exception;\nstatus %+v;", code)
|
||||
log.Error(errlog)
|
||||
err = errors.New(errlog)
|
||||
return
|
||||
}
|
||||
if msg.Code != "1" {
|
||||
errlog = fmt.Sprintf("yongli ToPay be rejected;\n msg:%+v:", msg)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
var data YongLiMsgData
|
||||
bytes, err := json.Marshal(msg.Data)
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("yongli payUrl urlDecode fail \nerror:%+v;", err)
|
||||
log.Error(errlog)
|
||||
err = errors.New(errlog)
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal(bytes, &data); err != nil {
|
||||
errlog = fmt.Sprintf("yongli payUrl urlDecode fail \nerror:%+v;", err)
|
||||
log.Error(errlog)
|
||||
err = errors.New(errlog)
|
||||
return
|
||||
}
|
||||
res.PayUrl = data.PayURL
|
||||
res.OID = data.OID
|
||||
res.Mode = "url"
|
||||
return
|
||||
}
|
||||
|
||||
// ASenCallBack 阿森结构回调函数
|
||||
func (this *YongLiBack) Notify() (RchgBack, error) {
|
||||
r := RchgBack{}
|
||||
if this.Sign != this.ToSign() {
|
||||
err := errors.New("check sign fail")
|
||||
log.Error(fmt.Sprintf("ASen callback sign verify fail error:%+v:", err))
|
||||
return r, err
|
||||
}
|
||||
r.Code = 200
|
||||
if this.Status != "success" {
|
||||
r.Code = 400
|
||||
}
|
||||
r.PaymentAt = time.Unix(this.PayTime, 0)
|
||||
r.PayMoney = int64(this.PayMoney * 100)
|
||||
r.TransNo = this.TradeNo
|
||||
r.OID = this.OID
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (this *YongLiBack) Success() string {
|
||||
return "success"
|
||||
}
|
||||
|
||||
// Fill 补全配置信息和签名信息
|
||||
func (this *YongLi) Fill() {
|
||||
switch this.PayMethod {
|
||||
case "alipay":
|
||||
this.Type = "12"
|
||||
case "wechat":
|
||||
this.Type = "2"
|
||||
}
|
||||
this.PayMethod = ""
|
||||
this.Format = "json"
|
||||
this.Desc = "充值"
|
||||
this.IP = genIpaddr()
|
||||
this.MercID = this.GetMercID()
|
||||
this.NotifyURL = this.GetCallBackURL()
|
||||
this.Sign = this.sign()
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (this *YongLi) sign() string {
|
||||
ss := ToStringSlice(*this)
|
||||
sort.Sort(&ss)
|
||||
var buf bytes.Buffer
|
||||
for k := range ss {
|
||||
buf.WriteString(ss[k])
|
||||
buf.WriteString("&")
|
||||
}
|
||||
buf.WriteString("key=" + ylc.AppSecret)
|
||||
s := buf.String()
|
||||
log.Info(fmt.Sprintf("--------------%s", s))
|
||||
return strings.ToLower(md5Sign(s))
|
||||
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (this *YongLiBack) ToSign() string {
|
||||
ss := ToStringSlice(*this)
|
||||
sort.Sort(&ss)
|
||||
var buf bytes.Buffer
|
||||
for k := range ss {
|
||||
buf.WriteString(ss[k])
|
||||
buf.WriteString("&")
|
||||
}
|
||||
buf.WriteString("key=" + ylc.AppSecret)
|
||||
log.Info(fmt.Sprintf("--------------%s", buf.String()))
|
||||
return strings.ToLower(md5Sign(buf.String()))
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (this *YongLi) GetBody() interface{} {
|
||||
m := make(map[string]string)
|
||||
jsonStr, err := json.Marshal(this)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("YongLi GetBody json.Marshal is fail error:%+v/data:%+v", err, this))
|
||||
}
|
||||
// sstr := string(jsonStr)
|
||||
_ = json.Unmarshal(jsonStr, &m)
|
||||
log.Info(fmt.Sprintf("==================%+v", m))
|
||||
return m
|
||||
}
|
||||
|
||||
// GetHeader 获取请求头信息
|
||||
func (g *YongLi) GetHeader() map[string]string {
|
||||
header := make(map[string]string, 0)
|
||||
return header
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (*YongLi) GetURL() string {
|
||||
return ylc.ExeUrl
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (*YongLi) GetCallBackURL() string {
|
||||
return appg.Conf.URL.LocalWebUrl + ylc.NotifyUrl
|
||||
}
|
||||
|
||||
// GetMercID 获取商户编号
|
||||
func (*YongLi) GetMercID() string {
|
||||
return ylc.MercID
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"crypto/rc4"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
)
|
||||
|
||||
var ylws = config{
|
||||
MercID: "10105",
|
||||
AppSecret: "DA1C5476400B1D",
|
||||
ExeUrl: "http://x.aee7.com/gateway/index/checkpoint.do?",
|
||||
NotifyUrl: "/3rd/defray/callback/rchg/",
|
||||
}
|
||||
|
||||
// 订单请求体
|
||||
type WsylInfo struct {
|
||||
AccountId string `json:"account_id"` // 商户ID
|
||||
ContentType string `json:"content_type"` // 返回的网页类型
|
||||
Thoroughfare string `json:"thoroughfare"` // 通道
|
||||
Type string `json:"type"` // 支付类型
|
||||
OutTradeNo string `json:"out_trade_no"` // 商户订单号
|
||||
Robin string `json:"robin"` // 轮训
|
||||
UseCity string `json:"use_city"` // 按地区收款
|
||||
Amount string `json:"amount"` // 支付金额
|
||||
CallbackUrl string `json:"callback_url"` // 异步通知地址
|
||||
SuccessUrl string `json:"success_url"` // 支付成功后网页自动跳转地址
|
||||
ErrorUrl string `json:"error_url"` // 支付失败时,或支付超时后网页自动跳转地址
|
||||
Sign string `json:"sign"` // 签名 必填
|
||||
}
|
||||
|
||||
type WsylMsgData struct {
|
||||
OrderId string `json:"order_id"`
|
||||
Qrcode string `json:"qrcode"`
|
||||
}
|
||||
|
||||
type WsylMsg struct {
|
||||
Code int `json:"code"` // 交易返回码,返回SUCCESS 表示交易成功(不代表最终结果),
|
||||
Msg string `json:"msg"` // 签名
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// 回调函数参数
|
||||
type WsylResultRes struct {
|
||||
AccountName string `form:"account_name" json:"account_name"` // 商户登录名
|
||||
PayTime string `form:"pay_time" json:"pay_time"` // 支付成功的时间戳(10位)
|
||||
Status string `form:"status" json:"status"` // 状态
|
||||
Amount string `form:"amount" json:"amount"` // 订单到账实际金额
|
||||
OutTradeNo string `form:"out_trade_no" json:"out_trade_no"` // 订单信息,在发起订单时附加的信息,如用户名,充值订单号等字段参数
|
||||
TradeNo string `form:"trade_no" json:"trade_no"` // 交易流水号,由系统生成的交易流水号
|
||||
Fees string `form:"fees" json:"fees"` // 手续费,本次回调过程产生的手续费用(已经在平台账户中扣除)
|
||||
Sign string `form:"sign" json:"sign"` // 签名
|
||||
CallbackTime string `form:"callback_time" json:"callback_time"` // 回调时间,在回调时产生的时间戳(10位)
|
||||
Type string `form:"type" json:"type"` // 支付类型
|
||||
AccountKey string `form:"account_key" json:"account_key"` // 商户KEY
|
||||
}
|
||||
|
||||
// ToPay 支付发起
|
||||
func (wyi *WsylInfo) toPay() (res RchgMsg, err error) {
|
||||
var errLog string
|
||||
msg := WsylMsg{}
|
||||
wyi.fill()
|
||||
code, err := httputil.DefaultClientPostJsonWithResp(&msg, ylws.ExeUrl, wyi.getHeader(), wyi.getBody())
|
||||
if err != nil {
|
||||
errLog = fmt.Sprintf("Wsyl ToPay requset fail \nerror:%+v\n\ndata:%+v;", err, wyi)
|
||||
log.Error(errLog)
|
||||
err = errors.New(errLog)
|
||||
return
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
errLog = fmt.Sprintf("Wsyl ToPay response status exception;\nstatus %+v;", code)
|
||||
log.Error(errLog)
|
||||
err = errors.New(errLog)
|
||||
return
|
||||
}
|
||||
if msg.Code != 200 {
|
||||
errLog = fmt.Sprintf("Wsyl ToPay be rejected;\n msg:%+v:", msg)
|
||||
err = errors.New(errLog)
|
||||
log.Error(errLog)
|
||||
return
|
||||
}
|
||||
var data WsylMsgData
|
||||
bytes, err := json.Marshal(msg.Data)
|
||||
if err != nil {
|
||||
errLog = fmt.Sprintf("Wsyl payUrl urlDecode fail \nerror:%+v;", err)
|
||||
log.Error(errLog)
|
||||
err = errors.New(errLog)
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal(bytes, &data); err != nil {
|
||||
errLog = fmt.Sprintf("Wsyl payUrl urlDecode fail \nerror:%+v;", err)
|
||||
log.Error(errLog)
|
||||
err = errors.New(errLog)
|
||||
return
|
||||
}
|
||||
res.PayUrl = data.Qrcode
|
||||
res.Mode = "url"
|
||||
res.OID = data.OrderId
|
||||
return
|
||||
}
|
||||
|
||||
// Notify 回调函数
|
||||
func (this *WsylResultRes) Notify() (RchgBack, error) {
|
||||
r := RchgBack{}
|
||||
if this.SignRes() != this.Sign {
|
||||
log.Error(fmt.Sprintf("Wsyl callback sign verify fail ,data:%+v", this))
|
||||
return r, errors.New("check sign fail")
|
||||
}
|
||||
if this.PayTime == "" {
|
||||
return r, errors.New("querry order err,no payTime")
|
||||
}
|
||||
sec, err := strconv.ParseInt(this.PayTime, 10, 64)
|
||||
if err != nil {
|
||||
log.Error("time.ParseInLocation failed", log.Any("TradeNo", this.TradeNo), log.E(err))
|
||||
return r, err
|
||||
}
|
||||
paymentAt := time.Unix(sec, 0)
|
||||
payMoneyf, err := strconv.ParseFloat(this.Amount, 64)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("Wsyl callback ParseFloat fail data:%+v:", this))
|
||||
return r, fmt.Errorf("invalid payMoney %s", this.Amount)
|
||||
}
|
||||
r.PayMoney = int64(payMoneyf * 100)
|
||||
r.PaymentAt = paymentAt
|
||||
r.TransNo = this.OutTradeNo
|
||||
r.OID = this.TradeNo
|
||||
r.Code = 400
|
||||
if this.Status == "success" {
|
||||
r.Code = 200
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (this *WsylResultRes) Success() string {
|
||||
return "success"
|
||||
}
|
||||
|
||||
// 补全配置信息和签名信息
|
||||
func (wyi *WsylInfo) fill() {
|
||||
wyi.AccountId = ylws.MercID
|
||||
wyi.ContentType = "json"
|
||||
wyi.Thoroughfare = "paofen_auto"
|
||||
wyi.Type = "71"
|
||||
wyi.Robin = "2"
|
||||
wyi.UseCity = "2"
|
||||
wyi.CallbackUrl = wyi.getNotifyURL()
|
||||
wyi.SuccessUrl = wyi.getNotifyURL()
|
||||
wyi.ErrorUrl = wyi.getNotifyURL()
|
||||
wyi.Sign = wyi.signReq()
|
||||
}
|
||||
|
||||
// 充值请求签名
|
||||
func (wyi *WsylInfo) signReq() (sign string) {
|
||||
return DealSign(ylws.AppSecret, wyi.Amount, wyi.OutTradeNo)
|
||||
}
|
||||
|
||||
func DealSign(key_id string, amount string, out_trade_no string) (sign string) {
|
||||
var data = amount + out_trade_no
|
||||
md5Str := md5Sign(data)
|
||||
c, err := rc4.NewCipher([]byte(key_id))
|
||||
if err != nil {
|
||||
// log.Fatalln(err)
|
||||
return
|
||||
}
|
||||
src := []byte(md5Str)
|
||||
dst := make([]byte, len(src))
|
||||
c.XORKeyStream(dst, src)
|
||||
fmt.Println(string(src), string(dst))
|
||||
rc4Str := md5Sign(string(dst))
|
||||
return rc4Str
|
||||
}
|
||||
|
||||
// 充值成功回调签名
|
||||
func (wyc *WsylResultRes) SignRes() (sign string) {
|
||||
return DealSign(ylws.AppSecret, wyc.Amount, wyc.OutTradeNo)
|
||||
}
|
||||
|
||||
// 获取请求body
|
||||
func (wyi *WsylInfo) getBody() interface{} {
|
||||
m := make(map[string]string)
|
||||
jsonStr, err := json.Marshal(wyi)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("WSYL GetBody json.Marshal is fail error:%+v/data:%+v", err, wyi))
|
||||
}
|
||||
sstr := string(jsonStr)
|
||||
log.Info(fmt.Sprintf("==================%+v", sstr))
|
||||
_ = json.Unmarshal(jsonStr, &m)
|
||||
return m
|
||||
}
|
||||
|
||||
// 获取请求头
|
||||
func (wyi *WsylInfo) getHeader() map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取回掉函数
|
||||
func (wyi *WsylInfo) getNotifyURL() (url string) {
|
||||
return appg.Conf.URL.LocalWebUrl + ylws.NotifyUrl + YongLiWanShun
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
package rchgutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/web/webg"
|
||||
)
|
||||
|
||||
var zfc = config{
|
||||
MercID: "191309702",
|
||||
AppSecret: "oaha2s6ed67buc2rpy7of1p3mj17jpqwa0i0n3fjy633et7thwzmv1s3zbwaim9z2o4r3km799u8lp7a1luh1vpd350bazq5bmph66ffm3p9u8trow5lzmtmsx6b66rkya1up22x1rbjvhuby7wkpcidix064ay25d6ri48boo5f5fc0m05oi558d154qw6816p7ym1h52r2gsbndo6pi5i7qgonqp7aagkrh5ar3k3ircgvunqmcfbd4z45k9nz",
|
||||
ExeUrl: "http://www.518006.com/Pay_Index.html",
|
||||
QueryUrl: "http://www.518006.com/Pay_Trade_query.html",
|
||||
NotifyUrl: "/3rd/defray/callback/zhongfu",
|
||||
CallbackURL: "/refuse",
|
||||
VerifySecret: "muykk2dlwnmvsn5m5eg5ajs8vhfvfdihqqc2t2rd0297h2bwnkhf2jrk6qveffog038jsfsk4js0yjmkb9ydeijdtjbq98ouh8eqm04gvva3ql6mo0yknaq1v377mw1j",
|
||||
}
|
||||
|
||||
// ZhongFu 充值订单请求体
|
||||
type ZhongFu struct {
|
||||
Version string `json:"pay_version" sign:"1"`
|
||||
MercID string `json:"pay_memberid" sign:"1"` //商户编号
|
||||
Type string `json:"pay_bankcode" sign:"1"`
|
||||
TradeNo string `json:"pay_orderid" sign:"1"` //商户订单号
|
||||
Money string `json:"pay_amount" sign:"1"` // 充值⾦额
|
||||
CallbackUrl string `json:"pay_callbackurl" sign:"1"` //支付成功后的跳转地址
|
||||
NotifyURL string `json:"pay_notifyurl" sign:"1"` // 回调地址
|
||||
ProductName string `json:"pay_productname"` // 商品信息
|
||||
UserIP string `json:"pay_ip" sign:"1"` //用户ip
|
||||
SignType string `json:"pay_signtype" sign:"1"` //签名类型
|
||||
Charset string `json:"pay_inputcharset" sign:"1"`
|
||||
Time string `json:"pay_applydate" sign:"1"`
|
||||
PayFormat string `json:"pay_retformat"` //参数类型
|
||||
Sign string `json:"pay_md5sign" ` // 签名
|
||||
PayMethod string `json:"pay_method,omitempty"` // 支付类型
|
||||
}
|
||||
|
||||
// ZhongFuRes 回调函数参数model
|
||||
type ZhongFuRes struct {
|
||||
Version string `json:"version" form:"version" sign:"1"`
|
||||
MercID string `json:"memberid" form:"memberid" sign:"1"` //商户编号
|
||||
TradeNo string `json:"orderid" form:"orderid" sign:"1"` //商户订单号
|
||||
OID string `json:"transaction_id" form:"transaction_id" sign:"1"` //支付平台订单号
|
||||
PayMoney string `json:"amount" form:"amount" sign:"1"` //订单到账实际金额
|
||||
PayTime string `json:"datetime" form:"datetime" sign:"1"` //交易时间
|
||||
Code string `json:"returncode" form:"returncode" sign:"1"`
|
||||
Sign string `json:"sign" form:"sign"` //签名
|
||||
}
|
||||
|
||||
// ToPay 支付发起
|
||||
func (this *ZhongFu) ToPay() (payUrl string, err error) {
|
||||
defer func(err *error, payUrl string, obj interface{}) {
|
||||
if err == nil && payUrl == "" {
|
||||
fmt.Printf("zhongfu ToPay Http.PostJson fail error:data %+v;\r\n", this)
|
||||
}
|
||||
}(&err, payUrl, this)
|
||||
var errlog string
|
||||
this.Fill()
|
||||
var msg struct {
|
||||
PayURL string `json:"payurl"`
|
||||
Msg string `json:"msg"`
|
||||
Data interface{} `json:"data"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
code, err := httputil.DefaultClientPostWithRespWithProxy(appg.ProxyCfg, &msg, this.GetURL(), this.GetHeader(), this.GetBody())
|
||||
if err != nil {
|
||||
errlog = fmt.Sprintf("zhongfu 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("zhongfu ToPay Http.PostJson fail error:%+v/,data:%+v;", err, code)
|
||||
log.Error(errlog)
|
||||
err = errors.New(errlog)
|
||||
return
|
||||
}
|
||||
if msg.Msg != "success" {
|
||||
errlog = fmt.Sprintf("zhongfu topay response err :%+v:", msg)
|
||||
err = errors.New(errlog)
|
||||
log.Error(errlog)
|
||||
return
|
||||
}
|
||||
payUrl = msg.PayURL
|
||||
return
|
||||
}
|
||||
|
||||
// QueryOrder 订单状态查询发起
|
||||
func (this *ZhongFuRes) QueryOrder() (payTime time.Time, err error) {
|
||||
msg := msgModel{}
|
||||
body := make(map[string]string)
|
||||
body["partner_id"] = zfc.MercID
|
||||
body["partner_order"] = this.TradeNo
|
||||
body["sign"] = md5Sign("partner_id=" + zfc.MercID + "&partner_order=" + this.TradeNo + "&key=" + zfc.AppSecret)
|
||||
code, err := httputil.DefaultClientPostWithRespWithProxy(webg.ProxyCfg, &msg, zfc.QueryUrl, nil, body)
|
||||
if err != nil || code != 200 {
|
||||
log.Error(fmt.Sprintf("zhongfu QueryOrder http.Get fail error:%+v:", err))
|
||||
return
|
||||
}
|
||||
if msg.Code != 1 {
|
||||
err = errors.New("zhongfu QueryOrder fail")
|
||||
log.Error(fmt.Sprintf("zhongfu 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 *ZhongFu) Fill() {
|
||||
this.Version = "v2.3.5"
|
||||
this.MercID = this.GetMercID()
|
||||
this.NotifyURL = this.GetNotifyURL()
|
||||
this.CallbackUrl = this.GetCallBackURL()
|
||||
if this.UserIP == "" {
|
||||
this.UserIP = genIpaddr()
|
||||
}
|
||||
this.Type = this.PayMethod
|
||||
this.PayMethod = ""
|
||||
this.Charset = "UTF-8"
|
||||
this.SignType = "MD5"
|
||||
this.PayFormat = "json"
|
||||
this.Sign = this.sign()
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (this *ZhongFu) 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("ZhongFu topay sign :%s", buf.String()))
|
||||
return strings.ToUpper(md5Sign(buf.String()))
|
||||
}
|
||||
|
||||
// sign 签名
|
||||
func (this *ZhongFuRes) ToSign() (sign string) {
|
||||
ss := this.ToStringSlice()
|
||||
sort.Sort(&ss)
|
||||
var buf bytes.Buffer
|
||||
for _, v := range ss {
|
||||
buf.WriteString(v)
|
||||
buf.WriteString("&")
|
||||
}
|
||||
buf.WriteString("key=")
|
||||
buf.WriteString(zfc.VerifySecret)
|
||||
log.Info(fmt.Sprintf("ZhongFu callback sign:%s", buf.String()))
|
||||
str := buf.String()
|
||||
sign = strings.ToUpper(md5Sign(str))
|
||||
return
|
||||
}
|
||||
|
||||
// ToStringSlice 转化为stirng切片切片
|
||||
func (this *ZhongFu) 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
|
||||
}
|
||||
|
||||
// ToStringSlice 转化为stirng切片切片
|
||||
func (this *ZhongFuRes) 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")
|
||||
if signTag == "1" && v.Field(k).String() != "" {
|
||||
data = append(data, jsonTag+"="+v.Field(k).String())
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// GetBody 获取请求body
|
||||
func (this *ZhongFu) GetBody() interface{} {
|
||||
jsonStr, err := json.Marshal(this)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("ZhongFu GetBody json.Marshal is fail error:%+v/data:%+v", err, this))
|
||||
}
|
||||
log.Info(fmt.Sprintf("==================%+v", string(jsonStr)))
|
||||
return jsonStr
|
||||
}
|
||||
|
||||
// GetHeader 获取请求头信息
|
||||
func (*ZhongFu) GetHeader() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
// GetURL 获取请求地址
|
||||
func (*ZhongFu) GetURL() string {
|
||||
return zfc.ExeUrl
|
||||
}
|
||||
|
||||
// GetQueryURL 获取请求地址
|
||||
func (*ZhongFu) GetQueryURL() string {
|
||||
return zfc.QueryUrl
|
||||
}
|
||||
|
||||
// GetLowAndUpperURL 获取请求地址
|
||||
func (*ZhongFu) GetLowAndUpperURL() string {
|
||||
return zfc.LowAndUpperURL
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (*ZhongFu) GetNotifyURL() string {
|
||||
if appg.Conf != nil {
|
||||
return appg.Conf.URL.LocalWebUrl + zfc.NotifyUrl
|
||||
}
|
||||
return webg.Conf.URL.LocalAppUrl + zfc.NotifyUrl
|
||||
}
|
||||
|
||||
// GetCallBackURL 获取回掉函数
|
||||
func (*ZhongFu) GetCallBackURL() string {
|
||||
return zfc.CallbackURL
|
||||
}
|
||||
|
||||
// GetMercID 获取商户编号
|
||||
func (*ZhongFu) GetMercID() string {
|
||||
return zfc.MercID
|
||||
}
|
||||
|
||||
// GetAppSecret 获取app签名密钥
|
||||
func (*ZhongFu) GetAppSecret() string {
|
||||
return zfc.AppSecret
|
||||
}
|
||||
Reference in New Issue
Block a user