Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
+188
View File
@@ -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
}
+384
View File
@@ -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
}
+170
View File
@@ -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"
}
+131
View File
@@ -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"` //提现方式,alipaybankcard
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
}
+349
View File
@@ -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
}
+263
View File
@@ -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
}
+190
View File
@@ -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
}
+206
View File
@@ -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
}
+273
View File
@@ -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
}
+238
View File
@@ -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
}
+252
View File
@@ -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
}
+460
View File
@@ -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
}
+61
View File
@@ -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")
}
}
+205
View File
@@ -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
}
+260
View File
@@ -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
}
+214
View File
@@ -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
}
+207
View File
@@ -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
}
+264
View File
@@ -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
}