diff --git a/platformapi/tiktok/callback.go b/platformapi/tiktok/callback.go index b54690bd..2337b8f3 100644 --- a/platformapi/tiktok/callback.go +++ b/platformapi/tiktok/callback.go @@ -1,213 +1,90 @@ package tiktok -// -//import ( -// "encoding/base64" -// "encoding/xml" -// "fmt" -// "io/ioutil" -// "net/http" -// "strings" -// -// "git.rosy.net.cn/baseapi/utils" -// "git.rosy.net.cn/jx-callback/globals" -// "github.com/clbanning/mxj" -// "github.com/nanjishidu/gomini/gocrypto" -//) -// -//type CData string -// -//func (c CData) MarshalXTT(e *xml.Encoder, start xml.StartElement) error { -// return e.EncodeElement(struct { -// string `xml:",cdata"` -// }{string(c)}, start) -//} -// -//const ( -// MsgTypeUnkown = 0 // 未知 -// MsgTypePay = 1 // 支付结果回调 -// MsgTypeRefund = 2 // 退款结果回调 -//) -// -//type CallbackResponse struct { -// XMLName xml.Name `json:"-" xml:"xml"` -// -// ReturnCode string `json:"return_code" xml:"return_code"` -// ReturnMsg CData `json:"return_msg" xml:"return_msg"` -//} -// -//type BaseResultMsg struct { -// ReturnCode string `json:"return_code" xml:"return_code"` -// ReturnMsg string `json:"return_msg" xml:"return_msg"` -// -// AppID string `json:"appid" xml:"appid"` -// DeviceInfo string `json:"device_info,omitempty" xml:"device_info,omitempty"` -// MchID string `json:"mch_id" xml:"mch_id"` -// NonceStr string `json:"nonce_str" xml:"nonce_str"` -// Sign string `json:"sign" xml:"sign"` -// ResultCode string `json:"result_code" xml:"result_code"` -// ResultMsg string `json:"result_msg" xml:"result_msg"` -// ErrCode string `json:"err_code,omitempty" xml:"err_code,omitempty"` -// ErrCodeDes string `json:"err_code_des,omitempty" xml:"err_code_des,omitempty"` -//} -// -//type PayResultMsg struct { -// ReturnCode string `json:"return_code" xml:"return_code"` -// ReturnMsg string `json:"return_msg" xml:"return_msg"` -// -// AppID string `json:"appid" xml:"appid"` -// DeviceInfo string `json:"device_info,omitempty" xml:"device_info,omitempty"` -// MchID string `json:"mch_id" xml:"mch_id"` -// NonceStr string `json:"nonce_str" xml:"nonce_str"` -// Sign string `json:"sign" xml:"sign"` -// ResultCode string `json:"result_code" xml:"result_code"` -// ResultMsg string `json:"result_msg" xml:"result_msg"` -// ErrCode string `json:"err_code,omitempty" xml:"err_code,omitempty"` -// ErrCodeDes string `json:"err_code_des,omitempty" xml:"err_code_des,omitempty"` -// -// BankType string `json:"bank_type"` -// CashFee string `json:"cash_fee"` -// FeeType string `json:"fee_type"` -// IsSubscribe string `json:"is_subscribe"` -// OpenID string `json:"openid"` -// OutTradeNo string `json:"out_trade_no"` -// TimeEnd string `json:"time_end"` -// TotalFee string `json:"total_fee"` -// TradeType string `json:"trade_type"` -// TransactionID string `json:"transaction_id"` -//} -// -//type RefundReqInfo struct { -// OutRefundNo string `json:"out_refund_no"` -// OutTradeNo string `json:"out_trade_no"` -// RefundAccount string `json:"refund_account"` -// RefundFee string `json:"refund_fee" xml:"refund_fee"` -// RefundID string `json:"refund_id"` -// RefundRecvAccout string `json:"refund_recv_accout"` -// RefundRequestSource string `json:"refund_request_source"` -// RefundStatus string `json:"refund_status"` -// SettlementRefundFee string `json:"settlement_refund_fee"` -// SettlementTotalFee string `json:"settlement_total_fee"` -// SuccessTime string `json:"success_time"` -// TotalFee string `json:"total_fee"` -// TransactionID string `json:"transaction_id"` -//} -// -//type RefundResultMsg struct { -// ReturnCode string `json:"return_code" xml:"return_code"` -// ReturnMsg string `json:"return_msg" xml:"return_msg"` -// -// AppID string `json:"appid" xml:"appid"` -// DeviceInfo string `json:"device_info,omitempty" xml:"device_info,omitempty"` -// MchID string `json:"mch_id" xml:"mch_id"` -// NonceStr string `json:"nonce_str" xml:"nonce_str"` -// Sign string `json:"sign" xml:"sign"` -// ResultCode string `json:"result_code" xml:"result_code"` -// ResultMsg string `json:"result_msg" xml:"result_msg"` -// ErrCode string `json:"err_code,omitempty" xml:"err_code,omitempty"` -// ErrCodeDes string `json:"err_code_des,omitempty" xml:"err_code_des,omitempty"` -// -// ReqInfoStr string `json:"req_info,omitempty"` -// ReqInfoObj *RefundReqInfo `json:"req_info_obj,omitempty"` -//} -// -//type CallbackMsg struct { -// MsgType int -// MapData map[string]interface{} -// Data interface{} -//} -// -//var ( -// SuccessResponse = &CallbackResponse{ -// ReturnCode: ResponseCodeSuccess, -// ReturnMsg: "OK", -// } -//) -// -//func Err2CallbackResponse(err error, data string) *CallbackResponse { -// if err == nil { -// return SuccessResponse -// } -// returnMsg := err.Error() -// if data != "" { -// returnMsg = fmt.Sprintf("%s,%s", returnMsg, data) -// } -// return &CallbackResponse{ -// ReturnCode: ResponseCodeFail, -// ReturnMsg: CData(returnMsg), -// } -//} -// -//func (a *API) decodeReqInfo(msg string) (decryptedMsg string, err error) { -// binMsg, err := base64.StdEncoding.DecodeString(msg) -// if err == nil { -// // aesKey := []byte(fmt.Sprintf("%x", md5.Sum([]byte(a.appKey)))) -// // binResult, err2 := utils.AESCBCDecpryt(binMsg, aesKey, aesKey[:16]) -// gocrypto.SetAesKey(strings.ToLower(gocrypto.Md5(a.appKey))) -// binResult, err2 := gocrypto.AesECBDecrypt(binMsg) -// if err = err2; err == nil { -// decryptedMsg = string(binResult) -// } -// } -// return decryptedMsg, err -//} -// -//func (a *API) GetCallbackMsg(request *http.Request) (msg *CallbackMsg, callbackResponse *CallbackResponse) { -// data, err := ioutil.ReadAll(request.Body) -// if err != nil { -// return nil, Err2CallbackResponse(err, "") -// } -// return a.getCallbackMsg(string(data)) -//} -// -//func (a *API) getCallbackMsg(msgBody string) (msg *CallbackMsg, callbackResponse *CallbackResponse) { -// mapData, _, err := a.parseXmlStrAsMap(msgBody) -// if err != nil { -// return nil, Err2CallbackResponse(err, "") -// } -// returnCode := utils.Interface2String(mapData["return_code"]) -// if returnCode != ResponseCodeSuccess { // 如果return_code出错,直接返回 -// return nil, SuccessResponse -// } -// -// reqInfo := utils.Interface2String(mapData["req_info"]) -// transactionID := utils.Interface2String(mapData["transaction_id"]) -// if reqInfo == "" && transactionID != "" { // 对于支付结果通知进行签名验证(退款结果通知不支持验证) -// sigType := utils.Interface2String(mapData[sigTypeKey]) -// sign := utils.Interface2String(mapData[sigKey]) -// desiredSign := a.signParam(sigType, mapData) -// if desiredSign != sign { -// globals.SugarLogger.Debugf("transactionID:%s, sigType:%s, desiredSign:%s <> sign:%s", transactionID, sigType, desiredSign, sign) -// return nil, Err2CallbackResponse(fmt.Errorf("desiredSign:%s <> sign:%s", desiredSign, sign), "") -// } -// } -// -// msg = &CallbackMsg{ -// MapData: mapData, -// } -// if reqInfo != "" { -// msg.MsgType = MsgTypeRefund -// var refundResult *RefundResultMsg -// if err = utils.Map2StructByJson(mapData, &refundResult, false); err == nil { -// if reqInfo, err = a.decodeReqInfo(reqInfo); err == nil { -// mv, err2 := mxj.NewMapXml([]byte(reqInfo)) -// if err = err2; err == nil { -// reqInfoMap := mv["root"].(map[string]interface{}) -// if err = utils.Map2StructByJson(reqInfoMap, &refundResult.ReqInfoObj, false); err == nil { -// msg.Data = refundResult -// } -// } -// } -// } -// } else if transactionID != "" { -// msg.MsgType = MsgTypePay -// var payResult *PayResultMsg -// if err = utils.Map2StructByJson(mapData, &payResult, false); err == nil { -// msg.Data = payResult -// } -// } -// if err != nil { -// callbackResponse = Err2CallbackResponse(err, "") -// } -// return msg, callbackResponse -//} +import ( + "encoding/json" + "git.rosy.net.cn/baseapi/utils" + "io/ioutil" + "net/http" +) + +const ( + PayStatus = "payment" // 回调类型标记,支付成功回调为"payment" + RefundStatus = "refund" // 回调类型标记,退款回调为"refund" + + WxPayWay = "1" // 1-微信支付 + ZfbPayWay = "2" // 2-支付宝支付 + TtPayWay = "10" // 10-抖音支付 +) + +type CallBackResult struct { + Timestamp int `json:"timestamp"` // Unix 时间戳,10 位,整型数 + Nonce string `json:"nonce"` // 随机数 + Msg string `json:"msg"` // 订单信息的 json 字符串 + TypePay string `json:"type"` // 回调类型标记,支付成功回调为"payment" + Msgsignature string `json:"msgsignature"` // 签名,详见 +} + +// 详细信息MSG(支付回调) +type DetailCallBackMessage struct { + AppId string `json:"appid"` // 当前交易发起的小程序id + CpOrderno string `json:"cp_orderno"` // 开发者侧的订单号 + CpExtra string `json:"cp_extra"` // 预下单时开发者传入字段 + Way string `json:"way"` // way 字段中标识了支付渠道:1-微信支付,2-支付宝支付,10-抖音支付 + ChannelNo string `json:"channel_no"` // 支付渠道侧单号 + PaymentOrderNo string `json:"payment_order_no"` // 支付渠道侧商家订单号 + TotalAmount int64 `json:"total_amount"` // 支付金额,单位为分 + Status string `json:"status"` // 固定SUCCESS + ItemId string `json:"item_id"` // 订单来源视频对应视频 id + SellerUid string `json:"seller_uid"` // 该笔交易卖家商户号 + PaidAt int64 `json:"paid_at"` // 支付时间,Unix 时间戳,10 位,整型数 + OrderId string `json:"order_id"` // 抖音侧订单号 +} + +// 详细信息MSG(退款回调) +type DetailCallBackMessage2Refund struct { + AppId string `json:"appid"` // 当前交易发起的小程序id + CpRefundno string `json:"cp_refundno"` // 开发者侧的退款订单号 + CpExtra string `json:"cp_extra"` // 预下单时开发者传入字段 + Status string `json:"status"` // 固定SUCCESS/FAIL + RefundAmount int64 `json:"refund_amount"` // 退款金额 + RefundedAt int64 `json:"refunded_at"` // 退款时间 + Message string `json:"message"` // 退款失败描述 + OrderId string `json:"order_id"` // 抖音侧订单号 + +} + +func (a *API) GetCallbackMsg(request *http.Request) (call *DetailCallBackMessage, refund *DetailCallBackMessage2Refund, payType string, err error) { + data, err := ioutil.ReadAll(request.Body) + if err != nil { + return nil, nil, "", err + } + values, err := utils.HTTPBody2Values(data, false) + if err != nil { + return nil, nil, "", err + } + + payInfo := &CallBackResult{} + if err := utils.Map2StructByJson(utils.URLValues2Map(values), &payInfo, false); err != nil { + return nil, nil, "", err + } + + // 支付回调 + if payInfo.TypePay == PayStatus { + payDetailResult := &DetailCallBackMessage{} + if err := json.Unmarshal([]byte(payInfo.Msg), payDetailResult); err != nil { + return nil, nil, "", err + } + return payDetailResult, nil, payInfo.TypePay, err + } + + // 退款回调 + if payInfo.TypePay == RefundStatus { + refundDetailResult := &DetailCallBackMessage2Refund{} + if err := json.Unmarshal([]byte(payInfo.Msg), refundDetailResult); err != nil { + return nil, nil, "", err + } + return nil, refundDetailResult, payInfo.TypePay, err + } + + return nil, nil, "", err +} diff --git a/platformapi/tiktok/tiktok_pay.go b/platformapi/tiktok/tiktok_pay.go index d1d6d61c..edcd01d7 100644 --- a/platformapi/tiktok/tiktok_pay.go +++ b/platformapi/tiktok/tiktok_pay.go @@ -10,7 +10,11 @@ import ( "time" ) -const salt = "TUsUuzcfWriQ8ZXUQOrxPcScjEGlgMSjJaDMCtVy" +const ( + salt = "TUsUuzcfWriQ8ZXUQOrxPcScjEGlgMSjJaDMCtVy" + ResponseCodeSuccess = "SUCCESS" + ResponseCodeFail = "FAIL" +) // 获取支付签名 func (a *API) Sign(paramsMap map[string]interface{}) string {