diff --git a/platformapi/jdeclpapi/jdeclpapi.go b/platformapi/jdeclpapi/jdeclpapi.go index d259e69e..fa9ffa7b 100644 --- a/platformapi/jdeclpapi/jdeclpapi.go +++ b/platformapi/jdeclpapi/jdeclpapi.go @@ -181,8 +181,8 @@ type WaybillReceiveParam struct { // SiteType int `json:"siteType"` //否 无 站点类型 // SiteID int `json:"siteId"` //否 无 站点编码 // SiteName string `json:"siteName"` //否 无 站点名称 - // ReceiveTel string `json:"receiveTel"` //否 无 收件人电话 - // ReceiveMobile string `json:"receiveMobile"` //否 无 收件人手机号(收件人电话、手机至少有一个不为空) + ReceiveTel string `json:"receiveTel"` //否 无 收件人电话 + ReceiveMobile string `json:"receiveMobile"` //否 无 收件人手机号(收件人电话、手机至少有一个不为空) // Postcode string `json:"postcode"` //否 100000 收件人邮编,长度:6 PackageCount int `json:"packageCount"` //是 无 包裹数(大于0,小于1000) Weight int `json:"weight"` //是 2.5 重量(单位:kg,保留小数点后两位) diff --git a/platformapi/jdshopapi/jdshopapi.go b/platformapi/jdshopapi/jdshopapi.go new file mode 100644 index 00000000..5933791c --- /dev/null +++ b/platformapi/jdshopapi/jdshopapi.go @@ -0,0 +1,108 @@ +package jdshopapi + +import ( + "crypto/md5" + "fmt" + "net/http" + "sort" + "strings" + "time" + + "git.rosy.net.cn/baseapi" + "git.rosy.net.cn/baseapi/platformapi" + "git.rosy.net.cn/baseapi/utils" +) + +const ( + prodURL = "https://api.jd.com/routerjson" + sigKey = "sign" +) + +type API struct { + platformapi.APICookie + + accessToken string + appKey string + appSecret string + client *http.Client + config *platformapi.APIConfig +} + +type UniteResp struct { + Num int `json:"num"` + IsSuccess bool `json:"is_success"` + ErrorCode string `json:"error_code"` + ErrorMsgCn string `json:"error_msg_cn"` + ErrorMsg string `json:"error_msg"` +} + +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{}) + 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)) + baseapi.SugarLogger.Debugf("jdeclp AccessAPI failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true)) + } + retVal = jsonResult1 + } + return errLevel, err + }) + return retVal, err +} diff --git a/platformapi/jdshopapi/jxshopapi_test.go b/platformapi/jdshopapi/jxshopapi_test.go new file mode 100644 index 00000000..993ec21a --- /dev/null +++ b/platformapi/jdshopapi/jxshopapi_test.go @@ -0,0 +1,19 @@ +package jdshopapi + +import ( + "git.rosy.net.cn/baseapi" + "go.uber.org/zap" +) + +var ( + api *API + sugarLogger *zap.SugaredLogger +) + +func init() { + logger, _ := zap.NewDevelopment() + sugarLogger = logger.Sugar() + baseapi.Init(sugarLogger) + api = New("da8db492e20149e494afaf5607e1d6654zgi", "E1D746D42474D5F1F1A10CECE75D99F6", "efa7e1d1a22640fa990e6cf164b28608") + api.SetCookie("thor", "80FAF09E9A09B6E618A68057BDFCFCB81C821714A15F3E8682FBAD9605C6284CE3D573A97D5021559891D214CDCCFA4A90F8254643B0A60E168F976FF8C3D2E5ACB0F3DB2ABFBC0A2E4EE6297EC49919CAE5CBBD6A686F1F7370B6ABD7AE8BE70DD216650EC9AAD79928DAC85CFA2D9BC581BA085F0D45C613A99F13F25AA3B24372930D5BB7CEBF685AF34698EBFD92") +} diff --git a/platformapi/jdshopapi/sku.go b/platformapi/jdshopapi/sku.go new file mode 100644 index 00000000..43517a20 --- /dev/null +++ b/platformapi/jdshopapi/sku.go @@ -0,0 +1,52 @@ +package jdshopapi + +import ( + "fmt" + + "git.rosy.net.cn/baseapi/utils" +) + +type FindShopCategoriesResult struct { + CID int64 `json:"cid"` //123456 分类编号 + VenderID int `json:"vender_id"` //123456 商家编号 + ShopID int `json:"shop_id"` // 123456 店铺编号 + ParentCID int64 `json:"parent_cid"` //123456 父分类编号 + OrderNo int `json:"order_no"` //1 分类排序 + Name string `json:"name"` //分类1 分类名称 + IsOpen bool `json:"is_open"` //false 是否展开子分类(false,不展开;true,展开) + IsHomeShow bool `json:"is_home_show"` //false 是否在首页展示分类(false,前台不展示,true前台展示 + Status int `json:"status"` // 1 状态(1:删除 1:正常) + CreateTime int64 `json:"create_time"` //1394089643000 创建时间 + ModifyTime int64 `json:"modify_time"` // 修改时间。每修改一次此值都会发生变化。 +} + +//查询商家所有的店内分类 +//https://open.jd.com/home/home#/doc/api?apiCateId=88&apiId=2801&apiName=jingdong.vender.shopcategory.findShopCategoriesByVenderId +func (a *API) FindShopCategories() (findShopCategoriesResult []*FindShopCategoriesResult, err error) { + result, err := a.AccessAPI("jingdong.vender.shopcategory.findShopCategoriesByVenderId", prodURL, nil) + if err == nil { + utils.Map2StructByJson(result["jingdong_vender_shopcategory_findShopCategoriesByVenderId_responce"].(map[string]interface{})["shopCategoryResult"].(map[string]interface{})["shop_category_list"], &findShopCategoriesResult, false) + } + return findShopCategoriesResult, err +} + +//删除店内分类 +//https://open.jd.com/home/home#/doc/api?apiCateId=88&apiId=3031&apiName=jingdong.vender.shopcategory.deleteShopCategoryByVenderIdAndCid +func (a *API) DeleteShopCategory(cid int64) (uniteResp *UniteResp, err error) { + result, err := a.AccessAPI("jingdong.vender.shopcategory.deleteShopCategoryByVenderIdAndCid", prodURL, map[string]interface{}{ + "cid": cid, + }) + if err == nil { + utils.Map2StructByJson(result["jingdong_vender_shopcategory_deleteShopCategoryByVenderIdAndCid_responce"].(map[string]interface{})["shopCategoryResult"], &uniteResp, false) + if !uniteResp.IsSuccess { + return nil, fmt.Errorf(uniteResp.ErrorMsgCn) + } + } + return uniteResp, err +} + +//京东商城发布商品(创建商品?) +//https://open.jd.com/home/home#/doc/api?apiCateId=48&apiId=1379&apiName=jingdong.ware.write.add +func (a *API) CreateSkuName() (err error) { + return err +} diff --git a/platformapi/jdshopapi/sku_test.go b/platformapi/jdshopapi/sku_test.go new file mode 100644 index 00000000..0c6cf3f8 --- /dev/null +++ b/platformapi/jdshopapi/sku_test.go @@ -0,0 +1,23 @@ +package jdshopapi + +import ( + "testing" + + "git.rosy.net.cn/baseapi/utils" +) + +func TestFindShopCategories(t *testing.T) { + result, err := api.FindShopCategories() + if err != nil { + t.Fatal(err) + } + t.Log(utils.Format4Output(result, false)) +} + +func TestDeleteShopCategory(t *testing.T) { + result, err := api.DeleteShopCategory(14439186) + if err != nil { + t.Fatal(err) + } + t.Log(utils.Format4Output(result, false)) +} diff --git a/platformapi/jdshopapi/store_page.go b/platformapi/jdshopapi/store_page.go new file mode 100644 index 00000000..3b8ac148 --- /dev/null +++ b/platformapi/jdshopapi/store_page.go @@ -0,0 +1,61 @@ +package jdshopapi + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + + "git.rosy.net.cn/baseapi" + "git.rosy.net.cn/baseapi/platformapi" + "git.rosy.net.cn/baseapi/utils" +) + +func (a *API) AccessStorePage(fullURL string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) { + if a.GetCookieCount() == 0 { + return nil, fmt.Errorf("需要设置Store Cookie才能使用此方法") + } + err = platformapi.AccessPlatformAPIWithRetry(a.client, + func() *http.Request { + request, _ := http.NewRequest(http.MethodPost, fullURL, strings.NewReader(utils.Map2URLValues(bizParams).Encode())) + request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + a.FillRequestCookies(request) + 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)) + baseapi.SugarLogger.Debugf("jdeclp AccessAPI failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true)) + } + retVal = jsonResult1 + } + return errLevel, err + }) + return retVal, err +} + +type CreateShopCategoryParam struct { + HomeShow int `json:"homeShow"` + ID int `json:"id"` + Open string `json:"open"` + OrderNo int `json:"orderNo"` + ParentID string `json:"parentId"` + Title string `json:"title"` + Type int `json:"type"` +} + +//京东商城创建或修改店内分类 +//https://seller.shop.jd.com/vendershop/vendershop_shopCategory.action# +func (a *API) CreateShopCategory(createShopCategoryParam []*CreateShopCategoryParam) (err error) { + result, _ := json.MarshalIndent(createShopCategoryParam, "", "") + _, err = a.AccessStorePage("https://seller.shop.jd.com/vendershop/vendershop_doShopCategory.action", map[string]interface{}{ + "categoryJson": string(result), + }) + return err +} diff --git a/platformapi/jdshopapi/store_page_test.go b/platformapi/jdshopapi/store_page_test.go new file mode 100644 index 00000000..0e2aae82 --- /dev/null +++ b/platformapi/jdshopapi/store_page_test.go @@ -0,0 +1,20 @@ +package jdshopapi + +import ( + "testing" +) + +func TestCreateShopCategory(t *testing.T) { + var CreateShopCategoryParams = []*CreateShopCategoryParam{ + &CreateShopCategoryParam{ + HomeShow: 0, + ID: 0, + Open: "", + OrderNo: 0, + ParentID: "", + Title: "测试1", + Type: 3, + }, + } + api.CreateShopCategory(CreateShopCategoryParams) +}