package jdeclpapi

import (
	"crypto/md5"
	"fmt"
	"net/http"
	"sort"
	"strings"
	"time"

	"git.rosy.net.cn/baseapi/platformapi"
	"git.rosy.net.cn/baseapi/utils"
)

const (
	prodURL  = "https://api.jd.com/routerjson"
	prodURL2 = "https://oauth.jd.com/oauth"

	sigKey       = "sign"
	IsvSource    = "ISV0020000000068"
	DepartmentNo = "EBU4418046609452"
	ShipperNo    = "CYS4398046511104"
	ShopNo       = "ESP0020000066348"
	WarehouseNo  = "110014006"
	CustomerCode = "028K595510"
	OrderMark    = "00000000000000000000000000000000000000000000000000"

	// CustomerCode2 = "028K588716"

	state                  = "1212"
	orderType10            = "10" //订单号类型(10：代表ECLP订单号, 20：代表商家订单号)
	orderType20            = "20"
	SalePlatformSource     = "6"
	SalePlatSourceDelivery = "0030001"

	SoStatusCode10010 = "10010" //订单初始化
	SoStatusCode10022 = "10022" //暂停
	SoStatusCode10014 = "10014" //已下发库房
	SoStatusCode10015 = "10015" //任务已分配
	SoStatusCode10016 = "10016" //拣货下架
	SoStatusCode10019 = "10019" //交接发货
	SoStatusCode10018 = "10018" //货品已打包
	SoStatusCode10017 = "10017" //复核
	SoStatusCode10054 = "10054" //分拣中心发货
	SoStatusCode10033 = "10033" //站点验收
	SoStatusCode10034 = "10034" //妥投
	SoStatusCode10038 = "10038" //逆向完成

	TraceInfoStateM625 = "-625" //揽收任务分配
	TraceInfoStateM190 = "-190" //上门接货
	TraceInfoStateM640 = "-640" //配送员完成揽收
	TraceInfoStateM170 = "-170" //分拣中心收货
	TraceInfoStateM790 = "-790" //下单取消
	TraceInfoStateM650 = "-650" //终止揽收

	TraceInfoState200 = "200" //站点装箱发货
	TraceInfoState10  = "10"  //分拣中心验货
	TraceInfoState13  = "13"  //分拣中心分拣
	TraceInfoState16  = "16"  //分拣中心发货
	TraceInfoState60  = "60"  //站点收货
	TraceInfoState80  = "80"  //站点验货
	TraceInfoState110 = "110" //配送员收货
	TraceInfoState150 = "150" //妥投
)

type API struct {
	accessToken string
	appKey      string
	appSecret   string
	client      *http.Client
	config      *platformapi.APIConfig
}

type QuerySpSourceResult struct {
	Website      string `json:"website"`      //销售平台网址
	SpSourceName string `json:"spSourceName"` //销售平台名称
	SpSourceNo   string `json:"spSourceNo"`   //销售平台编号(必填，长度：20)
	Reserve5     string `json:"reserve5"`
	Reserve4     string `json:"reserve4"`
	Reserve3     string `json:"reserve3"`
	Reserve2     string `json:"reserve2"`
	Reserve1     string `json:"reserve1"` //预留字段1
}

