From 35cd9ffa7966678a4a7558d44e772afd399ca032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=8F=E5=B0=B9=E5=B2=9A?= <770236076@qq.com> Date: Tue, 12 May 2020 15:37:04 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=AC=E4=B8=9C=E5=95=86=E5=9F=8E=E4=B8=80?= =?UTF-8?q?=E5=A0=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- platformapi/jdshopapi/jdshopapi.go | 44 ++++ platformapi/jdshopapi/jxshopapi_test.go | 4 +- platformapi/jdshopapi/sku.go | 268 ++++++++++++++++++++++-- platformapi/jdshopapi/sku_test.go | 215 +++++++++++++++++++ platformapi/jdshopapi/store.go | 26 +++ platformapi/jdshopapi/store_test.go | 11 + utils/typeconv.go | 25 +++ 7 files changed, 577 insertions(+), 16 deletions(-) create mode 100644 platformapi/jdshopapi/store.go create mode 100644 platformapi/jdshopapi/store_test.go diff --git a/platformapi/jdshopapi/jdshopapi.go b/platformapi/jdshopapi/jdshopapi.go index 28e574b9..ab67503e 100644 --- a/platformapi/jdshopapi/jdshopapi.go +++ b/platformapi/jdshopapi/jdshopapi.go @@ -19,6 +19,10 @@ const ( CreateCatType = "3" UpdateCatType = "1" + + TransportID = 2158480 + JxBrandId = 559853 + JdShopMaxStock = 9999 ) type API struct { @@ -109,3 +113,43 @@ func (a *API) AccessAPI(action string, url string, bizParams map[string]interfac }) return retVal, err } + +func (a *API) AccessAPI2(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) + // delete(params, "ware") + // delete(params, "skus") + // ware := bizParams["ware"].(string) + // skus := bizParams["skus"].(string) + err = platformapi.AccessPlatformAPIWithRetry(a.client, + func() *http.Request { + request, _ := http.NewRequest(http.MethodPost, fullURL, strings.NewReader(utils.URLQueryEscape(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 index 993ec21a..fcbe80b2 100644 --- a/platformapi/jdshopapi/jxshopapi_test.go +++ b/platformapi/jdshopapi/jxshopapi_test.go @@ -14,6 +14,6 @@ func init() { logger, _ := zap.NewDevelopment() sugarLogger = logger.Sugar() baseapi.Init(sugarLogger) - api = New("da8db492e20149e494afaf5607e1d6654zgi", "E1D746D42474D5F1F1A10CECE75D99F6", "efa7e1d1a22640fa990e6cf164b28608") - api.SetCookie("thor", "80FAF09E9A09B6E618A68057BDFCFCB81C821714A15F3E8682FBAD9605C6284CE3D573A97D5021559891D214CDCCFA4A90F8254643B0A60E168F976FF8C3D2E5ACB0F3DB2ABFBC0A2E4EE6297EC49919CAE5CBBD6A686F1F7370B6ABD7AE8BE70DD216650EC9AAD79928DAC85CFA2D9BC581BA085F0D45C613A99F13F25AA3B24372930D5BB7CEBF685AF34698EBFD92") + api = New("de8157b447584885910f429011e49cb93yjq", "E1D746D42474D5F1F1A10CECE75D99F6", "efa7e1d1a22640fa990e6cf164b28608") + api.SetCookie("thor", "80FAF09E9A09B6E618A68057BDFCFCB8B87C1706FE86F2E8F20251DD598C89ABC8F03DCAB3F5BE7A0CDD0F812D17258CA4603C28541A12C7183F098906F2EBD451175D5A5E341996FDBE3D23CA1D8B847A98C67F3533705D0757AFF57A4B0B4D1D6AD40D1E4AD9AF90E6BE6F807C2802DF5072847E20C96602C459A17166562FF47B9F01900825FF8EFE50C0FA08092F") } diff --git a/platformapi/jdshopapi/sku.go b/platformapi/jdshopapi/sku.go index 7ffb9979..ea90211b 100644 --- a/platformapi/jdshopapi/sku.go +++ b/platformapi/jdshopapi/sku.go @@ -1,6 +1,8 @@ package jdshopapi import ( + "encoding/base64" + "encoding/json" "fmt" "git.rosy.net.cn/baseapi/utils" @@ -20,6 +22,122 @@ type FindShopCategoriesResult struct { ModifyTime int64 `json:"modify_time"` // 修改时间。每修改一次此值都会发生变化。 } +type FindVendorCategoriesResult struct { + ID int `json:"id"` + Fid int `json:"fid"` + AliasName string `json:"aliasName"` + Lev int `json:"lev"` + IndexID int `json:"indexId"` + Status int `json:"status"` + Created int64 `json:"created"` + Name string `json:"name"` + Modified int64 `json:"modified"` +} + +type CreateSkuParamWare struct { + Title string `json:"title"` //是 无 商品名称(限制50个字符以内) + CategoryID int `json:"categoryId"` //是 无 已经授权过的京东“三级”类目(通过商家授权类目接口获取) + // MultiCategoryID int `json:"multiCategoryId"` // 否 无 末级类目ID + BrandID int `json:"brandId"` // 否 无 不同类目是否必填情况不同,若发布时提示[此类目要求品牌必填],则表示品牌需要必填。品牌ID获取方式通过商家授权类目接口获取。 + // TemplateID int `json:"templateId"` // 否 无 发布时不可设置 + TransportID int `json:"transportId"` //是 无 运费模板ID + WareStatus int `json:"wareStatus"` // 否 新增仅可以使用 1:从未上架 8:在售(上架) 商品状态1:从未上架 2:自主下架 4:系统下架 8:在售 513:从未上架 待审核 514:自主下架 待审核 516:系统下架 待审核 520:在售 待审核 1025:从未上架 审核不通过 暂时没用 1026:自主下架 审核不通过 暂时没用 1028:系统下架 审核不通过 1032:在售 审核不通过 + OuterID string `json:"outerId"` // 否 无 商品外部ID,商家自行设置的ID(便于关联京东商品) + VenderID int `json:"venderId"` + Is7ToReturn int `json:"is7ToReturn"` // 0 不支持,1 支持7天, 2支持90天 + // ItemNum string `json:"itemNum"` // 否 无 商品货号 + // BarCode string `json:"barCode"` // 否 无 商品的条形码.UPC码,SN码,PLU码统称为条形码 + // WareLocation int `json:"wareLocation"` // 否 无 商品产出地区 + // Delivery int `json:"delivery"` // 否 无 商品发货地 + // PromiseID int `json:"promiseId"` // 否 无 配送时效 + // adWords // 否 无 商品广告词对象 (单品页显示的优先级低于促销广告词) + // Wrap string `json:"wrap"` //否 无 包装规格(已废弃) + // PackListing string `json:"packListing"` // 否 无 商品包装清单 + Length int `json:"length"` // 否 无 商品长度,单位mm。根据类目区分 是 否必填 + Width int `json:"width"` // 否 无 商品宽度,单位mm。根据类目区分 是 否必填 + Height int `json:"height"` // 否 无 商品高度,单位mm。根据类目区分 是 否必填 + Weight int `json:"weight"` // 否 无 商品重量,单位kg。根据类目区分 是 否必填 + // Props []struct { + // AttrID string `json:"attrID"` // 否 无 属性ID + // AttrValues string `json:"attrValues"` //否 无 属性值ID数组 + // } `json:"props"` // 否 无 属性列表(已废弃 请使用multiCateProps,已经按照类目限制使用3级类目修改,请及时迁移到多级类目) + // Features []struct { + // Key string `json:"key"` //是 无 特殊属性key + // Value string `json:"value"` //否 无 特殊属性value + // } `json:"features"` // 否 无 商品维度的特殊属性 目前两个特殊属性 IBS、FBP、FCS、SCF 4种商家类型【规格型号】 model和【销售单位】 unit 字段且为必填(如 个、盒、袋等)请勿填写公司名称。 + Images []*CreateSkuParamImages `json:"images"` // 是 无 商品图片列表,发布时必须有主图(颜色为十个0,index为1的图片) + ShopCategorys []int `json:"shopCategorys"` // 否 无 商品店内分类(商家接口获取到的最末级的分类) + MobileDesc string `json:"mobileDesc"` // 是 无 移动版的商品介绍 长度限制10W个字符 + Introduction string `json:"introduction"` // 是 无 PC版的商品介绍 长度限制10W个字符 + // AfterSales string `json:"afterSales"` // 否 无 售后服务 + JdPrice int `json:"jdPrice"` // 否 无 商品的京东价,人民币单元 是元 + MarketPrice int `json:"marketPrice"` // 否 无 商品的市场价,人民币单元 是元 + // ZhuangBaID string `json:"zhuangBaId"` // 否 无 商品描述装吧实例ID + // IntroductionUseFlag string `json:"introductionUseFlag"` // 否 无 商品描述使用标识 ,0:使用默认的商品描述,1:使用装吧商详 + // MobileZhuangBaID string `json:"mobileZhuangBaId"` // 否 无 移动版商品描述装吧实例ID + // MobileDescUseFlag string `json:"mobileDescUseFlag"` // 否 无 移动版商品描述使用标识,0:使用默认的移动商详;1:使用装吧移动版商详 + // DesignConcept string `json:"designConcept"` // 否 无 商品设计理念,适用范围 是toplife类目 + // FitCaseHTMLApp string `json:"fitCaseHtmlApp"` // 否 无 装修案例移动版描述,装修类目才可填写 + // FitCaseHTMLPc string `json:"fitCaseHtmlPc"` // 否 无 装修案例PC版描述,装修类目才可填写 + // SpecialServices []string `json:"specialServices"` // 否 无 特色服务,装修类目才可填写,装修类必填,最大为5,每个值最长为8个字符 + MultiCateProps []*CreateSkuParamAttrs `json:"multiCateProps"` // 否 无 类目属性列表,类目属性中有必填项时,此字段必填;若未设置或设置错误,会有“通用属性必填”等错误提示! +} + +type CreateSkuParamImages struct { + ColorID string `json:"colorId"` //是 无 颜色id,颜色id和您设置的销售属性值id对应,使用接口jingdong.category.read.findValuesByAttrIdUnlimit 获取 ,如果没销售属性,则默认为10个0(主图,并且主图必填) + ImgIndex int `json:"imgIndex"` //是 无 图片顺序。index值:1N,如果index存在,则直接覆盖相应index图片 + ImgURL string `json:"imgUrl"` //是 无 京东图片服务器地址,不包括前缀。例如:jfs/t2116/102/1731643157/81969/c3df941a/5670f868Nc441d4c3.jpg + ImgZoneID string `json:"imgZoneId"` //否 无 图片空间中的图片Id +} + +type CreateSkuParamSkus struct { + // SkuID int `json:"skuId"` //否 无 skuID(新建商品不需要填写) + // SaleAttrs []struct { + // AttrValueAlias []string `json:"attrValueAlias"` //否 无 值别名,发布商品时不可设置 + // AttrID string `json:"attrId "` // 是 无 属性ID 通过接口 jingdong.category.read.findAttrsByCategoryIdUnlimitCate 传3级分类 type=4获取 + // AttrValues []string `json:"attrValues "` //是 无 销售属性值 使用接口jingdong.category.read.findValuesByAttrIdUnlimit获取 + // } `json:"saleAttrs"` //是 无 SKU销售属性 + // Features []struct { + // JdPrice int `json:"jdPrice"` //是 无 京东价必填 单位:元 + // OuterID string `json:"outerId"` //否 无 外部ID,系统不保证唯一性,如需唯一性自行保证 + // StockNum string `json:"stockNum"` //是 无 总库存数 + // BarCode string `json:"barCode"` //否 无 SKU的条形码 + // } `json:"features"` //否 无 特殊属性 + JdPrice int `json:"jdPrice"` //是 无 京东价必填 单位:元 + OuterID string `json:"outerId"` //否 无 外部ID,系统不保证唯一性,如需唯一性自行保证 + StockNum int `json:"stockNum"` //是 无 总库存数 + // BarCode string `json:"barCode"` //否 无 SKU的条形码 + // Props []struct{} `json:"props"` //否 无 SKU属性(已废弃 请使用multiCateProps,已经按照类目限制使用3级类目修改,请及时迁移到多级类目) + SaleAttrs []*CreateSkuParamAttrs `json:"saleAttrs"` //否 无 多级SKU属性,仅当属性可以下沉时才能设置,不验证必填!sku维度设置后,以sku上的属性为准! + // Capacity string `json:"capacity"` // 否 20L 20T 容量,在有特殊要求的类目下必填!最多支持6位小数。 + Type string `json:"type"` //"com.jd.pop.ware.ic.api.domain.sku" + Type2 string `json:"@type"` +} + +type CreateSkuParamAttrs struct { + // AttrValueAlias []string `json:"attrValueAlias"` //否 无 值别名,发布商品时不可设置 + AttrID string `json:"attrId"` //是 无 下沉到sku的属性ID 通过接口 jingdong.category.read.findAttrsByCategoryIdUnlimitCate 获取 features字段中attrLevel=1 + AttrValues []string `json:"attrValues"` //是 无 下沉到sku属性值 单选或者多选 通过接口jingdong.category.read.findValuesByAttrIdUnlimit获取 输入类型请手动输入 +} + +type CreateSkuResult struct { + WareID int `json:"wareId"` + skus []struct { + SkuID int `json:"skuId"` + saleAttrs []struct { + AttrValueAlias []string `json:"attrValueAlias"` + AttrID string `json:"attrId"` + AttrValues []string `json:"attrValues"` + } + } +} + +type UpdateWareParam struct { + WareID int `json:"wareId"` + Title string `json:"title"` //否 标题 商品名称 限制45个字符内 + Weight int `json:"weight"` //否 无 商品重量,单位kg +} + //查询商家所有的店内分类 //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) { @@ -45,18 +163,6 @@ func (a *API) DeleteShopCategory(cid int64) (uniteResp *UniteResp, err error) { return uniteResp, err } -type FindVendorCategoriesResult struct { - ID int `json:"id"` - Fid int `json:"fid"` - AliasName string `json:"aliasName"` - Lev int `json:"lev"` - IndexID int `json:"indexId"` - Status int `json:"status"` - Created int64 `json:"created"` - Name string `json:"name"` - Modified int64 `json:"modified"` -} - //查询商家所有的类目 //https://open.jd.com/home/home#/doc/api?apiCateId=88&apiId=2727&apiName=jingdong.vender.category.getValidCategoryResultByVenderId func (a *API) FindVendorCategories() (findVendorCategoriesResult []*FindVendorCategoriesResult, err error) { @@ -67,8 +173,142 @@ func (a *API) FindVendorCategories() (findVendorCategoriesResult []*FindVendorCa return findVendorCategoriesResult, err } -//京东商城发布商品(创建商品?) +//京东商城发布商品(创建商品) //https://open.jd.com/home/home#/doc/api?apiCateId=48&apiId=1379&apiName=jingdong.ware.write.add -func (a *API) CreateSku() (err error) { +func (a *API) CreateWare(createSkuParamWare *CreateSkuParamWare, createSkuParamSkus []*CreateSkuParamSkus) (createSkuResult *CreateSkuResult, err error) { + wares, _ := json.Marshal(createSkuParamWare) + skus, _ := json.Marshal(createSkuParamSkus) + result, err := a.AccessAPI2("jingdong.ware.write.add", prodURL, map[string]interface{}{ + "ware": string(wares), + "skus": string(skus), + }) + if err == nil { + utils.Map2StructByJson(result["jingdong_ware_write_add_responce"].(map[string]interface{})["ware"], &createSkuResult, false) + } + return createSkuResult, err +} + +type UploadPictureResult struct { + ReturnCode int `json:"returnCode"` //返回码:1,操作成功;0,操作失败 + Desc string `json:"desc"` //返回码为1时为操作成功,返回码为0时为操作失败原 + PictureID string `json:"pictureId "` //上传成功的图片i + PictureURL string `json:"pictureUrl"` //上传成功的图片url +} + +//京东商城上传图片 +//https://open.jd.com/home/home#/doc/api?apiCateId=61&apiId=164&apiName=jingdong.imgzone.picture.upload +func (a *API) UploadPicture(imageData []byte, pictureCateID int, pictureName string) (uploadPictureResult *UploadPictureResult, err error) { + result, err := a.AccessAPI("jingdong.imgzone.picture.upload", prodURL, map[string]interface{}{ + "image_data": base64.StdEncoding.EncodeToString(imageData), + "picture_name": pictureName, + }) + if err == nil { + utils.Map2StructByJson(result["jingdong_imgzone_picture_upload_responce"], &uploadPictureResult, false) + } + return uploadPictureResult, err +} + +//查询运费模板 +//https://open.jd.com/home/home#/doc/api?apiCateId=137&apiId=906&apiName=jingdong.ept.feight.outapi.query +func (a *API) GetFeightMb() (err error) { + _, err = a.AccessAPI("jingdong.SkuFareTemplateService.getTemplates", prodURL, nil) + return err +} + +//类目属性 +//https://open.jd.com/home/home#/doc/api?apiCateId=62&apiId=1264&apiName=jingdong.category.read.findAttrsByCategoryId +func (a *API) GetAttrsByCategoryId(currPage, pageSize int) (err error) { + _, err = a.AccessAPI("jingdong.category.read.findAttrsByCategoryId", prodURL, map[string]interface{}{ + "currPage": currPage, + "pageSize": pageSize, + }) + return err +} + +//修改商品基础信息 +//https://open.jd.com/home/home#/doc/api?apiCateId=48&apiId=1380&apiName=jingdong.ware.write.updateWare +func (a *API) UpdateWare(updateWareParam *UpdateWareParam) (err error) { + result2, _ := json.Marshal(utils.Struct2FlatMap(updateWareParam)) + result, err := a.AccessAPI("jingdong.ware.write.updateWare", prodURL, map[string]interface{}{ + "ware": string(result2), + }) + if err == nil { + if result["jingdong_ware_write_updateWare_responce"].(map[string]interface{})["success"] != "success" { + return err + } + } + return err +} + +//删除商品 +//https://open.jd.com/home/home#/doc/api?apiCateId=48&apiId=1250&apiName=jingdong.ware.write.delete +func (a *API) DeleteWare(wareId int) (err error) { + _, err = a.AccessAPI("jingdong.ware.write.delete", prodURL, map[string]interface{}{ + "wareId": wareId, + }) + return err +} + +//获取类目属性ID +//https://open.jd.com/home/home#/doc/api?apiCateId=62&apiId=2809&apiName=jingdong.category.read.findAttrsByCategoryIdUnlimitCate +func (a *API) FindAttrs(cid int) (err error) { + _, err = a.AccessAPI("jingdong.category.read.findAttrsByCategoryIdUnlimitCate", prodURL, map[string]interface{}{ + "cid": cid, + }) + return err +} + +//获取类目属性值 +//https://open.jd.com/home/home#/doc/api?apiCateId=62&apiId=2821&apiName=jingdong.category.read.findValuesByAttrIdUnlimit +func (a *API) FindValuesByAttrId(categoryAttrId int) (err error) { + _, err = a.AccessAPI("jingdong.category.read.findValuesByAttrIdUnlimit", prodURL, map[string]interface{}{ + "categoryAttrId": categoryAttrId, + }) + return err +} + +//新增类目属性值 +//https://open.jd.com/home/home#/doc/api?apiCateId=62&apiId=1262&apiName=jingdong.category.write.saveVenderAttrValue +func (a *API) SaveVenderAttrValue(attValue string, attributeId, categoryId, indexId int) (err error) { + _, err = a.AccessAPI("jingdong.category.write.saveVenderAttrValue", prodURL, map[string]interface{}{ + "attValue": attValue, + "attributeId": attributeId, + "categoryId": categoryId, + "indexId": indexId, + }) + return err +} + +//设置sku库存 +//https://open.jd.com/home/home#/doc/api?apiCateId=48&apiId=1224&apiName=jingdong.stock.write.updateSkuStock +func (a *API) UpdateSkuStock(skuId, stockNum int) (err error) { + _, err = a.AccessAPI("jingdong.stock.write.updateSkuStock", prodURL, map[string]interface{}{ + "skuId": skuId, + "stockNum": stockNum, + }) + return err +} + +//设置门店sku库存 +//https://open.jd.com/home/home#/doc/api?apiCateId=48&apiId=2980&apiName=jingdong.stock.write.updateSkuSiteStock +//siteId 门店ID,venderSource 固定传4 +func (a *API) UpdateSkuSiteStock(skuId, stockNum, siteId int) (err error) { + _, err = a.AccessAPI("jingdong.stock.write.updateSkuSiteStock", prodURL, map[string]interface{}{ + "skuId": skuId, + "stockNum": stockNum, + "siteId": siteId, + "venderSource": 4, + }) + return err +} + +//修改sku京东价 +//https://open.jd.com/home/home#/doc/api?apiCateId=48&apiId=1253&apiName=jingdong.price.write.updateSkuJdPrice +//单位为元 +func (a *API) UpdateSkuJdPrice(skuId, jdPrice int) (err error) { + _, err = a.AccessAPI("jingdong.price.write.updateSkuJdPrice", prodURL, map[string]interface{}{ + "skuId": skuId, + "jdPrice": jdPrice, + }) return err } diff --git a/platformapi/jdshopapi/sku_test.go b/platformapi/jdshopapi/sku_test.go index ea88f94e..7a1c41b7 100644 --- a/platformapi/jdshopapi/sku_test.go +++ b/platformapi/jdshopapi/sku_test.go @@ -1,9 +1,21 @@ package jdshopapi import ( + "bytes" + "crypto/md5" + "encoding/json" + "fmt" + "image" + "image/gif" + "image/jpeg" + "image/png" + "io/ioutil" + "net/http" "testing" + "git.rosy.net.cn/baseapi/platformapi" "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" ) func TestFindShopCategories(t *testing.T) { @@ -29,3 +41,206 @@ func TestFindVendorCategories(t *testing.T) { } t.Log(utils.Format4Output(result, false)) } + +func TestUploadPicture(t *testing.T) { + data, _, err := DownloadFileByURL("https://image.jxc4.com/noGoodsImg.jpg") + // img, outMimeType, _ := Binary2Image(data, "") + // result2, _ := Image2Binary(img, outMimeType) + result, err := api.UploadPicture(data, 0, "noGoodsImg") + if err != nil { + t.Fatal(err) + } + t.Log(utils.Format4Output(result, false)) +} + +func DownloadFileByURL(fileURL string) (bodyData []byte, fileMD5 string, err error) { + response, err := http.Get(fileURL) + if err == nil { + defer response.Body.Close() + if response.StatusCode == http.StatusOK { + if bodyData, err = ioutil.ReadAll(response.Body); err == nil { + fileMD5 = fmt.Sprintf("%X", md5.Sum(bodyData)) + } + } else { + err = platformapi.ErrHTTPCodeIsNot200 + } + } + return bodyData, fileMD5, err +} + +func Binary2Image(binaryData []byte, mimeType string) (img image.Image, outMimeType string, err error) { + if mimeType == "" { + mimeType = http.DetectContentType(binaryData) + } + switch mimeType { + case model.MimeTypeJpeg: + img, err = jpeg.Decode(bytes.NewReader(binaryData)) + case model.MimeTypePng: + img, err = png.Decode(bytes.NewReader(binaryData)) + case model.MimeTypeGif: + img, err = gif.Decode(bytes.NewReader(binaryData)) + } + return img, mimeType, err +} + +func Image2Binary(img image.Image, mimeType string) (binaryData []byte, err error) { + buf := new(bytes.Buffer) + switch mimeType { + case model.MimeTypeJpeg: + jpeg.Encode(buf, img, nil) + case model.MimeTypePng: + png.Encode(buf, img) + case model.MimeTypeGif: + gif.Encode(buf, img, nil) + } + binaryData = buf.Bytes() + return binaryData, err +} + +func TestGetFeightMb(t *testing.T) { + err := api.GetFeightMb() + if err != nil { + t.Fatal(err) + } + // t.Log(utils.Format4Output(result, false)) +} + +func TestAA(t *testing.T) { + ware := &CreateSkuParamWare{ + Title: "测试商品1", + CategoryID: 13577, + TransportID: TransportID, + MobileDesc: "测试", + Introduction: "测试", + WareStatus: 8, + OuterID: "1", + Weight: 2300, + Height: 100, + Length: 100, + Width: 100, + JdPrice: 20, + MarketPrice: 10, + VenderID: 0, + BrandID: JxBrandId, + } + result, _ := json.Marshal(ware) + fmt.Println(string(result)) +} + +func TestCreateSku(t *testing.T) { + var images []*CreateSkuParamImages + var skus []*CreateSkuParamSkus + var attrs []*CreateSkuParamAttrs + var attrs2 []*CreateSkuParamAttrs + var attrs3 []*CreateSkuParamAttrs + ware := &CreateSkuParamWare{ + Title: "测试商品1", + ShopCategorys: []int{11}, + CategoryID: 13577, + TransportID: TransportID, + MobileDesc: "测试", + Introduction: "测试", + WareStatus: 8, + OuterID: "1", + Weight: 2300, + Height: 100, + Length: 100, + Width: 100, + JdPrice: 20, + MarketPrice: 10, + VenderID: 0, + BrandID: JxBrandId, + Is7ToReturn: 0, + } + image := &CreateSkuParamImages{ + ColorID: "0000000000", + ImgIndex: 1, + ImgURL: "jfs/t1/124185/34/1067/20460/5eb90d1aE2a81b6e4/ab451433f5e963b0.jpg", + } + images = append(images, image) + ware.Images = images + sku := &CreateSkuParamSkus{ + JdPrice: 10, + StockNum: 1, + Type: "com.jd.pop.ware.ic.api.domain.sku", + Type2: "com.jd.pop.ware.ic.api.domain.Sku", + } + sku2 := &CreateSkuParamSkus{ + JdPrice: 10, + StockNum: 1, + Type: "com.jd.pop.ware.ic.api.domain.sku", + Type2: "com.jd.pop.ware.ic.api.domain.Sku", + } + attr1 := &CreateSkuParamAttrs{ + AttrID: "109692", + AttrValues: []string{"613613"}, + } + // attr2 := &CreateSkuParamAttrs{ + // AttrID: "109897", + // AttrValues: []string{"613771"}, + // } + attr3 := &CreateSkuParamAttrs{ + AttrID: "160508", + AttrValues: []string{"0.5"}, + } + attr4 := &CreateSkuParamAttrs{ + AttrID: "160781", + AttrValues: []string{"5"}, + } + attr5 := &CreateSkuParamAttrs{ + AttrID: "1001027606", + AttrValues: []string{"2440273517"}, + } + attr6 := &CreateSkuParamAttrs{ + AttrID: "1001027606", + AttrValues: []string{"2440272539"}, + } + attrs = append(attrs, attr1) + // attrs = append(attrs, attr2) + attrs = append(attrs, attr3) + attrs = append(attrs, attr4) + attrs2 = append(attrs2, attr5) + attrs3 = append(attrs3, attr6) + ware.MultiCateProps = attrs + sku2.SaleAttrs = attrs3 + sku.SaleAttrs = attrs2 + skus = append(skus, sku) + skus = append(skus, sku2) + result, err := api.CreateWare(ware, skus) + if err != nil { + t.Fatal(err) + } + t.Log(utils.Format4Output(result, false)) +} + +func TestFindAttrs(t *testing.T) { + err := api.FindAttrs(13577) + if err != nil { + t.Fatal(err) + } + // t.Log(utils.Format4Output(result, false)) +} + +func TestFindValuesByAttrId(t *testing.T) { + err := api.FindValuesByAttrId(109692) + if err != nil { + t.Fatal(err) + } + // t.Log(utils.Format4Output(result, false)) +} + +func TestSaveVenderAttrValue(t *testing.T) { + err := api.SaveVenderAttrValue("0.5", 160806, 13571, 1) + if err != nil { + t.Fatal(err) + } + // t.Log(utils.Format4Output(result, false)) +} + +func TestDeleteWare(t *testing.T) { + err := api.DeleteWare(14509148757) + if err != nil { + t.Fatal(err) + } + // t.Log(utils.Format4Output(result, false)) +} diff --git a/platformapi/jdshopapi/store.go b/platformapi/jdshopapi/store.go new file mode 100644 index 00000000..c66a108e --- /dev/null +++ b/platformapi/jdshopapi/store.go @@ -0,0 +1,26 @@ +package jdshopapi + +import ( + "git.rosy.net.cn/baseapi/utils" +) + +type CreateEntityStoreParam struct { + Name string `json:"name"` //是 门店名称 + AddCode int `json:"addCode"` //是 门店三级标准地址编码(京东) + AddCodeName string `json:"addCodeName"` //否 门店三级标准地址名称(京东) + AddName string `json:"addName"` //是 标准地址加扩展地址以@!分隔 必填 例:北京大兴区亦庄经济开发区@!京东大厦 + Coordinate string `json:"coordinate"` //是 门店坐标 纬度在前,经度在后 例:39.786683,116.563075 + Phone string `json:"phone"` //是 门店电话 + Item []int `json:"item"` //否 门店组ID + CustomerId string `json:"customerId"` //否 商家门店Id,商家维度不可重复 + CategoryName string `json:"categoryName"` //否 门店扩展属性类目名称固定填为:popmendianSelfdelivery + ExtendJson string `json:"extendJson"` //是 扩展属性JSON如:{name1:'value1',name2:'value2'},营业时间必传固定json格式:{\'businessBeginTime\':\'09:00\',\'businessEndTime\':\'22:00\'}' ,可将中间的时间变更 + ImageFile []byte `json:"imageFile"` //否 门店图片,图片二进制文件流,允许png、jpg、gif、jpeg、bmp图片格式,1M以内。 +} + +//创建门店 +//https://open.jd.com/home/home#/doc/api?apiCateId=351&apiId=2224&apiName=jingdong.createEntityStore +func (a *API) CreateEntityStore(createEntityStoreParam *CreateEntityStoreParam) (err error) { + _, err = a.AccessAPI("jingdong.createEntityStore", prodURL, utils.Struct2FlatMap(createEntityStoreParam)) + return err +} diff --git a/platformapi/jdshopapi/store_test.go b/platformapi/jdshopapi/store_test.go new file mode 100644 index 00000000..1f89d84e --- /dev/null +++ b/platformapi/jdshopapi/store_test.go @@ -0,0 +1,11 @@ +package jdshopapi + +import "testing" + +func TestCreateEntityStore(t *testing.T) { + err := api.CreateEntityStore(&CreateEntityStoreParam{}) + if err != nil { + t.Fatal(err) + } + // t.Log(utils.Format4Output(result, false)) +} diff --git a/utils/typeconv.go b/utils/typeconv.go index 5acea05d..d722d061 100644 --- a/utils/typeconv.go +++ b/utils/typeconv.go @@ -392,6 +392,18 @@ func Map2URLValues(mapData map[string]interface{}) (retVal url.Values) { return retVal } +func Map2URLValues2(mapData map[string]interface{}) (retVal url.Values) { + retVal = make(url.Values) + for k, v := range mapData { + if data, ok := v.(string); ok { + retVal.Set(k, data) + } else { + retVal.Set(k, fmt.Sprint(v)) + } + } + return retVal +} + func MapKV2List(mapData map[string]interface{}) []map[string]interface{} { retVal := make([]map[string]interface{}, len(mapData)) index := 0 @@ -542,3 +554,16 @@ func Int2Float64(i int) (f float64) { func Float32ToInt(f float32) (i int) { return int(Str2Int64(Float64ToStr(math.Round(float64(f))))) } + +func Str2Int(s string) (i int) { + return int(Str2Int64(s)) +} + +func Float64TwoInt(f float64) (i int) { + return int(Float64TwoInt64(f)) +} + +func URLQueryEscape(s string) (str string) { + str, _ = url.QueryUnescape(s) + return str +}