增加vendor

This commit is contained in:
hoteas
2022-05-24 13:49:25 +08:00
parent c3a24eeb3c
commit 65ece0418e
742 changed files with 509206 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
package notify
import (
"github.com/silenceper/wechat/v2/pay/config"
)
// Notify 回调
type Notify struct {
*config.Config
}
// NewNotify new
func NewNotify(cfg *config.Config) *Notify {
return &Notify{cfg}
}
+109
View File
@@ -0,0 +1,109 @@
package notify
import (
"fmt"
"reflect"
"sort"
"strings"
"github.com/fatih/structs"
"github.com/silenceper/wechat/v2/util"
"github.com/spf13/cast"
)
// doc: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
// PaidResult 下单回调
type PaidResult struct {
ReturnCode *string `xml:"return_code"`
ReturnMsg *string `xml:"return_msg"`
AppID *string `xml:"appid" json:"appid"`
MchID *string `xml:"mch_id"`
DeviceInfo *string `xml:"device_info"`
NonceStr *string `xml:"nonce_str"`
Sign *string `xml:"sign"`
SignType *string `xml:"sign_type"`
ResultCode *string `xml:"result_code"`
ErrCode *string `xml:"err_code"`
ErrCodeDes *string `xml:"err_code_des"`
OpenID *string `xml:"openid"`
IsSubscribe *string `xml:"is_subscribe"`
TradeType *string `xml:"trade_type"`
TradeState *string `xml:"trade_state"`
BankType *string `xml:"bank_type"`
TotalFee *int `xml:"total_fee"`
SettlementTotalFee *int `xml:"settlement_total_fee"`
FeeType *string `xml:"fee_type"`
CashFee *string `xml:"cash_fee"`
CashFeeType *string `xml:"cash_fee_type"`
CouponFee *int `xml:"coupon_fee"`
CouponCount *int `xml:"coupon_count"`
// coupon_type_$n 这里只声明 3 个,如果有更多的可以自己组合
CouponType0 *string `xml:"coupon_type_0"`
CouponType1 *string `xml:"coupon_type_1"`
CouponType2 *string `xml:"coupon_type_2"`
CouponID0 *string `xml:"coupon_id_0"`
CouponID1 *string `xml:"coupon_id_1"`
CouponID2 *string `xml:"coupon_id_2"`
CouponFee0 *string `xml:"coupon_fee_0"`
CouponFee1 *string `xml:"coupon_fee_1"`
CouponFee2 *string `xml:"coupon_fee_2"`
TransactionID *string `xml:"transaction_id"`
OutTradeNo *string `xml:"out_trade_no"`
Attach *string `xml:"attach"`
TimeEnd *string `xml:"time_end"`
}
// PaidResp 消息通知返回
type PaidResp struct {
ReturnCode string `xml:"return_code"`
ReturnMsg string `xml:"return_msg"`
}
// PaidVerifySign 支付成功结果验签
func (notify *Notify) PaidVerifySign(notifyRes PaidResult) bool {
// STEP1, 转换 struct 为 map,并对 map keys 做排序
resMap := structs.Map(notifyRes)
sortedKeys := make([]string, 0, len(resMap))
for k := range resMap {
sortedKeys = append(sortedKeys, k)
}
sort.Strings(sortedKeys)
// STEP2, 对key=value的键值对用&连接起来,略过空值 & sign
var signStrings string
for _, k := range sortedKeys {
value := fmt.Sprintf("%v", cast.ToString(resMap[k]))
if value != "" && strings.ToLower(k) != "sign" {
signStrings = signStrings + getTagKeyName(k, &notifyRes) + "=" + value + "&"
}
}
// STEP3, 在键值对的最后加上key=API_KEY
signStrings = signStrings + "key=" + notify.Key
// STEP4, 根据SignType计算出签名
var signType string
if notifyRes.SignType != nil {
signType = *notifyRes.SignType
}
sign, err := util.CalculateSign(signStrings, signType, notify.Key)
if err != nil {
return false
}
if sign != *notifyRes.Sign {
return false
}
return true
}
func getTagKeyName(key string, notifyRes *PaidResult) string {
s := reflect.TypeOf(notifyRes).Elem()
f, _ := s.FieldByName(key)
name := f.Tag.Get("xml")
return name
}
+77
View File
@@ -0,0 +1,77 @@
package notify
import (
"crypto/md5"
"encoding/base64"
"encoding/hex"
"encoding/xml"
"errors"
"github.com/silenceper/wechat/v2/util"
)
// reference: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_16&index=10
// RefundedResult 退款回调
type RefundedResult struct {
ReturnCode *string `xml:"return_code"`
ReturnMsg *string `xml:"return_msg"`
AppID *string `xml:"appid"`
MchID *string `xml:"mch_id"`
NonceStr *string `xml:"nonce_str"`
ReqInfo *string `xml:"req_info"`
}
// RefundedReqInfo 退款结果(明文)
type RefundedReqInfo struct {
TransactionID *string `xml:"transaction_id"`
OutTradeNO *string `xml:"out_trade_no"`
RefundID *string `xml:"refund_id"`
OutRefundNO *string `xml:"out_refund_no"`
TotalFee *int `xml:"total_fee"`
SettlementTotalFee *int `xml:"settlement_total_fee"`
RefundFee *int `xml:"refund_fee"`
SettlementRefundFee *int `xml:"settlement_refund_fee"`
RefundStatus *string `xml:"refund_status"`
SuccessTime *string `xml:"success_time"`
RefundRecvAccount *string `xml:"refund_recv_accout"`
RefundAccount *string `xml:"refund_account"`
RefundRequestSource *string `xml:"refund_request_source"`
}
// RefundedResp 消息通知返回
type RefundedResp struct {
ReturnCode string `xml:"return_code"`
ReturnMsg string `xml:"return_msg"`
}
// DecryptReqInfo 对退款结果进行解密
func (notify *Notify) DecryptReqInfo(result *RefundedResult) (*RefundedReqInfo, error) {
var err error
if result == nil || result.ReqInfo == nil {
return nil, errors.New("empty refunded_result or req_info")
}
base64Decode, err := base64.StdEncoding.DecodeString(*result.ReqInfo)
if err != nil {
return nil, err
}
hash := md5.New()
if _, err = hash.Write([]byte(notify.Key)); err != nil {
return nil, err
}
md5APIKey := hex.EncodeToString(hash.Sum(nil))
data, err := util.AesECBDecrypt(base64Decode, []byte(md5APIKey))
if err != nil {
return nil, err
}
res := &RefundedReqInfo{}
if err = xml.Unmarshal(data, res); err != nil {
return nil, err
}
return res, nil
}