type AddOrderParam struct {
	IsvUUID              string `json:"isvUUID"`              //isv出库单号（商家出库单号），作为isv出库的唯一性校验码：长度不能超125
	IsvSource            string `json:"isvSource"`            //ISV来源编号
	ShopNo               string `json:"shopNo"`               //店铺编号(B2C订单必填，B2B（soType=2）订单非必填)
	DepartmentNo         string `json:"departmentNo"`         //事业部编号，且与pin匹配
	WarehouseNo          string `json:"warehouseNo"`          //库房编号，事业部开启寻源拆分服务可不填；否则必填；
	ShipperNo            string `json:"shipperNo"`            //承运商编号
	SalesPlatformOrderNo string `json:"salesPlatformOrderNo"` //销售平台订单号，如果销售平台来源为京东平台，则该字段不能为空，长度不超过200
	SalePlatformSource   string `json:"salePlatformSource"`   //销售平台来源
	ConsigneeName        string `json:"consigneeName"`        //收货人姓名，长度不能超20
	ConsigneeMobile      string `json:"consigneeMobile"`      //收货人手机（收货人电话、手机至少有一个不为空），长度不能超30
	ConsigneeAddress     string `json:"consigneeAddress"`     //收货人地址 ，长度不能超100
	OrderMark            string `json:"orderMark"`            //订单标记位，首位为1代表货到付款
	GoodsNo              string `json:"goodsNo"`              //ECLP商品编号，与商家商品编号二选一必填（两者都指定，以goodsNo为准）
	Price                string `json:"price"`                //商品金额，会在订单面单上线上商品单价
	Quantity             string `json:"quantity"`             //商品的出库数量，必须>0
	// IsvGoodsNo string `json:"isvGoodsNo"` //商家商品编码
}

type AddOrderResult struct {
	EclpSoNo string `json:"eclpSoNo"` //订单的出库单号
}

type CancelOrderResult struct {
	Code string `json:"code"`
	Msg  string `json:"msg"`
}

type QueryOrderStatusResult struct {
	OrderStatusList []struct {
		SoStatusCode string `json:"soStatusCode"`
		OperateTime  string `json:"operateTime"`
		SoStatusName string `json:"soStatusName"`
		OperateUser  string `json:"operateUser"`
	} `json:"orderStatusList"`
	IsvUUID  string `json:"isvUUID"`
	EclpSoNo string `json:"eclpSoNo"`
}

type GetTrackMessagePlusByOrderResult struct {
	ResultData []struct {
		OpeTitle    string `json:"opeTitle"`
		OpeTime     string `json:"opeTime"`
		OpeRemark   string `json:"opeRemark"`
		OpeName     string `json:"opeName"`
		WaybillCode string `json:"waybillCode"`
	} `json:"resultData"`
	ResultCode    string `json:"resultCode"`
	ResultMessage string `json:"resultMessage"`
}

type SearchShopStockParam struct {
	RequestId  string `json:"requestId"`
	DeptNo     string `json:"deptNo"`
	ShopNo     string `json:"shopNo"`
	GoodsNo    string `json:"goodsNo"`
	PageSize   int    `json:"pageSize"`
	PageNumber int    `json:"pageNumber"`
}

type SearchShopStockResult struct {
	PageCount    string `json:"pageCount"`
	ResponseCode string `json:"responseCode"`
	RequestID    string `json:"requestId"`
	ErrMsg       string `json:"errMsg"`
	Data         []struct {
		DeptNo      string `json:"deptNo"`
		StockNum    string `json:"stockNum"`
		GoodsNo     string `json:"goodsNo"`
		WarehouseNo string `json:"warehouseNo"`
		ShopNo      string `json:"shopNo"`
	} `json:"data"`
	PageSize   string `json:"pageSize"`
	PageNumber string `json:"pageNumber"`
}

type QueryStockResult struct {
	RecordCount     int    `json:"recordCount"`
	IsvSku          string `json:"isvSku"`
	DeptName        string `json:"deptName"`
	SellerGoodsSign string `json:"sellerGoodsSign"`
	GoodsNo         string `json:"goodsNo"`
	UsableNum       int    `json:"usableNum"`
	DeptNo          string `json:"deptNo"`
	WarehouseName   string `json:"warehouseName"`
	TotalNum        int    `json:"totalNum"`
	StockType       string `json:"stockType"`
	StockStatus     string `json:"stockStatus"`
	GoodsLevel      string `json:"goodsLevel"`
	WarehouseNo     string `json:"warehouseNo"`
	GoodsName       string `json:"goodsName"`
}

