Files
baseapi/platformapi/jdapi/sku.go
2018-12-11 13:14:59 +08:00

563 lines
20 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package jdapi
import (
"fmt"
"math"
"git.rosy.net.cn/baseapi/utils"
)
const (
KeyBrandId = "brandId"
KeyBrandName = "brandName"
KeyBrandStatus = "brandStatus"
KeyCategoryId = "categoryId"
KeyChildIds = "childIds"
KeyFields = "fields"
KeyFixedStatus = "fixedStatus"
KeyHandleStatus = "handleStatus"
KeyHeight = "height"
KeyID = "id"
KeyImages = "images"
KeyImgType = "imgType"
KeyIfViewDesc = "ifViewDesc"
KeyIsFilterDel = "isFilterDel"
KeyIsSale = "isSale"
KeyKeyValue = "keyValue"
KeyLength = "length"
KeyLiquidStatue = "liquidStatue"
KeyOutSkuId = "outSkuId"
KeyOutSpuId = "outSuperId"
KeySpuName = "superName"
KeySkuMainInfo = "skuMainInfo"
KeyPID = "pid"
KeyProductDesc = "productDesc"
KeyPageNo = "pageNo"
KeyPageSize = "pageSize"
KeyPrefixKey = "prefixKey"
KeyPrefixKeyId = "prefixKeyId"
KeyPreKeyEndTime = "preKeyEndTime"
KeyPreKeyStartTime = "preKeyStartTime"
KeyPrescripition = "prescripition"
KeyShopCategoryLevel = "shopCategoryLevel"
KeyShopCategoryName = "shopCategoryName"
KeyShopCategories = "shopCategories"
KeySellCities = "sellCities"
KeySlogan = "slogan"
KeySloganEndTime = "sloganEndTime"
KeySloganStartTime = "sloganStartTime"
KeySort = "sort"
KeySkuId = "skuId"
KeySkuName = "skuName"
KeySkuPrice = "skuPrice"
KeyStoreId = "storeId"
KeySystemFixedStatus = "systemFixedStatus"
KeyTransportAttribute = "transportAttribute"
KeyUpcCode = "upcCode"
KeyWeight = "weight"
)
const (
MaxBatchSize4BatchUpdateOutSkuId = 50
)
const (
SkuFixedStatusOnline = 1
SkuFixedStatusOffline = 2
SkuFixedStatusDeleted = 4
)
type SkuIDPair struct {
SkuId int64 `json:"skuId"`
OutSkuId string `json:"outSkuId"`
}
type BrandInfo struct {
ID int `json:"id"`
BrandName string `json:"brandName"`
BrandStatus int `json:"brandStatus"`
}
type IDKeyValuePair struct {
ID string `json:"_id"`
KeyValue string `json:"keyValue"`
}
type ProductStatus struct {
Synchronized bool `json:"synchronized"`
EsEntity map[string]interface{} `json:"esEntity"`
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) {
if pageNo <= 0 {
pageNo = 1
}
if pageSize == 0 {
pageSize = 50
}
params := map[string]interface{}{
KeyPageNo: pageNo, // pageNo好像必须要有值否则一直不返回
KeyPageSize: pageSize,
KeyFields: []string{
"BRAND_ID",
"BRAND_NAME",
"BRAND_STATUS",
},
}
if brandId != 0 {
params[KeyBrandId] = brandId
}
if brandName == "" {
params[KeyBrandName] = brandName
}
result, totalCount, err := a.AccessAPIHavePage("pms/queryPageBrandInfo", params, nil, nil, nil)
if err == nil {
brandList = make([]*BrandInfo, len(result))
for index, v := range result {
mapData := v.(map[string]interface{})
brandList[index] = &BrandInfo{
ID: int(utils.MustInterface2Int64(mapData[KeyID])),
BrandName: utils.Interface2String(mapData[KeyBrandName]),
BrandStatus: int(utils.MustInterface2Int64(mapData[KeyBrandStatus])),
}
}
return brandList, totalCount, nil
}
return nil, 0, err
}
// 获取京东到家类目信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=d287d326124d42c090cff03c16385706
func (a *API) QueryChildCategoriesForOP(pid int64) (catList []*CategoryInfo, err error) {
result, err := a.AccessAPINoPage("api/queryChildCategoriesForOP", utils.Params2Map("fields", []string{
"ID",
"PID",
"CATEGORY_NAME",
"CATEGORY_LEVEL",
"CATEGORY_STATUS",
"FULLPATH",
}, "id", pid), nil, nil, nil)
if err == 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
}
// 新增商家店内分类信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=de26f24a62aa47a49e5ab7579d638cb3
func (a *API) AddShopCategory(pid int64, shopCategoryName string, shopCategoryLevel, sort int, userName string) (catId string, err error) {
params := map[string]interface{}{
KeyPID: pid,
KeyShopCategoryName: shopCategoryName,
KeyShopCategoryLevel: shopCategoryLevel,
KeySort: sort,
"createPin": utils.GetAPIOperator(userName),
}
result, err := a.AccessAPINoPage("pms/addShopCategory", params, nil, nil, nil)
if err == 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 []*CategoryInfo, err error) {
result, err := a.AccessAPINoPage("pms/queryCategoriesByOrgCode", utils.Params2Map("fields", []string{
"ID",
"PID",
"SHOP_CATEGORY_NAME",
"SORT",
}), nil, nil, nil)
if err == nil {
return interface2CatList(result, 1, nil), nil
}
return nil, err
}
// 修改商家店内分类信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=1de278c670b64da492f676ab78d62f73
func (a *API) UpdateShopCategory(id int64, shopCategoryName string) error {
params := map[string]interface{}{
KeyID: id,
KeyShopCategoryName: shopCategoryName,
}
_, err := a.AccessAPINoPage("pms/updateShopCategory", params, nil, nil, nullResultParser)
return err
}
// 修改商家店内分类顺序接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=2a8267602e814be9828f0c7ce307b872
func (a *API) ChangeShopCategoryOrder(pid int64, childIds []int64) error {
params := map[string]interface{}{
KeyPID: pid,
KeyChildIds: childIds,
}
_, 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, nullResultParser)
return err
}
// 新增商品信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=dfe6a5ca73fa421da1c9f969b848113e
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,
KeyShopCategories: shopCategories,
KeyBrandId: brandId,
KeySkuName: skuName,
KeySkuPrice: skuPrice,
KeyWeight: weight,
KeyImages: images,
KeyFixedStatus: fixedStatus,
KeyIsSale: isSale,
}
result, err := a.AccessAPINoPage("pms/sku/addSku", utils.MergeMaps(fixedParams, addParams), nil, nil, nil)
if err == nil {
return (result.(map[string]interface{}))["skuId"].(string), nil
}
return "", err
}
// 根据商家商品编码修改商品信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=290bdb0ea8a44e10b86b05591254ad68
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.(map[string]interface{}))["skuId"].(string), nil
}
return "", err
}
// 根据到家商品编码批量更新商家商品编码接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=4155d29bbdf649b69c67473b705ce7e7
func (a *API) BatchUpdateOutSkuId(skuInfoList []*SkuIDPair) (retVal interface{}, err error) {
result, err := a.AccessAPINoPage("pms/sku/batchUpdateOutSkuId", utils.Params2Map("skuInfoList", skuInfoList), nil, nil, nil)
if err == nil {
return result, nil
}
return nil, err
}
// 查询商家已上传商品信息列表接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=e433b95f74524dab91718432c0358977
// pageNo 从1开始
func (a *API) QuerySkuInfos(skuName string, skuId int64, pageNo, pageSize int, isFilterDel bool) (retVal []map[string]interface{}, totalCount int, err error) {
if pageNo <= 0 {
pageNo = 1
}
if pageSize == 0 {
pageSize = 50
}
params := map[string]interface{}{
KeyPageNo: pageNo, // pageNo好像必须要有值否则一直不返回
KeyPageSize: pageSize,
}
if skuName != "" {
params[KeySkuName] = skuName
}
if skuId != 0 {
params[KeySkuId] = skuId
}
if isFilterDel {
params[KeyIsFilterDel] = "1"
} else {
params[KeyIsFilterDel] = "0"
}
result, totalCount, err := a.AccessAPIHavePage("pms/querySkuInfos", params, nil, nil, nil)
if err == nil {
return utils.Slice2MapSlice(result), totalCount, nil
}
return nil, 0, err
}
// 查询商品图片处理结果接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=17506653e03542f9a49023711780c30d
func (a *API) QueryListBySkuIds(skuIds []int64, addParams map[string]interface{}) (retVal []map[string]interface{}, err error) {
result, err := a.AccessAPINoPage("order/queryListBySkuIds", utils.MergeMaps(addParams, utils.Params2Map("skuIds", skuIds)), nil, nil, nil)
if err == nil {
return utils.Slice2MapSlice(result.([]interface{})), nil
}
return nil, err
}
// 分页查询京东到家商品前缀库接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=2195b87baf0c4783bb1a4fda35aea7d1
func (a *API) QueryKeyWordDicInfo(pageNo, pageSize int, keyValue string) (values []*IDKeyValuePair, totalCount int, err error) {
if pageNo <= 0 {
pageNo = 1
}
if pageSize == 0 {
pageSize = 50
}
params := map[string]interface{}{
KeyPageNo: pageNo, // pageNo好像必须要有值否则一直不返回
KeyPageSize: pageSize,
KeyFields: []string{
"ID",
"KEYVALUE",
},
}
if keyValue != "" {
params[KeyKeyValue] = keyValue
}
result, totalCount, err := a.AccessAPIHavePage("pms/queryKeyWordDicInfo", params, nil, nil, nil)
if err == nil {
values = make([]*IDKeyValuePair, len(result))
for index, v := range result {
mapData := v.(map[string]interface{})
values[index] = &IDKeyValuePair{
ID: utils.Interface2String(mapData["_id"]),
KeyValue: utils.Interface2String(mapData[KeyKeyValue]),
}
}
return values, totalCount, nil
}
return nil, 0, err
}
// 商家商品状态同步接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=5e29d6c9317847e58b8cbcc70702fd52
func (a *API) SyncProduct(storeId, skuId string) (retVal bool, err error) {
result, err := a.AccessAPINoPage("search/syncProduct", utils.Params2Map(KeyStoreId, storeId, KeySkuId, skuId), nil, nil, func(data map[string]interface{}) (interface{}, error) {
status := utils.MustInterface2Int64(data["status"])
if status == 200 {
return data["synchronized"].(bool), nil
}
return nil, utils.NewErrorIntCode(data["message"].(string), int(status))
})
if err == nil {
return result.(bool), nil
}
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"])
if status == 200 {
return &ProductStatus{
Synchronized: data["synchronized"].(bool),
EsEntity: data["esEntity"].(map[string]interface{}),
ProductEntity: data["productEntity"].(map[string]interface{}),
}, nil
}
return nil, utils.NewErrorIntCode(data["message"].(string), int(status))
})
if err == nil {
return result.(*ProductStatus), nil
}
return nil, err
}
// 新增SPU信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=e30936da75294e55bcfdabb92c3815bc
func (a *API) AddSpu(outSpuId string, cagtegoryId int, shopCategories []int64, brandId int, spuName string, images []string, fixedStatus int, addParams map[string]interface{}, skus []map[string]interface{}) (spuId int64, skuPairs []*SkuIDPair, err error) {
attrList := []string{}
for k, v := range skus {
attr := getSkuAttr(v[KeyWeight].(float32))
attrList = append(attrList, attr)
skus[k] = utils.MergeMaps(map[string]interface{}{
"saleAttrValues": genAttrMapList(attr),
}, v)
}
fixedParams := map[string]interface{}{
KeyOutSpuId: outSpuId,
KeyCategoryId: cagtegoryId,
KeyShopCategories: shopCategories,
KeyBrandId: brandId,
KeySpuName: spuName,
KeyImages: images,
KeyFixedStatus: fixedStatus,
KeySkuMainInfo: skus,
KeyProductDesc: spuName, // todo
"saleAttrRelationInfoList": []map[string]interface{}{
map[string]interface{}{
"saleAttrName": "规格",
"saleAttrValueNameList": attrList,
},
map[string]interface{}{
"saleAttrName": "口味",
"saleAttrValueNameList": []string{"."},
},
},
}
result, err := a.AccessAPINoPage("pms/addSpu", utils.MergeMaps(fixedParams, addParams), nil, nil, nil)
if err == nil {
resultMap := result.(map[string]interface{})
skuMainParterResponseList := resultMap["skuMainParterResponseList"].([]interface{})
skuPairs = make([]*SkuIDPair, len(skuMainParterResponseList))
for k, v := range skuMainParterResponseList {
v2 := v.(map[string]interface{})
skuPairs[k] = &SkuIDPair{
OutSkuId: v2["outSkuId"].(string),
SkuId: utils.Str2Int64(v2["skuId"].(string)),
}
}
return utils.MustInterface2Int64(resultMap["superId"]), skuPairs, nil
}
return 0, nil, err
}
// 追加新的SKU到指定的SPU接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=cffb839b06f042b28d6397b6bd4f2676
func (a *API) AppendSku(outSpuId string, 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 int64, err error) {
attr := getSkuAttr(weight)
if err = a.AppendSpuSaleAttr(outSpuId, "1001", attr); err != nil {
return 0, err
}
fixedParams := map[string]interface{}{
KeyOutSpuId: outSpuId,
KeyOutSkuId: outSkuId,
KeyCategoryId: cagtegoryId,
KeyShopCategories: shopCategories,
KeyBrandId: brandId,
KeySkuName: skuName,
KeySkuPrice: skuPrice,
KeyWeight: weight,
KeyImages: images,
KeyFixedStatus: fixedStatus,
KeyIsSale: isSale,
"saleAttrValues": genAttrMapList(attr),
}
result, err := a.AccessAPINoPage("pms/appendSku", utils.MergeMaps(fixedParams, addParams), nil, nil, nil)
if err == nil {
resultMap := result.(map[string]interface{})
skuMainParterResponseList := resultMap["skuMainParterResponseList"].([]interface{})
return utils.Str2Int64(skuMainParterResponseList[0].(map[string]interface{})["skuId"].(string)), nil
}
return 0, err
}
// 更新SPU基础信息,不可以更新销售属性
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=3816c5eadc5d4f268f760cac14483ec0
func (a *API) UpdateSpu(outSpuId string, params map[string]interface{}) (err error) {
_, err = a.AccessAPINoPage("pms/updateSpu", utils.MergeMaps(params, utils.Params2Map(KeyOutSpuId, outSpuId)), nil, nil, nil)
return err
}
// 更新SPU下指定SKU的基础信息
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=8be2b5d153044179a13089e7f19e24e6
func (a *API) UpdateSkuBaseInfo(outSpuId, outSkuId string, params map[string]interface{}) (err error) {
_, err = a.AccessAPINoPage("pms/updateSkuBaseInfo", utils.MergeMaps(params, utils.Params2Map(KeyOutSpuId, outSpuId, KeyOutSkuId, outSkuId)), nil, nil, nil)
return err
}
func (a *API) GetSkuSaleAttrName() (saleAttrNameList []string, err error) {
result, err := a.AccessAPINoPage("pms/getSkuSaleAttrName", nil, nil, nil, nil)
if err == nil {
return utils.Slice2StringSlice(result.([]interface{})), nil
}
return nil, err
}
func (a *API) AppendSpuSaleAttr(outSpuId, attrName, attrNewValue string) (err error) {
_, err = a.AccessAPINoPage("pms/appendSpuSaleAttr", map[string]interface{}{
KeyOutSpuId: outSpuId,
"saleAttrId": attrName,
"saleAttrValueName": attrNewValue,
}, nil, nil, nil)
return err
}
func (a *API) GetSpuSaleAttr(outSpuId string) (attrList []map[string]interface{}, err error) {
result, err := a.AccessAPINoPage("pms/getSpuSaleAttr", map[string]interface{}{
KeyOutSpuId: outSpuId,
}, nil, nil, nil)
if err == nil {
return utils.Slice2MapSlice(result.([]interface{})), nil
}
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
}
func getSkuAttr(weight float32) (attr string) {
attr = fmt.Sprintf("约%dg", int(math.Round(float64(weight*1000))))
return attr
}
func genAttrMapList(kgAttr string) (attrList []map[string]interface{}) {
return []map[string]interface{}{
map[string]interface{}{
"saleAttrName": "规格",
"saleAttrValueName": kgAttr,
},
map[string]interface{}{
"saleAttrName": "口味",
"saleAttrValueName": ".",
},
}
}