silenceper 6 лет назад
Родитель
Сommit
340e1a3c5b
4 измененных файлов с 67 добавлено и 49 удалено
  1. 2 0
      go.mod
  2. 2 0
      go.sum
  3. 62 49
      pay/notify/paid.go
  4. 1 0
      wechat.go

+ 2 - 0
go.mod

@@ -4,7 +4,9 @@ go 1.14
 
 require (
 	github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b
+	github.com/fatih/structs v1.1.0
 	github.com/gomodule/redigo v1.8.1
 	github.com/sirupsen/logrus v1.6.0
+	github.com/spf13/cast v1.3.1
 	golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
 )

+ 2 - 0
go.sum

@@ -4,6 +4,7 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
 github.com/gomodule/redigo v1.8.1 h1:Abmo0bI7Xf0IhdIPc7HZQzZcShdnmxeoVuDDtIQp8N8=
 github.com/gomodule/redigo v1.8.1/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
@@ -11,6 +12,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=

+ 62 - 49
pay/notify/paid.go

@@ -2,37 +2,58 @@ package notify
 
 import (
 	"fmt"
+	"reflect"
 	"sort"
+	"strings"
 
+	"github.com/fatih/structs"
 	"github.com/silenceper/wechat/v2/util"
+	"github.com/spf13/cast"
 )
 
-// Base 公用参数
-type Base struct {
-	AppID    string `xml:"appid"`
-	MchID    string `xml:"mch_id"`
-	NonceStr string `xml:"nonce_str"`
-	Sign     string `xml:"sign"`
-}
+// doc: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
 
 // PaidResult 下单回调
 type PaidResult struct {
-	Base
-	ReturnCode    string `xml:"return_code"`
-	ReturnMsg     string `xml:"return_msg"`
-	ResultCode    string `xml:"result_code"`
-	OpenID        string `xml:"openid"`
-	IsSubscribe   string `xml:"is_subscribe"`
-	TradeType     string `xml:"trade_type"`
-	BankType      string `xml:"bank_type"`
-	TotalFee      int    `xml:"total_fee"`
-	FeeType       string `xml:"fee_type"`
-	CashFee       int    `xml:"cash_fee"`
-	CashFeeType   string `xml:"cash_fee_type"`
-	TransactionID string `xml:"transaction_id"`
-	OutTradeNo    string `xml:"out_trade_no"`
-	Attach        string `xml:"attach"`
-	TimeEnd       string `xml:"time_end"`
+	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"`
+	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"`
+	CouponFeed0 *string `xml:"coupon_fee_0"`
+	CouponFeed1 *string `xml:"coupon_fee_1"`
+	CouponFeed2 *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 消息通知返回
@@ -43,46 +64,38 @@ type PaidResp struct {
 
 // PaidVerifySign 支付成功结果验签
 func (notify *Notify) PaidVerifySign(notifyRes PaidResult) bool {
-	// 封装map 请求过来的 map
-	resMap := make(map[string]interface{})
-	// base
-	resMap["appid"] = notifyRes.AppID
-	resMap["mch_id"] = notifyRes.MchID
-	resMap["nonce_str"] = notifyRes.NonceStr
-	// NotifyResult
-	resMap["return_code"] = notifyRes.ReturnCode
-	resMap["result_code"] = notifyRes.ResultCode
-	resMap["openid"] = notifyRes.OpenID
-	resMap["is_subscribe"] = notifyRes.IsSubscribe
-	resMap["trade_type"] = notifyRes.TradeType
-	resMap["bank_type"] = notifyRes.BankType
-	resMap["total_fee"] = notifyRes.TotalFee
-	resMap["fee_type"] = notifyRes.FeeType
-	resMap["cash_fee"] = notifyRes.CashFee
-	resMap["transaction_id"] = notifyRes.TransactionID
-	resMap["out_trade_no"] = notifyRes.OutTradeNo
-	resMap["attach"] = notifyRes.Attach
-	resMap["time_end"] = notifyRes.TimeEnd
-	// 支付key
+	// 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的键值对用&连接起来,略过空值
+
+	// STEP2, 对key=value的键值对用&连接起来,略过空值 & sign
 	var signStrings string
 	for _, k := range sortedKeys {
-		value := fmt.Sprintf("%v", resMap[k])
-		if value != "" {
-			signStrings = signStrings + k + "=" + value + "&"
+		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, 进行MD5签名并且将所有字符转为大写.
 	sign := util.MD5Sum(signStrings)
-	if sign != notifyRes.Sign {
+	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
+}

+ 1 - 0
wechat.go

@@ -2,6 +2,7 @@ package wechat
 
 import (
 	"os"
+
 	"github.com/silenceper/wechat/v2/cache"
 	"github.com/silenceper/wechat/v2/miniprogram"
 	miniConfig "github.com/silenceper/wechat/v2/miniprogram/config"