type WaybillReceiveParam struct {
	SalePlat     string `json:"salePlat"`     //是	无	销售平台
	CustomerCode string `json:"customerCode"` //是	无	商家编码
	OrderID      string `json:"orderId"`      //是	无	订单号
	// ThrOrderID           string    `json:"thrOrderId"`           //否	无	销售平台订单号(例如京东订单号或天猫订单号等等。总长度不要超过100。如果有多个单号，用英文,间隔。例如：7898675,7898676)
	SenderName    string `json:"senderName"`    //是	无	寄件人姓名，说明：不能为生僻字
	SenderAddress string `json:"senderAddress"` //是	无	寄件人地址，说明：不能为生僻字
	SenderTel     string `json:"senderTel"`     //否	无	寄件人电话
	// SenderMobile         string    `json:"senderMobile"`         //否	无	寄件人手机(寄件人电话、手机至少有一个不为空)
	// SenderPostcode       string    `json:"senderPostcode"`       //否	100000	寄件人邮编，长度：6位
	ReceiveName    string `json:"receiveName"`    //是	无	收件人名称，说明：不能为生僻字
	ReceiveAddress string `json:"receiveAddress"` //是	无	收件人地址，说明：不能为生僻字
	// Province             string    `json:"province"`             //否	无	收件人省
	// City                 string    `json:"city"`                 //否	无	收件人市
	// County               string    `json:"county"`               //否	无	收件人县
	// Town                 string    `json:"town"`                 //否	无	收件人镇
	// ProvinceID           int       `json:"provinceId"`           //否	无	收件人省编码
	// CityID               int       `json:"cityId"`               //否	无	收件人市编码
	// CountyID             int       `json:"countyId"`             //否	无	收件人县编码
	// TownID               int       `json:"townId"`               //否	无	收件人镇编码
	// SiteType             int       `json:"siteType"`             //否	无	站点类型
	// SiteID               int       `json:"siteId"`               //否	无	站点编码
	// SiteName             string    `json:"siteName"`             //否	无	站点名称
	ReceiveTel string `json:"receiveTel"` //否	无	收件人电话
	// ReceiveMobile string `json:"receiveMobile"` //否	无	收件人手机号(收件人电话、手机至少有一个不为空)
	// Postcode             string    `json:"postcode"`             //否	100000	收件人邮编，长度：6
	PackageCount int     `json:"packageCount"` //是	无	包裹数(大于0，小于1000)
	Weight       float64 `json:"weight"`       //是	2.5	重量(单位：kg，保留小数点后两位)
	// VloumLong            int       `json:"vloumLong"`            //否	无	包裹长(单位：cm,保留小数点后两位)
	// VloumWidth           int       `json:"vloumWidth"`           //否	无	包裹宽(单位：cm，保留小数点后两位)
	// VloumHeight          int       `json:"vloumHeight"`          //否	无	包裹高(单位：cm，保留小数点后两位)
	Vloumn      float64 `json:"vloumn"`                //是	10000	体积(单位：cm3，保留小数点后两位)
	Description string  `json:"description,omitempty"` //否	无	商品描述
	// CollectionValue      int       `json:"collectionValue"`      //否	1	是否代收货款(是：1，否：0。不填或者超出范围，默认是0)
	// CollectionMoney      int       `json:"collectionMoney"`      //否	98.00	代收货款金额(保留小数点后两位)
	// GuaranteeValue       int       `json:"guaranteeValue"`       //否	1	是否保价(是：1，否：0。不填或者超出范围，默认是0)
	// GuaranteeValueAmount int       `json:"guaranteeValueAmount"` //否	100.00	保价金额(保留小数点后两位)
	// SignReturn           int       `json:"signReturn"`           //否	1	签单返还(签单返还类型：0 不返单，1 普通返单，2 校验身份返单，3 电子签返单，4 电子返单+普通返单)
	Aging int `json:"aging"` //否	1	时效(普通：1，工作日：2，非工作日：3，晚间：4。O2O一小时达：5。O2O定时达：6。不填或者超出范围，默认是1)
	// TransType            int       `json:"transType"`            //否	1	运输类型(陆运：1，航空：2。不填或者超出范围，默认是1)
	// Remark               string    `json:"remark"`               //否	无	运单备注，长度：20,说明：打印面单时备注内容也会显示在快递面单上
	// GoodsType            int       `json:"goodsType"`            //否	无	配送业务类型（ 1:普通，3:填仓，4:特配，6:控温，7:冷藏，8:冷冻，9:深冷）默认是1
	// OrderType            int       `json:"orderType"`            //否	无	运单类型。(普通外单：0，O2O外单：1)默认为0
	// ShopCode             string    `json:"shopCode"`             //否	无	门店编码(只O2O运单需要传，普通运单不需要传)
	// OrderSendTime        string    `json:"orderSendTime"`        //否	2014 09 18 08:30:00	预约配送时间（格式：yyyy MM dd HH:mm:ss）
	// WarehouseCode        string    `json:"warehouseCode"`        //否	无	发货仓编码
	// AreaProvID           int       `json:"areaProvId"`           //否	无	接货省ID
	// AreaCityID           int       `json:"areaCityId"`           //否	无	接货市ID
	// ShipmentStartTime    time.Time `json:"shipmentStartTime"`    //否	1	配送起始时间
	// ShipmentEndTime      time.Time `json:"shipmentEndTime"`      //否	1	配送结束时间
	// Idint                string    `json:"idint"`                //否	无	身份证号
	// AddedService         string    `json:"addedService"`         //否	无	扩展服务
	// ExtendField1         string    `json:"extendField1"`         //否	无	扩展字段1
	// ExtendField2         string    `json:"extendField2"`         //否	无	扩展字段2
	// ExtendField3         string    `json:"extendField3"`         //否	无	扩展字段3
	// ExtendField4         int       `json:"extendField4"`         //否	无	扩展字段4
	// ExtendField5         int       `json:"extendField5"`         //否	无	扩展字段5
	// SenderCompany        string    `json:"senderCompany"`        //否	北京市大兴区亦庄经济开发区京东大厦	寄件人公司，长度：50，说明：不能为生僻字
	// ReceiveCompany       string    `json:"receiveCompany"`       //否	北京市大兴区亦庄经济开发区京东大厦	收件人公司，长度：50，说明：不能为生僻字
	// Goods                string    `json:"goods"`                //否	服装、3C等	托寄物名称，长度：200，说明：为避免托运物品在铁路、航空安检中被扣押，请务必下传商品类目或名称，例如：服装、3C等
	// GoodsCount           int       `json:"goodsCount"`           //否	无	寄托物数量
	PromiseTimeType int `json:"promiseTimeType"` //否	无	产品类型（1：特惠送 2：特快送 4：城际闪送 5：同城当日达 6：次晨达 7：微小件 8: 生鲜专送 16：生鲜特快 17、生鲜特惠 21：特惠小包）
	// Freight              int       `json:"freight"`              //否	无	运费
	PickUpStartTime time.Time `json:"pickUpStartTime,omitempty"` //否	1	预约取件开始时间
	PickUpEndTime   time.Time `json:"pickUpEndTime,omitempty"`   //否	1	预约取件结束时间
	// UnpackingInspection  string    `json:"unpackingInspection"`  //否	无	开箱验货标识
	// BoxCode              []string  `json:"boxCode"`              //否	无	商家箱号,多个箱号请用逗号分隔，例如三个箱号为：a123,b456,c789
	// FileURL              string    `json:"fileUrl"`              //否	无	文件url
}

