package tiktok_store import ( "fmt" "regexp" "strings" "git.rosy.net.cn/baseapi/platformapi/mtwmapi" product_listV2_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_listV2/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" 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/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" ) 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 = 5 // tiktokShop.MaxStoreSkuBatchSize case partner.FuncDeleteStoreSkus: batchSize = 5 // tiktokShop.MaxBatchDeleteSize case partner.FuncCreateStoreSkus: batchSize = 5 // 可考虑用批量操作 case partner.FuncUpdateStoreSkus: batchSize = 5 // mtwmapi.MaxStoreSkuBatchSize case partner.FuncGetStoreSkusFullInfo: batchSize = 5 case partner.FuncCreateActs: batchSize = tiktokShop.MaxRetailDiscountCreateBatchSize case partner.FuncCancelActs: batchSize = tiktokShop.MaxRetailDiscountDeleteBatchSize } return batchSize } // 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 (p *PurchaseHandler) IsErrCategoryExist(err error) (isExist bool) { return mtwmapi.IsErrCategoryExist(err) } func (p *PurchaseHandler) IsErrCategoryNotExist(err error) (isNotExist bool) { return mtwmapi.IsErrCategoryNotExist(err) } func (p *PurchaseHandler) CreateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) { 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) { 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 (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) 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) return failedList, err } 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 v.VendorMainId == "" { continue } 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 } // UpdateStoreSkusStatus 批量更新商品上下架(上架商品库存更新最大,下架商品库存为0) 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 { // 子品商品id获取skuId //childrenSkuId, failedList := getProductSkuId4UpdateStock(api, v, storeID) //if len(failedList) > 0 { // continue //} param := &sku_syncStock_request.SkuSyncStockParam{ ProductId: utils.Str2Int64(v.VendorSkuID), Incremental: false, StockNum: 99999, OutSkuId: int64(v.SkuID), } if err := api.UpdateSkuStock(param); err != nil { failedList = append(failedList, putils.GetErrMsg2FailedSingleList(v, err, storeID, model.VendorChineseNames[model.VendorIDDD], fmt.Sprintf("上架商品,库存值最大化.%s", utils.Format4Output(param, false)))...) } } } else { // 上架 for _, v := range storeSkuList { // 子品商品id获取skuId //childrenSkuId, failedList := getProductSkuId4UpdateStock(api, v, storeID) //if len(failedList) > 0 { // continue //} param := &sku_syncStock_request.SkuSyncStockParam{ ProductId: utils.Str2Int64(v.VendorSkuID), Incremental: false, StockNum: 0, OutSkuId: int64(v.SkuID), } if err := api.UpdateSkuStock(param); err != nil { failedList = append(failedList, putils.GetErrMsg2FailedSingleList(v, err, storeID, model.VendorChineseNames[model.VendorIDDD], fmt.Sprintf("下架商品,库存值为0失败.%s", utils.Format4Output(param, false)))...) } } } 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 { tiktokSkuId, failedList := getProductSkuId4UpdateStock(api, v, storeID, vendorStoreID) if len(failedList) > 0 { return failedList, err } price := &sku_editPrice_request.SkuEditPriceParam{ Price: v.VendorPrice, SkuId: tiktokSkuId, ProductId: utils.Str2Int64(v.VendorSkuID), } //更新子品 if err = api.EditPrice(price); err != nil { failedList = append(failedList, putils.GetErrMsg2FailedSingleList(v, err, storeID, model.VendorChineseNames[model.VendorIDDD], "更新价格异常")...) } } return failedList, err } // UpdateStoreSkusStock 全量/增量更新商品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 { // 子品商品id获取skuId //childrenSkuId, failedList := getProductSkuId4UpdateStock(tiktokApi, v, storeID) //if len(failedList) > 0 { // continue //} stockNum := &sku_syncStock_request.SkuSyncStockParam{ ProductId: utils.Str2Int64(v.VendorSkuID), Incremental: false, StockNum: int64(v.Stock), OutSkuId: int64(v.SkuID), } if stockNum.StockNum == 0 { stockNum.StockNum = 99999 } if err := tiktokApi.UpdateSkuStock(stockNum); err != nil { failedList = append(failedList, putils.GetErrMsg2FailedSingleList(v, err, storeID, model.VendorChineseNames[model.VendorIDDD], "更新库存错误")...) } } return failedList, err } func (p *PurchaseHandler) GetStoreSkusFullInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (skuNameList []*partner.SkuNameInfo, err error) { // 查询单个门店商品 appOrgCode := "" if len(storeSkuList) == 0 { storeDetail, _ := dao.GetStoreDetail(dao.GetDB(), storeID, model.VendorIDDD, "") appOrgCode = storeDetail.VendorOrgCode } else { appOrgCode = storeSkuList[0].VendorOrgCode } tiktokApi := getAPI(appOrgCode, storeID, vendorStoreID) if len(storeSkuList) != 0 { 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) } } } else { var page int64 = 1 var pageSize int64 = 100 for { skuInfo, err := tiktokApi.GetSkuDetailList(&product_listV2_request.ProductListV2Param{ Status: 0, CheckStatus: 3, ProductType: 0, Page: page, Size: pageSize, StoreId: utils.Str2Int64(vendorStoreID), }) if err != nil { return nil, err } for _, v := range skuInfo.Data { skuInfo, err := tiktokApi.GetSkuDetail(utils.Int64ToStr(v.ProductId), "") if err != nil { return nil, err } if skuName := vendorSku2Jx(skuInfo); skuName != nil { skuNameList = append(skuNameList, skuName) } } if page*pageSize > skuInfo.Total { page++ } else { break } } } return skuNameList, err } 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)) } // UpdateStoreSkusSpecTag 更新限购 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 } func GetProductAuditList(vendorOrgCode string, page, pageSize int64) (map[string]string, int64) { updateCategory := make(map[string]string, 100) // 修改分类的Map data, total, err := getAPI(vendorOrgCode, 0, "").GetProductAuditList(page, pageSize, 2) if err != nil || len(data) == 0 { return nil, 0 } for _, v := range data { if _, ok := v.AuditReason["综合原因"]; ok { if strings.Contains(v.AuditReason["综合原因"][0], "该商品类目选择错误,推荐放置在") { list := strings.Split(v.AuditReason["综合原因"][0], `“`) list2 := strings.Split(list[1], `”`) categoryNameList := strings.Split(list2[0], "/") updateCategory[utils.Int64ToStr(v.ProductId)] = categoryNameList[len(categoryNameList)-1] } } } return updateCategory, total } func (p *PurchaseHandler) GetSkuCategoryIdByName(vendorOrgCode, skuName string) (string, error) { vendorCategoryId, err := getAPI(vendorOrgCode, 0, "").GetRecommendCategory(strings.Split(skuName, "|")) return utils.Int64ToStr(vendorCategoryId), err }