package cms import ( "fmt" "regexp" "sort" "strings" "time" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/partner/putils" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/refutil" "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" ) const ( AmendPruneOnlyAmend = 1 AmendPruneOnlyPrune = 2 AmendPruneAll = 3 ) var ( subSensitiveWordRegexp = regexp.MustCompile(`[^\[\]\"\}]`) ) func CreateStoreCategoryByStoreSku(ctx *jxcontext.Context, vendorID, storeID int, vendorStoreID string, nameIDs, skuIDs []int) (err error) { globals.SugarLogger.Debugf("CreateStoreCategoryByStoreSku vendorID:%d, storeID:%d", vendorID, storeID) db := dao.GetDB() defer func() { if r := recover(); r != nil { dao.Rollback(db) panic(r) } }() for i := 0; i < 2; i++ { localCats, err2 := dao.GetSkusCategories(db, vendorID, storeID, skuIDs, i+1) if err = err2; err != nil { return err } if len(localCats) > 0 { dao.Begin(db) for _, v := range localCats { if v.MapID == 0 { if err = dao.AddStoreCategoryMap(db, storeID, v.ID, vendorID, "", model.SyncFlagNewMask, ctx.GetUserName()); err != nil { dao.Rollback(db) return err } } } dao.Commit(db) } } return err } func SyncStoreCategories(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID, storeID int, vendorStoreID string, nameIDs, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) { globals.SugarLogger.Debugf("SyncStoreCategories %s storeID:%d, %s, userName:%s", model.VendorChineseNames[vendorID], storeID, vendorStoreID, ctx.GetUserName()) handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler) num := 0 db := dao.GetDB() rootTask := tasksch.NewSeqTask(fmt.Sprintf("%s SyncStoreCategory step1", model.VendorChineseNames[vendorID]), ctx, func(rootTask *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { level := step + 1 catList, err := dao.GetDirtyStoreCategories(db, vendorID, storeID, level, skuIDs) if len(catList) > 0 { num += len(catList) task := tasksch.NewParallelTask(fmt.Sprintf("%s SyncStoreCategory step2, level=%d", model.VendorChineseNames[vendorID], level), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { updateFields := []string{dao.GetSyncStatusStructField(model.VendorNames[vendorID])} idFieldName := dao.GetVendorThingIDStructField(model.VendorNames[vendorID]) catInfo := batchItemList[0].(*dao.SkuStoreCatInfo) storeCatMap := &model.StoreSkuCategoryMap{} storeCatMap.ID = catInfo.MapID var failedList []*partner.StoreSkuInfoWithErr if model.IsSyncStatusDelete(catInfo.CatSyncStatus) { // 删除 if model.IsSyncStatusDelete(catInfo.CatSyncStatus) && !dao.IsVendorThingIDEmpty(catInfo.VendorCatID) { err = handler.DeleteStoreCategory(ctx, storeID, vendorStoreID, catInfo.VendorCatID, level) if err != nil && handler.IsErrCategoryNotExist(err) { err = nil } else if err != nil && !handler.IsErrCategoryNotExist(err) { failedList = putils.GetErrMsg2FailedSingleList(nil, err, storeID, vendorID, "删除分类") } } } else if model.IsSyncStatusNew(catInfo.CatSyncStatus) { // 新增 err = handler.CreateStoreCategory(ctx, storeID, vendorStoreID, catInfo) if err != nil && handler.IsErrCategoryExist(err) { if cat, err2 := handler.GetStoreCategory(ctx, storeID, vendorStoreID, catInfo.Name); err2 == nil { catInfo.VendorCatID = cat.VendorCatID err = nil } else if err != nil && !handler.IsErrCategoryExist(err) { failedList = putils.GetErrMsg2FailedSingleList(nil, err, storeID, vendorID, "新增分类") } } if err == nil { updateFields = append(updateFields, idFieldName) // if vendorID == model.VendorIDMTWM { // storeCatMap.LastOperator = utils.Time2Str(time.Now()) // updateFields = append(updateFields, model.FieldLastOperator) // } } } else if model.IsSyncStatusUpdate(catInfo.CatSyncStatus) { // 修改 err = handler.UpdateStoreCategory(ctx, storeID, vendorStoreID, catInfo) if err == nil { updateFields = append(updateFields, idFieldName) } else { failedList = putils.GetErrMsg2FailedSingleList(nil, err, storeID, vendorID, "修改分类") } } if len(failedList) > 0 { for _, v := range failedList { v.CategoryName = catInfo.Name } task.AddFailedList(failedList) } if err == nil { if vendorID == model.VendorIDMTWM { refutil.SetObjFieldByName(storeCatMap, idFieldName, catInfo.VendorCatID) } else { refutil.SetObjFieldByName(storeCatMap, idFieldName, utils.Str2Int64WithDefault(catInfo.VendorCatID, 0)) } _, err = dao.UpdateEntity(db, storeCatMap, updateFields...) } return nil, err }, catList) rootTask.AddChild(task).Run() _, err = task.GetResult(0) } return nil, err }, 2) tasksch.AddChild(parentTask, rootTask).Run() if !isAsync { _, err = rootTask.GetResult(0) } else { hint = rootTask.GetID() } return hint, err } func SyncStoreSkuNew(ctx *jxcontext.Context, parentTask tasksch.ITask, causeFlag int, vendorID, storeID int, vendorStoreID string, nameIDs, skuIDs, excludeSkuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) { return SyncStoreSkuNew2(ctx, parentTask, causeFlag, vendorID, storeID, vendorStoreID, nameIDs, skuIDs, excludeSkuIDs, false, isAsync, isContinueWhenError) } func SyncStoreSkuNew2(ctx *jxcontext.Context, parentTask tasksch.ITask, causeFlag int, vendorID, storeID int, vendorStoreID string, nameIDs, skuIDs, excludeSkuIDs []int, useVendorPriceDirectly, isAsync, isContinueWhenError bool) (hint string, err error) { singleStoreHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler) if singleStoreHandler != nil { if err = CreateStoreCategoryByStoreSku(ctx, vendorID, storeID, vendorStoreID, nameIDs, skuIDs); err != nil { return "", err } } task := tasksch.NewSeqTask(fmt.Sprintf("SyncStoreSkuNew, storeID:%d", storeID), ctx, func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { switch step { case 0: if singleStoreHandler != nil { _, err = SyncStoreCategories(ctx, task, vendorID, storeID, vendorStoreID, nameIDs, skuIDs, false, isContinueWhenError) } case 1: err = syncStoreSkuNew(ctx, task, causeFlag, false, vendorID, storeID, nameIDs, skuIDs, excludeSkuIDs, useVendorPriceDirectly, isContinueWhenError) } return result, err }, 2) tasksch.HandleTask(task, parentTask, true).Run() if !isAsync { _, err = task.GetResult(0) } else { hint = task.GetID() } return hint, err } func FullSyncStoreSkuNew(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID, storeID int, vendorStoreID string, excludeSkuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) { singleStoreHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler) task := tasksch.NewParallelTask("FullSyncStoreSkuNew", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { step := batchItemList[0].(int) switch step { case 0: if singleStoreHandler != nil { // _, err = ClearRemoteStoreStuffAndSetNew(ctx, task, vendorID, storeID, vendorStoreID, false, isContinueWhenError) _, err = amendAndPruneStoreStuff(ctx, parentTask, vendorID, storeID, vendorStoreID, false, isContinueWhenError, AmendPruneAll, true) } else { _, err = dao.SetStoreSkuSyncStatus(dao.GetDB(), vendorID, []int{storeID}, nil, model.SyncFlagStoreSkuOnlyMask) } case 1: if singleStoreHandler != nil { _, err = SyncStoreSkuNew(ctx, task, 0, vendorID, storeID, vendorStoreID, nil, nil, excludeSkuIDs, false, isContinueWhenError) } else { err = syncStoreSkuNew(ctx, task, 0, true, vendorID, storeID, nil, nil, excludeSkuIDs, false, isContinueWhenError) } } return retVal, err }, []int{0, 1}) tasksch.HandleTask(task, parentTask, true).Run() if !isAsync { _, err = task.GetResult(0) } else { hint = task.GetID() } return hint, err } func isStoreSkuSyncNeedDelete(storeSku *dao.StoreSkuSyncInfo) bool { return model.IsSyncStatusDelete(storeSku.SkuSyncStatus) || storeSku.BindDeletedAt != utils.DefaultTimeValue || storeSku.BindID == 0 || storeSku.NameID == 0 || storeSku.NameStatus != model.SkuStatusNormal || storeSku.Status != model.SkuStatusNormal } func storeSkuSyncInfo2Bare(inSku *dao.StoreSkuSyncInfo) (outSku *partner.StoreSkuInfo) { outSku = &partner.StoreSkuInfo{ SkuID: inSku.SkuID, VendorSkuID: inSku.VendorSkuID, NameID: inSku.NameID, VendorNameID: inSku.VendorNameID, Status: inSku.MergedStatus, VendorPrice: inSku.VendorPrice, Seq: inSku.Seq, } if !isStoreSkuSyncNeedDelete(inSku) { outSku.Stock = model.MaxStoreSkuStockQty } return outSku } func calVendorPrice4StoreSku(inSku *dao.StoreSkuSyncInfo, pricePercentagePack model.PricePercentagePack, pricePercentage int) (outSku *dao.StoreSkuSyncInfo) { if inSku.VendorPrice <= 0 { // 避免重新计算 inSku.VendorPrice = int64(jxutils.CaculatePriceByPricePack(pricePercentagePack, pricePercentage, int(inSku.Price))) if inSku.VendorPrice <= 0 { inSku.VendorPrice = 1 // 最少1分钱 } } return inSku } func getSkuBoxFee(vendorID int) (boxFee int64) { if vendorID == model.VendorIDMTWM { boxFee, _ = dao.GetSysConfigAsInt64(dao.GetDB(), model.ConfigSysMtwmSkuBoxFee) } return boxFee } func formalizeStoreSkuList(inSkuList []*dao.StoreSkuSyncInfo) []*dao.StoreSkuSyncInfo { if len(inSkuList) > 0 { boxFee := getSkuBoxFee(inSkuList[0].VendorID) for _, skuItem := range inSkuList { if skuItem.VendorPrice > skuItem.BoxFee { skuItem.BoxFee = boxFee } skuItem.MergedStatus = jxutils.MergeSkuStatus(jxutils.MergeSkuStatus(skuItem.NameStatus, skuItem.Status), skuItem.StoreSkuStatus) skuItem.SkuName = jxutils.ComposeSkuNameSync(skuItem.Prefix, skuItem.Name, skuItem.Comment, skuItem.Unit, skuItem.SpecQuality, skuItem.SpecUnit, 0, skuItem.ExPrefix, skuItem.ExPrefixBegin, skuItem.ExPrefixEnd) } } return inSkuList } func sku2Update(vendorID int, sku *dao.StoreSkuSyncInfo, syncStatus int8) (item *dao.KVUpdateItem) { kvs := map[string]interface{}{} if !isSkuLockTimeValid(sku) { kvs[dao.GetVendorLockTimeStructField(model.VendorNames[vendorID])] = nil } if syncStatus&(model.SyncFlagDeletedMask|model.SyncFlagNewMask|model.SyncFlagModifiedMask) != 0 { if model.IsSyncStatusNew(syncStatus) { sku.SkuSyncStatus = 0 kvs[dao.GetVendorThingIDStructField(model.VendorNames[vendorID])] = utils.Str2Int64WithDefault(sku.VendorSkuID, 0) } else if model.IsSyncStatusDelete(syncStatus) { sku.SkuSyncStatus = 0 if utils.IsTimeZero(sku.BindDeletedAt) && (sku.NameID == 0) { kvs[model.FieldDeletedAt] = time.Now() } if !dao.IsVendorThingIDEmpty(sku.VendorSkuID) && !partner.IsMultiStore(vendorID) { kvs[dao.GetVendorThingIDStructField(model.VendorNames[vendorID])] = 0 } } else { sku.SkuSyncStatus = sku.SkuSyncStatus & model.SyncFlagPriceMask } } else if syncStatus&model.SyncFlagStockMask != 0 { if isStoreSkuSyncNeedDelete(sku) { sku.SkuSyncStatus = 0 } else { sku.SkuSyncStatus = sku.SkuSyncStatus & (model.SyncFlagPriceMask | model.SyncFlagSaleMask) } } else { sku.SkuSyncStatus = sku.SkuSyncStatus & ^syncStatus } kvs[dao.GetSyncStatusStructField(model.VendorNames[vendorID])] = sku.SkuSyncStatus if sku.VendorPrice > 0 { kvs[dao.GetVendorPriceStructField(model.VendorNames[vendorID])] = sku.VendorPrice } storeSku := &model.StoreSkuBind{} storeSku.ID = sku.BindID item = &dao.KVUpdateItem{ Item: storeSku, KVs: kvs, } return item } func updateStoreSku(db *dao.DaoDB, vendorID int, storeSkuList []*dao.StoreSkuSyncInfo, syncStatus int8) (num int64, err error) { if len(storeSkuList) > 0 { // defer func() { // if r := recover(); r != nil { // globals.SugarLogger.Debugf("updateStoreSku panic, vendorID:%d, len:%d, storeID0:%d, skuID0:%d, syncStatus:%d", vendorID, len(storeSkuList), storeSkuList[0].StoreID, storeSkuList[0].SkuID, syncStatus) // panic(r) // } // }() updateItemList := make([]*dao.KVUpdateItem, len(storeSkuList)) for k, v := range storeSkuList { updateItemList[k] = sku2Update(vendorID, v, syncStatus) } num, err = dao.BatchUpdateEntityByKV(db, updateItemList) } return num, err } func isSkuLockTimeValid(sku *dao.StoreSkuSyncInfo) bool { return sku.LockTime != nil && time.Now().Sub(*sku.LockTime) < 0 } func syncStoreSkuNew(ctx *jxcontext.Context, parentTask tasksch.ITask, causeFlag int, isFull bool, vendorID, storeID int, nameIDs, skuIDs, excludeSkuIDs []int, useVendorPriceDirectly, isContinueWhenError bool) (err error) { globals.SugarLogger.Debugf("syncStoreSkuNew causeFlag:%d", causeFlag) db := dao.GetDB() storeDetail, err := dao.GetStoreDetail(db, storeID, vendorID) if err != nil { return err } vendorStoreID := storeDetail.VendorStoreID var skus []*dao.StoreSkuSyncInfo if isFull { skus, err = dao.GetFullStoreSkus(db, vendorID, storeID) } else { skus, err = dao.GetStoreSkus(db, vendorID, storeID, skuIDs) } if err != nil || len(skus) == 0 { return err } if len(excludeSkuIDs) > 0 { excludeSkuMap := jxutils.IntList2Map(excludeSkuIDs) var skus2 []*dao.StoreSkuSyncInfo for _, v := range skus { if excludeSkuMap[v.SkuID] == 0 { skus2 = append(skus2, v) } } skus = skus2 } formalizeStoreSkuList(skus) singleStoreHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler) storeSkuHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler) reorderHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IStoreSkuSorter) var ( createList, updateList []*dao.StoreSkuSyncInfo deleteList, stockList, onlineList, offlineList, priceList []*partner.StoreSkuInfo updateItems []*dao.KVUpdateItem reorderSkuMap map[string][]*dao.StoreSkuSyncInfo ) skuMap := make(map[*partner.StoreSkuInfo]*dao.StoreSkuSyncInfo) if reorderHandler != nil { reorderSkuMap = make(map[string][]*dao.StoreSkuSyncInfo) } now := jxutils.OperationTime2HourMinuteFormat(time.Now()) var failedList []*partner.StoreSkuInfoWithErr for _, sku := range skus { if !useVendorPriceDirectly && !isSkuLockTimeValid(sku) { sku.VendorPrice = 0 } sku.MergedStatus = MergeSkuSaleStatusWithStoreOpTime(sku, storeDetail, now) var bareSku *partner.StoreSkuInfo isNeedReorder := false if isStoreSkuSyncNeedDelete(sku) { if !dao.IsVendorThingIDEmpty(sku.VendorSkuID) { bareSku = storeSkuSyncInfo2Bare(sku) if singleStoreHandler == nil { stockList = append(stockList, bareSku) } else { deleteList = append(deleteList, bareSku) } } else { updateItems = append(updateItems, sku2Update(vendorID, sku, model.SyncFlagDeletedMask)) } } else if model.IsSyncStatusNew(sku.SkuSyncStatus) { calVendorPrice4StoreSku(sku, storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage)) if singleStoreHandler == nil { if dao.IsVendorThingIDEmpty(sku.VendorSkuID) { // todo 多平台商品库没有正常创建,直接跳过 } else { sku.SkuSyncStatus |= model.SyncFlagSaleMask | model.SyncFlagPriceMask bareSku = storeSkuSyncInfo2Bare(sku) stockList = append(stockList, bareSku) priceList = append(priceList, bareSku) if sku.MergedStatus == model.SkuStatusNormal { onlineList = append(onlineList, bareSku) } else { offlineList = append(offlineList, bareSku) } } } else { if sku.MergedStatus == model.SkuStatusNormal { if dao.IsVendorThingIDEmpty(sku.VendorCatID) { globals.SugarLogger.Warnf("syncStoreSkuNew 创建门店:%d商品:%d,但没有平台分类ID", storeID, sku.SkuID) } else { createList = append(createList, sku) } } } isNeedReorder = true } else { if dao.IsVendorThingIDEmpty(sku.VendorSkuID) { // err = fmt.Errorf("门店:%d,修改没有创建的商品:%d", storeID, sku.SkuID) err = utils.NewErrorCode(fmt.Sprintf("门店:%d,修改没有创建的商品:%d", storeID, sku.SkuID), "-1", 0) failedList = putils.GetErrMsg2FailedSingleList(nil, err, storeID, vendorID, "异常同步错误") if parentTask == nil { return err } parentTask.AddBatchErr(err) parentTask.AddFailedList(failedList) } else { isAdded2Update := false // 修改商品信息时不改价(以免活动引起的失败),而用单独的改价来改 if (model.IsSyncStatusUpdate(sku.SkuSyncStatus) || (model.IsSyncStatusSeq(sku.SkuSyncStatus) && reorderHandler == nil)) && singleStoreHandler != nil { if dao.IsVendorThingIDEmpty(sku.VendorCatID) { globals.SugarLogger.Warnf("syncStoreSkuNew 修改门店:%d商品:%d,但没有平台分类ID", storeID, sku.SkuID) } else { isAdded2Update = true updateList = append(updateList, calVendorPrice4StoreSku(sku, storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage))) } } if model.IsSyncStatusPrice(sku.SkuSyncStatus) { bareSku = storeSkuSyncInfo2Bare(calVendorPrice4StoreSku(sku, storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage))) priceList = append(priceList, bareSku) } if !isAdded2Update { if model.IsSyncStatusUpdate(sku.SkuSyncStatus) && singleStoreHandler == nil { // 正常就不应该进到这里 if bareSku == nil { bareSku = storeSkuSyncInfo2Bare(sku) } updateItems = append(updateItems, sku2Update(vendorID, sku, model.SyncFlagStockMask)) } if model.IsSyncStatusSale(sku.SkuSyncStatus) { if bareSku == nil { bareSku = storeSkuSyncInfo2Bare(sku) } if sku.MergedStatus == model.SkuStatusNormal { onlineList = append(onlineList, bareSku) stockList = append(stockList, bareSku) } else { offlineList = append(offlineList, bareSku) // 因为京东平台以是否有库存表示是否关注,所以不论是否可售,都要设置库存 if singleStoreHandler == nil { stockList = append(stockList, bareSku) } } } } isNeedReorder = model.IsSyncStatusSeq(sku.SkuSyncStatus) } } if isNeedReorder && reorderHandler != nil && sku.VendorCatID != "" { reorderSkuMap[sku.VendorCatID] = append(reorderSkuMap[sku.VendorCatID], sku) } if bareSku != nil { skuMap[bareSku] = sku } } if _, err = dao.BatchUpdateEntityByKV(db, updateItems); err != nil { return err } bareSku2Sync := func(bareSkuList []*partner.StoreSkuInfo) (skuList []*dao.StoreSkuSyncInfo) { if len(bareSkuList) > 0 { skuList = make([]*dao.StoreSkuSyncInfo, len(bareSkuList)) for k, v := range bareSkuList { skuList[k] = skuMap[v] } } return skuList } isContinueWhenError2 := true task := tasksch.NewParallelTask("syncStoreSkuNew", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError2), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { step := batchItemList[0].(int) // globals.SugarLogger.Debugf("step:%d", step) switch step { case 0: if len(deleteList) > 0 { _, err = putils.FreeBatchStoreSkuInfo("删除门店商品", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) { var failedList []*partner.StoreSkuInfoWithErr failedList, err = singleStoreHandler.DeleteStoreSkus(ctx, storeID, vendorStoreID, batchedStoreSkuList) if len(failedList) > 0 { task.AddFailedList(failedList) } if singleStoreHandler.IsErrSkuNotExist(err) { err = nil } if err != nil { offlineList = append(offlineList, batchedStoreSkuList...) } successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList)) if len(successList) > 0 { updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagDeletedMask) } return nil, len(successList), err }, ctx, task, deleteList, 1 /*singleStoreHandler.GetStoreSkusBatchSize(partner.FuncDeleteStoreSkus)*/, isContinueWhenError2) } case 1: if len(createList) > 0 { _, err = putils.FreeBatchStoreSkuSyncInfo("创建门店商品", func(task tasksch.ITask, batchedStoreSkuList []*dao.StoreSkuSyncInfo) (result interface{}, successCount int, err error) { var failedList []*partner.StoreSkuInfoWithErr if failedList, err = singleStoreHandler.CreateStoreSkus(ctx, storeID, vendorStoreID, batchedStoreSkuList); singleStoreHandler.IsErrSkuExist(err) { if skuNameList, err2 := singleStoreHandler.GetStoreSkusFullInfo(ctx, task, storeID, vendorStoreID, []*partner.StoreSkuInfo{ &partner.StoreSkuInfo{ SkuID: batchedStoreSkuList[0].SkuID, }, }); err2 == nil && len(skuNameList) > 0 { batchedStoreSkuList[0].VendorNameID = skuNameList[0].VendorNameID batchedStoreSkuList[0].VendorSkuID = skuNameList[0].SkuList[0].VendorSkuID // 如果创建商品时已经存在,需要更新 updateList = append(updateList, calVendorPrice4StoreSku(batchedStoreSkuList[0], storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage))) err = nil } else if err2 != nil { failedList = append(failedList, putils.GetErrMsg2FailedSingleList(batchedStoreSkuList, err2, storeID, vendorID, "查询是否有该商品")...) } } if len(failedList) > 0 { task.AddFailedList(failedList) } if err != nil { //handle error for sensitive words, if find, then insert to table sensitive_words if sensitiveWord := GetSensitiveWord(singleStoreHandler, err.Error()); sensitiveWord != "" { dao.InsertSensitiveWord(sensitiveWord, vendorID, ctx.GetUserName()) } } successList := putils.UnselectStoreSkuSyncListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList)) if len(successList) > 0 { updateStoreSku(dao.GetDB(), vendorID, successList, model.SyncFlagNewMask) } return nil, len(successList), err }, ctx, task, createList, 1 /*singleStoreHandler.GetStoreSkusBatchSize(partner.FuncCreateStoreSkus)*/, isContinueWhenError2) } case 2: if len(updateList) > 0 { _, err = putils.FreeBatchStoreSkuSyncInfo("更新门店商品基础信息", func(task tasksch.ITask, batchedStoreSkuList []*dao.StoreSkuSyncInfo) (result interface{}, successCount int, err error) { var failedList []*partner.StoreSkuInfoWithErr failedList, err = singleStoreHandler.UpdateStoreSkus(ctx, storeID, vendorStoreID, batchedStoreSkuList) if len(failedList) > 0 { task.AddFailedList(failedList) } successList := putils.UnselectStoreSkuSyncListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList)) if len(successList) > 0 { updateStoreSku(dao.GetDB(), vendorID, successList, model.SyncFlagModifiedMask) } return nil, len(successList), err }, ctx, task, updateList, singleStoreHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkus), isContinueWhenError2) } case 3: for k, list := range [][]*partner.StoreSkuInfo{stockList /*, onlineList*/} { if len(list) > 0 { _, err = putils.FreeBatchStoreSkuInfo("更新门店商品库存", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) { var failedList []*partner.StoreSkuInfoWithErr failedList, err = storeSkuHandler.UpdateStoreSkusStock(ctx, storeDetail.VendorOrgCode, storeID, vendorStoreID, batchedStoreSkuList) if len(failedList) > 0 { task.AddFailedList(failedList) } successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList)) if k == 0 && len(successList) > 0 { updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagStockMask) } return nil, len(successList), err }, ctx, task, list, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusStock), isContinueWhenError2) } } case 4, 5: statusList := onlineList status := model.SkuStatusNormal name := "可售门店商品" if step == 5 { statusList = offlineList status = model.SkuStatusDontSale name = "不可售门店商品" } if len(statusList) > 0 { _, err = putils.FreeBatchStoreSkuInfo(name, func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) { var failedList []*partner.StoreSkuInfoWithErr failedList, err = storeSkuHandler.UpdateStoreSkusStatus(ctx, storeDetail.VendorOrgCode, storeID, vendorStoreID, batchedStoreSkuList, status) if len(failedList) > 0 { task.AddFailedList(failedList) } successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList)) if len(successList) > 0 { updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagSaleMask) } return nil, len(successList), err }, ctx, task, statusList, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusStatus), isContinueWhenError2) } case 6: if len(priceList) > 0 { _, err = putils.FreeBatchStoreSkuInfo("更新门店商品价格", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) { if isNeedHandleAct(causeFlag) { cancelStoreSkuActs(ctx, task, vendorID, storeDetail.VendorOrgCode, storeID, vendorStoreID, batchedStoreSkuList) } var failedList []*partner.StoreSkuInfoWithErr failedList, err = storeSkuHandler.UpdateStoreSkusPrice(ctx, storeDetail.VendorOrgCode, storeID, vendorStoreID, batchedStoreSkuList) if len(failedList) > 0 { task.AddFailedList(failedList) } successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList)) if len(successList) > 0 { updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagPriceMask) } if isNeedHandleAct(causeFlag) { createStoreSkuActs(ctx, task, vendorID, storeDetail.VendorOrgCode, storeID, vendorStoreID, batchedStoreSkuList) } return nil, len(successList), err }, ctx, task, priceList, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusPrice), isContinueWhenError2) } case 7: if len(reorderSkuMap) > 0 { var vendorCatIDs []string for vendorCatID := range reorderSkuMap { vendorCatIDs = append(vendorCatIDs, vendorCatID) } reorderTask := tasksch.NewParallelTask("门店商品排序", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError2), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { vendorCatID := batchItemList[0].(string) skuList := reorderSkuMap[vendorCatID] var bareList []*partner.StoreSkuInfo for _, v := range skuList { bareList = append(bareList, storeSkuSyncInfo2Bare(calVendorPrice4StoreSku(v, storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage)))) } sort.Sort(partner.BareStoreSkuInfoList(bareList)) if err = reorderHandler.ReorderStoreSkus(ctx, storeID, vendorStoreID, vendorCatID, bareList); err == nil { updateStoreSku(dao.GetDB(), vendorID, skuList, model.SyncFlagSeqMask) } return retVal, err }, vendorCatIDs) tasksch.HandleTask(reorderTask, task, true).Run() _, err = reorderTask.GetResult(0) } } return retVal, err }, []int{0, 1, 2, 3, 4, 5, 6, 7}) tasksch.HandleTask(task, parentTask, true).Run() _, err = task.GetResult(0) return err } func isNeedHandleAct(causeFlag int) bool { return globals.IsStoreSkuAct && (causeFlag&model.SyncFlagPriceMask != 0) } func checkRemoteCatExist(outRemoteCatMap map[string]int, localCatMap map[string]*dao.SkuStoreCatInfo, remoteCatList []*partner.BareCategoryInfo) (cat2Delete []*partner.BareCategoryInfo) { for _, v := range remoteCatList { localCat := localCatMap[v.VendorCatID] // if localCat == nil { // localCat = localCatMap[v.Name] // } if localCat == nil || v.Level != int(localCat.Level) { cat2Delete = append(cat2Delete, v) } else { outRemoteCatMap[v.VendorCatID] = 1 } cat2Delete = append(cat2Delete, checkRemoteCatExist(outRemoteCatMap, localCatMap, v.Children)...) } return cat2Delete } // 清除京西没有,平台有的商品与商家分类 // todo !!!,因为美团外卖分类当前是用的名字关联的,所以改名后如果没有及时同步,这个函数会导致美团平台的分类被误删 func PruneMissingStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID, storeID int, vendorStoreID string, isAsync, isContinueWhenError bool) (hint string, err error) { return amendAndPruneStoreStuff(ctx, parentTask, vendorID, storeID, vendorStoreID, isAsync, isContinueWhenError, AmendPruneOnlyPrune, false) } func amendAndPruneStoreStuff(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID, storeID int, vendorStoreID string, isAsync, isContinueWhenError bool, opType int, isForceUpdate bool) (hint string, err error) { handler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler) if handler == nil { return "", fmt.Errorf("平台:%s不支持此操作", model.VendorChineseNames[vendorID]) } db := dao.GetDB() storeDetail, err := dao.GetStoreDetail(db, storeID, vendorID) if err != nil { return "", err } var sku2Delete []*partner.StoreSkuInfo var cat2Delete []*partner.BareCategoryInfo task := tasksch.NewParallelTask(fmt.Sprintf("修补门店:%d,平台:%s上的商品与商家分类", storeID, model.VendorChineseNames[vendorID]), tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { step := batchItemList[0].(int) switch step { case 0: localSkuList, err := dao.GetStoreSkus2(db, vendorID, storeID, nil, false) if err != nil { return nil, err } localSkuMap := make(map[string]*dao.StoreSkuSyncInfo) for _, v := range localSkuList { localSkuMap[v.VendorSkuID] = v } remoteSkuList, err2 := handler.GetStoreSkusFullInfo(ctx, task, storeID, vendorStoreID, nil) if err = err2; err == nil { remoteSkuMap := make(map[string]int) for _, v := range remoteSkuList { if vendorSkuID := v.SkuList[0].VendorSkuID; vendorSkuID != "" { if localSkuMap[vendorSkuID] == nil || remoteSkuMap[vendorSkuID] == 1 /*skuID在平台重复,典型的是美团可能会出现此类情况*/ { sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{ SkuID: v.SkuList[0].SkuID, VendorSkuID: vendorSkuID, }) } else { remoteSkuMap[vendorSkuID] = 1 } } else if v.VendorNameID != "" { sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{ SkuID: v.NameID, VendorSkuID: v.VendorNameID, }) } } if opType == AmendPruneOnlyAmend || opType == AmendPruneAll { for _, v := range localSkuList { if !model.IsSyncStatusDelete(v.SkuSyncStatus) && v.BindID != 0 { syncStatus := int8(0) if remoteSkuMap[v.VendorSkuID] == 0 { if !model.IsSyncStatusNew(v.SkuSyncStatus) { syncStatus = model.SyncFlagNewMask } } else if isForceUpdate { syncStatus = model.SyncFlagStoreSkuModifiedMask } if syncStatus != 0 { skuBind := &model.StoreSkuBind{} skuBind.ID = v.BindID // skuBind.LastOperator = ctx.GetUserName() // skuBind.UpdatedAt = time.Now() dao.SetStoreSkuBindSyncStatus(skuBind, vendorID, syncStatus|v.SkuSyncStatus) dao.UpdateEntity(db, skuBind, dao.GetSyncStatusStructField(model.VendorNames[vendorID]) /*, model.FieldLastOperator, model.FieldUpdatedAt*/) } } } } } case 1: if (opType == AmendPruneOnlyPrune || opType == AmendPruneAll) && len(sku2Delete) > 0 { _, err = putils.FreeBatchStoreSkuInfo("删除门店商品", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) { if _, err = handler.DeleteStoreSkus(ctx, storeID, vendorStoreID, batchedStoreSkuList); err != nil { if batchedStoreSkuList[0].Status == model.SkuStatusNormal { // 如果删除失败,尝试设置不可售,假定删除批处理SIZE小于等于设置门店商品可售批处理SIZE handler.UpdateStoreSkusStatus(ctx, storeDetail.VendorOrgCode, storeID, vendorStoreID, batchedStoreSkuList, model.SkuStatusDontSale) } } return nil, 0, err }, ctx, task, sku2Delete, 1 /*handler.GetStoreSkusBatchSize(partner.FuncDeleteStoreSkus)*/, isContinueWhenError) } sku2Delete = nil case 2: localCatList, err := dao.GetStoreCategories(db, vendorID, storeID, nil, 0, false) if err != nil { return nil, err } localCatMap := make(map[string]*dao.SkuStoreCatInfo) for _, v := range localCatList { localCatMap[v.VendorCatID] = v localCatMap[v.Name] = v localCatMap[utils.Int2Str(v.ID)] = v } remoteCatList, err2 := handler.GetStoreAllCategories(ctx, storeID, vendorStoreID) if err = err2; err == nil { remoteCatMap := make(map[string]int) cat2Delete = checkRemoteCatExist(remoteCatMap, localCatMap, remoteCatList) for _, v := range localCatList { if !model.IsSyncStatusDelete(v.CatSyncStatus) && v.MapID != 0 { syncStatus := int8(0) if remoteCatMap[v.VendorCatID] == 0 { if !model.IsSyncStatusNew(v.CatSyncStatus) { syncStatus = model.SyncFlagNewMask } } else if isForceUpdate && !model.IsSyncStatusUpdate(v.CatSyncStatus) { syncStatus = model.SyncFlagModifiedMask } if syncStatus != 0 { catBind := &model.StoreSkuCategoryMap{} catBind.ID = v.MapID // catBind.LastOperator = ctx.GetUserName() // catBind.UpdatedAt = time.Now() dao.SetStoreCatMapSyncStatus(catBind, vendorID, syncStatus|v.CatSyncStatus) dao.UpdateEntity(db, catBind, dao.GetSyncStatusStructField(model.VendorNames[vendorID]) /*, model.FieldLastOperator, model.FieldUpdatedAt*/) } } } } case 3: if (opType == AmendPruneOnlyPrune || opType == AmendPruneAll) && len(cat2Delete) > 0 { for i := 0; i < 2; i++ { level := 2 - i var levelCat2Delete []*partner.BareCategoryInfo for _, v := range cat2Delete { if v.Level == level { levelCat2Delete = append(levelCat2Delete, v) } } if len(levelCat2Delete) > 0 { task4Delete := tasksch.NewParallelTask(fmt.Sprintf("删除商家分类,level:%d", level), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { cat := batchItemList[0].(*partner.BareCategoryInfo) err = handler.DeleteStoreCategory(ctx, storeID, vendorStoreID, cat.VendorCatID, level) return nil, err }, levelCat2Delete) tasksch.HandleTask(task4Delete, task, true).Run() _, err = task4Delete.GetResult(0) } } } cat2Delete = nil } return nil, err }, []int{0, 1, 2, 3}) tasksch.HandleTask(task, parentTask, true).Run() if !isAsync { _, err = task.GetResult(0) hint = "1" } else { hint = task.ID } return hint, err } // 把京西有,平台无且没有待创建标记的商品加上待创建标记 func AddCreateFlagForJxStoreSku(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID, storeID int, vendorStoreID string, isAsync, isContinueWhenError bool) (hint string, err error) { return amendAndPruneStoreStuff(ctx, parentTask, vendorID, storeID, vendorStoreID, isAsync, isContinueWhenError, AmendPruneOnlyAmend, false) } func ClearRemoteStoreStuffAndSetNew(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID, storeID int, vendorStoreID string, isAsync, isContinueWhenError bool) (hint string, err error) { userName := ctx.GetUserName() globals.SugarLogger.Debugf("ClearRemoteStoreStuffAndSetNew storeID:%d, isContinueWhenError:%t, userName:%s", storeID, isContinueWhenError, userName) handler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler) if handler == nil { return "", fmt.Errorf("平台:%s不支持此操作", model.VendorChineseNames[vendorID]) } db := dao.GetDB() task := tasksch.NewParallelTask(fmt.Sprintf("删除门店:%d,平台:%s上的商品与商家分类", storeID, model.VendorChineseNames[vendorID]), tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { step := batchItemList[0].(int) switch step { case 0: err = handler.DeleteStoreAllSkus(ctx, task, storeID, vendorStoreID, isContinueWhenError) case 1: _, err = dao.SetStoreSkuSyncStatus(db, vendorID, []int{storeID}, nil, model.SyncFlagNewMask) case 2: err = handler.DeleteStoreAllCategories(ctx, task, storeID, vendorStoreID, isContinueWhenError) case 3: _, err = dao.SetStoreCategorySyncStatus(db, vendorID, []int{storeID}, nil, model.SyncFlagNewMask) } return nil, err }, []int{0, 1, 2, 3}) tasksch.HandleTask(task, parentTask, true).Run() if !isAsync { _, err = task.GetResult(0) hint = "1" } else { hint = task.ID } return hint, err } func GetSensitiveWord(singleStoreHandler partner.ISingleStoreStoreSkuHandler, str string) string { sensitiveWordRegexp := singleStoreHandler.GetSensitiveWordRegexp() findResult := sensitiveWordRegexp.FindStringSubmatch(str) if findResult != nil && len(findResult) > 1 { findSubResult := subSensitiveWordRegexp.FindAllString(findResult[1], -1) return strings.Join(findSubResult, "") } return "" } func MergeSkuSaleStatusWithStoreOpTime(sku *dao.StoreSkuSyncInfo, storeDetail *dao.StoreDetail, now int16) (outStatus int) { if sku.MergedStatus == model.SkuStatusNormal && sku.StatusSaleBegin > 0 && sku.StatusSaleEnd > 0 && storeDetail.Status == model.StoreStatusOpened { //商品可售时间的差集与门店营业时间的交集为不可售,其余为原本状态 var openTime int16 var closeTime int16 saleBeginTime := sku.StatusSaleBegin saleEndTime := sku.StatusSaleEnd if storeDetail.OpenTime2 != 0 && storeDetail.CloseTime2 != 0 { if storeDetail.OpenTime1 < storeDetail.OpenTime2 { openTime = storeDetail.OpenTime1 } else { openTime = storeDetail.OpenTime2 } if storeDetail.CloseTime1 > storeDetail.CloseTime2 { closeTime = storeDetail.CloseTime1 } else { closeTime = storeDetail.CloseTime2 } } else { openTime = storeDetail.OpenTime1 closeTime = storeDetail.CloseTime1 } beginAt1, endAt1 := GetTimeMixByInt(0, saleBeginTime, openTime, closeTime) beginAt2, endAt2 := GetTimeMixByInt(saleEndTime, 2400, openTime, closeTime) if beginAt1 != 0 && endAt1 != 0 { if now >= beginAt1 && now < endAt1 { return model.SkuStatusDontSale } } if beginAt2 != 0 && endAt2 != 0 { if now >= beginAt2 && now < endAt2 { return model.SkuStatusDontSale } } } return sku.MergedStatus } func GetVendorSkuIDList(l []*partner.StoreSkuInfoWithErr) (vendorSkuIDs []string) { vendorSkuIDs2 := make([]string, len(l)) if len(l) > 0 { for k, v := range l { vendorSkuIDs2[k] = v.StoreSkuInfo.VendorSkuID } } return vendorSkuIDs2 } func skuAct2Update(storeSkuAct *model.StoreSkuAct, isCreateAct bool) (item *dao.KVUpdateItem) { storeSkuAct.SyncStatus = 0 if !isCreateAct { storeSkuAct.VendorActID = "" } kvs := map[string]interface{}{ "VendorActID": storeSkuAct.VendorActID, "VendorActPrice": storeSkuAct.VendorActPrice, "SyncStatus": storeSkuAct.SyncStatus, } item = &dao.KVUpdateItem{ Item: storeSkuAct, KVs: kvs, } return item } func updateStoreSkuAct(db *dao.DaoDB, vendorID int, storeSkuActList []*model.StoreSkuAct, isCreateAct bool) (num int64, err error) { if len(storeSkuActList) > 0 { updateItemList := make([]*dao.KVUpdateItem, len(storeSkuActList)) for k, v := range storeSkuActList { updateItemList[k] = skuAct2Update(v, isCreateAct) } num, err = dao.BatchUpdateEntityByKV(db, updateItemList) } return num, err } func bareSku2StoreSkuAct(storeSkuActMap map[int]*model.StoreSkuAct, storeSkuList []*partner.StoreSkuInfo) (storeSkuActList []*model.StoreSkuAct) { for _, v := range storeSkuList { storeSkuAct := storeSkuActMap[v.SkuID] storeSkuAct.VendorActID = v.VendorActID storeSkuAct.VendorActPrice = v.ActPrice storeSkuActList = append(storeSkuActList, storeSkuAct) } return storeSkuActList } func parseStoreSkuActList(isCreateAct bool, storeSkuList []*partner.StoreSkuInfo, storeSkuActList []*model.StoreSkuAct) (outStoreSkuList []*partner.StoreSkuInfo, storeSkuActMap map[int]*model.StoreSkuAct) { storeSkuMap := make(map[int]*partner.StoreSkuInfo) for _, v := range storeSkuList { storeSkuMap[v.SkuID] = v } storeSkuActMap = make(map[int]*model.StoreSkuAct) for _, v := range storeSkuActList { if isCreateAct && v.VendorActID == "" && v.ActPercentage > 0 || !isCreateAct && v.VendorActID != "" { storeSku := storeSkuMap[v.SkuID] if isCreateAct { storeSku.ActPrice = int64(jxutils.CaculateSkuVendorPrice(int(storeSku.VendorPrice), v.ActPercentage, 0)) } else { storeSku.VendorActID = v.VendorActID } outStoreSkuList = append(outStoreSkuList, storeSku) storeSkuActMap[v.SkuID] = v } } return outStoreSkuList, storeSkuActMap } func createStoreSkuActs(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID int, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (err error) { globals.SugarLogger.Debugf("createStoreSkuActs vendorID:%d, storeID:%d, storeSkuList:%s", vendorID, storeID, utils.Format4Output(storeSkuList, true)) skuIDs := putils.StoreSkuList2IDs(storeSkuList) db := dao.GetDB() storeSkuActList, err := dao.GetStoresSkusAct(db, []int{storeID}, skuIDs, []int{vendorID}, 1, 0) if err == nil { storeSkuList2, storeSkuActMap := parseStoreSkuActList(true, storeSkuList, storeSkuActList) if len(storeSkuList2) > 0 { storeSkuHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler) _, err = putils.FreeBatchStoreSkuInfo(fmt.Sprintf("创建门店%d直降活动", storeID), func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) { var failedList []*partner.StoreSkuInfoWithErr failedList, err = storeSkuHandler.CreateStoreSkusAct(ctx, vendorOrgCode, storeID, vendorStoreID, batchedStoreSkuList) if len(failedList) > 0 { task.AddFailedList(failedList) } successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList)) if len(successList) > 0 { updateStoreSkuAct(dao.GetDB(), vendorID, bareSku2StoreSkuAct(storeSkuActMap, successList), true) } return nil, len(successList), err }, ctx, parentTask, storeSkuList2, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncCancelActs), true) } } return err } func cancelStoreSkuActs(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID int, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (err error) { globals.SugarLogger.Debugf("cancelStoreSkuActs vendorID:%d, storeID:%d, storeSkuList:%s", vendorID, storeID, utils.Format4Output(storeSkuList, true)) skuIDs := putils.StoreSkuList2IDs(storeSkuList) db := dao.GetDB() storeSkuActList, err := dao.GetStoresSkusAct(db, []int{storeID}, skuIDs, []int{vendorID}, 0, 0) if err == nil { storeSkuList2, storeSkuActMap := parseStoreSkuActList(false, storeSkuList, storeSkuActList) if len(storeSkuList2) > 0 { storeSkuHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler) _, err = putils.FreeBatchStoreSkuInfo(fmt.Sprintf("取消门店%d直降活动", storeID), func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) { var failedList []*partner.StoreSkuInfoWithErr failedList, err = storeSkuHandler.CancelActs(ctx, vendorOrgCode, storeID, vendorStoreID, batchedStoreSkuList) if len(failedList) > 0 { task.AddFailedList(failedList) } successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList)) if len(successList) > 0 { updateStoreSkuAct(dao.GetDB(), vendorID, bareSku2StoreSkuAct(storeSkuActMap, successList), false) } return nil, len(successList), err }, ctx, parentTask, storeSkuList2, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncCancelActs), true) } } return err }