type CancelWayBillParam struct {
	// UserPin      string `json:"userPin"`      //否	pin	用户唯一标识,与下单一致可不填写
	WaybillCode  string `json:"waybillCode"`  //是	VA12345678	运单号
	CustomerCode string `json:"customerCode"` //是	010K00000	商家编码
	Source       string `json:"source"`       //是	JOS	来源
	CancelReason string `json:"cancelReason"` //是	客户取消	取消原因
	OperatorName string `json:"operatorName"` //是	张三	操作人
}

func New(accessToken, appKey, appSecret string, config ...*platformapi.APIConfig) *API {
	curConfig := platformapi.DefAPIConfig
	if len(config) > 0 {
		curConfig = *config[0]
	}
	return &API{
		accessToken: accessToken,
		appKey:      appKey,
		appSecret:   appSecret,
		client:      &http.Client{Timeout: curConfig.ClientTimeout},
		config:      &curConfig,
	}
}

func (a *API) signParam(params map[string]interface{}) (sig string) {
	var valueList []string
	for k, v := range params {
		if k != sigKey {
			if str := fmt.Sprint(v); str != "" {
				valueList = append(valueList, fmt.Sprintf("%s%s", k, str))
			}
		}
	}
	sort.Sort(sort.StringSlice(valueList))
	valueList = append(valueList, fmt.Sprintf("%s", a.appSecret))
	var valueList2 = make([]string, len(valueList)+1)
	at := copy(valueList2, valueList[:0])
	at += copy(valueList2[at:], []string{a.appSecret})
	copy(valueList2[at:], valueList[0:])
	sig = strings.Join(valueList2, "")
	binSig := md5.Sum([]byte(sig))
	sig = fmt.Sprintf("%X", binSig)
	return sig
}

