825 lines
33 KiB
Go
825 lines
33 KiB
Go
package tiktok_store
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
|
||
freightTemplate_create_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/freightTemplate_create/request"
|
||
product_addV2_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_addV2/request"
|
||
product_detail_response "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_detail/response"
|
||
product_editV2_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_editV2/request"
|
||
shop_bindStoreFreight_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/shop_bindStoreFreight/request"
|
||
shop_bindStoreSaleLimit_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/shop_bindStoreSaleLimit/request"
|
||
sku_editPrice_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/sku_editPrice/request"
|
||
sku_syncStock_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/sku_syncStock/request"
|
||
trade_createTradeLimitTemplate_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/trade_createTradeLimitTemplate/request"
|
||
tiktokShop "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/tiktok_api"
|
||
"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/business/partner/putils"
|
||
"git.rosy.net.cn/jx-callback/globals"
|
||
"math/rand"
|
||
"regexp"
|
||
"strings"
|
||
)
|
||
|
||
const (
|
||
updateTypeStock = iota
|
||
updateTypeStatus
|
||
updateTypePrice
|
||
)
|
||
|
||
const (
|
||
defVendorCatID = 200001903 // 生菜
|
||
|
||
specialStoreID = "8171010"
|
||
// specialStoreID = "2523687"
|
||
)
|
||
|
||
var (
|
||
sensitiveWordRegexp = regexp.MustCompile(`包含敏感词:(\[.*\])`)
|
||
)
|
||
|
||
// GetStoreSkusBatchSize 当前任务最大更新条数
|
||
func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) (batchSize int) {
|
||
switch funcID {
|
||
case partner.FuncUpdateStoreSkusStock, partner.FuncUpdateStoreSkusStatus, partner.FuncUpdateStoreSkusPrice:
|
||
batchSize = tiktokShop.MaxStoreSkuBatchSize
|
||
case partner.FuncDeleteStoreSkus:
|
||
batchSize = tiktokShop.MaxBatchDeleteSize
|
||
case partner.FuncCreateStoreSkus:
|
||
batchSize = 1 // 可考虑用批量操作
|
||
case partner.FuncUpdateStoreSkus:
|
||
batchSize = 1 // mtwmapi.MaxStoreSkuBatchSize
|
||
case partner.FuncGetStoreSkusFullInfo:
|
||
batchSize = 1
|
||
case partner.FuncCreateActs:
|
||
batchSize = tiktokShop.MaxRetailDiscountCreateBatchSize
|
||
case partner.FuncCancelActs:
|
||
batchSize = tiktokShop.MaxRetailDiscountDeleteBatchSize
|
||
}
|
||
return batchSize
|
||
}
|
||
|
||
func getStoreVendorOrgCode(storeID int) (vendorOrgCode string) {
|
||
if storeMap, _ := dao.GetStoreDetail(dao.GetDB(), storeID, model.VendorIDDD, ""); storeMap != nil {
|
||
return storeMap.VendorOrgCode
|
||
}
|
||
return vendorOrgCode
|
||
}
|
||
|
||
// GetStoreAllCategories 门店分类
|
||
func (p *PurchaseHandler) GetStoreAllCategories(ctx *jxcontext.Context, storeID int, vendorStoreID string) (cats []*partner.BareCategoryInfo, err error) {
|
||
remoteCats, err := getAPI(getStoreVendorOrgCode(storeID), storeID, vendorStoreID).GetShopCategory(0)
|
||
if err == nil {
|
||
cats = convertVendorCatList(remoteCats)
|
||
}
|
||
return cats, err
|
||
}
|
||
|
||
func convertVendorCatList(remoteCats []*tiktokShop.RetailCategoryInfo) (cats []*partner.BareCategoryInfo) {
|
||
for _, rCat := range remoteCats {
|
||
cat := &partner.BareCategoryInfo{
|
||
VendorCatID: utils.Int64ToStr(rCat.Id),
|
||
Name: rCat.Name,
|
||
Level: int(rCat.Level),
|
||
Seq: 0,
|
||
Children: convertVendorCatList(rCat.Children),
|
||
}
|
||
if cat.VendorCatID == "" {
|
||
cat.VendorCatID = rCat.Name
|
||
}
|
||
cats = append(cats, cat)
|
||
}
|
||
return cats
|
||
}
|
||
|
||
func (p *PurchaseHandler) IsErrCategoryExist(err error) (isExist bool) {
|
||
return mtwmapi.IsErrCategoryExist(err)
|
||
}
|
||
|
||
func (p *PurchaseHandler) IsErrCategoryNotExist(err error) (isNotExist bool) {
|
||
return mtwmapi.IsErrCategoryNotExist(err)
|
||
}
|
||
|
||
func catCode2Str(catCode int) (catCodeStr string) {
|
||
if catCode > 0 {
|
||
catCodeStr = utils.Int2Str(catCode)
|
||
}
|
||
return catCodeStr
|
||
}
|
||
|
||
func tryCatName2Code(originName string) (catCodeStr string) {
|
||
if intValue := utils.Str2Int64WithDefault(originName, 0); intValue > 0 {
|
||
catCodeStr = utils.Int64ToStr(intValue)
|
||
if catCodeStr != originName {
|
||
catCodeStr = ""
|
||
}
|
||
}
|
||
return catCodeStr
|
||
}
|
||
|
||
func (p *PurchaseHandler) CreateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
|
||
//level := 1
|
||
//if storeCat.ParentCatName != "" {
|
||
// level = 2
|
||
//}
|
||
//originName := ""
|
||
//catName := storeCat.Name
|
||
//catCode := storeCat.ID
|
||
//
|
||
//subCatName := ""
|
||
//subCatCode := 0
|
||
//if storeCat.CatSyncStatus&model.SyncFlagNewMask == 0 {
|
||
// // 修改一级分类
|
||
// originName = storeCat.VendorCatID
|
||
//}
|
||
//if level == 2 { // 二级分类
|
||
// // 创建二级分类
|
||
// originName = storeCat.ParentVendorCatID
|
||
// catName = storeCat.ParentCatName
|
||
// catCode = storeCat.ParentID
|
||
// subCatName = storeCat.Name
|
||
// subCatCode = storeCat.ID
|
||
// if storeCat.CatSyncStatus&model.SyncFlagNewMask == 0 {
|
||
// // 修改二级分类
|
||
// originName = storeCat.VendorCatID
|
||
// catName = storeCat.Name
|
||
// catCode = storeCat.ID
|
||
// subCatName = ""
|
||
// subCatCode = 0
|
||
// }
|
||
//}
|
||
//if catName == "" {
|
||
// panic("catName is empty")
|
||
//}
|
||
//catName = utils.FilterEmoji(catName)
|
||
//subCatName = utils.FilterEmoji(subCatName)
|
||
//globals.SugarLogger.Debugf("mtwm CreateStoreCategory vendorStoreID:%s, originName:%s, catCode:%d, catName:%s, subCatCode:%d, subCatName:%s, seq:%d",
|
||
// vendorStoreID, originName, catCode, catName, subCatCode, subCatName, storeCat.Seq)
|
||
//if globals.EnableMtwmStoreWrite {
|
||
// // err = api.MtwmAPI.RetailCatUpdate2(vendorStoreID, tryCatName2Code(originName), originName, catCode2Str(catCode), catName, catCode2Str(subCatCode), subCatName, storeCat.Seq)
|
||
// param4Update := &mtwmapi.Param4UpdateCat{
|
||
// CategoryCodeOrigin: tryCatName2Code(originName),
|
||
// CategoryNameOrigin: originName,
|
||
// CategoryCode: catCode2Str(catCode),
|
||
// SecondaryCategoryCode: catCode2Str(subCatCode),
|
||
// SecondaryCategoryName: subCatName,
|
||
// Sequence: storeCat.Seq,
|
||
// }
|
||
// err = getAPI(storeCat.VendorOrgCode, storeID, vendorStoreID).RetailCatUpdate(vendorStoreID, catName, param4Update)
|
||
// if storeCat.CatSyncStatus&model.SyncFlagNewMask == 0 && p.IsErrCategoryNotExist(err) && originName != "" { // 修改分类名,但分类不存在
|
||
// storeCat.CatSyncStatus |= model.SyncFlagNewMask
|
||
// err = p.CreateStoreCategory(ctx, storeID, vendorStoreID, storeCat)
|
||
// }
|
||
//}
|
||
//if err == nil {
|
||
// // storeCat.VendorCatID = utils.FilterEmoji(storeCat.Name)
|
||
// storeCat.VendorCatID = utils.Int2Str(storeCat.ID)
|
||
//}
|
||
return err
|
||
}
|
||
|
||
func (p *PurchaseHandler) UpdateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
|
||
return p.CreateStoreCategory(ctx, storeID, vendorStoreID, storeCat)
|
||
}
|
||
|
||
func (p *PurchaseHandler) DeleteStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID, vendorCatID string, level int) (err error) {
|
||
//if false {
|
||
// if globals.EnableMtwmStoreWrite {
|
||
// err = getAPI(getStoreVendorOrgCode(storeID), storeID, vendorStoreID).RetailCatDelete(vendorStoreID, tryCatName2Code(vendorCatID), vendorCatID)
|
||
// }
|
||
//} else {
|
||
// var catCodes []string
|
||
// if catCode := tryCatName2Code(vendorCatID); catCode != "" {
|
||
// catCodes = []string{catCode}
|
||
// }
|
||
// if globals.EnableMtwmStoreWrite {
|
||
// if level == 1 {
|
||
// err = getAPI(getStoreVendorOrgCode(storeID), storeID, vendorStoreID).RetailCatSkuBatchDelete2(ctx.GetTrackInfo(), vendorStoreID, catCodes, []string{vendorCatID}, nil, nil, nil)
|
||
// } else {
|
||
// err = getAPI(getStoreVendorOrgCode(storeID), storeID, vendorStoreID).RetailCatSkuBatchDelete2(ctx.GetTrackInfo(), vendorStoreID, nil, nil, catCodes, []string{vendorCatID}, nil)
|
||
// }
|
||
// }
|
||
//}
|
||
return err
|
||
}
|
||
|
||
// 门店商品
|
||
|
||
// 多门店平台不需要实现这个接口
|
||
|
||
func (p *PurchaseHandler) IsErrSkuExist(err error) (isExist bool) {
|
||
return false
|
||
}
|
||
|
||
func (p *PurchaseHandler) IsErrSkuNotExist(err error) (isNotExist bool) {
|
||
return mtwmapi.IsErrSkuNotExist(err)
|
||
}
|
||
|
||
// func duplicateStoreSkuList(storeSkuList []*dao.StoreSkuSyncInfo, index int) (newStoreSkuList []*dao.StoreSkuSyncInfo) {
|
||
// newStoreSkuList = make([]*dao.StoreSkuSyncInfo, len(storeSkuList))
|
||
// for k, v := range storeSkuList {
|
||
// tmp := *v
|
||
// tmp.SkuName = fmt.Sprintf("%s.%d", tmp.SkuName, index)
|
||
// tmp.SkuID = index*1000000 + tmp.SkuID
|
||
// newStoreSkuList[k] = &tmp
|
||
// }
|
||
// return newStoreSkuList
|
||
// }
|
||
|
||
func (p *PurchaseHandler) UpdateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||
failedList, err = p.createOrUpdateStoreSkus(ctx, storeID, vendorStoreID, storeSkuList, false)
|
||
// if err == nil && vendorStoreID == specialStoreID {
|
||
// for i := 0; i < 2; i++ {
|
||
// p.createOrUpdateStoreSkus(ctx, storeID, vendorStoreID, duplicateStoreSkuList(storeSkuList, i+1), true)
|
||
// }
|
||
// }
|
||
return failedList, err
|
||
}
|
||
|
||
// CreateStoreSkus 门店创建商品
|
||
func (p *PurchaseHandler) CreateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||
failedList, err = p.createOrUpdateStoreSkus(ctx, storeID, vendorStoreID, storeSkuList, true)
|
||
//if err == nil && vendorStoreID == specialStoreID {
|
||
// for i := 0; i < 2; i++ {
|
||
// p.createOrUpdateStoreSkus(ctx, storeID, vendorStoreID, duplicateStoreSkuList(storeSkuList, i+1), true)
|
||
// }
|
||
//}
|
||
globals.SugarLogger.Debugf("============CreateStoreSkus===============%s", utils.Format4Output(failedList, false))
|
||
globals.SugarLogger.Debugf("============CreateStoreSkus===============%s", err)
|
||
return failedList, err
|
||
}
|
||
|
||
// 对于多门店平台来说,storeSkuList中只有SkuID与VendorSkuID有意义
|
||
// 抖店的商品只管创建,创建接口会返回成功,但是审核的时候不一定成功.当前系统无法判定此商品是否已经创建过了!
|
||
func (p *PurchaseHandler) createOrUpdateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo, isCreate bool) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||
globals.SugarLogger.Debug("==============vendorStoreID", vendorStoreID)
|
||
var syncType string
|
||
storeDetail, _ := dao.GetStoreDetail(dao.GetDB(), storeID, model.VendorIDDD, "")
|
||
api := getAPI(storeDetail.VendorOrgCode, storeID, vendorStoreID)
|
||
freightId, _ := api.GetStoreBindTemp(utils.Str2Int64(vendorStoreID))
|
||
if freightId == 0 {
|
||
// 创建门店运费模板
|
||
temp, err := api.FreightTemplateCreate(&freightTemplate_create_request.FreightTemplateCreateParam{
|
||
Template: &freightTemplate_create_request.Template{
|
||
TemplateName: storeDetail.Name + "_" + utils.Int64ToStr(rand.Int63n(int64(storeID))) + "_系统模板",
|
||
ProductProvince: utils.Str2Int64(utils.Int2Str(storeDetail.ProvinceCode)[0:2]),
|
||
ProductCity: int64(storeDetail.CityCode),
|
||
CalculateType: 2,
|
||
TransferType: 1, // 快递
|
||
RuleType: 1,
|
||
FixedAmount: 500,
|
||
},
|
||
Columns: nil,
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
// 绑定门店运费模板
|
||
err = api.BindFreightTemplate(&shop_bindStoreFreight_request.ShopBindStoreFreightParam{
|
||
StoreId: utils.Str2Int64(vendorStoreID),
|
||
FreightId: temp.TemplateId,
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
freightId = temp.TemplateId
|
||
}
|
||
|
||
if isCreate {
|
||
syncType = "创建商品"
|
||
for _, storeSku := range storeSkuList {
|
||
// 创建子商品
|
||
param := &product_addV2_request.ProductAddV2Param{
|
||
CategoryLeafId: utils.Str2Int64(storeSku.SkuVendorMapCatID),
|
||
Name: storeSku.Name,
|
||
PayType: tiktokShop.TiktokPayType1,
|
||
ReduceType: tiktokShop.SkuReduceTypePayMakeOrder,
|
||
Weight: utils.Int2Float64(storeSku.Weight),
|
||
DeliveryDelayDay: tiktokShop.DeliveryDelayDayToDay,
|
||
PresellType: tiktokShop.SendGoodsTypeNow,
|
||
Supply7dayReturn: 0,
|
||
Mobile: storeDetail.Tel1,
|
||
Commit: true,
|
||
Specs: "净重|" + fmt.Sprintf("%f", storeSku.SpecQuality) + storeSku.SpecUnit,
|
||
NeedRechargeMode: false,
|
||
SellChannel: []int64{0},
|
||
StartSaleType: 0,
|
||
PickupMethod: "0",
|
||
}
|
||
// param.AccountTemplateId = ""
|
||
// 获取上传图,商品轮播图
|
||
img, err := GetTiktokImgList(utils.Int2Str(storeSku.StoreID), storeDetail.VendorOrgCode, storeSku.ImgOrigin, storeSku.Img2, storeSku.Img3, storeSku.Img4, storeSku.Img5)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
param.Pic = img
|
||
// 商品详情图
|
||
img2, err := GetTiktokImgList(utils.Int2Str(storeSku.StoreID), storeDetail.VendorOrgCode, storeSku.DescImg)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
param.Description = img2
|
||
|
||
// weight_unit 目前抖音只支持g和kg两种
|
||
switch storeSku.Unit {
|
||
case "g", "ml", "G", "ML":
|
||
param.WeightUnit = tiktokShop.WeightUint_G
|
||
case "kg", "l", "L", "KG":
|
||
param.WeightUnit = tiktokShop.WeightUint_G
|
||
}
|
||
|
||
// spec_prices
|
||
param.SpecPrices = GetSpecPrices(param.Specs, vendorStoreID, 0, storeSku)
|
||
// ProductFormatNew 获取商品属性
|
||
productFormatNew, err := GetProductFormatNew(param.CategoryLeafId, storeDetail.VendorOrgCode)
|
||
globals.SugarLogger.Debug("创建=============productFormatNew", productFormatNew)
|
||
globals.SugarLogger.Debug("创建=============productFormatNew err", err)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
param.ProductFormatNew = productFormatNew
|
||
globals.SugarLogger.Debug("创建=============param", utils.Format4Output(param, false))
|
||
|
||
// 获取品牌
|
||
brandID, err := api.GetSkuBrand(param.CategoryLeafId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
param.StandardBrandId = brandID
|
||
|
||
tiktokResult, err := api.CreateStoreCommodity(param) // 创建主商品
|
||
if err != nil {
|
||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
|
||
storeSku.VendorSkuID = utils.Int2Str(storeSku.SkuID)
|
||
continue
|
||
}
|
||
globals.SugarLogger.Debugf("tiktokResult main ===%s", utils.Format4Output(tiktokResult, false))
|
||
|
||
// 创建子商品
|
||
param.FreightId = freightId
|
||
param.MainProductId = tiktokResult.ProductId
|
||
param.SpecPrices = GetSpecPrices(param.Specs, vendorStoreID, tiktokResult.ProductId, storeSku)
|
||
// 获取门店限售模板
|
||
saleLimitId, err := CreateSaleTemp(utils.Str2Int64(vendorStoreID), api)
|
||
globals.SugarLogger.Debug("==22213123131231231", saleLimitId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
param.SaleLimitId = saleLimitId
|
||
param.StoreId = utils.Str2Int64(vendorStoreID)
|
||
// 抖店创建商品
|
||
globals.SugarLogger.Debugf("zishangping=============%s", utils.Format4Output(param, false))
|
||
tiktokResultChildren, err := api.CreateStoreCommodity(param)
|
||
if err != nil {
|
||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
|
||
storeSku.VendorSkuID = utils.Int2Str(storeSku.SkuID)
|
||
continue
|
||
}
|
||
storeSku.VendorSkuID = utils.Int64ToStr(tiktokResultChildren.ProductId) // 子商品主id
|
||
storeSku.VendorMainId = utils.Int64ToStr(tiktokResult.ProductId) // 商品主id
|
||
var attrId []string
|
||
for _, v := range tiktokResult.Sku {
|
||
attrId = append(attrId, utils.Int64ToStr(v.SkuId))
|
||
}
|
||
storeSku.VendorSkuAttrId = strings.Join(attrId, ",") // 属性id skuID
|
||
}
|
||
} else {
|
||
syncType = "更新商品"
|
||
for _, storeSku := range storeSkuList {
|
||
// 更新商品(目前只更新子商品,主商品暂不支持)
|
||
param := &product_editV2_request.ProductEditV2Param{
|
||
CategoryLeafId: utils.Str2Int64(storeSku.SkuVendorMapCatID),
|
||
Name: storeSku.Name,
|
||
PayType: tiktokShop.TiktokPayType1,
|
||
ReduceType: tiktokShop.SkuReduceTypePayMakeOrder,
|
||
Weight: utils.Int2Float64(storeSku.Weight),
|
||
DeliveryDelayDay: tiktokShop.DeliveryDelayDayToDay,
|
||
PresellType: tiktokShop.SendGoodsTypeNow,
|
||
Supply7dayReturn: 0,
|
||
Mobile: storeDetail.Tel1,
|
||
Commit: true,
|
||
Specs: "净重|" + fmt.Sprintf("%f", storeSku.SpecQuality) + storeSku.SpecUnit,
|
||
NeedRechargeMode: false,
|
||
SellChannel: []int64{0},
|
||
StartSaleType: 0,
|
||
PickupMethod: "0",
|
||
}
|
||
// param.AccountTemplateId = ""
|
||
// 获取上传图,商品轮播图
|
||
img, err := GetTiktokImgList(utils.Int2Str(storeSku.StoreID), storeDetail.VendorOrgCode, storeSku.ImgOrigin, storeSku.Img2, storeSku.Img3, storeSku.Img4, storeSku.Img5)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
param.Pic = img
|
||
// 商品详情图
|
||
img2, err := GetTiktokImgList(utils.Int2Str(storeSku.StoreID), storeDetail.VendorOrgCode, storeSku.DescImg)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
param.Description = img2
|
||
|
||
// weight_unit 目前抖音只支持g和kg两种
|
||
switch storeSku.Unit {
|
||
case "g", "ml", "G", "ML":
|
||
param.WeightUnit = tiktokShop.WeightUint_G
|
||
case "kg", "l", "L", "KG":
|
||
param.WeightUnit = tiktokShop.WeightUint_G
|
||
}
|
||
|
||
// spec_prices
|
||
param.SpecPrices = GetSpecPrices(param.Specs, vendorStoreID, utils.Str2Int64(storeSku.VendorSkuID), storeSku)
|
||
// ProductFormatNew 获取商品属性
|
||
productFormatNew, err := GetProductFormatNew(param.CategoryLeafId, storeDetail.VendorOrgCode)
|
||
globals.SugarLogger.Debug("更新=============productFormatNew", productFormatNew)
|
||
globals.SugarLogger.Debug("更新=============productFormatNew err", err)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
param.ProductFormatNew = productFormatNew
|
||
globals.SugarLogger.Debug("更新=============param", utils.Format4Output(param, false))
|
||
|
||
// 获取品牌
|
||
//brandID, err := api.GetSkuBrand(param.CategoryLeafId)
|
||
//if err != nil {
|
||
// return nil, err
|
||
//}
|
||
//param.StandardBrandId = brandID
|
||
|
||
//tiktokResult, err := api.EditStoreCommodity(param) // 创建主商品
|
||
//if err != nil {
|
||
// failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
|
||
// storeSku.VendorSkuID = utils.Int2Str(storeSku.SkuID)
|
||
// continue
|
||
//}
|
||
//globals.SugarLogger.Debugf("tiktokResult main ===%s", utils.Format4Output(tiktokResult, false))
|
||
|
||
// 创建子商品
|
||
//param.FreightId = freightId
|
||
param.ProductId = utils.Str2Int64(storeSku.VendorSkuID)
|
||
//param.SpecPrices = GetSpecPrices(param.Specs, vendorStoreID, tiktokResult.ProductId, storeSku)
|
||
// 获取门店限售模板
|
||
//saleLimitId, err := CreateSaleTemp(utils.Str2Int64(vendorStoreID), api)
|
||
//globals.SugarLogger.Debug("==22213123131231231", saleLimitId)
|
||
//if err != nil {
|
||
// return nil, err
|
||
//}
|
||
//param.SaleLimitId = saleLimitId
|
||
//param.StoreId = utils.Str2Int64(vendorStoreID)
|
||
// 抖店创建商品
|
||
globals.SugarLogger.Debugf("更新子商品=============%s", utils.Format4Output(param, false))
|
||
if err := api.EditStoreCommodity(param); err != nil {
|
||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
|
||
storeSku.VendorSkuID = utils.Int2Str(storeSku.SkuID)
|
||
continue
|
||
}
|
||
storeSku.VendorSkuID = storeSku.VendorSkuID
|
||
}
|
||
return
|
||
}
|
||
|
||
if len(failedList) > 0 {
|
||
err = nil
|
||
}
|
||
return failedList, err
|
||
}
|
||
|
||
// CreateSaleTemp 创建限售模板
|
||
func CreateSaleTemp(storeId int64, api *tiktokShop.API) (int64, error) {
|
||
// 获取限售模板
|
||
saleLimitId, _ := api.StoreQuerySaleLimitTemp(storeId)
|
||
globals.SugarLogger.Debug("==========saleLimitId1", saleLimitId)
|
||
if saleLimitId != 0 {
|
||
return saleLimitId, nil
|
||
}
|
||
|
||
// 创建限售模板
|
||
param := &trade_createTradeLimitTemplate_request.TradeCreateTradeLimitTemplateParam{
|
||
StoreId: storeId,
|
||
TradeLimitRuleRequestList: []trade_createTradeLimitTemplate_request.TradeLimitRuleRequestListItem{},
|
||
}
|
||
tradeLimitRuleRequestList := make([]trade_createTradeLimitTemplate_request.TradeLimitRuleRequestListItem, 0)
|
||
tradeLimitRuleRequest := trade_createTradeLimitTemplate_request.TradeLimitRuleRequestListItem{
|
||
TradeLimitModel: 1, // 限购模型 1-重量,2-数量,3-地区,4-金额
|
||
TradeLimitResource: 2, // 限购资源类别1-抖店,2-门店,3-商品ID,4-sku,5-类目,6-活动,7-商品标
|
||
TradeLimitResourceObject: nil,
|
||
TradeLimitPattern: &trade_createTradeLimitTemplate_request.TradeLimitPattern{
|
||
Minimum: 1, // 1毫克
|
||
Maximum: 500 * 1000 * 1000, //500千克
|
||
CumulativeMax: 99999,
|
||
},
|
||
TimePeriod: nil,
|
||
TradeLimitSubjectList: []int32{1},
|
||
}
|
||
tradeLimitRuleRequestList = append(tradeLimitRuleRequestList, tradeLimitRuleRequest)
|
||
result, err := api.CreateTradeLimitTemplate(param)
|
||
globals.SugarLogger.Debug("==========err2222", err)
|
||
globals.SugarLogger.Debug("==========result222", utils.Format4Output(result, false))
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
|
||
if result.TradeLimitId == 0 {
|
||
return 0, errors.New("限售模板创建错误,联系管理员")
|
||
}
|
||
|
||
// 绑定限售模板
|
||
if err := api.BindStoreSaleLimit(&shop_bindStoreSaleLimit_request.ShopBindStoreSaleLimitParam{
|
||
StoreId: storeId,
|
||
SaleLimitId: result.TradeLimitId,
|
||
}); err != nil {
|
||
globals.SugarLogger.Debug("==========BindStoreSaleLimit", err)
|
||
return 0, err
|
||
}
|
||
|
||
return result.TradeLimitId, nil
|
||
}
|
||
|
||
func (p *PurchaseHandler) DeleteStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||
if globals.EnableDdStoreWrite {
|
||
for _, v := range storeSkuList {
|
||
if err = getAPI(storeSkuList[0].VendorOrgCode, storeID, vendorStoreID).DeleteStoreCommodity(utils.Str2Int64(v.VendorSkuID)); err != nil {
|
||
failedList = append(failedList, putils.GetErrMsg2FailedSingleList(v, err, storeID, model.VendorChineseNames[model.VendorIDDD], "删除商品")...)
|
||
}
|
||
}
|
||
}
|
||
if len(failedList) > 0 {
|
||
err = nil
|
||
}
|
||
return failedList, err
|
||
}
|
||
|
||
func stockCount2Mtwm(stock int) (mtwmStock string) {
|
||
return utils.Int2Str(stock)
|
||
}
|
||
|
||
func storeSku2Mtwm(storeSkuList []*partner.StoreSkuInfo, updateType int) (skuList []*mtwmapi.BareStoreFoodInfo) {
|
||
for _, storeSku := range storeSkuList {
|
||
skuInfo := &mtwmapi.BareStoreFoodInfo{
|
||
AppFoodCode: storeSku.VendorSkuID,
|
||
Skus: []*mtwmapi.BareStoreSkuInfo{
|
||
&mtwmapi.BareStoreSkuInfo{
|
||
SkuID: storeSku.VendorSkuID,
|
||
},
|
||
},
|
||
}
|
||
if updateType == updateTypeStock {
|
||
skuInfo.Skus[0].Stock = stockCount2Mtwm(storeSku.Stock)
|
||
} else if updateType == updateTypePrice {
|
||
skuInfo.Skus[0].Price = jxutils.IntPrice2StandardString(storeSku.VendorPrice)
|
||
} else {
|
||
skuInfo.Skus = nil
|
||
}
|
||
skuList = append(skuList, skuInfo)
|
||
}
|
||
return skuList
|
||
}
|
||
|
||
// UpdateStoreSkusStatus 批量更新商品上下架
|
||
func (p *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo, status int) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||
api := getAPI(vendorOrgCode, storeID, vendorStoreID)
|
||
if status == model.SkuStatusNormal { // 上架
|
||
for _, v := range storeSkuList {
|
||
// p.createOrUpdateStoreSkus(ctx, storeID, vendorStoreID, storeSkuList, false)
|
||
if err := api.EditStoreCommodity(&product_editV2_request.ProductEditV2Param{
|
||
ProductId: utils.Str2Int64(v.VendorSkuID),
|
||
Commit: true,
|
||
}); err != nil {
|
||
failedList = append(failedList, putils.GetErrMsg2FailedSingleList(v, err, storeID, model.VendorChineseNames[model.VendorIDDD], "上架商品异常")...)
|
||
} else {
|
||
failedList = append(failedList, putils.GetErrMsg2FailedSingleList(v, err, storeID, model.VendorChineseNames[model.VendorIDDD], "上架商品正常")...)
|
||
}
|
||
}
|
||
} else { // 下架
|
||
for _, v := range storeSkuList {
|
||
err := api.ProductSetOffline(utils.Str2Int64(v.VendorSkuID))
|
||
if err == nil {
|
||
failedList = append(failedList, putils.GetErrMsg2FailedSingleList(v, err, storeID, model.VendorChineseNames[model.VendorIDDD], "下架商品正常")...)
|
||
} else {
|
||
failedList = append(failedList, putils.GetErrMsg2FailedSingleList(v, err, storeID, model.VendorChineseNames[model.VendorIDDD], "下架商品异常")...)
|
||
}
|
||
}
|
||
}
|
||
|
||
if len(failedList) > 0 {
|
||
err = nil
|
||
}
|
||
return failedList, err
|
||
}
|
||
|
||
// UpdateStoreSkusPrice 更新商品价格
|
||
func (p *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||
api := getAPI(vendorOrgCode, storeID, vendorStoreID)
|
||
for _, v := range storeSkuList {
|
||
//param := &product_editV2_request.ProductEditV2Param{}
|
||
//param.ProductId = utils.Str2Int64(v.VendorSkuID)
|
||
//param.Specs = "净重|" + fmt.Sprintf("%f", v.SpecQuality) + v.SpecUnit
|
||
//
|
||
//skuSize := make([]*tiktokShop.SpecDetailList, 0, 0)
|
||
//detail1 := strings.Split(param.Specs, "^")
|
||
//name1 := strings.Split(strings.Split(detail1[0], "|")[1], ",")
|
||
//for i := 0; i < len(name1); i++ {
|
||
// sku := &tiktokShop.SpecDetailList{
|
||
// SpecDetailName1: name1[i],
|
||
// StockNum: v.Stock,
|
||
// Price: int(v.VendorPrice),
|
||
// Code: utils.Int2Str(v.SkuID),
|
||
// StepStockNum: 0,
|
||
// SupplierID: "",
|
||
// OuterSkuID: utils.Int2Str(v.NameID),
|
||
// DeliveryInfos: []*tiktokShop.DeliveryInfos{
|
||
// {InfoType: "weight", InfoUnit: v.SpecUnit, InfoValue: fmt.Sprintf("%f", v.SpecQuality)},
|
||
// },
|
||
// }
|
||
// skuSize = append(skuSize, sku)
|
||
//}
|
||
//data, _ := json.Marshal(skuSize)
|
||
//param.SpecPrices = string(data)
|
||
err := api.EditPrice(&sku_editPrice_request.SkuEditPriceParam{
|
||
Price: v.VendorPrice,
|
||
SkuId: utils.Str2Int64(v.VendorSkuAttrId),
|
||
ProductId: utils.Str2Int64(v.VendorSkuID),
|
||
})
|
||
if err != nil {
|
||
failedList = append(failedList, putils.GetErrMsg2FailedSingleList(v, err, storeID, model.VendorChineseNames[model.VendorIDDD], "更新价格异常")...)
|
||
} else {
|
||
failedList = append(failedList, putils.GetErrMsg2FailedSingleList(v, err, storeID, model.VendorChineseNames[model.VendorIDDD], "更新价格正常")...)
|
||
}
|
||
}
|
||
|
||
if len(failedList) > 0 {
|
||
err = nil
|
||
}
|
||
return failedList, err
|
||
}
|
||
|
||
// 全量/增量更新商品sku库存
|
||
func (p *PurchaseHandler) UpdateStoreSkusStock(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||
tiktokApi := getAPI(storeSkuList[0].VendorOrgCode, storeID, vendorStoreID)
|
||
for _, v := range storeSkuList {
|
||
err := tiktokApi.UpdateSkuStock(&sku_syncStock_request.SkuSyncStockParam{
|
||
SkuId: utils.Str2Int64(v.VendorSkuAttrId),
|
||
ProductId: utils.Str2Int64(v.VendorSkuID),
|
||
Incremental: false,
|
||
IdempotentId: "",
|
||
StockNum: int64(v.Stock),
|
||
OutWarehouseId: vendorStoreID,
|
||
})
|
||
if err != nil {
|
||
failedList = append(failedList, putils.GetErrMsg2FailedSingleList(v, err, storeID, model.VendorChineseNames[model.VendorIDDD], "更新库存错误")...)
|
||
} else {
|
||
failedList = append(failedList, putils.GetErrMsg2FailedSingleList(v, err, storeID, model.VendorChineseNames[model.VendorIDDD], "更新库存正常")...)
|
||
}
|
||
}
|
||
|
||
return p.UpdateStoreSkusPrice(ctx, vendorOrgCode, storeID, vendorStoreID, storeSkuList)
|
||
}
|
||
|
||
func tiktokSkuStatus2Jx(skuStatus int64) (jxSkuStatus int) {
|
||
if skuStatus == mtwmapi.SellStatusOnline {
|
||
jxSkuStatus = model.SkuStatusNormal
|
||
} else {
|
||
jxSkuStatus = model.SkuStatusDontSale
|
||
}
|
||
return jxSkuStatus
|
||
}
|
||
|
||
func (p *PurchaseHandler) GetStoreSkusFullInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (skuNameList []*partner.SkuNameInfo, err error) {
|
||
// 查询单个门店商品
|
||
tiktokApi := getAPI(storeSkuList[0].VendorOrgCode, storeID, vendorStoreID)
|
||
|
||
for _, v := range storeSkuList {
|
||
skuInfo, err := tiktokApi.GetSkuDetail(v.VendorSkuID, utils.Int2Str(v.SkuID))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if skuName := vendorSku2Jx(skuInfo); skuName != nil {
|
||
skuNameList = append(skuNameList, skuName)
|
||
}
|
||
}
|
||
//switch len(storeSkuList) {
|
||
//case 1:
|
||
//
|
||
//default:
|
||
// // 列表查询门店商品
|
||
// //var storeSkuMap map[string]*partner.StoreSkuInfo
|
||
// //if storeSkuList != nil {
|
||
// // storeSkuMap = putils.StoreSkuList2MapByVendorSkuID(storeSkuList)
|
||
// //}
|
||
// //for {
|
||
// // result, err := mtapi.RetailList(vendorStoreID, len(skuNameList), mtwmapi.GeneralMaxLimit)
|
||
// // if err != nil {
|
||
// // return nil, err
|
||
// // }
|
||
// // if storeSkuMap == nil {
|
||
// // skuNameList = append(skuNameList, vendorSkuList2Jx(result)...)
|
||
// // } else {
|
||
// // for _, v := range result {
|
||
// // if storeSkuMap[v.AppFoodCode] != nil {
|
||
// // if skuName := vendorSku2Jx(v); skuName != nil {
|
||
// // skuNameList = append(skuNameList, skuName)
|
||
// // }
|
||
// // }
|
||
// // }
|
||
// // }
|
||
// // if len(result) < mtwmapi.GeneralMaxLimit {
|
||
// // break
|
||
// // }
|
||
// //}
|
||
//}
|
||
return skuNameList, err
|
||
}
|
||
|
||
func vendorSku2Jx(tiktokSku *product_detail_response.ProductDetailData) (skuName *partner.SkuNameInfo) {
|
||
if len(tiktokSku.SpecPrices) == 0 {
|
||
globals.SugarLogger.Warnf("vendorSku2Jx, strange tiktokSku:%s", utils.Format4Output(tiktokSku, true))
|
||
return nil
|
||
}
|
||
prefix, name, comment, specUnit, unit, specQuality := jxutils.SplitSkuName(tiktokSku.Name)
|
||
vendorSku := tiktokSku.SpecPrices[0]
|
||
weight := jxutils.FormatSkuWeight(specQuality, specUnit)
|
||
|
||
skuName = &partner.SkuNameInfo{
|
||
NameID: utils.Str2Int(vendorSku.OuterSkuId),
|
||
VendorNameID: utils.Int64ToStr(tiktokSku.MainProductId),
|
||
UPC: tiktokSku.ProductIdStr,
|
||
Prefix: prefix,
|
||
Name: name,
|
||
Unit: unit,
|
||
Status: tiktokSkuStatus2Jx(tiktokSku.Status), //此处为之前一个bug 如果吧状态放到切片内层 对于内层函数中映射无法关联 永远获取到的初始值为0
|
||
SkuList: []*partner.SkuInfo{
|
||
&partner.SkuInfo{
|
||
StoreSkuInfo: partner.StoreSkuInfo{
|
||
VendorSkuID: utils.Int64ToStr(vendorSku.SkuId),
|
||
SkuID: int(vendorSku.OutSkuId),
|
||
IsSpecialty: 0,
|
||
Stock: int(vendorSku.StockNum),
|
||
VendorPrice: vendorSku.Price,
|
||
Status: tiktokSkuStatus2Jx(tiktokSku.Status),
|
||
},
|
||
SkuName: tiktokSku.Name,
|
||
Comment: comment,
|
||
SpecQuality: float64(specQuality),
|
||
SpecUnit: specUnit,
|
||
Weight: weight,
|
||
},
|
||
},
|
||
PictureList: tiktokSku.Pic,
|
||
}
|
||
if tiktokSku.CategoryDetail != nil {
|
||
// todo, 因为当前我们用的是分类名操作这种方式,所以要返回分类名(而不是分类code)
|
||
skuName.VendorCatIDList = []string{tiktokSku.CategoryDetail.FirstCname, tiktokSku.CategoryDetail.SecondCname, tiktokSku.CategoryDetail.ThirdCname, tiktokSku.CategoryDetail.FourthCname}
|
||
}
|
||
return skuName
|
||
}
|
||
|
||
func (p *PurchaseHandler) GetSensitiveWordRegexp() *regexp.Regexp {
|
||
return sensitiveWordRegexp
|
||
}
|
||
|
||
// CreateStoreSkusAct 创建商品活动
|
||
func (p *PurchaseHandler) CreateStoreSkusAct(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||
//actStoreSkuList := putils.StoreSku2ActStoreSku(model.SyncFlagNewMask, vendorStoreID, storeSkuList)
|
||
//failedList, err = createOneShopAct(putils.GetFixDirectDownAct(vendorOrgCode, storeID, 0), vendorStoreID, actStoreSkuList)
|
||
//storeSkuMap := putils.StoreSkuList2MapBySkuID(storeSkuList)
|
||
//for _, v := range actStoreSkuList {
|
||
// storeSkuMap[v.SkuID].VendorActID = v.VendorActID
|
||
//}
|
||
//if len(failedList) > 0 {
|
||
// err = nil
|
||
//}
|
||
return failedList, err
|
||
}
|
||
|
||
func (p *PurchaseHandler) CancelActs(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||
return nil, err
|
||
// return cancelOneShopAct(putils.GetFixDirectDownAct(vendorOrgCode, storeID, 0), vendorStoreID, putils.StoreSku2ActStoreSku(model.SyncFlagDeletedMask, vendorStoreID, storeSkuList))
|
||
}
|
||
|
||
func (p *PurchaseHandler) UpdateStoreSkusSpecTag(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (err error) {
|
||
//var foodDataList []map[string]interface{}
|
||
//for _, v := range storeSkuList {
|
||
// var foodData = make(map[string]interface{})
|
||
// if v.IsSpecialty != 0 && v.IsSpecialty == -1 {
|
||
// v.IsSpecialty = 0
|
||
// }
|
||
// foodData["is_specialty"] = v.IsSpecialty
|
||
// foodData["app_food_code"] = v.SkuID
|
||
// foodDataList = append(foodDataList, foodData)
|
||
//}
|
||
//if globals.EnableMtwmStoreWrite {
|
||
// if len(foodDataList) == 1 {
|
||
// err = getAPI(vendorOrgCode, storeID, vendorStoreID).RetailInitData(ctx.GetTrackInfo(), vendorStoreID, utils.Int2Str(storeSkuList[0].SkuID), foodDataList[0])
|
||
// } else if len(foodDataList) > 0 {
|
||
// _, err = getAPI(vendorOrgCode, storeID, vendorStoreID).RetailBatchInitData(ctx.GetTrackInfo(), vendorStoreID, foodDataList)
|
||
// }
|
||
//}
|
||
return err
|
||
}
|