package mtwmapi import ( "net/http" "net/url" "strings" "time" "git.rosy.net.cn/baseapi" "git.rosy.net.cn/baseapi/utils" ) const ( MsgPoiStatusOpened = 121 // 121=营业 MsgPoiStatusClosed = 120 // 120=休息 MsgPoiStatusOnline = 18 // 18=上线 MsgPoiStatusOffline = 19 // 19=下线 ) const ( MsgTypeWaybillStatus = "waybillStatus" MsgTypeNewOrder = "newOrder" MsgTypeOrderAccepted = "orderAccepted" MsgTypeOrderFinished = "orderFinished" MsgTypeOrderFinancial = "orderFinancial" MsgTypeOrderCanceled = "orderCanceled" MsgTypeUserUrgeOrder = "userUrgeOrder" MsgTypePrivateNumberDowngrade = "numberDowngrade" MsgTypeOrderModified = "orderModified" // 这个不是订单调整,是订单信息(地址、联系人等)变化后推送的消息 MsgTypeOrderRefund = "orderRefund" MsgTypeOrderPartialRefund = "orderPartialRefund" MsgTypeOrderFinishedPickup = "orderFinishedPickup" MsgTypeStoreStatusChanged = "storeStatusChanged" MsgTypeStoreAuditStatusChanged = "storeAuditStatusChanged" ) type CallbackResponse struct { Data string `json:"data"` } // 全额退款没有Food, FoodList, Money项 type CallbackRefundInfo struct { Timestamp int64 `json:"timestamp"` AppID string `json:"app_id"` Sig string `json:"sig"` OrderID int64 `json:"order_id"` NotifyType string `json:"notify_type"` RefundID int64 `json:"refund_id"` Ctime int64 `json:"ctime"` Reason string `json:"reason"` ResType int `json:"res_type"` IsAppeal int `json:"is_appeal"` Pictures string `json:"pictures"` PictureList []string `json:"pictureList"` Food string `json:"food"` FoodList []*RefundSkuDetail `json:"foodList"` Money float32 `json:"money"` } type CallbackMsg struct { Cmd string Timestamp int64 `json:"timestamp"` AppID string `json:"app_id"` Sig string `json:"sig"` FormData url.Values Data interface{} } var ( SuccessResponse = &CallbackResponse{Data: "ok"} SignatureIsNotOk = &CallbackResponse{Data: "sign failed"} ) func Err2CallbackResponse(err error, data string) *CallbackResponse { if err == nil { return SuccessResponse } if data == "" { data = err.Error() } return &CallbackResponse{ Data: data, } } func (a *API) GetCallbackMsg(request *http.Request) (msg *CallbackMsg, callbackResponse *CallbackResponse) { err := request.ParseForm() if err == nil { data := utils.URLValues2Map(request.Form) if dataSign, ok := data[signKey]; ok { fullURL := strings.TrimRight(a.callbackURL+request.URL.Path, "/") sign := a.signParams(fullURL+"?", data) if sign != dataSign.(string) { baseapi.SugarLogger.Debugf("mtwm GetCallbackMsg my sign:%v, data sign:%v", sign, dataSign.(string)) callbackResponse = SignatureIsNotOk } else { cmd := strings.Trim(request.URL.EscapedPath(), "/") cmd = cmd[strings.LastIndex(cmd, "/")+1:] msg = &CallbackMsg{ Cmd: cmd, } msg.FormData = make(url.Values) for k, v := range data { // 美团外卖的用户催单信息的timestamp是毫秒(其它的事件是秒),统一归一化为秒 if cmd == MsgTypeUserUrgeOrder && k == "timestamp" { intV := utils.Str2Int64(v.(string)) if intV > time.Now().Unix()*2 { v = utils.Int64ToStr(intV / 1000) data[k] = v } } msg.FormData.Set(k, v.(string)) } msg.Timestamp = utils.Str2Int64(msg.FormData.Get("timestamp")) msg.Sig = dataSign.(string) msg.AppID = msg.FormData.Get("app_id") if msg.Cmd == MsgTypeOrderRefund || msg.Cmd == MsgTypeOrderPartialRefund { var refundData *CallbackRefundInfo if err = utils.Map2StructByJson(data, &refundData, true); err == nil { if refundData.Food != "" { utils.UnmarshalUseNumber([]byte(refundData.Food), &refundData.FoodList) } if refundData.Pictures != "" { utils.UnmarshalUseNumber([]byte(refundData.Pictures), &refundData.PictureList) } msg.Data = refundData } } } } else { callbackResponse = SuccessResponse // 美团外卖PING消息没有sign } } else { baseapi.SugarLogger.Warnf("mtwm GetCallbackMsg ParseForm failed with error:%v", err) callbackResponse = Err2CallbackResponse(err, "") } return msg, callbackResponse } func (a *API) GetRefundSkuDetailFromMsg(msg *CallbackMsg) (refundSkuDetail []*RefundSkuDetail) { utils.UnmarshalUseNumber([]byte(msg.FormData.Get("food")), &refundSkuDetail) return refundSkuDetail }