package mtpsapi import ( "crypto/sha1" "fmt" "net/http" "net/url" "sort" "strconv" "strings" "git.rosy.net.cn/baseapi/platformapi" "git.rosy.net.cn/baseapi/utils" ) const ( mtpsAPIURL = "https://peisongopen.meituan.com/api" signKey = "sign" ) const ( OrderStatusWaitingForSchedule = 0 OrderStatusAccepted = 20 OrderStatusPickedUp = 30 OrderStatusDeliverred = 50 OrderStatusCanceled = 99 ) const ( OrderExceptCodePhonePoweroff = 10001 OrderExceptCodePhoneSuspended = 10002 OrderExceptCodePhoneNobody = 10003 OrderExceptCodePhoneEmpty = 10004 OrderExceptCodePhoneWrong = 10005 OrderExceptCodePhoneOther = 10006 OrderExceptCodeAddressWrong = 10101 OrderExceptCodeAddressOutOfService = 10201 OrderExceptCodeUserReject = 10202 OrderExceptCodeUserRequestDelay = 10203 OrderExceptCodeStoreClosed = 10401 ) var ( OrderStatusName = map[int]string{ OrderExceptCodePhonePoweroff: "电话关机", OrderExceptCodePhoneSuspended: "电话停机", OrderExceptCodePhoneNobody: "无人接听", OrderExceptCodePhoneEmpty: "电话空号", OrderExceptCodePhoneWrong: "电话错误", OrderExceptCodePhoneOther: "电话其它原因", OrderExceptCodeAddressWrong: "地址错误", OrderExceptCodeAddressOutOfService: "地址超区", OrderExceptCodeUserReject: "用户拒收", OrderExceptCodeUserRequestDelay: "要求延迟配送", OrderExceptCodeStoreClosed: "门店关店", } ) const ( DeliveryServiceCodeRapid = 4011 DeliveryServiceCodeIntime = 4012 DeliveryServiceCodeTogether = 4013 ) const ( PickupTypeClientSendToStation = 1 PickupTypeMtPick = 2 ) const ( OrderTypeASAP = 0 OrderTypeBook = 1 ) const ( CoordinateTypeMars = 0 CoordinateTypeBaidu = 1 ) // 错误码 const ( ResponseCodeSuccess = 0 ) // 取消原因 const ( CancelReasonClientActive = 101 CancelReasonClientChangeTimeOrAddress = 102 CancelReasonGoodsRelated = 103 CancelReasonMerchantOther = 199 CancelReasonMtpsAttitude = 201 CancelReasonRidderSendNotIntime = 202 CancelReasonRideerGetGoodNotIntime = 203 CancelReasonRideerMtpsOther = 299 CancelReasonRideerOther = 399 ) type OrderInfoCommon struct { DeliveryID int64 MtPeisongID string OrderID string CourierName string CourierPhone string } type OrderInfo struct { OrderInfoCommon Status int OperateTime int CancelReasonID int CancelReason string } type OrderResponse struct { MtPeisongID string `json:"mt_peisong_id"` DeliveryID int64 `json:"delivery_id"` OrderID string `json:"order_id"` } type ResponseResult struct { Code int `json:"code"` Message string `json:"message"` Data map[string]interface{} `json:"data"` } type CreateOrderByShopParam struct { DeliveryID int64 `json:"delivery_id"` OrderID string `json:"order_id"` ShopID string `json:"shop_id"` DeliveryServiceCode int `json:"delivery_service_code"` ReceiverName string `json:"receiver_name"` ReceiverAddress string `json:"receiver_address"` ReceiverPhone string `json:"receiver_phone"` ReceiverLng int `json:"receiver_lng"` ReceiverLat int `json:"receiver_lat"` CoordinateType int `json:"coordinate_type"` GoodsValue float64 `json:"goods_value"` GoodsWeight float64 `json:"goods_weight"` // ExpectedDeliveryTime int64 `json:"expected_delivery_time"` OrderType int `json:"order_type"` } type GoodsItem struct { GoodCount int `json:"goodCount"` GoodName string `json:"goodName"` GoodPrice float64 `json:"goodPrice"` GoodUnit string `json:"goodUnit"` } type GoodsDetail struct { Goods []*GoodsItem `json:"goods"` } type API struct { appKey string secret string client *http.Client config *platformapi.APIConfig } func New(appKey, secret string, config ...*platformapi.APIConfig) *API { curConfig := platformapi.DefAPIConfig if len(config) > 0 { curConfig = *config[0] } return &API{ appKey: appKey, secret: secret, client: &http.Client{Timeout: curConfig.ClientTimeout}, config: &curConfig, } } func (a *API) signParams(params url.Values) string { keys := make([]string, 0) for k := range params { if k != signKey { keys = append(keys, k) } } sort.Strings(keys) finalStr := a.secret for _, key := range keys { valStr := strings.Join(params[key], "") if valStr != "" { finalStr += key + valStr } } // baseapi.SugarLogger.Debug(finalStr) return fmt.Sprintf("%x", sha1.Sum([]byte(finalStr))) } func (a *API) AccessAPI(action string, params map[string]interface{}) (retVal *ResponseResult, err error) { if params == nil { panic("params is nil!") } params2 := make(url.Values) for k, v := range params { params2[k] = []string{fmt.Sprint(v)} } params2["appkey"] = []string{a.appKey} params2["timestamp"] = []string{utils.Int64ToStr(utils.GetCurTimestamp())} params2["version"] = []string{"1.0"} params2[signKey] = []string{a.signParams(params2)} // baseapi.SugarLogger.Debug(params2.Encode()) err = platformapi.AccessPlatformAPIWithRetry(a.client, func() *http.Request { request, _ := http.NewRequest(http.MethodPost, mtpsAPIURL+"/"+action, strings.NewReader(params2.Encode())) request.Header.Set("Content-Type", "application/x-www-form-urlencoded") return request }, a.config, func(jsonResult1 map[string]interface{}) (result string, err error) { code := int(utils.MustInterface2Int64(jsonResult1["code"])) retVal = &ResponseResult{ Code: code, } if code == ResponseCodeSuccess { if innerData, ok := jsonResult1["data"]; ok { retVal.Data, _ = innerData.(map[string]interface{}) } return platformapi.ErrLevelSuccess, nil } retVal.Message = jsonResult1["message"].(string) newErr := utils.NewErrorIntCode(retVal.Message, code) return platformapi.ErrLevelCodeIsNotOK, newErr }) return retVal, err } func (a *API) result2OrderResponse(result *ResponseResult) (order *OrderResponse) { order = new(OrderResponse) order.MtPeisongID = result.Data["mt_peisong_id"].(string) order.DeliveryID = utils.MustInterface2Int64(result.Data["delivery_id"]) order.OrderID = result.Data["order_id"].(string) return order } func (a *API) CreateOrderByShop(basicParams *CreateOrderByShopParam, addParams map[string]interface{}) (order *OrderResponse, err error) { params := utils.Struct2MapByJson(basicParams) params["goods_value"] = strconv.FormatFloat(basicParams.GoodsValue, 'f', 2, 64) params["goods_weight"] = strconv.FormatFloat(basicParams.GoodsWeight, 'f', 2, 64) allParams := utils.MergeMaps(params, addParams) if params["order_type"] != utils.Int2Str(OrderTypeBook) { delete(params, "expected_delivery_time") } if result, err := a.AccessAPI("order/createByShop", allParams); err != nil { return nil, err } else { return a.result2OrderResponse(result), nil } } func (a *API) QueryOrderStatus(deliveryId int64, mtPeiSongId string) (retVal map[string]interface{}, err error) { params := map[string]interface{}{ "delivery_id": deliveryId, "mt_peisong_id": mtPeiSongId, } if result, err := a.AccessAPI("order/status/query", params); err != nil { return nil, err } else { return result.Data, nil } } func (a *API) CancelOrder(deliveryId int64, mtPeiSongId string, cancelReasonId int, cancelReason string) (result *OrderResponse, err error) { params := map[string]interface{}{ "delivery_id": deliveryId, "mt_peisong_id": mtPeiSongId, "cancel_reason_id": cancelReasonId, "cancel_reason": cancelReason, } if result, err := a.AccessAPI("order/delete", params); err != nil { return nil, err } else { return a.result2OrderResponse(result), nil } } func (a *API) simulateOrderBehavior(action string, deliveryId int64, mtPeiSongId string) (err error) { params := map[string]interface{}{ "delivery_id": deliveryId, "mt_peisong_id": mtPeiSongId, } _, err = a.AccessAPI("test/order/"+action, params) return err } func (a *API) SimulateArrange(deliveryId int64, mtPeiSongId string) (err error) { return a.simulateOrderBehavior("arrange", deliveryId, mtPeiSongId) } func (a *API) SimulatePickup(deliveryId int64, mtPeiSongId string) (err error) { return a.simulateOrderBehavior("pickup", deliveryId, mtPeiSongId) } func (a *API) SimulateDeliver(deliveryId int64, mtPeiSongId string) (err error) { return a.simulateOrderBehavior("deliver", deliveryId, mtPeiSongId) } func (a *API) SimulateRearrange(deliveryId int64, mtPeiSongId string) (err error) { return a.simulateOrderBehavior("rearrange", deliveryId, mtPeiSongId) } func (a *API) SimulateReportException(deliveryId int64, mtPeiSongId string) (err error) { return a.simulateOrderBehavior("reportException", deliveryId, mtPeiSongId) }