505 lines
14 KiB
Go
505 lines
14 KiB
Go
package jd
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
|
||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||
"git.rosy.net.cn/baseapi/utils"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||
"git.rosy.net.cn/jx-callback/business/model"
|
||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||
"git.rosy.net.cn/jx-callback/business/partner"
|
||
"git.rosy.net.cn/jx-callback/globals"
|
||
"git.rosy.net.cn/jx-callback/globals/api"
|
||
beego "github.com/astaxie/beego/adapter"
|
||
)
|
||
|
||
const (
|
||
DefBrandID = 35247
|
||
|
||
DefJdCategoryID = 20362
|
||
DefJdCategoryID4Jxgy = 22410 // 其他国产水果
|
||
)
|
||
|
||
func getDefJdCategoryID() int {
|
||
if beego.BConfig.RunMode == "jxgy" {
|
||
return DefJdCategoryID4Jxgy
|
||
}
|
||
return DefJdCategoryID
|
||
}
|
||
|
||
func jdCat2Jx(jdCat *jdapi.CategoryInfo) (jxCat *partner.BareCategoryInfo) {
|
||
return &partner.BareCategoryInfo{
|
||
VendorCatID: utils.Int64ToStr(jdCat.Id),
|
||
Level: jdCat.Level,
|
||
Name: jdCat.Name,
|
||
Seq: jdCat.Sort,
|
||
}
|
||
}
|
||
|
||
func (p *PurchaseHandler) GetAllCategories(ctx *jxcontext.Context, vendorOrgCode string) (cats []*partner.BareCategoryInfo, err error) {
|
||
result, err := getAPI(vendorOrgCode).QueryCategoriesByOrgCode()
|
||
if err == nil {
|
||
catMap := make(map[int64]*partner.BareCategoryInfo)
|
||
level := 1
|
||
for {
|
||
processedCount := 0
|
||
for _, jdCat := range result {
|
||
if jdCat.Level == level {
|
||
processedCount++
|
||
jxCat := jdCat2Jx(jdCat)
|
||
if level == 1 {
|
||
cats = append(cats, jxCat)
|
||
} else {
|
||
parentCat := catMap[jdCat.ParentId]
|
||
if parentCat != nil {
|
||
parentCat.Children = append(parentCat.Children, jxCat)
|
||
}
|
||
}
|
||
catMap[jdCat.Id] = jxCat
|
||
}
|
||
}
|
||
if processedCount == 0 {
|
||
break
|
||
}
|
||
level++
|
||
}
|
||
}
|
||
return cats, err
|
||
}
|
||
|
||
func (p *PurchaseHandler) CreateCategory2(ctx *jxcontext.Context, cat *dao.SkuStoreCatInfo) (err error) {
|
||
globals.SugarLogger.Debugf("CreateCategory2 cat:%s", utils.Format4Output(cat, true))
|
||
parentID := int64(0)
|
||
if cat.Level != 1 {
|
||
parentID = utils.Str2Int64(cat.ParentVendorCatID)
|
||
}
|
||
if globals.EnableJdStoreWrite {
|
||
result, err2 := getAPI(cat.VendorOrgCode).AddShopCategory(parentID, cat.Name, int(cat.Level), cat.Seq, ctx.GetUserName())
|
||
if err = err2; err == nil {
|
||
if jdID := utils.Str2Int64WithDefault(result, 0); jdID != 0 {
|
||
cat.VendorCatID = utils.Int64ToStr(jdID)
|
||
}
|
||
}
|
||
} else {
|
||
cat.VendorCatID = utils.Int64ToStr(jxutils.GenFakeID())
|
||
}
|
||
return err
|
||
}
|
||
|
||
func (p *PurchaseHandler) UpdateCategory2(ctx *jxcontext.Context, cat *dao.SkuStoreCatInfo) (err error) {
|
||
globals.SugarLogger.Debugf("UpdateCategory2 cat:%s", utils.Format4Output(cat, true))
|
||
if globals.EnableJdStoreWrite {
|
||
err = getAPI(cat.VendorOrgCode).UpdateShopCategory(utils.Str2Int64(cat.VendorCatID), cat.Name)
|
||
}
|
||
return err
|
||
}
|
||
|
||
func (p *PurchaseHandler) DeleteCategory2(ctx *jxcontext.Context, vendorOrgCode, vendorCatID string) (err error) {
|
||
globals.SugarLogger.Debugf("DeleteCategory2 vendorOrgCode:%s, vendorCatID:%s", vendorOrgCode, vendorCatID)
|
||
if globals.EnableJdStoreWrite {
|
||
err = getAPI(vendorOrgCode).DelShopCategory(utils.Str2Int64(vendorCatID))
|
||
}
|
||
return err
|
||
}
|
||
|
||
func (p *PurchaseHandler) ReorderCategories2(ctx *jxcontext.Context, vendorOrgCode, vendorParentCatID string, vendorCatIDList []string) (err error) {
|
||
if globals.EnableJdStoreWrite {
|
||
err = getAPI(vendorOrgCode).ChangeShopCategoryOrder(utils.Str2Int64WithDefault(vendorParentCatID, 0), utils.StringSlice2Int64(vendorCatIDList))
|
||
}
|
||
return err
|
||
}
|
||
|
||
func (p *PurchaseHandler) getVendorCategories(level int, pid int64) (vendorCats []*model.SkuVendorCategory, err error) {
|
||
// 得到平台的分类,不需要指定分账号
|
||
cats, err := api.JdAPI.QueryChildCategoriesForOP(pid)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
for _, v := range cats {
|
||
if v.Status == 1 {
|
||
cat := &model.SkuVendorCategory{
|
||
VendorID: model.VendorIDJD,
|
||
Name: v.Name,
|
||
Level: level,
|
||
VendorCategoryID: utils.Int64ToStr(v.Id),
|
||
}
|
||
if level > 1 {
|
||
cat.ParentID = utils.Int64ToStr(v.ParentId)
|
||
if level == 3 {
|
||
cat.IsLeaf = 1
|
||
}
|
||
}
|
||
vendorCats = append(vendorCats, cat)
|
||
if level < 3 {
|
||
childVendorCats, err2 := p.getVendorCategories(level+1, v.Id)
|
||
if err2 == nil && len(childVendorCats) > 0 {
|
||
vendorCats = append(vendorCats, childVendorCats...)
|
||
} else {
|
||
cat.IsLeaf = 1
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return vendorCats, nil
|
||
}
|
||
|
||
func (p *PurchaseHandler) GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error) {
|
||
vendorCats, err = p.getVendorCategories(1, 0)
|
||
return vendorCats, err
|
||
}
|
||
|
||
func skuInfo2Param(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (param *jdapi.OpSkuParam) {
|
||
param = &jdapi.OpSkuParam{
|
||
TraceID: ctx.GetTrackInfo(),
|
||
OutSkuID: utils.Int2Str(sku.SkuID),
|
||
ShopCategories: []int64{},
|
||
CategoryID: sku.VendorVendorCatID,
|
||
BrandID: DefBrandID,
|
||
SkuName: utils.LimitUTF8StringLen(sku.SkuName, jdapi.MaxSkuNameCharCount),
|
||
SkuPrice: int(sku.Price),
|
||
Weight: float64(jxutils.IntWeight2Float(sku.Weight)),
|
||
FixedStatus: jxStatus2jdStatus(sku.MergedStatus),
|
||
IsSale: jdapi.IsSaleNo, // todo ?
|
||
|
||
Upc: sku.Upc,
|
||
// Images: jxutils.BatchString2Slice(sku.Img, sku.Img2),
|
||
}
|
||
if sku.VendorCatID != "" {
|
||
param.ShopCategories = append(param.ShopCategories, utils.Str2Int64(sku.VendorCatID))
|
||
}
|
||
if sku.ImgMix != "" {
|
||
param.Images = jxutils.BatchString2Slice(sku.ImgMix, sku.Img2, sku.Img3, sku.Img4, sku.Img5)
|
||
} else {
|
||
param.Images = jxutils.BatchString2Slice(sku.Img, sku.Img2, sku.Img3, sku.Img4, sku.Img5)
|
||
}
|
||
|
||
if param.CategoryID == 0 {
|
||
param.CategoryID = int64(getDefJdCategoryID())
|
||
}
|
||
// 京东强制要求upc的商品,如果没有设置upc,自动生成一个假的
|
||
if param.Upc == "" && isSkuMustHaveUpc(sku.Unit, param.CategoryID) {
|
||
param.Upc = jxutils.GenFakeUPC(sku.SkuID)
|
||
}
|
||
if sku.IsGlobal == 0 && len(sku.SellCities) > 0 {
|
||
param.SellCities = utils.StringSlice2Int64(sku.SellCities)
|
||
}
|
||
if sku.DescImg != "" {
|
||
param.ProductDesc = fmt.Sprintf(`<img src="%s" alt="一张图片" />`, sku.DescImg)
|
||
}
|
||
return param
|
||
}
|
||
|
||
func (p *PurchaseHandler) CreateSku2(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (err error) {
|
||
globals.SugarLogger.Debugf("CreateSku2 sku:%s", utils.Format4Output(sku, true))
|
||
param := skuInfo2Param(ctx, sku)
|
||
if globals.EnableJdStoreWrite {
|
||
sku.VendorSkuID, err = getAPI(sku.VendorOrgCode).AddSku2(param)
|
||
if err != nil && strings.Contains(err.Error(), jdapi.ErrMustUPC) {
|
||
result, err2 := getAPI(sku.VendorOrgCode).BatchAddSkuByUPC([]*jdapi.CreateByUpcParam2{
|
||
&jdapi.CreateByUpcParam2{
|
||
OutSkuId: utils.Int2Str(sku.SkuID),
|
||
Upc: sku.Upc,
|
||
JdPrice: utils.Int64ToStr(sku.Price),
|
||
ShopCategoryID: utils.Str2Int64WithDefault((sku.VendorCatID), 0),
|
||
},
|
||
})
|
||
if err2 == nil {
|
||
sku.VendorSkuID = result.SkuID
|
||
} else {
|
||
err = err2
|
||
}
|
||
}
|
||
} else {
|
||
sku.VendorSkuID = utils.Int64ToStr(jxutils.GenFakeID())
|
||
}
|
||
return err
|
||
}
|
||
|
||
func (p *PurchaseHandler) UpdateSku2(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (err error) {
|
||
globals.SugarLogger.Debugf("UpdateSku2 sku:%s", utils.Format4Output(sku, true))
|
||
param := skuInfo2Param(ctx, sku)
|
||
if globals.EnableJdStoreWrite {
|
||
_, err = getAPI(sku.VendorOrgCode).UpdateSku2(param)
|
||
}
|
||
return err
|
||
}
|
||
|
||
func (p *PurchaseHandler) DeleteSku2(ctx *jxcontext.Context, vendorOrgCode string, sku *partner.StoreSkuInfo) (err error) {
|
||
globals.SugarLogger.Debugf("DeleteSku2 vendorOrgCode:%s, sku:%s", vendorOrgCode, utils.Format4Output(sku, true))
|
||
|
||
// 京东到家只能通过商家ID删除SKU,如果没有的话,先绑定,再删除
|
||
if sku.SkuID == 0 {
|
||
skuPairList := []*jdapi.SkuIDPair{
|
||
&jdapi.SkuIDPair{
|
||
SkuId: utils.Str2Int64(sku.VendorSkuID),
|
||
OutSkuId: sku.VendorSkuID,
|
||
},
|
||
}
|
||
if globals.EnableJdStoreWrite {
|
||
_, err = getAPI(vendorOrgCode).BatchUpdateOutSkuId(skuPairList)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
sku.SkuID = int(utils.Str2Int64(sku.VendorSkuID))
|
||
}
|
||
}
|
||
param := &jdapi.OpSkuParam{
|
||
TraceID: ctx.GetTrackInfo(),
|
||
OutSkuID: utils.Int2Str(sku.SkuID),
|
||
FixedStatus: jdapi.SkuFixedStatusDeleted,
|
||
}
|
||
if globals.EnableJdStoreWrite {
|
||
_, err = getAPI(vendorOrgCode).UpdateSku2(param)
|
||
}
|
||
return err
|
||
}
|
||
|
||
func (p *PurchaseHandler) GetSkus(ctx *jxcontext.Context, vendorOrgCode string, skuID int, vendorSkuID string) (skuNameList []*partner.SkuNameInfo, err error) {
|
||
param := &jdapi.QuerySkuParam{
|
||
SkuID: utils.Str2Int64WithDefault(vendorSkuID, 0),
|
||
IsFilterDel: jdapi.IsFilterDelTrue,
|
||
PageNo: 1,
|
||
PageSize: jdapi.MaxSkuIDsCount4QueryListBySkuIds, // 为了同时取图,这个值不要大于jdapi.MaxSkuIDsCount4QueryListBySkuIds
|
||
}
|
||
for {
|
||
skuList, _, err2 := getAPI(vendorOrgCode).QuerySkuInfos(param)
|
||
if err = err2; err != nil {
|
||
return nil, err
|
||
}
|
||
if len(skuList) > 0 {
|
||
batchSkuNameList := make([]*partner.SkuNameInfo, len(skuList))
|
||
for k, v := range skuList {
|
||
batchSkuNameList[k] = vendorSku2Jx(v)
|
||
}
|
||
setSkuNameListPic(vendorOrgCode, batchSkuNameList)
|
||
skuNameList = append(skuNameList, batchSkuNameList...)
|
||
}
|
||
if len(skuList) < param.PageSize {
|
||
break
|
||
}
|
||
param.PageNo++
|
||
}
|
||
return skuNameList, err
|
||
}
|
||
|
||
func setSkuNameListPic(vendorOrgCode string, skuNameList []*partner.SkuNameInfo) []*partner.SkuNameInfo {
|
||
jdSkuIDs := make([]int64, len(skuNameList))
|
||
for k, v := range skuNameList {
|
||
jdSkuIDs[k] = utils.Str2Int64(v.SkuList[0].VendorSkuID)
|
||
}
|
||
|
||
imgMap := make(map[int64]*jdapi.ImgHandleQueryResult)
|
||
if imgList, err2 := getAPI(vendorOrgCode).QueryListBySkuIds(&jdapi.QueryListBySkuIdsParam{
|
||
SkuIDs: jdSkuIDs,
|
||
}); err2 == nil {
|
||
for _, v := range imgList {
|
||
if v.ImgType == jdapi.ImgTypeMain {
|
||
imgResult := imgMap[v.SkuID]
|
||
if imgResult == nil || imgResult.IsMain < v.IsMain {
|
||
imgMap[v.SkuID] = v
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 使用扒页面方式获取商品图片
|
||
if false {
|
||
var leftJdSkuIDs []int64
|
||
for _, v := range jdSkuIDs {
|
||
if imgMap[v] == nil {
|
||
leftJdSkuIDs = append(leftJdSkuIDs, v)
|
||
}
|
||
}
|
||
task := tasksch.NewParallelTask("jd setSkuNameListPic", nil, jxcontext.AdminCtx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
jdSkuID := batchItemList[0].(int64)
|
||
imgList, err := getAPI(vendorOrgCode).GetSkuPageImageInfo(jdSkuID)
|
||
if err == nil && len(imgList) > 0 {
|
||
retVal = [][]string{
|
||
[]string{utils.Int64ToStr(jdSkuID), imgList[0].Big},
|
||
}
|
||
}
|
||
return retVal, err
|
||
}, leftJdSkuIDs)
|
||
task.Run()
|
||
if resultList, err := task.GetResult(0); err == nil {
|
||
for _, v := range resultList {
|
||
strList := v.([]string)
|
||
imgMap[utils.Str2Int64(strList[0])] = &jdapi.ImgHandleQueryResult{
|
||
SourceImgURL: strList[1],
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 设置商品图片
|
||
for _, v := range skuNameList {
|
||
if imgResult := imgMap[utils.Str2Int64(v.SkuList[0].VendorSkuID)]; imgResult != nil {
|
||
v.PictureList = []string{imgResult.SourceImgURL}
|
||
}
|
||
}
|
||
return skuNameList
|
||
}
|
||
|
||
func vendorSku2Jx(vendorSku *jdapi.SkuMain) (skuName *partner.SkuNameInfo) {
|
||
prefix, name, comment, specUnit, unit, specQuality := jxutils.SplitSkuName(vendorSku.SkuName)
|
||
weight := int(vendorSku.Weight * 1000)
|
||
if weight <= 0 {
|
||
weight = jxutils.FormatSkuWeight(specQuality, specUnit)
|
||
}
|
||
skuID := int(utils.Str2Int64WithDefault(vendorSku.OutSkuID, 0))
|
||
vendorSkuID := utils.Int64ToStr(vendorSku.SkuID)
|
||
skuName = &partner.SkuNameInfo{
|
||
NameID: skuID,
|
||
VendorNameID: vendorSkuID,
|
||
VendorCatIDList: []string{utils.Int64ToStr(vendorSku.CategoryID)},
|
||
|
||
Prefix: prefix,
|
||
Name: name,
|
||
Unit: unit,
|
||
SkuList: []*partner.SkuInfo{
|
||
&partner.SkuInfo{
|
||
StoreSkuInfo: partner.StoreSkuInfo{
|
||
VendorSkuID: vendorSkuID,
|
||
SkuID: skuID,
|
||
|
||
VendorPrice: int64(vendorSku.SkuPrice),
|
||
Status: jdStatus2jxStatus(vendorSku.FixedStatus),
|
||
},
|
||
SkuName: vendorSku.SkuName,
|
||
Comment: comment,
|
||
SpecQuality: float64(specQuality),
|
||
SpecUnit: specUnit,
|
||
Weight: weight,
|
||
},
|
||
},
|
||
}
|
||
return skuName
|
||
}
|
||
|
||
func jdStatus2jxStatus(jdStatus int) (jxStatus int) {
|
||
switch jdStatus {
|
||
case jdapi.SkuFixedStatusOnline:
|
||
jxStatus = model.SkuStatusNormal
|
||
case jdapi.SkuFixedStatusOffline:
|
||
jxStatus = model.SkuStatusDontSale
|
||
case jdapi.SkuFixedStatusDeleted:
|
||
jxStatus = model.SkuStatusDeleted
|
||
}
|
||
return jxStatus
|
||
}
|
||
|
||
func jxStatus2jdStatus(jxStatus int) (jdStatus int) {
|
||
switch jxStatus {
|
||
case model.SkuStatusNormal:
|
||
jdStatus = jdapi.SkuFixedStatusOnline
|
||
case model.SkuStatusDontSale:
|
||
jdStatus = jdapi.SkuFixedStatusOffline
|
||
case model.SkuStatusDeleted:
|
||
jdStatus = jdapi.SkuFixedStatusDeleted
|
||
}
|
||
return jdStatus
|
||
}
|
||
|
||
func isSkuMustHaveUpc(unit string, vendorVendorCatID int64) bool {
|
||
return unit != model.SpecialUnit || !upcLessMap[vendorVendorCatID]
|
||
}
|
||
|
||
var (
|
||
upcLessMap = map[int64]bool{
|
||
20250: true,
|
||
20252: true,
|
||
20258: true,
|
||
20259: true,
|
||
20261: true,
|
||
20262: true,
|
||
20263: true,
|
||
20264: true,
|
||
20265: true,
|
||
20266: true,
|
||
20267: true,
|
||
22822: true,
|
||
20269: true,
|
||
20270: true,
|
||
20271: true,
|
||
20272: true,
|
||
20273: true,
|
||
20275: true,
|
||
20276: true,
|
||
20277: true,
|
||
20278: true,
|
||
20279: true,
|
||
20281: true,
|
||
20282: true,
|
||
20283: true,
|
||
20285: true,
|
||
20286: true,
|
||
20287: true,
|
||
22821: true,
|
||
20289: true,
|
||
20290: true,
|
||
23018: true,
|
||
20354: true,
|
||
20355: true,
|
||
20357: true,
|
||
20359: true,
|
||
23019: true,
|
||
20294: true,
|
||
20295: true,
|
||
20296: true,
|
||
20297: true,
|
||
20298: true,
|
||
20299: true,
|
||
20300: true,
|
||
20302: true,
|
||
20303: true,
|
||
20304: true,
|
||
22840: true,
|
||
22841: true,
|
||
20317: true,
|
||
20320: true,
|
||
20321: true,
|
||
20323: true,
|
||
20325: true,
|
||
20326: true,
|
||
20328: true,
|
||
20329: true,
|
||
20331: true,
|
||
20335: true,
|
||
20337: true,
|
||
20338: true,
|
||
20339: true,
|
||
22842: true,
|
||
22843: true,
|
||
23020: true,
|
||
20309: true,
|
||
20310: true,
|
||
20311: true,
|
||
20312: true,
|
||
20313: true,
|
||
20314: true,
|
||
20315: true,
|
||
22410: true,
|
||
23050: true,
|
||
20319: true,
|
||
20322: true,
|
||
20330: true,
|
||
20332: true,
|
||
20334: true,
|
||
20336: true,
|
||
20340: true,
|
||
20342: true,
|
||
23049: true,
|
||
20356: true,
|
||
20358: true,
|
||
20360: true,
|
||
20361: true,
|
||
20362: true,
|
||
20364: true,
|
||
}
|
||
)
|