| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- package exchange
- import (
- "crypto/md5"
- "encoding/hex"
- "encoding/json"
- "fmt"
- "github.com/demdxx/gocast"
- "reflect"
- "sort"
- "strings"
- "time"
- )
- // doc: https://dsgxajqzhgq3.sg.larksuite.com/wiki/Flk1wnbUPiSucBk47TClBnC4g7m
- // 获取充值入口
- func GetTransferUri(customParams string, args ...string) string {
- uri := fmt.Sprintf("/zh-CN/application-center/transfer?appid=%s&custom_param=%s&redirect_uri=%s",
- conf().Appid, customParams, conf().RedirectUrl)
- if len(args) > 0 {
- uri = fmt.Sprintf("/zh-CN/application-center/transfer?appid=%s&custom_param=%s&redirect_uri=%s",
- conf().Appid, customParams, strings.Join(args, ""))
- }
- return uri
- }
- // /v1/act/public/application/third/transfer
- // /v1/act/public/application/third/transfer?accessToken={ACCESSTOKEN}&openId={OPENID}
- // accessToken openId 至少一个不为空,两者都不为空时,accesToken优先有效。
- // 转出
- type TransferOutReq struct {
- Currency string `json:"currency,omitempty"` // 必填
- Amount string `json:"amount,omitempty"` // 必填
- OrderId string `json:"orderId,omitempty"` // 必填
- AppId string `json:"appId,omitempty"`
- Timestamp string `json:"timestamp,omitempty"`
- Sign string `json:"sign,omitempty"`
- }
- type TransferOutResp struct {
- Code int `json:"code"`
- Msg string `json:"msg"`
- Data interface{} `json:"data"`
- }
- func TransferOut(openId string, req *TransferOutReq) (*TransferOutResp, error) {
- uri := fmt.Sprintf("/v1/act/public/application/third/transfer-apply?openId=%s",
- openId)
- url := ToPath(conf().RootUrl, uri)
- req.Timestamp = gocast.ToString(time.Now().UnixMilli())
- req.AppId = conf().Appid
- reqMap, err := structToJSONMap(req)
- if err != nil {
- return nil, err
- }
- sign := signMd5(reqMap)
- req.Sign = sign
- data, _ := json.Marshal(&req)
- return post[TransferOutResp](url, data)
- }
- // 回调处理(充值 提现)
- const (
- TransferUserToApp = "user_to_application"
- TransferAppToUser = "application_to_user"
- )
- const (
- ExchangeRwStatusRechargeSuccess = 0
- ExchangeRwStatusWithdrawSuccess = 1
- ExchangeRwStatusWithdrawFail = 2
- )
- type TransferCallbackReq struct {
- Currency string `json:"currency,omitempty"`
- Amount string `json:"amount,omitempty"`
- OrderId string `json:"orderId,omitempty"`
- OpenId string `json:"openId,omitempty"`
- CreateTime int64 `json:"createTime,omitempty"`
- Type string `json:"type,omitempty"` // user_to_application application_to_user
- AppId string `json:"appId,omitempty"`
- CustomParam string `json:"customParam"`
- Status int `json:"status,omitempty"`
- Sign string `json:"sign,omitempty"`
- }
- type CheckTransferCallbackReq struct {
- Currency string `json:"currency,omitempty"`
- Amount string `json:"amount,omitempty"`
- OrderId string `json:"orderId,omitempty"`
- OpenId string `json:"openId,omitempty"`
- CreateTime string `json:"createTime"`
- Type string `json:"type"` // user_to_application application_to_user
- AppId string `json:"appId,omitempty"`
- CustomParam string `json:"customParam"`
- Status int `json:"status,omitempty"`
- Sign string `json:"sign,omitempty"`
- }
- // 加密检查
- func SignCheck(req *TransferCallbackReq) bool {
- sign := req.Sign
- checkReq := &CheckTransferCallbackReq{
- Currency: req.Currency,
- Amount: req.Amount,
- OrderId: req.OrderId,
- OpenId: req.OpenId,
- CreateTime: fmt.Sprintf("%d", req.CreateTime),
- Type: req.Type,
- AppId: req.AppId,
- Status: req.Status,
- CustomParam: req.CustomParam,
- }
- reqMap, err := structToJSONMap(checkReq)
- if err != nil {
- return false
- }
- return sign == signMd5(reqMap)
- }
- func SignCheckMap(req map[string]interface{}, sign string) bool {
- return sign == signMd5(req)
- }
- // 将结构体转换为 map
- func beanToMap(req interface{}) map[string]interface{} {
- result := make(map[string]interface{})
- value := reflect.ValueOf(req)
- for i := 0; i < value.NumField(); i++ {
- field := value.Type().Field(i)
- result[field.Name] = value.Field(i).Interface()
- }
- return result
- }
- // 计算MD5签名 -- 不实用
- func CalculateSign(req TransferCallbackReq) string {
- // 实体转map
- hashMap := beanToMap(req)
- // 将HashMap转换为TreeMap(按键排序)
- treeMap := make(map[string]string)
- for key, value := range hashMap {
- if value != nil {
- treeMap[key] = fmt.Sprintf("%v", value)
- }
- }
- // 排序键
- keys := make([]string, 0, len(treeMap))
- for key := range treeMap {
- keys = append(keys, key)
- }
- sort.Strings(keys)
- // 拼接字符串
- var stringBuilder strings.Builder
- for _, key := range keys {
- value := treeMap[key]
- if value != "" && key != "sign" { // 过滤空值和 "sign" 字段
- stringBuilder.WriteString(key)
- stringBuilder.WriteString(value)
- }
- }
- // appSecret拼接
- stringBuilder.WriteString(conf().Secret)
- // md5加密
- hash := md5.Sum([]byte(stringBuilder.String()))
- return hex.EncodeToString(hash[:])
- }
|