Files
jx-callback/business/partner/purchase/mtwm/store_sku.go
gazebo 0d9bb63161 - fk
2018-12-04 20:07:54 +08:00

397 lines
14 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package mtwm
import (
"errors"
"fmt"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"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/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
defVendorCatID = 200000380
)
// hint如果是异步返回的是任务ID如果是同步返回是本次需要同步的目录数
func (p *PurchaseHandler) SyncStoreCategory(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, isAsync bool) (hint string, err error) {
userName := ctx.GetUserName()
strStoreID := utils.Int2Str(storeID)
num := 0
db := dao.GetDB()
rootTask := tasksch.NewSeqTask("美团外卖SyncStoreCategory step1", userName, func(rootTask *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
level := step + 1
catList, err := dao.GetStoreCategories(db, model.VendorIDMTWM, storeID, level)
if len(catList) > 0 {
num += len(catList)
task := tasksch.NewParallelTask(fmt.Sprintf("美团外卖SyncStoreCategory step2, level=%d", level), nil, userName, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
updateFields := []string{dao.GetSyncStatusStructField(model.VendorNames[model.VendorIDMTWM])}
catInfo := batchItemList[0].(*dao.StoreCatSyncInfo)
if globals.EnableStoreWrite && globals.EnableMtwmStoreWrite {
if catInfo.MtwmSyncStatus&model.SyncFlagDeletedMask != 0 { // 删除
globals.SugarLogger.Debugf("RetailCatDelete strStoreID:%s, MtwmID:%s", strStoreID, catInfo.MtwmID)
err = api.MtwmAPI.RetailCatDelete(strStoreID, catInfo.MtwmID)
} else if catInfo.MtwmSyncStatus&(model.SyncFlagNewMask|model.SyncFlagModifiedMask) != 0 { // 新增
catName := catInfo.CatName
subCatName := ""
originName := ""
if catInfo.MtwmSyncStatus&model.SyncFlagNewMask == 0 {
originName = catInfo.MtwmID
}
if level == 2 {
originName = catInfo.ParentCatName
catName = catInfo.ParentCatName
subCatName = catInfo.CatName
if catInfo.MtwmSyncStatus&model.SyncFlagNewMask == 0 {
originName = catInfo.MtwmID
catName = catInfo.CatName
subCatName = ""
}
}
if catName == "" {
panic("catName is empty")
}
globals.SugarLogger.Debugf("RetailCatUpdate strStoreID:%s, originName:%s, catName:%s, subCatName:%s, seq:%d", strStoreID, originName, catName, subCatName, catInfo.Seq)
if err := api.MtwmAPI.RetailCatUpdate(strStoreID, originName, catName, subCatName, catInfo.Seq); err == nil {
catInfo.MtwmID = catInfo.CatName
updateFields = append(updateFields, dao.GetVendorThingIDStructField(model.VendorNames[model.VendorIDMTWM]))
}
}
}
if err == nil {
db2 := dao.GetDB()
catInfo.MtwmSyncStatus = 0
_, err = dao.UpdateEntity(db2, &catInfo.StoreSkuCategoryMap, updateFields...)
}
return nil, err
}, catList)
rootTask.AddChild(task).Run()
_, err = task.GetResult(0)
}
return nil, err
}, 2)
tasksch.AddChild(parentTask, rootTask).Run()
if !isAsync {
hint = utils.Int2Str(num)
_, err = rootTask.GetResult(0)
} else {
hint = rootTask.ID
}
return hint, err
}
func (p *PurchaseHandler) ReadStoreCategories(storeID int) (cats []*model.SkuCategory, err error) {
return nil, nil
}
// 此函数根据门店商品信息重建分类信息
// 远程有,本地无, --> 删除远程
// 远程有,本地有,映射无, --> 添加关联
// 远程有,本地有,映射有, --> 不处理
// 远程无,本地有,映射无, --> 添加本地
// 远程无,本地有,映射有, --> 同步标记改为新增
// hint如果是异步返回的是任务ID如果是同步返回是本次需要同步的目录数
func (p *PurchaseHandler) SyncLocalStoreCategory(ctx *jxcontext.Context, db *dao.DaoDB, storeID int, isCheckRemote, isAsync bool) (hint string, err error) {
if db == nil {
db = dao.GetDB()
}
catMap := make([]map[string]*dao.SkuStoreCatInfo, 2)
for i := 0; i < 2; i++ {
catMap[i] = make(map[string]*dao.SkuStoreCatInfo)
localCats, err := dao.GetSkusCategories(db, model.VendorIDMTWM, storeID, nil, i+1)
// globals.SugarLogger.Debug(utils.Format4Output(localCats, false))
if err != nil {
return "", err
}
for _, cat := range localCats {
catID := cat.VendorCatID
if catID == "" {
catID = cat.Name
}
parentCatID := cat.ParentVendorCatID
if parentCatID == "" {
parentCatID = cat.ParentCatName
}
catMap[i][parentCatID+"/"+catID] = cat
}
}
if isCheckRemote {
strStoreID := utils.Int2Str(storeID)
remoteCats, err := api.MtwmAPI.RetailCatList(utils.Int2Str(storeID))
if err != nil {
return "", err
}
if err = TranverseRemoteCatList("", remoteCats, func(level int, parentCatName, catName string) (err error) {
localCat := catMap[level-1][parentCatName+"/"+catName]
// globals.SugarLogger.Debug(parentCatName, " ", catName, " ", localCat)
if localCat == nil { // 本地分类就没有这个名字,直接删除
if globals.EnableStoreWrite && globals.EnableMtwmStoreWrite {
globals.SugarLogger.Debugf("RetailCatDelete2 strStoreID:%s, catName:%s", strStoreID, catName)
if err = api.MtwmAPI.RetailCatDelete(strStoreID, catName); err != nil {
return err
}
}
} else { // 本地分类有这个名字
if localCat.MapID == 0 { // 本地映射没有
localCat.MapID = -1 // 表示远程有同名的
} else { // 本地映射有
localCat.MapID = -2 // 表示不处理
}
}
return nil
}); err != nil {
return "", err
}
}
dao.Begin(db)
defer func() {
dao.Rollback(db)
}()
num := 0
for i := 0; i < 2; i++ {
for _, v := range catMap[i] {
if v.MapID == -1 || v.MapID == 0 { // 本地缺失
mtwmSyncStatus := int8(model.SyncFlagNewMask)
if v.MapID == -1 { // 远程有同名的,只是简单增加一条本地记录关联
mtwmSyncStatus = 0
}
catMap := &model.StoreSkuCategoryMap{
StoreID: storeID,
CategoryID: v.ID,
MtwmID: v.Name,
MtwmSyncStatus: mtwmSyncStatus,
EbaiSyncStatus: model.SyncFlagNewMask,
ElmSyncStatus: model.SyncFlagNewMask,
}
num++
dao.WrapAddIDCULDEntity(catMap, ctx.GetUserName())
if err = dao.CreateEntity(db, catMap); err != nil {
return "", err
}
} else if v.MapID != -2 {
catMap := &model.StoreSkuCategoryMap{
MtwmSyncStatus: model.SyncFlagNewMask,
}
catMap.ID = v.MapID
num++
if _, err = dao.UpdateEntity(db, catMap, "MtwmSyncStatus"); err != nil {
return "", err
}
}
}
}
dao.Commit(db)
return utils.Int2Str(num), err
}
func TranverseRemoteCatList(parentCatName string, remoteCats []*mtwmapi.RetailCategoryInfo, handler func(level int, parentCatName, catName string) error) (err error) {
for _, remoteCat := range remoteCats {
name := utils.Interface2String(remoteCat.Name)
TranverseRemoteCatList(name, remoteCat.Children, handler)
if err = handler(remoteCat.Level, parentCatName, name); err != nil {
return err
}
}
return nil
}
func (p *PurchaseHandler) ReadStoreSku(storeID, skuID int) (skuNameExt *model.SkuNameExt, err error) {
return nil, nil
}
// hint如果是异步返回的是任务ID如果是同步返回是本次需要同步的目录数
func (p *PurchaseHandler) SyncStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
db := dao.GetDB()
for i := 0; i < 3; i++ { // 最多重试三次
if hint, err = p.SyncLocalStoreCategory(ctx, db, storeID, false, false); err != nil {
return "", err
}
if hint != "0" {
if hint, err = p.SyncStoreCategory(ctx, parentTask, storeID, false); err != nil {
return "", err
}
}
if hint == "0" {
break
}
}
if hint != "0" {
return "", errors.New("同步门店商品所需目录失败")
}
skus, err := dao.GetStoreSkus(db, model.VendorIDMTWM, storeID, skuIDs)
// globals.SugarLogger.Debug(utils.Format4Output(skus, false))
strStoreID := utils.Int2Str(storeID)
rootTask := tasksch.NewParallelTask("美团外卖SyncStoreSkus", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx.GetUserName(), func(rootTask *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
foodDataList := make([]map[string]interface{}, len(batchItemList))
// for k, v := range batchItemList {
v := batchItemList[0]
skuItem := v.(*dao.StoreSkuSyncInfo)
if skuItem.SkuSyncStatus&model.SyncFlagDeletedMask != 0 {
err = api.MtwmAPI.RetailDelete(strStoreID, utils.Int2Str(skuItem.ID))
} else if skuItem.SkuSyncStatus&(model.SyncFlagModifiedMask|model.SyncFlagNewMask) != 0 {
foodData := make(map[string]interface{})
foodDataList[0] = foodData
foodData[mtwmapi.KeyAppFoodCode] = utils.Int2Str(skuItem.ID)
foodData["name"] = jxutils.ComposeSkuName(skuItem.Prefix, skuItem.Name, skuItem.Comment, skuItem.Unit, skuItem.SpecQuality, skuItem.SpecUnit, 30)
foodData["description"] = skuItem.Comment
foodData["price"] = jxutils.IntPrice2Standard(skuItem.Price)
foodData["min_order_count"] = 1
foodData["unit"] = skuItem.Unit
foodData["box_num"] = 0
foodData["box_price"] = 0
foodData["category_name"] = skuItem.VendorCatID
foodData["is_sold_out"] = skuStatusJX2Mtwm(jxutils.MergeSkuStatus(skuItem.Status, skuItem.StoreSkuStatus))
foodData["picture"] = skuItem.Img
if skuItem.VendorVendorCatID != 0 {
foodData["tag_id"] = utils.Int64ToStr(skuItem.VendorVendorCatID)
} else {
foodData["tag_id"] = utils.Int64ToStr(defVendorCatID)
}
foodData["skus"] = []map[string]interface{}{
map[string]interface{}{
"sku_id": foodData[mtwmapi.KeyAppFoodCode],
"spec": jxutils.ComposeSkuSpec(skuItem.SpecQuality, skuItem.SpecUnit),
"weight": skuItem.Weight,
"price": foodData["price"],
"stock": "*",
},
}
if globals.EnableStoreWrite && globals.EnableMtwmStoreWrite {
err = api.MtwmAPI.RetailBatchInitData(strStoreID, foodDataList)
}
}
if err == nil {
storeSkuBind := &model.StoreSkuBind{}
storeSkuBind.ID = skuItem.BindID
_, err = dao.UpdateEntity(nil, storeSkuBind, model.FieldMtwmSyncStatus)
}
return nil, err
}, skus)
if parentTask != nil {
parentTask.AddChild(rootTask)
}
rootTask.Run()
if !isAsync {
_, err = rootTask.GetResult(0)
hint = utils.Int2Str(len(skus))
} else {
hint = rootTask.ID
}
return hint, err
}
func (p *PurchaseHandler) RefreshStoresAllSkusID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool, storeIDs []int) (hint string, err error) {
return hint, err
}
func (p *PurchaseHandler) FullSyncStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, isAsync, isContinueWhenError bool) (hint string, err error) {
userName := ctx.GetUserName()
globals.SugarLogger.Debugf("mtwm FullSyncStoreSkus storeID:%d, isContinueWhenError:%t, userName:%s", storeID, isContinueWhenError, userName)
db := dao.GetDB()
rootTask := tasksch.NewSeqTask("美团外卖FullSyncStoreSkus", userName, func(rootTask *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
err = p.DeleteRemoteSkus(storeID, nil)
case 1:
_, err = dao.SetStoreSkuSyncStatus(ctx, db, model.VendorIDMTWM, storeID, nil, model.SyncFlagNewMask)
case 2:
_, err = p.SyncLocalStoreCategory(ctx, db, storeID, true, false)
case 3:
_, err = p.SyncStoreCategory(ctx, rootTask, storeID, false)
case 4:
// _, err = p.SyncStoreSkus(ctx, rootTask, storeID, nil, true, isContinueWhenError)
}
return nil, err
}, 5)
tasksch.AddChild(parentTask, rootTask).Run()
if !isAsync {
_, err = rootTask.GetResult(0)
}
return rootTask.ID, err
}
func (p *PurchaseHandler) DeleteRemoteSkus(storeID int, vendorSkuIDs []string) (err error) {
if vendorSkuIDs == nil {
result, err2 := p.GetAllRemoteSkus(storeID)
if err = err2; err == nil {
vendorSkuIDs = make([]string, len(result))
for k, v := range result {
vendorSkuIDs[k] = utils.Interface2String(v["app_food_code"])
}
}
}
strStoreID := utils.Int2Str(storeID)
task := tasksch.NewParallelTask("mtwm DeleteRemoteSkus", nil, "", func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
if globals.EnableStoreWrite && globals.EnableMtwmStoreWrite {
err = api.MtwmAPI.RetailDelete(strStoreID, batchItemList[0].(string))
}
return nil, err
}, vendorSkuIDs)
task.Run()
_, err = task.GetResult(0)
return err
}
func (p *PurchaseHandler) GetAllRemoteSkus(storeID int) (skus []map[string]interface{}, err error) {
strStoreID := utils.Int2Str(storeID)
for {
result, err := api.MtwmAPI.RetailList(strStoreID, len(skus), mtwmapi.GeneralMaxLimit)
if err != nil {
return nil, err
}
skus = append(skus, result...)
if len(result) < mtwmapi.GeneralMaxLimit {
break
}
}
return skus, err
}
func (p *PurchaseHandler) DeleteRemoteCategories(storeID int, vendorCatIDs []string) (err error) {
strStoreID := utils.Int2Str(storeID)
vendorCatIDs2 := make([]string, 0)
if vendorCatIDs == nil {
result, err := api.MtwmAPI.RetailCatList(strStoreID)
if err != nil {
return err
}
vendorCatIDs = make([]string, len(result))
for k, v := range result {
vendorCatIDs[k] = v.Name
for _, v2 := range v.Children {
vendorCatIDs2 = append(vendorCatIDs2, v2.Name)
}
}
}
rootTask := tasksch.NewSeqTask("mtwm DeleteRemoteCategories", "", func(rootTask *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
var catIDs []string
if step == 0 {
catIDs = vendorCatIDs2
} else {
catIDs = vendorCatIDs
}
if len(catIDs) > 0 {
task := tasksch.NewParallelTask("mtwm DeleteRemoteCategories paralle", nil, "", func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
if globals.EnableStoreWrite && globals.EnableMtwmStoreWrite {
err = api.MtwmAPI.RetailCatDelete(strStoreID, batchItemList[0].(string))
}
return nil, err
}, catIDs)
rootTask.AddChild(task).Run()
_, err = task.GetResult(0)
}
return nil, err
}, 2)
rootTask.Run()
_, err = rootTask.GetResult(0)
return err
}