Files
baseapi/platformapi/jdapi/callback.go
2019-12-07 23:52:35 +08:00

342 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package jdapi
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
)
const (
CallbackPrefix = "/djsw/"
)
// 如下的常量其实都是京东回调消息的
const (
OrderStatusAddComment = "12001"
OrderStatusModifyComment = "12006"
OrderStatusTipChanged = "12008"
OrderStatusPurchased = "41000" // 也即待处理JD的消息很怪新订单消息发过来是32000但如果不是自动接单的去查却是41000接单后才变为32000
OrderStatusPayed = "31020" // 已付款
StatusIDNewOrder = "32000"
OrderStatusWaitOutStore = "32000"
OrderStatusAdjust = "33080"
StatusIDWaitOutStore = "32001"
OrderStatusFinishedPickup = "2"
OrderStatusDelivering = "33040"
OrderStatusDelivered = "33060"
OrderStatusFinished = "90000"
OrderStatusCanceled = "20020"
OrderStatusUserApplyCancel = "20030" // 这个其实不是一个状态,是一个动作
OrderStatusLocked = "20010"
OrderStatusUnlocked = "20050"
OrderStatusInfoChanged = "1" // 订单信息变更消息
OrderStatusPayFinishedSettle = "330901" // 订单支付完成应结
OrderStatusAdjustSettle = "330902" // 订单调整后应结
OrderStatusSwitch2SelfSettle = "330903" // 订单众包配送转自送后应结
PromotionStatusSingleOK = "35" // 单品直降活动已生效
PromotionStatusLimitTimeOK = "45" // 限时抢活动已生效
)
const (
StatusIDAddStore = "12003" // 新增门店消息
StatusIDDelStore = "12004" // 删除门店消息
StatusIDUpdateStore = "12009" // 修改门店消息
)
const (
AfsServiceStateWaiting4Audit = "10" // 待审核
AfsServiceStateWaiting4UserFeedback = "11" // 待用户反馈
AfsServiceStateWaiting4CSFeedback = "12" // 待客服反馈
AfsServiceStateWaiting4GetGoods = "20" // 待取件
AfsServiceStateRefundProcessing = "30" // 退款处理中
AfsServiceStateWaiting4MerchantReceiveGoods = "31" // 待商家收货审核
AfsServiceStateRefundSuccess = "32" // 退款成功
AfsServiceStateRefundFailed = "33" // 退款失败
AfsServiceStateAuditRefused = "40" // 审核不通过-驳回
AfsServiceStateUserCanceled = "50" // 客户取消
AfsServiceStateMerchantFailedReceiveGoods = "60" // 商家收货审核不通过
AfsServiceStateSolved = "70" // 已解决
AfsServiceStateWaiting4DirectCompensate = "90" // 待直陪
AfsServiceStateDirectCompensate = "91" // 直赔
AfsServiceStateDirectCompensateSuccess = "92" // 直赔成功
AfsServiceStateDirectCompensateFailed = "93" // 直赔失败
AfsServiceStateWaiting4ReturnGoods = "110" // 待退货
AfsServiceStateGetGoodsSuccess = "111" // 取货成功
AfsServiceStateGettingGoods = "1101" // 取货中
AfsServiceStateGetGoods2Shop = "1111" // 退货成功-商品已送至门店
AfsServiceStateGetGoodsConfirmed = "1112" // 退货成功-商家已确认收货
AfsServiceStateGetGoodsWaiting4Refund = "112" // 退货成功-待退款
AfsServiceStateReturnGoodsFailed = "113" // 退货失败
AfsServiceStateReturnGoodsSuccess = "114" // 退货成功
)
const (
// 订单
CallbackMsgDeliveryCarrierModify = "deliveryCarrierModify" // 订单转自送消息(是指转自送成功后,用处不大)
CallbackMsgOrderAccounting = "orderAccounting" // 订单应结消息
CallbackMsgApplyCancelOrder = "applyCancelOrder"
CallbackMsgPushDeliveryStatus = "pushDeliveryStatus"
// 账务
CallbackMsgEndOrderFinance = "endOrderFinance" // 订单金额拆分完成消息
CallbackMsgFinanceAdjustment = "financeAdjustment" // 财务调整单消息
// 售后
CallbackMsgNewApplyAfterSaleBill = "newApplyAfterSaleBill" // 新建售后单申请消息
CallbackMsgUpdateApplyAfterSaleBill = "updateApplyAfterSaleBill" // 修改售后单申请消息
CallbackMsgNewAfterSaleBill = "newAfterSaleBill" // 新建售后单消息
CallbackMsgAfterSaleBillStatus = "afterSaleBillStatus" // 售后单状态消息
CallbackMsgStockIsHave = "stockIsHave"
)
type CallbackResponse struct {
Code string `json:"code"`
Msg string `json:"msg"`
Data string `json:"data"`
}
type CallbackMsg struct {
MsgURL string `json:"msgURL"`
AppKey string `json:"app_key"`
Token string `json:"token"`
Timestamp string `json:"timestamp"`
Sign string `json:"sign"`
Format string `json:"format"`
V string `json:"v"`
JdParamJSON string `json:"jd_param_json"`
Param interface{} `json:"-"` // 这里json必须是-否则会导致json encode时死递归
}
type CallbackOrderMsg struct {
*CallbackMsg
BillID string `json:"billId"`
OutBillID string `json:"outBillId"`
StatusID string `json:"statusId"`
Timestamp string `json:"timestamp"`
Remark string `json:"remark"`
}
type CallbackDeliveryStatusMsg struct {
*CallbackMsg
OrderID string `json:"orderId"`
DeliveryStatusTime string `json:"deliveryStatusTime"`
DeliveryManNo string `json:"deliveryManNo"`
DeliveryManName string `json:"deliveryManName"`
DeliveryManPhone string `json:"deliveryManPhone"`
DeliveryCarrierNo string `json:"deliveryCarrierNo"`
DeliveryCarrierName string `json:"deliveryCarrierName"`
DeliveryStatus string `json:"deliveryStatus"`
Remark string `json:"remark"`
FailType string `json:"failType"`
CreatePin string `json:"createPin"`
OpTime string `json:"opTime"`
InputTime string `json:"inputTime"`
}
type CallbackStoreStockMsg struct {
*CallbackMsg
StationNo string `json:"stationNo"`
SkuID int64 `json:"skuId"`
Have bool `json:"have"`
Vendibility int `json:"vendibility"`
OperPin string `json:"operPin"`
OperTime int64 `json:"operTime"`
OperSource int `json:"operSource"`
}
const (
OpenSourceJDLSP = 1
OpenSourceJDMedicineCity = 2
OpenSourceJDMerchantDirect = 3
OpenSourceJDOne = 4
OpenSourceStockCenter = 5
OpenSourceOrderCenter = 6
OpenSourceGoodsSystem = 7
OpenSourcePrepositionWH = 8
OpenSourceStoreSystem = 9
OpenSourceMerchantCenter = 10
OpenSourceOpenPlatform = 11
OpenSourcePickupSystem = 13
OpenSourceBatchTask = 14
)
var (
SuccessResponse = &CallbackResponse{Code: "0", Msg: "success", Data: ""}
FormatErrorResponse = &CallbackResponse{Code: "-1", Msg: "failed", Data: ""}
needDecodeMap = map[string]bool{
CallbackMsgApplyCancelOrder: true,
CallbackMsgPushDeliveryStatus: true,
CallbackMsgStockIsHave: true,
}
)
func Err2CallbackResponse(err error, data string) *CallbackResponse {
if err == nil {
return SuccessResponse
}
return &CallbackResponse{
Code: ResponseCodeFailedCanAutoRetry,
Msg: err.Error(),
Data: data,
}
}
func unmarshalData(strData string, msg interface{}) (callbackResponse *CallbackResponse) {
err := utils.UnmarshalUseNumber([]byte(strData), msg)
if err != nil {
return &CallbackResponse{
Code: ResponseCodeAbnormalParam,
Msg: fmt.Sprintf(platformapi.ErrStrUnmarshalError, strData, err),
Data: strData,
}
}
return nil
}
func GetCallbackMsg(request *http.Request, needDecode bool) (values url.Values, token, msgURL string, callbackResponse *CallbackResponse) {
data, err := ioutil.ReadAll(request.Body)
if err != nil {
return nil, "", "", Err2CallbackResponse(err, "")
}
values, err = utils.HTTPBody2Values(data, needDecode)
if err != nil {
return nil, "", "", FormatErrorResponse
}
token = values.Get("token")
return values, token, getMsgURLFromRequest(request), nil
}
func (a *API) CheckCallbackValidation(values url.Values) (callbackResponse *CallbackResponse) {
mapData := utils.URLValues2Map(values)
sign := a.signParams(mapData)
if sign != values.Get(signKey) {
baseapi.SugarLogger.Infof("Signature is not ok, mine:%v, get:%v", sign, values.Get(signKey))
return FormatErrorResponse
}
return nil
}
func (a *API) getCommonOrderCallbackMsg(values url.Values, msg interface{}) (callbackResponse *CallbackResponse) {
if callbackResponse = a.CheckCallbackValidation(values); callbackResponse != nil {
return callbackResponse
}
jdParamJSON := values.Get(paramJson)
// baseapi.SugarLogger.Debug(jdParamJSON)
if callbackResponse = unmarshalData(jdParamJSON, msg); callbackResponse != nil {
return callbackResponse
}
return nil
}
func (a *API) GetOrderCallbackMsg(values url.Values, msgURL string) (msg *CallbackOrderMsg, callbackResponse *CallbackResponse) {
if callbackResponse = a.getCommonOrderCallbackMsg(values, &msg); callbackResponse == nil {
msg.CallbackMsg = &CallbackMsg{
MsgURL: msgURL,
}
}
return msg, callbackResponse
}
func (a *API) GetOrderDeliveryCallbackMsg(values url.Values, msgURL string) (msg *CallbackDeliveryStatusMsg, callbackResponse *CallbackResponse) {
callbackResponse = a.getCommonOrderCallbackMsg(values, &msg)
return msg, callbackResponse
}
func (a *API) GetStoreStockCallbackMsg(values url.Values, msgURL string) (msg *CallbackStoreStockMsg, callbackResponse *CallbackResponse) {
var tmpMsg map[string]interface{}
callbackResponse = a.getCommonOrderCallbackMsg(values, &tmpMsg)
if callbackResponse == nil {
msg = map2StockCallbackMsg(tmpMsg)
}
return msg, callbackResponse
}
func map2StockCallbackMsg(mapData map[string]interface{}) (msg *CallbackStoreStockMsg) {
msg = &CallbackStoreStockMsg{
StationNo: utils.Interface2String(mapData["stationNo"]),
SkuID: utils.Str2Int64(utils.Interface2String(mapData["skuId"])),
Vendibility: int(utils.Str2Int64(utils.Interface2String(mapData["vendibility"]))),
OperPin: utils.Interface2String(mapData["operPin"]),
OperTime: utils.Str2Int64(utils.Interface2String(mapData["operTime"])),
OperSource: int(utils.Str2Int64((utils.Interface2String(mapData["operSource"])))),
Have: utils.Interface2String(mapData["have"]) == "true",
}
return msg
}
func getMsgURLFromRequest(request *http.Request) (msgURL string) {
index := strings.Index(request.URL.Path, CallbackPrefix)
if index >= 0 {
msgURL = request.URL.Path[index+len(CallbackPrefix):]
}
return msgURL
}
func GetCallbackMsg2(request *http.Request) (callbackMsg *CallbackMsg, mapData map[string]interface{}, callbackResponse *CallbackResponse) {
msgURL := getMsgURLFromRequest(request)
data, err := ioutil.ReadAll(request.Body)
if err != nil {
return nil, nil, Err2CallbackResponse(err, "")
}
values, err := utils.HTTPBody2Values(data, needDecodeMap[msgURL])
if err != nil {
return nil, nil, FormatErrorResponse
}
mapData = utils.URLValues2Map(values)
if err = utils.Map2StructByJson(mapData, &callbackMsg, false); err == nil {
callbackMsg.MsgURL = msgURL
if msgURL == CallbackMsgDeliveryCarrierModify {
var deliveryMsg *CallbackDeliveryStatusMsg
if err = utils.UnmarshalUseNumber([]byte(callbackMsg.JdParamJSON), &deliveryMsg); err == nil {
callbackMsg.Param = deliveryMsg
deliveryMsg.CallbackMsg = callbackMsg
}
} else if msgURL == CallbackMsgStockIsHave {
var mapData map[string]interface{}
if err = utils.UnmarshalUseNumber([]byte(callbackMsg.JdParamJSON), &mapData); err == nil {
stockMsg := map2StockCallbackMsg(mapData)
callbackMsg.Param = stockMsg
stockMsg.CallbackMsg = callbackMsg
}
} else {
var orderMsg *CallbackOrderMsg
if err = utils.UnmarshalUseNumber([]byte(callbackMsg.JdParamJSON), &orderMsg); err == nil {
callbackMsg.Param = orderMsg
orderMsg.CallbackMsg = callbackMsg
}
}
}
if err != nil {
return nil, nil, Err2CallbackResponse(err, "")
}
return callbackMsg, mapData, callbackResponse
}
func (a *API) CheckCallbackValidation2(mapData map[string]interface{}, signInData string) (callbackResponse *CallbackResponse) {
sign := a.signParams(mapData)
if sign != signInData {
baseapi.SugarLogger.Infof("Signature is not ok, mine:%s, signInData:%s", sign, signInData)
return FormatErrorResponse
}
return nil
}