func (a *API) AccessAPI(action string, url string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
	params := make(map[string]interface{})
	var fullURL string
	if url == prodURL2 {
		params = utils.MergeMaps(params, bizParams)
		fullURL = utils.GenerateGetURL(url, action, nil)
	} else {
		params["access_token"] = a.accessToken
		params["app_key"] = a.appKey
		params["timestamp"] = utils.Time2Str(time.Now())
		params["method"] = action
		params["v"] = "2.0"
		params = utils.MergeMaps(params, bizParams)
		signStr := a.signParam(params)
		params["sign"] = signStr
		fullURL = utils.GenerateGetURL(url, "", nil)
	}
	err = platformapi.AccessPlatformAPIWithRetry(a.client,
		func() *http.Request {
			request, _ := http.NewRequest(http.MethodPost, fullURL, strings.NewReader(utils.Map2URLValues(params).Encode()))
			request.Header.Set("charset", "UTF-8")
			request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
			return request
		},
		a.config,
		func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
			if jsonResult1 == nil {
				return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
			}
			if err == nil {
				if jsonResult1["error_response"] != nil {
					errLevel = platformapi.ErrLevelGeneralFail
					err = utils.NewErrorCode(jsonResult1["error_response"].(map[string]interface{})["zh_desc"].(string), jsonResult1["error_response"].(map[string]interface{})["code"].(string))
				}
				retVal = jsonResult1
			}
			return errLevel, err
		})
	return retVal, err
}

//获取销售平台信息
//https://open.jd.com/home/home#/doc/api?apiCateId=138&apiId=947&apiName=jingdong.eclp.master.querySpSource
func (a *API) QuerySpSource() (querySpSourceResult []*QuerySpSourceResult, err error) {
	result, err := a.AccessAPI("jingdong.eclp.master.querySpSource", prodURL, nil)
	if err == nil {
		utils.Map2StructByJson(result["jingdong_eclp_master_querySpSource_responce"].(map[string]interface{})["queryspsource_result"], &querySpSourceResult, false)
	}
	return querySpSourceResult, err
}

//销售出库单下发
//https://open.jd.com/home/home#/doc/api?apiCateId=138&apiId=928&apiName=jingdong.eclp.order.addOrder
func (a *API) AddOrder(addOrderParam *AddOrderParam) (eclpSoNo string, err error) {
	result, err := a.AccessAPI("jingdong.eclp.order.addOrder", prodURL, utils.Struct2FlatMap(addOrderParam))
	if err == nil {
		return result["jingdong_eclp_order_addOrder_responce"].(map[string]interface{})["eclpSoNo"].(string), err
	}
	return "", err
}

