From 910e351c00e78c6b92a355449e2de4c41a54da28 Mon Sep 17 00:00:00 2001 From: gazebo Date: Mon, 9 Sep 2019 17:03:01 +0800 Subject: [PATCH] =?UTF-8?q?-=20PruneMissingStoreSkus=E4=B9=9F=E4=BC=9A?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=9C=AC=E5=9C=B0=E4=B8=8D=E5=AD=98=E5=9C=A8?= =?UTF-8?q?=E7=9A=84=E8=BF=9C=E7=A8=8B=E5=88=86=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- business/jxstore/cms/sync_store_sku.go | 74 +++++++++++++++++---- business/jxstore/cms/sync_store_sku_test.go | 31 +++++++++ business/model/dao/store_sku.go | 28 ++++++-- 3 files changed, 116 insertions(+), 17 deletions(-) diff --git a/business/jxstore/cms/sync_store_sku.go b/business/jxstore/cms/sync_store_sku.go index e25b4f8f5..8500ea535 100644 --- a/business/jxstore/cms/sync_store_sku.go +++ b/business/jxstore/cms/sync_store_sku.go @@ -61,7 +61,7 @@ func SyncStorCategories(ctx *jxcontext.Context, parentTask tasksch.ITask, vendor 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.GetStoreCategories(db, vendorID, storeID, level) + catList, err := dao.GetDirtyStoreCategories(db, vendorID, storeID, level) if len(catList) > 0 { num += len(catList) task := tasksch.NewParallelTask(fmt.Sprintf("%s SyncStoreCategory step2, level=%d", model.VendorChineseNames[vendorID], level), @@ -546,26 +546,39 @@ func syncStoreSkuNew(ctx *jxcontext.Context, parentTask tasksch.ITask, isFull bo return err } -// 清除京西没有,平台有的商品 +func checkRemoteCatExist(localCatMap map[string]*dao.SkuStoreCatInfo, catList []*partner.BareCategoryInfo) (cat2Delete []*partner.BareCategoryInfo) { + for _, v := range catList { + if localCatMap[v.VendorCatID] == nil { + cat2Delete = append(cat2Delete, v) + } + cat2Delete = append(cat2Delete, checkRemoteCatExist(localCatMap, v.Children)...) + } + return cat2Delete +} + +// 清除京西没有,平台有的商品与商家分类 func PruneMissingStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID, storeID int, vendorStoreID string, isAsync, isContinueWhenError bool) (hint string, err error) { handler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler) if handler == nil { return "", fmt.Errorf("平台:%s不支持此操作", model.VendorChineseNames[vendorID]) } db := dao.GetDB() - localSkuList, err := dao.GetStoreSkus2(db, vendorID, storeID, nil, false) - if err != nil { - return "", err - } - localSkuMap := make(map[int]*dao.StoreSkuSyncInfo) - for _, v := range localSkuList { - localSkuMap[v.SkuID] = v - } + var sku2Delete []*partner.StoreSkuInfo + var cat2Delete []*partner.BareCategoryInfo task := tasksch.NewSeqTask(fmt.Sprintf("清除平台:%s上多余的门店商品", model.VendorChineseNames[vendorID]), ctx, func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { switch step { case 0: + localSkuList, err := dao.GetStoreSkus2(db, vendorID, storeID, nil, false) + if err != nil { + return nil, err + } + localSkuMap := make(map[int]*dao.StoreSkuSyncInfo) + for _, v := range localSkuList { + localSkuMap[v.SkuID] = v + } + remoteSkuList, err2 := handler.GetStoreSkusFullInfo(ctx, task, storeID, vendorStoreID, nil) if err = err2; err == nil { for _, v := range remoteSkuList { @@ -577,7 +590,6 @@ func PruneMissingStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, ven } } } - localSkuMap = nil case 1: if len(sku2Delete) > 0 { _, err = putils.FreeBatchStoreSkuInfo("删除门店商品", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) { @@ -585,9 +597,47 @@ func PruneMissingStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, ven return nil, 0, err }, ctx, parentTask, sku2Delete, handler.GetStoreSkusBatchSize(partner.FuncDeleteStoreSkus), isContinueWhenError) } + sku2Delete = nil + case 2: + localCatList, err := dao.GetStoreCategories(db, vendorID, storeID, 0, false) + if err != nil { + return nil, err + } + localCatMap := make(map[string]*dao.SkuStoreCatInfo) + for _, v := range localCatList { + localCatMap[v.VendorCatID] = v + } + + remoteCatList, err2 := handler.GetStoreAllCategories(ctx, storeID, vendorStoreID) + if err = err2; err == nil { + cat2Delete = checkRemoteCatExist(localCatMap, remoteCatList) + } + case 3: + if 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) + return nil, err + }, levelCat2Delete) + tasksch.HandleTask(task4Delete, task, true).Run() + _, err = task4Delete.GetResult(0) + } + } + } + cat2Delete = nil } return nil, err - }, 2) + }, 4) tasksch.HandleTask(task, parentTask, true).Run() if isAsync { hint = task.GetID() diff --git a/business/jxstore/cms/sync_store_sku_test.go b/business/jxstore/cms/sync_store_sku_test.go index 5d2ac294f..acd9abfcf 100644 --- a/business/jxstore/cms/sync_store_sku_test.go +++ b/business/jxstore/cms/sync_store_sku_test.go @@ -1 +1,32 @@ package cms + +import ( + "testing" + + "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/partner" + "git.rosy.net.cn/jx-callback/business/partner/putils" +) + +func TestFreeBatchStoreSkuInfo(t *testing.T) { + var sku2Delete []*partner.StoreSkuInfo + for i := 0; i < 123; i++ { + sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{ + SkuID: i + 1, + }) + } + + ctx := jxcontext.AdminCtx + var parentTask tasksch.ITask + isContinueWhenError := true + handler, _ := partner.GetPurchasePlatformFromVendorID(model.VendorIDEBAI).(partner.ISingleStoreStoreSkuHandler) + _, err := putils.FreeBatchStoreSkuInfo("删除门店商品", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) { + t.Log(len(batchedStoreSkuList)) + return nil, 0, err + }, ctx, parentTask, sku2Delete, handler.GetStoreSkusBatchSize(partner.FuncDeleteStoreSkus), isContinueWhenError) + if err != nil { + t.Fatal(err) + } +} diff --git a/business/model/dao/store_sku.go b/business/model/dao/store_sku.go index 1a31217ae..b456a3aad 100644 --- a/business/model/dao/store_sku.go +++ b/business/model/dao/store_sku.go @@ -156,9 +156,9 @@ func GetSkusCategories(db *DaoDB, vendorID, storeID int, skuIDs []int, level int // 单门店模式厂商适用 // 单纯的从已经创建的store_sku_category_map中,得到相关的同步信息 -func GetStoreCategories(db *DaoDB, vendorID, storeID int, level int) (cats []*SkuStoreCatInfo, err error) { +func GetStoreCategories(db *DaoDB, vendorID, storeID int, level int, isDirty bool) (cats []*SkuStoreCatInfo, err error) { fieldPrefix := ConvertDBFieldPrefix(model.VendorNames[vendorID]) - sql := fmt.Sprintf(` + sql := ` SELECT t4.*, t5.id map_id, t5.%s_id vendor_cat_id, t5.%s_sync_status store_cat_sync_status, t4p.name parent_cat_name, @@ -167,14 +167,32 @@ func GetStoreCategories(db *DaoDB, vendorID, storeID int, level int) (cats []*Sk JOIN sku_category t4 ON t5.category_id = t4.id AND t4.deleted_at = ? LEFT JOIN sku_category t4p ON t4.parent_id = t4p.id LEFT JOIN store_sku_category_map t5p ON t4p.id = t5p.category_id AND t5.store_id = t5p.store_id AND t5p.deleted_at = ? - WHERE t5.store_id = ? AND t4.level = ? AND t5.%s_sync_status <> 0 AND t5.deleted_at = ? - `, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix) - if err = GetRows(db, &cats, sql, utils.DefaultTimeValue, utils.DefaultTimeValue, storeID, level, utils.DefaultTimeValue); err != nil { + WHERE t5.store_id = ? AND t5.deleted_at = ?` + fieldPrefixParams := []interface{}{fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix} + sqlParams := []interface{}{ + utils.DefaultTimeValue, + utils.DefaultTimeValue, + storeID, + utils.DefaultTimeValue, + } + if isDirty { + sql += " AND t5.%s_sync_status <> 0" + fieldPrefixParams = append(fieldPrefixParams, fieldPrefix) + } + if level > 0 { + sql += " AND t4.level = ?" + sqlParams = append(sqlParams, level) + } + if err = GetRows(db, &cats, fmt.Sprintf(sql, fieldPrefixParams...), sqlParams...); err != nil { return nil, err } return cats, err } +func GetDirtyStoreCategories(db *DaoDB, vendorID, storeID int, level int) (cats []*SkuStoreCatInfo, err error) { + return GetStoreCategories(db, vendorID, storeID, level, true) +} + // 以store_sku_bind为基础来做同步,正常情况下使用 // !!! 此函数不要将store_sku_bind中的vendor_price取出来放到StoreSkuSyncInfo.VendorPrice中,因为之后会依赖这个VendorPrice进行重算 // 单多门店模式厂商通用