- refactor result parser.

This commit is contained in:
gazebo
2018-08-29 23:23:34 +08:00
parent cc7be396ea
commit e0c1aae0fc
10 changed files with 466 additions and 270 deletions

View File

@@ -0,0 +1,14 @@
package jdapi
// 新版订单金额拆分接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=182&apiid=4d1494c5e7ac4679bfdaaed950c5bc7f
func (a *API) QueryOassBussMoney(orderId string) ([]interface{}, error) {
jdParams := map[string]interface{}{
"orderId": orderId,
}
result, err := a.AccessAPINoPage("oassBussService/queryOassBussMoney", jdParams, nil, nil, genNoPageResultParser("errorCode", "errorInfos", "data", "0"))
if err != nil {
return nil, err
}
return result.([]interface{}), nil
}

View File

@@ -0,0 +1,15 @@
package jdapi
import (
"testing"
)
func TestQueryOassBussMoney(t *testing.T) {
bussResult, bussErr := jdapi.QueryOassBussMoney("815536199000222")
if bussErr != nil {
t.Error(bussErr.Error())
}
if len(bussResult) <= 0 {
t.Error("错误返回数据长度不该为0")
}
}

View File

@@ -73,21 +73,24 @@ var (
ResponseCodeLoadUnexpected: 1,
}
innerCodeKeys = []string{"code", "retCode", "errorCode"}
// innerCodeKeys = []string{"code", "retCode", "errorCode"}
// innerCodeOKCodes = map[string]int{
// "None": 1,
// "0": 1,
// "1": 1,
// "200": 1,
// "190005": 1, // 部分失败
// }
// noPageInnerDataKeys = []string{"result", "data"}
innerCodeOKCodes = map[string]int{
"None": 1,
"0": 1,
"1": 1,
"200": 1,
"190005": 1, // 部分失败
}
noPageInnerDataKeys = []string{"result", "data"}
havePageInner2DataKeys = []string{"result", "resultList"}
havePageTotalCountKeys = []string{"totalCount", "count"}
)
var (
nullResultParser = genNoPageResultParser("code", "msg", "", "0")
)
type PageResultParser func(map[string]interface{}, int) ([]interface{}, int, error)
func (a *API) signParams(jdParams map[string]interface{}) string {
@@ -153,6 +156,7 @@ func (a *API) AccessAPI(apiStr string, jdParams map[string]interface{}) (retVal
a.config,
func(response *http.Response) (errLevel string, err error) {
jsonResult1, err := utils.HTTPResponse2Json(response)
// baseapi.SugarLogger.Debug(utils.Format4Output(jsonResult1, false))
if err != nil {
return platformapi.ErrLevelGeneralFail, platformapi.ErrResponseDataFormatWrong
}
@@ -173,32 +177,34 @@ func (a *API) AccessAPI(apiStr string, jdParams map[string]interface{}) (retVal
return retVal, err
}
func normalNoPageResultParser(data map[string]interface{}) (interface{}, error) {
innerCode := ""
for _, innerCodeKey := range innerCodeKeys {
if innerCode2, ok := data[innerCodeKey]; ok {
innerCode = forceInnerCode2Str(innerCode2)
break
func genNoPageResultParser(codeKey, msgKey, resultKey, okCode string) func(data map[string]interface{}) (interface{}, error) {
return func(data map[string]interface{}) (interface{}, error) {
rawInnerCode, ok := data[codeKey]
if !ok {
panic(fmt.Sprintf("genNoPageResultParser codeKey %s can not be found in result:%v", codeKey, data))
}
}
if innerCode == "" {
panic(fmt.Sprintf("can not find innerCode, data:%v", data))
}
if _, ok := innerCodeOKCodes[innerCode]; ok {
for _, innerDataKey := range noPageInnerDataKeys {
if innerData, ok := data[innerDataKey]; ok {
return innerData, nil
innerCode := forceInnerCode2Str(rawInnerCode)
if innerCode == okCode {
if resultKey != "" {
if innerData, ok := data[resultKey]; ok {
return innerData, nil
}
baseapi.SugarLogger.Warnf("genNoPageResultParser resultKey %s can not be found in result:%v", resultKey, data)
return nil, nil // 容错
// panic(fmt.Sprintf("genNoPageResultParser resultKey %s can not be found in result:%v", resultKey, data))
}
return nil, nil
}
panic(fmt.Sprintf("can not find inner data, data:%v", data))
// return nil, platformapi.ErrResponseDataFormatWrong
if msg, ok := data[msgKey]; ok {
return nil, utils.NewErrorCode(msg.(string), innerCode, 1)
}
panic(fmt.Sprintf("genNoPageResultParser msgKey %s can not be found in result:%v", msgKey, data))
}
return nil, utils.NewErrorCode(getErrMsgFromData(data), innerCode, 1)
}
func (a *API) AccessAPINoPage(apiStr string, jdParams map[string]interface{}, keyToRemove, keyToKeep []string, resultParser func(data map[string]interface{}) (interface{}, error)) (interface{}, error) {
if resultParser == nil {
resultParser = normalNoPageResultParser
resultParser = genNoPageResultParser("code", "msg", "result", "0")
}
jsonResult, err := a.AccessAPI(apiStr, jdParams)
if err != nil {
@@ -305,7 +311,7 @@ func (a *API) AccessAPIHavePage(apiStr string, jdParams map[string]interface{},
}
innerCode := forceInnerCode2Str(data["code"])
if innerCode != "0" && innerCode != "200" {
if innerCode != "0" {
return nil, totalCount, utils.NewErrorCode(getErrMsgFromData(data), innerCode, 1)
}

View File

@@ -1,9 +1,7 @@
package jdapi
import (
"io/ioutil"
"net/http"
"net/url"
"testing"
"git.rosy.net.cn/baseapi"
@@ -97,176 +95,3 @@ func TestGenerateURL(t *testing.T) {
}
defer response.Body.Close()
}
func TestOrderQuery(t *testing.T) {
jdParams := map[string]interface{}{
"orderId": "813344594000041",
}
result, totalCount, err := jdapi.OrderQuery(jdParams)
if err != nil {
t.Fatalf("OrderQuery return error:%v", err)
}
if len(result) == 0 || totalCount == 0 {
t.Fatal("OrderQuery return empty data")
}
buyerCityOk := false
orderInfo, _ := result[0].(map[string]interface{})
if buyerCity1, ok := orderInfo["buyerCity"]; ok {
if buyerCity, ok := buyerCity1.(string); ok && buyerCity == "2376" {
buyerCityOk = true
}
}
if !buyerCityOk {
t.Fatal("OrderQuery get data wrong")
}
}
func TestGetOrderCallbackMsg(t *testing.T) {
callbackStr := "timestamp=2018-06-27+12%3A43%3A51&sign=84096ADFAB81E224D6231269AD1F6AAB&v=1.0&jd_param_json=%7B%22billId%22%3A%22815338526000221%22%2C%22statusId%22%3A%2232000%22%2C%22timestamp%22%3A%222018-06-27+12%3A42%3A34%22%7D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json"
result, resp := jdapi.GetOrderCallbackMsg([]byte(callbackStr))
if resp != nil {
t.Fatal(resp)
}
sugarLogger.Debug(result)
}
func TestGetOrderDeliveryCallbackMsg(t *testing.T) {
callbackStr := "timestamp=2018-06-27%2B09%253A08%253A41&sign=54D9A8515BB5650DC3B81366E3286570&v=1.0&jd_param_json=%257B%2522createPin%2522%253A%2522JD_21134dac1c251d2%2522%252C%2522deliveryCarrierName%2522%253A%2522%25E8%25BE%25BE%25E8%25BE%25BE%25E4%25B8%2593%25E9%2580%2581%2522%252C%2522deliveryCarrierNo%2522%253A%25229966%2522%252C%2522deliveryStatus%2522%253A%252210%2522%252C%2522deliveryStatusTime%2522%253A%25222018-06-27%2B09%253A08%253A41%2522%252C%2522inputTime%2522%253A%25222018-06-27%2B09%253A08%253A41%2522%252C%2522orderId%2522%253A%2522815324888000121%2522%257D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json"
result, resp := jdapi.GetOrderDeliveryCallbackMsg([]byte(callbackStr))
if resp != nil {
t.Fatal(resp)
}
sugarLogger.Debug(result)
}
func TestGetOrderApplyCancelCallbackMsg(t *testing.T) {
callbackStr := "timestamp=2018-06-27%2B13%253A35%253A29&sign=F1398D658514D8864FFB56F5EF2C4792&v=1.0&jd_param_json=%257B%2522billId%2522%253A%2522815339944000322%2522%252C%2522remark%2522%253A%2522%25E5%2595%2586%25E5%25AE%25B6%25E7%25BC%25BA%25E8%25B4%25A7%2522%252C%2522statusId%2522%253A%252220030%2522%252C%2522timestamp%2522%253A%25222018-06-27%2B13%253A35%253A24%2522%257D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json"
result, resp := jdapi.GetOrderApplyCancelCallbackMsg([]byte(callbackStr))
if resp != nil {
t.Fatal(resp)
}
sugarLogger.Debug(result)
}
func TestSimulateSendNewOrderMsg(t *testing.T) {
orderInfo := &CallbackOrderMsg{
BillID: "813344594000041",
StatusID: OrderStatusNew,
Timestamp: utils.GetCurTimeStr(),
}
params := make(url.Values)
params.Set("token", jdapi.token)
params.Set("app_key", jdapi.appKey)
params.Set("timestamp", utils.GetCurTimeStr())
params.Set("v", "1.0")
params.Set("format", "json")
params.Set(paramJson, string(utils.MustMarshal(orderInfo)))
mapData := utils.URLValues2Map(params)
mapData["app_secret"] = jdapi.appSecret
params.Set(signKey, jdapi.signParams(mapData))
response, err := http.PostForm("http://callback.test.jxc4.com/djsw/newOrder", params)
if err != nil {
t.Fatal(err)
}
bodyData, _ := ioutil.ReadAll(response.Body)
sugarLogger.Debug(string(bodyData))
}
/*
DELETE t1
FROM jdorder t1
WHERE t1.jdorderid = 815438712001141;
*/
func TestCallbackMsgPlayback(t *testing.T) {
baseURL := "http://callback.test.jxc4.com:8080/"
playbackData := [][]string{
[]string{
"timestamp=2018-06-28+16%3A33%3A06&sign=B9FF8D5428F1DD1031DEF84AD08AB546&v=1.0&jd_param_json=%7B%22billId%22%3A%22815438712001141%22%2C%22statusId%22%3A%2232000%22%2C%22timestamp%22%3A%222018-06-28+16%3A33%3A03%22%7D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json",
baseURL + "djsw/newOrder",
},
[]string{
"timestamp=2018-06-28+16%3A40%3A19&sign=10C8ACAC71D954C0607046AC669079ED&v=1.0&jd_param_json=%7B%22billId%22%3A%22815438712001141%22%2C%22statusId%22%3A%222%22%2C%22timestamp%22%3A%222018-06-28+16%3A40%3A19%22%7D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json",
baseURL + "djsw/pickFinishOrder",
},
[]string{
"timestamp=2018-06-28%2B16%253A40%253A19&sign=E270E90A7F1712331AD210CCB477ED32&v=1.0&jd_param_json=%257B%2522createPin%2522%253A%2522JD_33d45ba55afeb1%2522%252C%2522deliveryCarrierName%2522%253A%2522%25E8%25BE%25BE%25E8%25BE%25BE%25E4%25B8%2593%25E9%2580%2581%2522%252C%2522deliveryCarrierNo%2522%253A%25229966%2522%252C%2522deliveryStatus%2522%253A%252210%2522%252C%2522deliveryStatusTime%2522%253A%25222018-06-28%2B16%253A40%253A19%2522%252C%2522inputTime%2522%253A%25222018-06-28%2B16%253A40%253A19%2522%252C%2522orderId%2522%253A%2522815438712001141%2522%257D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json",
baseURL + "djsw/pushDeliveryStatus",
},
[]string{
"sign=5d506d2ed7d0f353bd578df64a47c1a2b596278a&timestamp=1530176122&delivery_id=423701&status=0&appkey=3c0a05d464c247c19d7ec13accc78605&order_id=815438712001141&mt_peisong_id=1530176122092538",
baseURL + "mtps/status",
},
[]string{
"sign=037e8ef50ce575c3fcc00b9507a46432c0a64768&timestamp=1530176299&delivery_id=423701&status=20&appkey=3c0a05d464c247c19d7ec13accc78605&courier_phone=13281800720&courier_name=%E6%9D%8E%E5%B7%9D&order_id=815438712001141&mt_peisong_id=1530176122092538",
baseURL + "mtps/status",
},
[]string{
"timestamp=2018-06-28+16%3A58%3A20&sign=1DD702433D915DE19F4AC3DD39287E04&v=1.0&jd_param_json=%7B%22billId%22%3A%22815438712001141%22%2C%22statusId%22%3A%2233040%22%2C%22timestamp%22%3A%222018-06-28+16%3A58%3A20%22%7D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json",
baseURL + "djsw/deliveryOrder",
},
[]string{
"sign=73aae156870e530541d3da1c372411e9bc589470&timestamp=1530176533&delivery_id=423701&status=30&appkey=3c0a05d464c247c19d7ec13accc78605&courier_phone=13281800720&courier_name=%E6%9D%8E%E5%B7%9D&order_id=815438712001141&mt_peisong_id=1530176122092538",
baseURL + "mtps/status",
},
[]string{
"sign=ffe6c9ac09d21505106631bb92fb983599dde69d&timestamp=1530177544&delivery_id=423701&status=50&appkey=3c0a05d464c247c19d7ec13accc78605&courier_phone=13281800720&courier_name=%E6%9D%8E%E5%B7%9D&order_id=815438712001141&mt_peisong_id=1530176122092538",
baseURL + "mtps/status",
},
[]string{
"timestamp=2018-06-28+17%3A19%3A25&sign=06D8763C5B569485FD250F5C283E8B76&v=1.0&jd_param_json=%7B%22billId%22%3A%22815438712001141%22%2C%22statusId%22%3A%2233060%22%2C%22timestamp%22%3A%222018-06-28+17%3A19%3A04%22%7D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json",
baseURL + "djsw/finishOrder",
},
}
for _, v := range playbackData {
_, err := utils.SendFakeRequest(http.MethodPost, v[1], v[0], "")
if err != nil {
t.Fatal(err)
}
}
}
func TestOrderAcceptOperate(t *testing.T) {
result, err := jdapi.OrderAcceptOperate("813344594000041", true, "")
if err != nil {
t.Fatal(err.Error())
}
sugarLogger.Debug(result)
}
func TestOrderJDZBDelivery(t *testing.T) {
result, err := jdapi.OrderJDZBDelivery("813344594000041", "")
if err != nil {
t.Fatal(err.Error())
}
sugarLogger.Debug(result)
}
func TestModifySellerDelivery(t *testing.T) {
result, err := jdapi.ModifySellerDelivery("813344594000041", "")
if err != nil {
t.Fatal(err.Error())
}
sugarLogger.Debug(result)
}
func TestOrderSerllerDelivery(t *testing.T) {
result, err := jdapi.OrderSerllerDelivery("813344594000041", "")
if err != nil {
t.Fatal(err.Error())
}
sugarLogger.Debug(result)
}
func TestDeliveryEndOrder(t *testing.T) {
result, err := jdapi.DeliveryEndOrder("813344594000041", "")
if err != nil {
t.Fatal(err.Error())
}
sugarLogger.Debug(result)
}

View File

@@ -51,12 +51,34 @@ const (
PromotionTypeBuyGiveGift = 6
)
const (
QueryOrderRetryCount = 1 // 因为京东到家当前不存在的订单也返回-4暂时不重试
)
var (
ErrCanNotFindOrder = errors.New("can not find order")
)
var (
orderOperationResultParser = genNoPageResultParser("code", "msg", "detail", "0")
)
// 订单列表查询接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=169&apiid=ba3027848c3c4fda9674966e2a466482
func (a *API) OrderQuery(jdParams map[string]interface{}) (retVal []interface{}, totalCount int, err error) {
return a.AccessAPIHavePage("order/es/query", jdParams, nil, nil, nil)
// 最多试三次
for i := 0; i < QueryOrderRetryCount; i++ {
retVal, totalCount, err = a.AccessAPIHavePage("order/es/query", jdParams, nil, nil, nil)
if err != nil {
if err2, ok := err.(*utils.ErrorWithCode); ok {
if err2.IntCode() == -4 {
continue
}
}
}
break
}
return retVal, totalCount, err
}
// orderFreightMoney 基础运费
@@ -66,7 +88,7 @@ func (a *API) OrderQuery(jdParams map[string]interface{}) (retVal []interface{},
func (a *API) QuerySingleOrder(orderId string) (map[string]interface{}, error) {
jdParams := make(map[string]interface{})
jdParams["orderId"] = orderId
result, _, err := a.AccessAPIHavePage("order/es/query", jdParams, nil, nil, nil)
result, _, err := a.OrderQuery(jdParams)
if err != nil {
return nil, err
}
@@ -97,64 +119,71 @@ func (a *API) LegacyQuerySingleOrder(orderId string) (map[string]interface{}, er
return result, nil
}
func (a *API) OrderAcceptOperate(orderId string, isAgreed bool, userName string) (interface{}, error) {
// 商家确认接单接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=169&apiid=c1a15129d1374e9da7fa35487f878604
func (a *API) OrderAcceptOperate(orderId string, isAgreed bool, userName string) error {
jdParams := map[string]interface{}{
"orderId": orderId,
"isAgreed": utils.Bool2String(isAgreed),
"operator": utils.GetAPIOperator(userName),
}
return a.AccessAPINoPage("ocs/orderAcceptOperate", jdParams, nil, nil, nil)
_, err := a.AccessAPINoPage("ocs/orderAcceptOperate", jdParams, nil, nil, orderOperationResultParser)
return err
}
// 拣货完成且众包配送接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=169&apiid=ed93745b86c6487eaaea5f55a84785ac
func (a *API) OrderJDZBDelivery(orderId string, userName string) (interface{}, error) {
func (a *API) OrderJDZBDelivery(orderId string, userName string) (detail string, err error) {
jdParams := map[string]interface{}{
"orderId": orderId,
"operator": utils.GetAPIOperator(userName),
}
return a.AccessAPINoPage("bm/open/api/order/OrderJDZBDelivery", jdParams, nil, nil, nil)
result, err := a.AccessAPINoPage("bm/open/api/order/OrderJDZBDelivery", jdParams, nil, nil, orderOperationResultParser)
if err == nil {
return result.(string), nil
}
return "", err
}
// 订单达达配送转商家自送接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=169&apiid=e7b4950164754eecac7ea87278c2b071
func (a *API) ModifySellerDelivery(orderId string, userName string) (interface{}, error) {
func (a *API) ModifySellerDelivery(orderId string, userName string) (detail string, err error) {
jdParams := map[string]interface{}{
"orderId": orderId,
"updatePin": utils.GetAPIOperator(userName),
}
return a.AccessAPINoPage("order/modifySellerDelivery", jdParams, nil, nil, nil)
result, err := a.AccessAPINoPage("order/modifySellerDelivery", jdParams, nil, nil, orderOperationResultParser)
if err == nil {
return result.(string), nil
}
return "", err
}
// 拣货完成且商家自送接口(这个接口是商家本身配置为自送模式下才能调用的接口,如果启用了达达配送,是不能调用的)
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=169&apiid=0e08e71a45dc48b6a337e06a852ac33a
func (a *API) OrderSerllerDelivery(orderId string, userName string) (interface{}, error) {
func (a *API) OrderSerllerDelivery(orderId string, userName string) (detail string, err error) {
jdParams := map[string]interface{}{
"orderId": orderId,
"operator": utils.GetAPIOperator(userName),
}
return a.AccessAPINoPage("bm/open/api/order/OrderSerllerDelivery", jdParams, nil, nil, nil)
result, err := a.AccessAPINoPage("bm/open/api/order/OrderSerllerDelivery", jdParams, nil, nil, orderOperationResultParser)
if err == nil {
return result.(string), nil
}
return "", err
}
// 商家自送,订单妥投接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=169&apiid=ecc80f06d35141979f4841f345001f74
func (a *API) DeliveryEndOrder(orderId string, userName string) (interface{}, error) {
func (a *API) DeliveryEndOrder(orderId string, userName string) (result map[string]interface{}, err error) {
jdParams := map[string]interface{}{
"orderId": orderId,
"operPin": utils.GetAPIOperator(userName),
"operTime": utils.GetCurTimeStr(),
}
return a.AccessAPINoPage("ocs/deliveryEndOrder", jdParams, nil, nil, nil)
}
//订单金额拆分接口
func (a *API) QueryOassBussMoney(orderId string) ([]interface{}, error) {
jdParams := map[string]interface{}{
"orderId": orderId,
tmpResult, err := a.AccessAPINoPage("ocs/deliveryEndOrder", jdParams, nil, nil, nil)
if err == nil {
return tmpResult.(map[string]interface{}), nil
}
result, err := a.AccessAPINoPage("oassBussService/queryOassBussMoney", jdParams, nil, nil, nil)
if err != nil {
return nil, err
}
return result.([]interface{}), nil
return nil, err
}

View File

@@ -1,16 +1,196 @@
package jdapi
import (
"io/ioutil"
"net/http"
"net/url"
"testing"
"git.rosy.net.cn/baseapi/utils"
)
func TestQueryOassBussMoney(t *testing.T) {
bussResult, bussErr := jdapi.QueryOassBussMoney("815536199000222")
if bussErr != nil {
t.Error(bussErr.Error())
func TestQuerySingleOrder(t *testing.T) {
retVal, err := jdapi.QuerySingleOrder("815536199000222")
if err != nil {
t.Error(err)
}
if len(bussResult) <= 0 {
t.Error("错误返回数据长度不该为0")
if false {
t.Log(utils.Format4Output(retVal, false))
}
retVal, err = jdapi.QuerySingleOrder("999999")
if err == nil {
t.Error("应该找不到这个订单!")
}
}
func TestOrderQuery(t *testing.T) {
jdParams := map[string]interface{}{
"orderId": "813344594000041",
}
result, totalCount, err := jdapi.OrderQuery(jdParams)
if err != nil {
t.Fatalf("OrderQuery return error:%v", err)
}
if len(result) == 0 || totalCount == 0 {
t.Fatal("OrderQuery return empty data")
}
buyerCityOk := false
orderInfo, _ := result[0].(map[string]interface{})
if buyerCity1, ok := orderInfo["buyerCity"]; ok {
if buyerCity, ok := buyerCity1.(string); ok && buyerCity == "2376" {
buyerCityOk = true
}
}
if !buyerCityOk {
t.Fatal("OrderQuery get data wrong")
}
}
func TestGetOrderCallbackMsg(t *testing.T) {
callbackStr := "timestamp=2018-06-27+12%3A43%3A51&sign=84096ADFAB81E224D6231269AD1F6AAB&v=1.0&jd_param_json=%7B%22billId%22%3A%22815338526000221%22%2C%22statusId%22%3A%2232000%22%2C%22timestamp%22%3A%222018-06-27+12%3A42%3A34%22%7D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json"
result, resp := jdapi.GetOrderCallbackMsg([]byte(callbackStr))
if resp != nil {
t.Fatal(resp)
}
sugarLogger.Debug(result)
}
func TestGetOrderDeliveryCallbackMsg(t *testing.T) {
callbackStr := "timestamp=2018-06-27%2B09%253A08%253A41&sign=54D9A8515BB5650DC3B81366E3286570&v=1.0&jd_param_json=%257B%2522createPin%2522%253A%2522JD_21134dac1c251d2%2522%252C%2522deliveryCarrierName%2522%253A%2522%25E8%25BE%25BE%25E8%25BE%25BE%25E4%25B8%2593%25E9%2580%2581%2522%252C%2522deliveryCarrierNo%2522%253A%25229966%2522%252C%2522deliveryStatus%2522%253A%252210%2522%252C%2522deliveryStatusTime%2522%253A%25222018-06-27%2B09%253A08%253A41%2522%252C%2522inputTime%2522%253A%25222018-06-27%2B09%253A08%253A41%2522%252C%2522orderId%2522%253A%2522815324888000121%2522%257D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json"
result, resp := jdapi.GetOrderDeliveryCallbackMsg([]byte(callbackStr))
if resp != nil {
t.Fatal(resp)
}
sugarLogger.Debug(result)
}
func TestGetOrderApplyCancelCallbackMsg(t *testing.T) {
callbackStr := "timestamp=2018-06-27%2B13%253A35%253A29&sign=F1398D658514D8864FFB56F5EF2C4792&v=1.0&jd_param_json=%257B%2522billId%2522%253A%2522815339944000322%2522%252C%2522remark%2522%253A%2522%25E5%2595%2586%25E5%25AE%25B6%25E7%25BC%25BA%25E8%25B4%25A7%2522%252C%2522statusId%2522%253A%252220030%2522%252C%2522timestamp%2522%253A%25222018-06-27%2B13%253A35%253A24%2522%257D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json"
result, resp := jdapi.GetOrderApplyCancelCallbackMsg([]byte(callbackStr))
if resp != nil {
t.Fatal(resp)
}
sugarLogger.Debug(result)
}
func TestSimulateSendNewOrderMsg(t *testing.T) {
orderInfo := &CallbackOrderMsg{
BillID: "813344594000041",
StatusID: OrderStatusNew,
Timestamp: utils.GetCurTimeStr(),
}
params := make(url.Values)
params.Set("token", jdapi.token)
params.Set("app_key", jdapi.appKey)
params.Set("timestamp", utils.GetCurTimeStr())
params.Set("v", "1.0")
params.Set("format", "json")
params.Set(paramJson, string(utils.MustMarshal(orderInfo)))
mapData := utils.URLValues2Map(params)
mapData["app_secret"] = jdapi.appSecret
params.Set(signKey, jdapi.signParams(mapData))
response, err := http.PostForm("http://callback.test.jxc4.com/djsw/newOrder", params)
if err != nil {
t.Fatal(err)
}
bodyData, _ := ioutil.ReadAll(response.Body)
sugarLogger.Debug(string(bodyData))
}
/*
DELETE t1
FROM jdorder t1
WHERE t1.jdorderid = 815438712001141;
*/
func TestCallbackMsgPlayback(t *testing.T) {
baseURL := "http://callback.test.jxc4.com:8080/"
playbackData := [][]string{
[]string{
"timestamp=2018-06-28+16%3A33%3A06&sign=B9FF8D5428F1DD1031DEF84AD08AB546&v=1.0&jd_param_json=%7B%22billId%22%3A%22815438712001141%22%2C%22statusId%22%3A%2232000%22%2C%22timestamp%22%3A%222018-06-28+16%3A33%3A03%22%7D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json",
baseURL + "djsw/newOrder",
},
[]string{
"timestamp=2018-06-28+16%3A40%3A19&sign=10C8ACAC71D954C0607046AC669079ED&v=1.0&jd_param_json=%7B%22billId%22%3A%22815438712001141%22%2C%22statusId%22%3A%222%22%2C%22timestamp%22%3A%222018-06-28+16%3A40%3A19%22%7D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json",
baseURL + "djsw/pickFinishOrder",
},
[]string{
"timestamp=2018-06-28%2B16%253A40%253A19&sign=E270E90A7F1712331AD210CCB477ED32&v=1.0&jd_param_json=%257B%2522createPin%2522%253A%2522JD_33d45ba55afeb1%2522%252C%2522deliveryCarrierName%2522%253A%2522%25E8%25BE%25BE%25E8%25BE%25BE%25E4%25B8%2593%25E9%2580%2581%2522%252C%2522deliveryCarrierNo%2522%253A%25229966%2522%252C%2522deliveryStatus%2522%253A%252210%2522%252C%2522deliveryStatusTime%2522%253A%25222018-06-28%2B16%253A40%253A19%2522%252C%2522inputTime%2522%253A%25222018-06-28%2B16%253A40%253A19%2522%252C%2522orderId%2522%253A%2522815438712001141%2522%257D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json",
baseURL + "djsw/pushDeliveryStatus",
},
[]string{
"sign=5d506d2ed7d0f353bd578df64a47c1a2b596278a&timestamp=1530176122&delivery_id=423701&status=0&appkey=3c0a05d464c247c19d7ec13accc78605&order_id=815438712001141&mt_peisong_id=1530176122092538",
baseURL + "mtps/status",
},
[]string{
"sign=037e8ef50ce575c3fcc00b9507a46432c0a64768&timestamp=1530176299&delivery_id=423701&status=20&appkey=3c0a05d464c247c19d7ec13accc78605&courier_phone=13281800720&courier_name=%E6%9D%8E%E5%B7%9D&order_id=815438712001141&mt_peisong_id=1530176122092538",
baseURL + "mtps/status",
},
[]string{
"timestamp=2018-06-28+16%3A58%3A20&sign=1DD702433D915DE19F4AC3DD39287E04&v=1.0&jd_param_json=%7B%22billId%22%3A%22815438712001141%22%2C%22statusId%22%3A%2233040%22%2C%22timestamp%22%3A%222018-06-28+16%3A58%3A20%22%7D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json",
baseURL + "djsw/deliveryOrder",
},
[]string{
"sign=73aae156870e530541d3da1c372411e9bc589470&timestamp=1530176533&delivery_id=423701&status=30&appkey=3c0a05d464c247c19d7ec13accc78605&courier_phone=13281800720&courier_name=%E6%9D%8E%E5%B7%9D&order_id=815438712001141&mt_peisong_id=1530176122092538",
baseURL + "mtps/status",
},
[]string{
"sign=ffe6c9ac09d21505106631bb92fb983599dde69d&timestamp=1530177544&delivery_id=423701&status=50&appkey=3c0a05d464c247c19d7ec13accc78605&courier_phone=13281800720&courier_name=%E6%9D%8E%E5%B7%9D&order_id=815438712001141&mt_peisong_id=1530176122092538",
baseURL + "mtps/status",
},
[]string{
"timestamp=2018-06-28+17%3A19%3A25&sign=06D8763C5B569485FD250F5C283E8B76&v=1.0&jd_param_json=%7B%22billId%22%3A%22815438712001141%22%2C%22statusId%22%3A%2233060%22%2C%22timestamp%22%3A%222018-06-28+17%3A19%3A04%22%7D&token=91633f2a-c5f5-4982-a925-a220d19095c3&app_key=1dba76d40cac446ca500c0391a0b6c9d&format=json",
baseURL + "djsw/finishOrder",
},
}
for _, v := range playbackData {
_, err := utils.SendFakeRequest(http.MethodPost, v[1], v[0], "")
if err != nil {
t.Fatal(err)
}
}
}
func TestOrderAcceptOperate(t *testing.T) {
err := jdapi.OrderAcceptOperate("813344594000041", true, "")
if err != nil {
t.Fatal(err.Error())
}
}
func TestOrderJDZBDelivery(t *testing.T) {
result, err := jdapi.OrderJDZBDelivery("813344594000041", "")
if err != nil {
t.Fatal(err.Error())
}
sugarLogger.Debug(result)
}
func TestModifySellerDelivery(t *testing.T) {
result, err := jdapi.ModifySellerDelivery("813344594000041", "")
if err != nil {
t.Fatal(err.Error())
}
sugarLogger.Debug(result)
}
func TestOrderSerllerDelivery(t *testing.T) {
result, err := jdapi.OrderSerllerDelivery("813344594000041", "")
if err != nil {
t.Fatal(err.Error())
}
sugarLogger.Debug(result)
}
func TestDeliveryEndOrder(t *testing.T) {
result, err := jdapi.DeliveryEndOrder("813344594000041", "")
if err != nil {
t.Fatal(err.Error())
}
sugarLogger.Debug(result)
}

View File

@@ -1,6 +1,8 @@
package jdapi
import "git.rosy.net.cn/baseapi/utils"
import (
"git.rosy.net.cn/baseapi/utils"
)
const (
KeyBrandId = "brandId"
@@ -71,6 +73,17 @@ type ProductStatus struct {
ProductEntity map[string]interface{} `json:"productEntity"`
}
// 这个类型商家店内分类与到家分类共用,
type CategoryInfo struct {
Id int64 `json:"id"`
ParentId int64 `json:"pid"`
Name string `json:"categoryName"`
Level int `json:"categoryLevel"`
Sort int `json:"sort"` // 店内分类独有
Status int `json:"status"` // 到家分类独有
FullPath string `json:"fullPath"` // 到家分类独有
}
// 分页查询商品品牌信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=1ca07a3e767649a7a44fc6ea7e9ed8dd
func (a *API) QueryPageBrandInfo(pageNo, pageSize, brandId int, brandName string) (brandList []*BrandInfo, totalCount int, err error) {
@@ -114,7 +127,7 @@ func (a *API) QueryPageBrandInfo(pageNo, pageSize, brandId int, brandName string
// 获取京东到家类目信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=d287d326124d42c090cff03c16385706
func (a *API) QueryChildCategoriesForOP(pid int64) (catList []map[string]interface{}, err error) {
func (a *API) QueryChildCategoriesForOP(pid int64) (catList []*CategoryInfo, err error) {
result, err := a.AccessAPINoPage("api/queryChildCategoriesForOP", utils.Params2Map("fields", []string{
"ID",
"PID",
@@ -124,7 +137,20 @@ func (a *API) QueryChildCategoriesForOP(pid int64) (catList []map[string]interfa
"FULLPATH",
}, "id", pid), nil, nil, nil)
if err == nil {
return utils.Slice2MapSlice(result.([]interface{})), nil
return interface2CatList(result, 1, func(data interface{}, level int) (cat *CategoryInfo) {
mapData, ok := data.(map[string]interface{})
if ok {
cat = &CategoryInfo{
Id: utils.MustInterface2Int64(mapData["id"]),
ParentId: utils.MustInterface2Int64(mapData["pid"]),
Name: utils.Interface2String(mapData["categoryName"]),
Level: int(utils.MustInterface2Int64(mapData["categoryLevel"])),
Status: int(utils.MustInterface2Int64(mapData["categoryStatus"])),
FullPath: utils.Interface2String(mapData["fullPath"]),
}
}
return cat
}), nil
}
return nil, err
}
@@ -141,14 +167,14 @@ func (a *API) AddShopCategory(pid int64, shopCategoryName string, shopCategoryLe
}
result, err := a.AccessAPINoPage("pms/addShopCategory", params, nil, nil, nil)
if err == nil {
return result.(string), nil
return (result.(map[string]interface{}))["id"].(string), nil
}
return "", err
}
// 查询商家店内分类信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=964f2d248a7e42b196be2ab35b4e93b4
func (a *API) QueryCategoriesByOrgCode() (catList []map[string]interface{}, err error) {
func (a *API) QueryCategoriesByOrgCode() (catList []*CategoryInfo, err error) {
result, err := a.AccessAPINoPage("pms/queryCategoriesByOrgCode", utils.Params2Map("fields", []string{
"ID",
"PID",
@@ -156,7 +182,7 @@ func (a *API) QueryCategoriesByOrgCode() (catList []map[string]interface{}, err
"SORT",
}), nil, nil, nil)
if err == nil {
return utils.Slice2MapSlice(result.([]interface{})), nil
return interface2CatList(result, 1, nil), nil
}
return nil, err
}
@@ -168,7 +194,7 @@ func (a *API) UpdateShopCategory(id int64, shopCategoryName string) error {
KeyID: id,
KeyShopCategoryName: shopCategoryName,
}
_, err := a.AccessAPINoPage("pms/updateShopCategory", params, nil, nil, nil)
_, err := a.AccessAPINoPage("pms/updateShopCategory", params, nil, nil, nullResultParser)
return err
}
@@ -179,20 +205,20 @@ func (a *API) ChangeShopCategoryOrder(pid int64, childIds []int) error {
KeyPID: pid,
KeyChildIds: childIds,
}
_, err := a.AccessAPINoPage("pms/changeShopCategoryOrder", params, nil, nil, nil)
_, err := a.AccessAPINoPage("pms/changeShopCategoryOrder", params, nil, nil, nullResultParser)
return err
}
// 删除商家店内分类接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=c17b96e9fe254b2a8574f6d1bc0c1667
func (a *API) DelShopCategory(id int64) error {
_, err := a.AccessAPINoPage("pms/delShopCategory", utils.Params2Map(KeyID, id), nil, nil, nil)
_, err := a.AccessAPINoPage("pms/delShopCategory", utils.Params2Map(KeyID, id), nil, nil, nullResultParser)
return err
}
// 新增商品信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=dfe6a5ca73fa421da1c9f969b848113e
func (a *API) AddSku(outSkuId string, cagtegoryId int64, shopCategories []int, brandId int, skuName string, skuPrice int, weight float32, images []string, fixedStatus int, isSale bool, addParams map[string]interface{}) (skuId string, err error) {
func (a *API) AddSku(outSkuId string, cagtegoryId int, shopCategories []int64, brandId int, skuName string, skuPrice int, weight float32, images []string, fixedStatus int, isSale bool, addParams map[string]interface{}) (skuId string, err error) {
fixedParams := map[string]interface{}{
KeyOutSkuId: outSkuId,
KeyCategoryId: cagtegoryId,
@@ -207,7 +233,7 @@ func (a *API) AddSku(outSkuId string, cagtegoryId int64, shopCategories []int, b
}
result, err := a.AccessAPINoPage("pms/sku/addSku", utils.MergeMaps(fixedParams, addParams), nil, nil, nil)
if err == nil {
return result.(string), nil
return (result.(map[string]interface{}))["skuId"].(string), nil
}
return "", err
}
@@ -217,7 +243,7 @@ func (a *API) AddSku(outSkuId string, cagtegoryId int64, shopCategories []int, b
func (a *API) UpdateSku(outSkuId string, params map[string]interface{}) (skuId string, err error) {
result, err := a.AccessAPINoPage("pms/sku/updateSku", utils.MergeMaps(params, utils.Params2Map("outSkuId", outSkuId)), nil, nil, nil)
if err == nil {
return result.(string), nil
return (result.(map[string]interface{}))["skuId"].(string), nil
}
return "", err
}
@@ -327,6 +353,8 @@ func (a *API) SyncProduct(storeId, skuId string) (retVal bool, err error) {
return false, err
}
// 商家商品状态检查接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=a348122182ef459982cae1280407ff17
func (a *API) GetProductStatus(storeId, skuId string) (retVal *ProductStatus, err error) {
result, err := a.AccessAPINoPage("search/getProductStatus", utils.Params2Map(KeyStoreId, storeId, KeySkuId, skuId), nil, nil, func(data map[string]interface{}) (interface{}, error) {
status := utils.MustInterface2Int64(data["status"])
@@ -345,3 +373,33 @@ func (a *API) GetProductStatus(storeId, skuId string) (retVal *ProductStatus, er
return nil, err
}
///////////////////////////
// 私有辅助函数
func interface2Cat(data interface{}, level int) (cat *CategoryInfo) {
mapData, ok := data.(map[string]interface{})
if ok {
cat = &CategoryInfo{
Id: utils.MustInterface2Int64(mapData["id"]),
ParentId: utils.MustInterface2Int64(mapData["pid"]),
Name: utils.Interface2String(mapData["shopCategoryName"]),
Level: int(utils.Interface2Int64WithDefault(mapData["shopCategoryLevel"], 0)),
Sort: int(utils.MustInterface2Int64(mapData["sort"])),
}
}
return cat
}
func interface2CatList(data interface{}, level int, interface2CatHandler func(data interface{}, level int) (cat *CategoryInfo)) (cats []*CategoryInfo) {
if interface2CatHandler == nil {
interface2CatHandler = interface2Cat
}
maps, ok := data.([]interface{})
if ok {
cats = make([]*CategoryInfo, len(maps))
for index, v := range maps {
cats[index] = interface2CatHandler(v, level)
}
}
return cats
}

View File

@@ -68,7 +68,7 @@ func TestQuerySkuInfos(t *testing.T) {
}
func TestQueryListBySkuIds(t *testing.T) {
ids := []int{
ids := []int64{
2018806493,
2018805873,
}

View File

@@ -32,12 +32,13 @@ const (
type CreateShopResult struct {
DeliveryRangeType int `json:"deliveryRangeType"`
CoordinatePoints string `json:"coordinatePoints"`
StationNo string `json:"stationNo"`
}
// 获取门店编码列表接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=194&apiid=138426aa19b54c48ae8464af1ca3b681
func (a *API) GetStationsByVenderId() ([]string, error) {
result, err := a.AccessAPINoPage("store/getStationsByVenderId", nil, nil, nil, nil)
result, err := a.AccessAPINoPage("store/getStationsByVenderId", nil, nil, nil, genNoPageResultParser("code", "msg", "result", "1"))
if err == nil {
result2 := result.([]interface{})
retVal := make([]string, len(result2))
@@ -67,14 +68,17 @@ func (a *API) CreateStore(stationName, phone string, city, county int, stationAd
KeyCoordinateType: coordinateType,
KeyStandByPhone: standByPhone,
}
result, err := a.AccessAPINoPage("store/createStore", utils.MergeMaps(params, addParams), nil, nil, nil)
if err == nil {
result2 := result.(map[string]interface{})
retVal := &CreateShopResult{
DeliveryRangeType: int(utils.MustInterface2Int64(result2["deliveryRangeType"])),
CoordinatePoints: utils.Interface2String(result2["coordinatePoints"]),
result, err := a.AccessAPINoPage("store/createStore", utils.MergeMaps(params, addParams), nil, nil, func(data map[string]interface{}) (interface{}, error) {
innerCode := data["code"].(string)
if data["code"] == "0" {
mapData := data["data"].(map[string]interface{})
mapData["result"] = data["result"].(string)
return mapData, nil
}
return retVal, nil
return nil, utils.NewErrorCode(data["msg"].(string), innerCode, 1)
})
if err == nil {
return interface2CreateShopResult(result), nil
}
return nil, err
}
@@ -91,19 +95,25 @@ func (a *API) GetStoreInfoByStationNo(storeNo string) (map[string]interface{}, e
// 修改门店基础信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=194&apiid=2600369a456446f0921e918f3d15e96a
func (a *API) UpdateStoreInfo4Open(storeNo, userName string, addParams map[string]interface{}) (string, error) {
func (a *API) UpdateStoreInfo4Open(storeNo, userName string, addParams map[string]interface{}) (*CreateShopResult, error) {
jdParams := map[string]interface{}{
"stationNo": storeNo,
"operator": utils.GetAPIOperator(userName),
}
for k, v := range addParams {
jdParams[k] = v
}
result, err := a.AccessAPINoPage("store/updateStoreInfo4Open", jdParams, nil, nil, nil)
jdParams = utils.MergeMaps(jdParams, addParams)
result, err := a.AccessAPINoPage("store/updateStoreInfo4Open", jdParams, nil, nil, func(data map[string]interface{}) (interface{}, error) {
innerCode := data["code"].(string)
if data["code"] == "0" {
mapData := data["data"].(map[string]interface{})
mapData["result"] = data["result"].(string)
return mapData, nil
}
return nil, utils.NewErrorCode(data["msg"].(string), innerCode, 1)
})
if err == nil {
return result.(string), nil
return interface2CreateShopResult(result), nil
}
return "", err
return nil, err
}
// 根据订单号查询商家门店评价信息接口
@@ -113,14 +123,14 @@ func (a *API) GetCommentByOrderId(orderId int64) (map[string]interface{}, error)
"orderId": orderId,
}
result, err := a.AccessAPINoPage("commentOutApi/getCommentByOrderId", jdParams, nil, nil, nil)
if err != nil {
return nil, err
if err == nil {
return result.(map[string]interface{}), nil
}
return result.(map[string]interface{}), nil
return nil, err
}
// 商家门店评价信息回复接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=194&apiid=ea0b466a7fa8489b813e8b197efca2d4?
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=194&apiid=ea0b466a7fa8489b813e8b197efca2d4
func (a *API) OrgReplyComment(orderID int64, storeID, content, replayPin string) (string, error) {
jdParams := map[string]interface{}{
"orderId": orderID,
@@ -128,11 +138,11 @@ func (a *API) OrgReplyComment(orderID int64, storeID, content, replayPin string)
"content": content,
"replyPin": replayPin,
}
result, err := a.AccessAPINoPage("commentOutApi/orgReplyComment", jdParams, nil, nil, nil)
if err != nil {
return "", err
result, err := a.AccessAPINoPage("commentOutApi/orgReplyComment", jdParams, nil, nil, genNoPageResultParser("code", "msg", "result", "200"))
if err == nil {
return result.(string), nil
}
return result.(string), nil
return "", err
}
// 根据到家门店编码修改商家自动接单接口
@@ -153,3 +163,15 @@ func (a *API) UpdateStoreConfig4Open(stationNo string, isAutoOrder bool) (bool,
}
return result.(bool), nil
}
// 私有函数
func interface2CreateShopResult(data interface{}) (retVal *CreateShopResult) {
if result, ok := data.(map[string]interface{}); ok {
retVal = &CreateShopResult{
DeliveryRangeType: int(utils.MustInterface2Int64(result["deliveryRangeType"])),
CoordinatePoints: utils.Interface2String(result["coordinatePoints"]),
StationNo: utils.Interface2String(result["result"]),
}
}
return retVal
}

View File

@@ -93,6 +93,30 @@ func Interface2String(data interface{}) string {
return data.(string)
}
func Interface2Int64List(data interface{}) []int64 {
if data == nil {
return nil
}
list := data.([]interface{})
retVal := make([]int64, len(list))
for k, v := range list {
retVal[k] = MustInterface2Int64(v)
}
return retVal
}
func Interface2StringList(data interface{}) []string {
if data == nil {
return nil
}
list := data.([]interface{})
retVal := make([]string, len(list))
for k, v := range list {
retVal[k] = Interface2String(v)
}
return retVal
}
func Slice2MapSlice(data []interface{}) []map[string]interface{} {
retVal := make([]map[string]interface{}, len(data))
for k, v := range data {
@@ -250,3 +274,26 @@ func MapKV2List(mapData map[string]interface{}) []map[string]interface{} {
}
return retVal
}
func Format4Output(obj interface{}, isSingleLine bool) (retVal string) {
retVal, ok := obj.(string)
if !ok {
var (
result []byte
err error
)
if isSingleLine {
if result, err = json.Marshal(obj); err == nil {
retVal = string(result)
}
} else {
if result, err = json.MarshalIndent(obj, "", "\t"); err == nil {
retVal = string(result)
}
}
if err != nil {
retVal = fmt.Sprintf("%v", obj)
}
}
return retVal
}