//销售出库单取消
//https://open.jd.com/home/home#/doc/api?apiCateId=138&apiId=957&apiName=jingdong.eclp.order.cancelOrder
func (a *API) CancelOrder(eclpSoNo string) (cancelOrderResult *CancelOrderResult, err error) {
	result, err := a.AccessAPI("jingdong.eclp.order.cancelOrder", prodURL, map[string]interface{}{
		"eclpSoNo": eclpSoNo,
	})
	if err == nil {
		utils.Map2StructByJson(result["jingdong_eclp_order_cancelOrder_responce"].(map[string]interface{})["cancelorder_result"], &cancelOrderResult, false)
	}
	return cancelOrderResult, err
}

//销售出库单状态查询
//https://jos.jd.com/api/detail.htm?apiName=jingdong.eclp.order.queryOrderStatus&id=929
func (a *API) QueryOrderStatus(eclpSoNo string) (queryOrderStatus *QueryOrderStatusResult, err error) {
	result, err := a.AccessAPI("jingdong.eclp.order.queryOrderStatus", prodURL, map[string]interface{}{
		"eclpSoNo": eclpSoNo,
	})
	if err == nil {
		utils.Map2StructByJson(result["jingdong_eclp_order_queryOrderStatus_responce"].(map[string]interface{})["queryorderstatus_result"], &queryOrderStatus, false)
	}
	return queryOrderStatus, err
}

//查询物流跟踪消息
//https://open.jd.com/home/home#/doc/api?apiCateId=138&apiId=2378&apiName=jingdong.eclp.order.getTrackMessagePlusByOrder
func (a *API) GetTrackMessagePlusByOrder(bizCode string) (getTrackMessagePlusByOrderResult *GetTrackMessagePlusByOrderResult, err error) {
	result, err := a.AccessAPI("jingdong.eclp.order.getTrackMessagePlusByOrder", prodURL, map[string]interface{}{
		"bizCode":      bizCode,
		"customerCode": CustomerCode,
		"type":         orderType20,
	})
	if err == nil {
		utils.Map2StructByJson(result["jingdong_eclp_order_getTrackMessagePlusByOrder_responce"].(map[string]interface{})["getTrackMessagePlusByOrder_result"], &getTrackMessagePlusByOrderResult, false)
	}
	return getTrackMessagePlusByOrderResult, err
}

//查询仓库商品库存
//https://open.jd.com/home/home#/doc/api?apiCateId=138&apiId=3396&apiName=jingdong.eclp.stock.searchShopStock
func (a *API) SearchShopStock(goodsNo string) (searchShopStockResult *SearchShopStockResult, err error) {
	params := map[string]interface{}{
		"requestId":  utils.GetUUID(),
		"deptNo":     DepartmentNo,
		"shopNo":     ShopNo,
		"pageSize":   100,
		"pageNumber": 1,
	}
	if goodsNo != "" {
		params["goodsNo"] = goodsNo
	}
	result, err := a.AccessAPI("jingdong.eclp.stock.searchShopStock", prodURL, params)
	if err == nil {
		utils.Map2StructByJson(result["jingdong_eclp_stock_searchShopStock_responce"].(map[string]interface{})["shopStockSearchResponse"], &searchShopStockResult, false)
	}
	return searchShopStockResult, err
}

//查询仓库商品库存
//https://open.jd.com/home/home#/doc/api?apiCateId=138&apiId=3396&apiName=jingdong.eclp.stock.searchShopStock
func (a *API) QueryStock(goodsNo string) (queryStockResult []*QueryStockResult, err error) {
	params := map[string]interface{}{
		"deptNo":          DepartmentNo,
		"warehouseNo":     WarehouseNo,
		"returnZeroStock": 2, //表示返回库存为0的数据
		"stockType":       1,
		"stockStatus":     1, //良品
	}
	if goodsNo != "" {
		params["goodsNo"] = goodsNo
	}
	result, err := a.AccessAPI("jingdong.eclp.stock.queryStock", prodURL, params)
	if err == nil {
		utils.Map2StructByJson(result["jingdong_eclp_stock_queryStock_responce"].(map[string]interface{})["querystock_result"], &queryStockResult, false)
	}
	return queryStockResult, err
}

