package ebaiapi import ( "errors" "fmt" "git.rosy.net.cn/baseapi" "git.rosy.net.cn/baseapi/utils" "net/http" "net/url" ) const ( CmdOrderCreate = "order.create" CmdOrderDeliveryStatus = "order.deliveryStatus.push" CmdOrderPartRefund = "order.partrefund.push" // 售前只能是商户发起 售后是用户, 你看是由谁发起的就可以知道,来自惠焕(部分退款,饿百废弃了) CmdOrderReversePush = "order.reverse.push" // 订单逆向消息推送 CmdOrderStatus = "order.status.push" CmdOrderUserCancel = "order.user.cancel" CmdShopMsgPush = "shop.msg.push" CmdShopBindMsg = "shop.bind.msg" CmdShopUnbindMsg = "shop.unbind.msg" //IM消息回调通知 CmdImMessageSendEvent = "im.message.send.event" //用户/骑手消息通知 CmdImMessageReadEvent = "im.message.read.event" //用户/骑手已读通知 ) type CallbackResponse struct { Cmd string `json:"cmd"` Sign string `json:"sign"` Source string `json:"source"` Ticket string `json:"ticket"` Encrypt string `json:"encrypt"` Timestamp int64 `json:"timestamp"` Version int `json:"version"` Body *ResponseResult `json:"body"` } type CallbackMsg struct { Cmd string `json:"cmd"` Version string `json:"version"` Timestamp int64 `json:"timestamp"` Ticket string `json:"ticket"` Source string `json:"source"` Sign string `json:"sign"` Encrypt string `json:"encrypt"` Body map[string]interface{} `json:"body"` Data interface{} `json:"data"` } type EBaiShopList struct { BaiduShopID string `json:"baidu_shop_id"` ShopID string `json:"shop_id"` Name string `json:"name"` Source string `json:"source"` SupplierID string `json:"supplier_id"` } type CBPartRefundInfo struct { OrderID int64 `json:"order_id"` RefundID string `json:"refund_id"` Type int `json:"type"` Status int `json:"status"` AdditionReason string `json:"addition_reason"` Photos []string `json:"photos"` ReasonType string `json:"reason_type"` Reason string `json:"reason"` RefundProducts []*struct { SkuID string `json:"sku_id"` Upc string `json:"upc"` CustomSkuID string `json:"custom_sku_id"` Name string `json:"name"` Number int `json:"number"` TotalRefund int64 `json:"total_refund"` ShopEleRefund int64 `json:"shop_ele_refund"` } `json:"refund_products"` RefundPrice int64 `json:"refund_price"` } type CBOrderReversePush struct { EventId string `json:"event_id"` // 操作事件全局唯一事件 PlatformShopId int `json:"platform_shop_id"` // 平台门店ID OrderId string `json:"order_id"` // 订单ID RefundOrderId int64 `json:"refund_order_id"` // 逆向单号 CurReverseEvent struct { EventId string `json:"event_id"` // 操作事件全局唯一事件 ImageList []string `json:"image_list"` // 操作凭证列表 LastRefundStatus int `json:"last_refund_status"` // 逆向单操作前的退货状态:0-无效状态,1001-买家已申请退货,等待审批处理,1002-商家拒绝退货申请,1003-退货仲裁已发起,客服介入中,1004-已同意退货,等待发货,1005-已发货,等待卖家确认收货,1006-已收到货,并同意退款, 1007-未收到货,不同意退款,1008-退货关闭 LastReturnGoodsStatus int `json:"last_return_goods_status"` // 逆向单操作前的逆向单状态:0-初始化,10-申请,20-拒绝,30-仲裁,40-关闭,50-成功,60-失败 OccurTime int64 `json:"occur_time"` // 逆向单操作事件发生时间 单位:毫秒 OperatorRole int `json:"operator_role"` // 逆向单操作者角色:10 用户 ,20商户,30客服 ,25 API商家代客发起,40系统 OrderId string `json:"order_id"` // 订单ID ReasonCode int `json:"reason_code"` // 逆向单操作原因对应code,具体原因枚举详见文档https://open-retail.ele.me/#/guide?topic=ntmt8f ReasonContent string `json:"reason_content"` // 逆向单操作原因备注内容 RefundOrderId int64 `json:"refund_order_id"` // 逆向单号 RefundReasonDesc string `json:"refund_reason_desc"` // 逆向单操作原因code对应的文案 RefundStatus int `json:"refund_status"` // 即当前的逆向单状态:0-初始化,10-申请,20-拒绝,30-仲裁,40-关闭,50-成功,60-失败 ReturnGoodsStatus int `json:"return_goods_status"` // 即当前的退货状态):0-无效状态,1001-买家已申请退货,等待审批处理,1002-商家拒绝退货申请,1003-退货仲裁已发起,客服介入中,1004-已同意退货,等待发货,1005-已发货,等待卖家确认收货,1006-已收到货,并同意退款, 1007-未收到货,不同意退款,1008-退货关闭 } `json:"cur_reverse_event"` // 逆向单当前操作信息 } type CBUserCancelInfo struct { OrderID int64 `json:"order_id"` CancelReason string `json:"cancel_reason"` AdditionReason string `json:"addition_reason"` RefuseReason string `json:"refuse_reason"` Pictures []string `json:"pictures"` Type int `json:"type"` CancelType int `json:"cancel_type"` ReasonCodeDesc string `json:"reason_code_desc"` PlatformShopId int `json:"platform_shop_id"` ReasonCode int `json:"reason_code"` RefundOrderId string `json:"refund_order_id"` IsReturnGoods string `json:"is_return_goods"` } //temp IM 用户/骑手消息通知 type TempSent struct { SubBizType string `json:"subBizType"` //业务子类型,枚举值:SEND_MESSAGE-发送消息 BizType string `json:"bizType"` //业务类型,枚举值:IM-消息 PayLoad struct { SenderID string `json:"senderId"` //角色+随机数字串;角色:10(用户)、20(骑手)、30(商家)、32(连锁账号登录) ReceiverIDs []string `json:"receiverIds"` //角色+随机数字串;角色:10(用户)、20(骑手)、30(商家)、32(连锁账号登录) CreateTime int64 `json:"createTime"` //时间戳 GroupID string `json:"groupId"` //会话id MsgID string `json:"msgId"` //消息ID ContentType int `json:"contentType"` //消息类型,枚举值:1-普通文本 } `json:"payload"` PlatformShopID string `json:"platformShopId"` //平台门店ID } //IM 用户/骑手消息通知 type ImMessageSend struct { SubBizType string `json:"subBizType"` //业务子类型,枚举值:SEND_MESSAGE-发送消息 BizType string `json:"bizType"` //业务类型,枚举值:IM-消息 PayLoad PayLoad `json:"payLoad"` PlatformShopID string `json:"platformShopId"` //平台门店ID } type PayLoad struct { SenderID string `json:"senderId"` //角色+随机数字串;角色:10(用户)、20(骑手)、30(商家)、32(连锁账号登录) ReceiverIDs []string `json:"receiverIds"` //角色+随机数字串;角色:10(用户)、20(骑手)、30(商家)、32(连锁账号登录) CreateTime int `json:"createTime"` //时间戳 GroupID string `json:"groupId"` //会话id MsgID string `json:"msgId"` //消息ID ContentType string `json:"contentType"` //消息类型,枚举值:1-普通文本 Content string `json:"content"` } //ContentType =1-普通文本,8-@消息 type Content struct { Text string `json:"text"` } //IM 用户/骑手已读通知 type ImMessageRead struct { PlatformShopID string `json:"platformShopId"` //平台门店ID BizType string `json:"bizType"` //业务类型,枚举值:IM-消息 SubBizType string `json:"subBizType"` //业务子类型,枚举值:READ_MESSAGE-读取消息 PayLoad struct { MsgIDs string `json:"msgIds"` //消息ID 列表 CID string `json:"cid"` //会话id UID string `json:"uid"` //已读操作人 } `json:"payLoad"` } func (a *API) Err2CallbackResponse(cmd string, err error, data interface{}) *CallbackResponse { response := &CallbackResponse{ Cmd: "resp." + cmd, Source: a.source, Ticket: utils.GetUpperUUID(), Timestamp: utils.GetCurTimestamp(), Version: 3, } if err == nil { response.Body = &ResponseResult{ Error: "success", ErrNo: 0, Data: data, } } else { response.Body = &ResponseResult{ Error: fmt.Sprintf("error:%v, data:%v", err, data), ErrNo: -1, Data: data, } } params := url.Values{ "cmd": []string{response.Cmd}, "version": []string{utils.Int2Str(response.Version)}, "timestamp": []string{utils.Int64ToStr(response.Timestamp)}, "ticket": []string{response.Ticket}, "source": []string{response.Source}, "body": []string{string(utils.MustMarshal(response.Body))}, "encrypt": []string{""}, } response.Sign = a.signParams(params) return response } func (a *API) unmarshalData(cmd string, data []byte, msg interface{}) (callbackResponse *CallbackResponse) { err := utils.UnmarshalUseNumber(data, msg) if err != nil { return a.Err2CallbackResponse(cmd, err, nil) } return nil } func (a *API) CheckCallbackValidation(cmd string, params url.Values) (callbackResponse *CallbackResponse) { sign := a.signParams(params) if sign != params.Get(signKey) { msg := fmt.Sprintf("Signature is not ok, mine:%v, get:%v", sign, params.Get(signKey)) baseapi.SugarLogger.Info(msg) return a.Err2CallbackResponse(cmd, errors.New(msg), nil) } return nil } func (a *API) GetCallbackMsg(request *http.Request) (msg *CallbackMsg, callbackResponse *CallbackResponse) { err := request.ParseForm() if err == nil { params := make(url.Values) for k := range request.PostForm { decodedValue, _ := url.QueryUnescape(request.PostFormValue(k)) params.Set(k, decodedValue) } msg = new(CallbackMsg) msg.Cmd = GetCmd(request) if callbackResponse = a.CheckCallbackValidation(msg.Cmd, params); callbackResponse != nil { return nil, callbackResponse } if callbackResponse = a.unmarshalData(msg.Cmd, []byte(params.Get("body")), &msg.Body); callbackResponse != nil { return nil, callbackResponse } msg.Timestamp = utils.Str2Int64(params.Get("timestamp")) msg.Version = params.Get("version") msg.Ticket = params.Get("ticket") msg.Source = params.Get("source") msg.Sign = params.Get("sign") msg.Encrypt = params.Get("encrypt") var tmpObj interface{} switch msg.Cmd { case CmdOrderPartRefund: var partRefundData CBPartRefundInfo tmpObj = &partRefundData case CmdOrderUserCancel: var userCancelData CBUserCancelInfo tmpObj = &userCancelData case CmdImMessageSendEvent: tmpObj = &ImMessageSend{} case CmdImMessageReadEvent: tmpObj = &ImMessageRead{} case CmdOrderReversePush: var reversePush CBOrderReversePush tmpObj = &reversePush } if tmpObj != nil { if utils.Map2StructByJson(msg.Body, tmpObj, true) == nil { msg.Data = tmpObj } } return msg, nil } return nil, a.Err2CallbackResponse("", err, nil) } func GetCmd(request *http.Request) (cmd string) { cmd, _ = url.QueryUnescape(request.FormValue("cmd")) return cmd }