// 根据 URL RawQuery 来初始化 data *OrderNotifyURLData.
// 如果 RawQuery 里的参数不合法(包括签名不正确) 则返回错误信息, 否则返回 nil.
//  partnerKey: 财付通商户权限密钥Key
func (data *OrderNotifyURLData) CheckAndInit(RawQuery string, partnerKey string) (err error) {
	urlValues, err := url.ParseQuery(RawQuery)
	if err != nil {
		return
	}

	var signature string
	if vs := urlValues["sign"]; len(vs) > 0 && len(vs[0]) > 0 {
		signature = vs[0]
	} else {
		return errors.New("sign is empty")
	}

	var signMethod string
	if vs := urlValues["sign_type"]; len(vs) > 0 && len(vs[0]) > 0 {
		signMethod = vs[0]
	} else {
		signMethod = "MD5"
	}

	// 验证签名是否正确 ===========================================================

	switch signMethod {
	case "MD5", "md5":
		if len(signature) != md5.Size*2 {
			err = fmt.Errorf(`不正确的签名: %q, 长度不对, have: %d, want: %d`,
				signature, len(signature), md5.Size*2)
			return
		}

		urlValues.Del("sign") // sign 不参与签名

		keys := make([]string, 0, len(urlValues))
		for key := range urlValues {
			keys = append(keys, key)
		}
		sort.Strings(keys)

		Hash := md5.New()
		for _, key := range keys {
			// len(urlValues[key]) == 1, 都是单值
			value := urlValues[key][0]
			if len(value) == 0 {
				continue
			}

			Hash.Write([]byte(key))
			Hash.Write([]byte{'='})
			Hash.Write([]byte(value))
			Hash.Write([]byte{'&'})
		}
		Hash.Write([]byte("key="))
		Hash.Write([]byte(partnerKey))

		SignatureHave := make([]byte, md5.Size*2)
		hex.Encode(SignatureHave, Hash.Sum(nil))
		copy(SignatureHave, bytes.ToUpper(SignatureHave))

		if subtle.ConstantTimeCompare(SignatureHave, []byte(signature)) != 1 {
			err = fmt.Errorf("不正确的签名, \r\nhave: %q, \r\nwant: %q", SignatureHave, signature)
			return
		}

	default:
		return fmt.Errorf("没有实现对签名方法 %q 的支持", signMethod)
	}

	// 初始化 ===================================================================

	data.Signature = signature
	data.SignMethod = signMethod

	if vs := urlValues["input_charset"]; len(vs) > 0 && len(vs[0]) > 0 {
		data.Charset = vs[0]
	} else {
		data.Charset = CHARSET_GBK
	}

	if vs := urlValues["notify_id"]; len(vs) > 0 && len(vs[0]) > 0 {
		data.NotifyId = vs[0]
	} else {
		return errors.New("notify_id is empty")
	}

	if vs := urlValues["trade_mode"]; len(vs) > 0 && len(vs[0]) > 0 {
		v0, err := strconv.ParseInt(vs[0], 10, 64)
		if err != nil {
			return err
		}
		data.TradeMode = int(v0)
	} else {
		return errors.New("trade_mode is empty")
	}

	if vs := urlValues["trade_state"]; len(vs) > 0 && len(vs[0]) > 0 {
		v0, err := strconv.ParseInt(vs[0], 10, 64)
		if err != nil {
			return err
		}
		data.TradeState = int(v0)
	} else {
		return errors.New("trade_state is empty")
	}

	if vs := urlValues["bank_billno"]; len(vs) > 0 {
		data.BankBillNo = vs[0]
	}

	if vs := urlValues["transaction_id"]; len(vs) > 0 && len(vs[0]) > 0 {
		data.TransactionId = vs[0]
	} else {
		return errors.New("transaction_id is empty")
	}

	if vs := urlValues["time_end"]; len(vs) > 0 && len(vs[0]) > 0 {
		v0, err := util.ParseTime(vs[0])
		if err != nil {
			return err
		}
		data.TimeEnd = v0
	} else {
		return errors.New("time_end is empty")
	}

	if vs := urlValues["bank_type"]; len(vs) > 0 && len(vs[0]) > 0 {
		data.BankType = vs[0]
	} else {
		return errors.New("bank_type is empty")
	}

	if vs := urlValues["partner"]; len(vs) > 0 && len(vs[0]) > 0 {
		data.PartnerId = vs[0]
	} else {
		return errors.New("partner is empty")
	}

	if vs := urlValues["out_trade_no"]; len(vs) > 0 && len(vs[0]) > 0 {
		data.OutTradeNo = vs[0]
	} else {
		return errors.New("out_trade_no is empty")
	}

	if vs := urlValues["attach"]; len(vs) > 0 {
		data.Attach = vs[0]
	}

	if vs := urlValues["total_fee"]; len(vs) > 0 && len(vs[0]) > 0 {
		v0, err := strconv.ParseInt(vs[0], 10, 64)
		if err != nil {
			return err
		}
		data.TotalFee = int(v0)
	} else {
		return errors.New("total_fee is empty")
	}

	if vs := urlValues["discount"]; len(vs) > 0 && len(vs[0]) > 0 {
		v0, err := strconv.ParseInt(vs[0], 10, 64)
		if err != nil {
			return err
		}
		data.Discount = int(v0)
	}

	if vs := urlValues["transport_fee"]; len(vs) > 0 && len(vs[0]) > 0 {
		v0, err := strconv.ParseInt(vs[0], 10, 64)
		if err != nil {
			return err
		}
		data.TransportFee = int(v0)
	}

	if vs := urlValues["product_fee"]; len(vs) > 0 && len(vs[0]) > 0 {
		v0, err := strconv.ParseInt(vs[0], 10, 64)
		if err != nil {
			return err
		}
		data.ProductFee = int(v0)
	}

	if vs := urlValues["fee_type"]; len(vs) > 0 && len(vs[0]) > 0 {
		v0, err := strconv.ParseInt(vs[0], 10, 64)
		if err != nil {
			return err
		}
		data.FeeType = int(v0)
	} else {
		return errors.New("fee_type is empty")
	}

	return
}
func (this *OrderQueryResponse) GetTimeEnd() (t time.Time, err error) {
	return util.ParseTime(this.TimeEnd)
}