//京东物流接单接口
//https://open.jd.com/home/home#/doc/api?apiCateId=64&apiId=2122&apiName=jingdong.ldop.waybill.receive
func (a *API) WaybillReceive(waybillReceiveParam *WaybillReceiveParam) (deliveryId string, err error) {
	result, err := a.AccessAPI("jingdong.ldop.waybill.receive", prodURL, utils.Struct2FlatMap(waybillReceiveParam))
	if err == nil {
		if utils.MustInterface2Int64(result["jingdong_ldop_waybill_receive_responce"].(map[string]interface{})["receiveorderinfo_result"].(map[string]interface{})["resultCode"]) != 100 {
			return deliveryId, fmt.Errorf(result["jingdong_ldop_waybill_receive_responce"].(map[string]interface{})["receiveorderinfo_result"].(map[string]interface{})["resultMessage"].(string))
		} else {
			deliveryId = result["jingdong_ldop_waybill_receive_responce"].(map[string]interface{})["receiveorderinfo_result"].(map[string]interface{})["deliveryId"].(string)
		}
	}
	return deliveryId, err
}

//京东物流取消接口
//https://open.jd.com/home/home#/doc/api?apiCateId=75&apiId=3482&apiName=jingdong.ldop.delivery.provider.cancelWayBill
func (a *API) CancelWayBill(cancelWayBillParam *CancelWayBillParam) (err error) {
	_, err = a.AccessAPI("jingdong.ldop.delivery.provider.cancelWayBill", prodURL, utils.Struct2FlatMap(cancelWayBillParam))
	return err
}

type QueryDynamicTraceInfoResult struct {
	OpeTitle    string `json:"opeTitle"`
	OpeTime     string `json:"opeTime"`
	State       string `json:"state"`
	OpeRemark   string `json:"opeRemark"`
	OpeName     string `json:"opeName"`
	WaybillCode string `json:"waybillCode"`
}

//京东物流全程跟踪接口
//https://open.jd.com/home/home#/doc/api?apiCateId=64&apiId=4257&apiName=jingdong.trace.dynamicQueryService.queryDynamicTraceInfo
func (a *API) QueryDynamicTraceInfo(waybillCode string) (queryDynamicTraceInfo []*QueryDynamicTraceInfoResult, err error) {
	result, err := a.AccessAPI("jingdong.trace.dynamicQueryService.queryDynamicTraceInfo", prodURL, map[string]interface{}{
		"waybillCode":  waybillCode,
		"customerCode": CustomerCode,
	})
	if err == nil {
		utils.Map2StructByJson(result["jingdong_trace_dynamicQueryService_queryDynamicTraceInfo_responce"].(map[string]interface{})["response"].(map[string]interface{})["data"], &queryDynamicTraceInfo, false)
	}
	return queryDynamicTraceInfo, err
}

type WaybillQueryResult struct {
	Weight        float64 `json:"weight"`
	DeliveryID    string  `json:"deliveryId"`
	GoodNumber    int     `json:"goodNumber"`
	StatusCode    int     `json:"statusCode"`
	StatusMessage string  `json:"statusMessage"`
}

//京东物流运单查询
//https://open.jd.com/home/home#/doc/api?apiCateId=64&apiId=2189&apiName=jingdong.ldop.waybill.query
func (a *API) WaybillQuery(deliveryId string) (waybill *WaybillQueryResult, err error) {
	result, err := a.AccessAPI("jingdong.ldop.waybill.query", prodURL, map[string]interface{}{
		"deliveryId":   deliveryId,
		"customerCode": CustomerCode,
	})
	if err == nil {
		utils.Map2StructByJson(result["jingdong_ldop_waybill_query_responce"].(map[string]interface{})["resultInfo"].(map[string]interface{})["data"], &waybill, false)
	}
	if waybill == nil {
		utils.Map2StructByJson(result["jingdong_ldop_waybill_query_responce"].(map[string]interface{})["resultInfo"], &waybill, false)
	}
	return waybill, err
}
