package mtwm import ( "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/business/partner" "git.rosy.net.cn/jx-callback/business/partner/putils" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" ) const ( updateTypeStock = iota updateTypeStatus updateTypePrice ) const ( defVendorCatID = 200001903 // 生菜 ) func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) (batchSize int) { switch funcID { case partner.FuncUpdateStoreSkusStock, partner.FuncUpdateStoreSkusStatus, partner.FuncUpdateStoreSkusPrice: batchSize = mtwmapi.MaxStoreSkuBatchSize case partner.FuncGetStoreSkusBareInfo: batchSize = partner.UnlimitedBatchSize case partner.FuncDeleteStoreSkus: batchSize = 1 // 可考虑用批量操作 case partner.FuncCreateStoreSkus, partner.FuncUpdateStoreSkus: batchSize = 1 // 可考虑用批量操作 case partner.FuncGetStoreSkusFullInfo: batchSize = 1 } return batchSize } // 门店分类 func (p *PurchaseHandler) GetStoreAllCategories(ctx *jxcontext.Context, storeID int, vendorStoreID string) (cats []*partner.BareCategoryInfo, err error) { remoteCats, err := api.MtwmAPI.RetailCatList(vendorStoreID) if err == nil { cats = convertVendorCatList(remoteCats) } return cats, err } func convertVendorCatList(remoteCats []*mtwmapi.RetailCategoryInfo) (cats []*partner.BareCategoryInfo) { for _, rCat := range remoteCats { cat := &partner.BareCategoryInfo{ VendorCatID: rCat.Name, Name: rCat.Name, Level: rCat.Level, Seq: rCat.Sequence, Children: convertVendorCatList(rCat.Children), } 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 (p *PurchaseHandler) CreateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) { level := 1 if storeCat.ParentCatName != "" { level = 2 } catName := storeCat.Name subCatName := "" originName := "" if storeCat.StoreCatSyncStatus&model.SyncFlagNewMask == 0 { originName = storeCat.VendorCatID } if level == 2 { originName = storeCat.ParentCatName catName = storeCat.ParentCatName subCatName = storeCat.Name if storeCat.StoreCatSyncStatus&model.SyncFlagNewMask == 0 { originName = storeCat.VendorCatID catName = storeCat.Name subCatName = "" } } if catName == "" { panic("catName is empty") } globals.SugarLogger.Debugf("mtwm CreateStoreCategory vendorStoreID:%s, originName:%s, catName:%s, subCatName:%s, seq:%d", vendorStoreID, originName, catName, subCatName, storeCat.Seq) if globals.EnableMtwmStoreWrite { err = api.MtwmAPI.RetailCatUpdate(vendorStoreID, originName, catName, subCatName, storeCat.Seq) } if err == nil { storeCat.VendorCatID = storeCat.Name } 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) (err error) { if globals.EnableMtwmStoreWrite { err = api.MtwmAPI.RetailCatDelete(vendorStoreID, vendorCatID) } 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) (successList []*dao.StoreSkuSyncInfo, err error) { return p.CreateStoreSkus(ctx, storeID, vendorStoreID, storeSkuList) } // 对于多门店平台来说,storeSkuList中只有SkuID与VendorSkuID有意义 func (p *PurchaseHandler) CreateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (successList []*dao.StoreSkuSyncInfo, err error) { foodDataList := make([]map[string]interface{}, len(storeSkuList)) for i, storeSku := range storeSkuList { foodData := make(map[string]interface{}) foodDataList[i] = foodData foodData[mtwmapi.KeyAppFoodCode] = utils.Int2Str(storeSku.SkuID) skus := []map[string]interface{}{ map[string]interface{}{ "sku_id": foodData[mtwmapi.KeyAppFoodCode], }, } foodData["skus"] = skus foodData["name"] = utils.LimitUTF8StringLen(storeSku.SkuName, mtwmapi.MaxSkuNameCharCount) foodData["description"] = storeSku.Comment foodData["price"] = jxutils.IntPrice2Standard(storeSku.VendorPrice) foodData["min_order_count"] = 1 foodData["unit"] = storeSku.Unit foodData["box_num"] = 0 foodData["box_price"] = 0.0 foodData["category_name"] = storeSku.VendorCatID foodData["is_sold_out"] = skuStatusJX2Mtwm(storeSku.MergedStatus) foodData["picture"] = storeSku.Img if storeSku.DescImg != "" { foodData["picture_contents"] = storeSku.DescImg } foodData["sequence"] = storeSku.VendorPrice if storeSku.VendorVendorCatID != 0 { foodData["tag_id"] = utils.Int64ToStr(storeSku.VendorVendorCatID) } else { // foodData["tag_id"] = utils.Int64ToStr(defVendorCatID) } skus[0]["spec"] = jxutils.ComposeSkuSpec(storeSku.SpecQuality, storeSku.SpecUnit) skus[0]["price"] = foodData["price"] skus[0]["stock"] = stockCount2Mtwm(model.MaxStoreSkuStockQty) skus[0]["upc"] = storeSku.Upc if foodData["tag_id"] != nil { skus[0]["weight"] = storeSku.Weight // weight字段仅限服饰鞋帽、美妆、日用品、母婴、生鲜果蔬、生活超市下的便利店/超市门店品类的商家使用 } } if globals.EnableMtwmStoreWrite { if len(foodDataList) == 1 { foodDataList[0]["skus"] = string(utils.MustMarshal(foodDataList[0]["skus"])) err = api.MtwmAPI.RetailInitData(vendorStoreID, utils.Int2Str(storeSkuList[0].SkuID), foodDataList[0]) } else if len(foodDataList) > 0 { failedFoodList, err2 := api.MtwmAPI.RetailBatchInitData(vendorStoreID, foodDataList) if err = err2; err == nil { if err = putils.GenPartialFailedErr(failedFoodList, len(failedFoodList)); err != nil { successList = putils.UnselectStoreSkuSyncListByVendorSkuIDs(storeSkuList, getAppFoodCodeList(failedFoodList)) } } } } for _, storeSku := range storeSkuList { storeSku.VendorSkuID = utils.Int2Str(storeSku.SkuID) } return successList, err } func getAppFoodCodeList(l []*mtwmapi.AppFoodResult) (vendorSkuIDs []string) { return vendorSkuIDs } func (p *PurchaseHandler) DeleteStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (successList []*partner.StoreSkuInfo, err error) { if globals.EnableMtwmStoreWrite { if len(storeSkuList) == 1 { err = api.MtwmAPI.RetailDelete(vendorStoreID, storeSkuList[0].VendorSkuID) } else { // todo 部分失败 err = api.MtwmAPI.RetailCatSkuBatchDelete(vendorStoreID, nil, nil, partner.BareStoreSkuInfoList(storeSkuList).GetVendorSkuIDList()) } } return nil, 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) } skuList = append(skuList, skuInfo) } return skuList } func (p *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo, status int) (successList []*partner.StoreSkuInfo, err error) { skuList := storeSku2Mtwm(storeSkuList, updateTypeStatus) mtwmStatus := skuStatusJX2Mtwm(status) if globals.EnableMtwmStoreWrite { failedFoodList, err2 := api.MtwmAPI.RetailSkuSellStatus(vendorStoreID, skuList, mtwmStatus) if err = err2; err == nil { if len(failedFoodList) > 0 { successList = putils.UnselectStoreSkuListByVendorSkuIDs(storeSkuList, getAppFoodCodeList(failedFoodList)) } } } return successList, err } func (p *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (successList []*partner.StoreSkuInfo, err error) { priceList := storeSku2Mtwm(storeSkuList, updateTypePrice) if globals.EnableMtwmStoreWrite { failedFoodList, err2 := api.MtwmAPI.RetailSkuPrice(vendorStoreID, priceList) if err = err2; err == nil { if err = putils.GenPartialFailedErr(failedFoodList, len(failedFoodList)); err != nil { successList = putils.UnselectStoreSkuListByVendorSkuIDs(storeSkuList, getAppFoodCodeList(failedFoodList)) } } } return successList, err } func (p *PurchaseHandler) UpdateStoreSkusStock(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (successList []*partner.StoreSkuInfo, err error) { stockList := storeSku2Mtwm(storeSkuList, updateTypeStock) if globals.EnableMtwmStoreWrite { failedFoodList, err2 := api.MtwmAPI.RetailSkuStock(vendorStoreID, stockList) if err = err2; err == nil { if err = putils.GenPartialFailedErr(failedFoodList, len(failedFoodList)); err != nil { successList = putils.UnselectStoreSkuListByVendorSkuIDs(storeSkuList, getAppFoodCodeList(failedFoodList)) } } } return successList, err } func mtwmSkuStatus2Jx(mtwmSkuStatus int) (jxSkuStatus int) { if mtwmSkuStatus == 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) { if len(storeSkuList) == 1 { skuInfo, err := api.MtwmAPI.RetailGet(vendorStoreID, utils.Int2Str(storeSkuList[0].SkuID)) if err != nil { return nil, err } skuNameList = append(skuNameList, vendorSku2Jx(skuInfo)) } else { var storeSkuMap map[string]*partner.StoreSkuInfo if storeSkuList != nil { storeSkuMap = putils.StoreSkuList2MapByVendorSkuID(storeSkuList) } for { // todo 待优化获取速度 result, err := api.MtwmAPI.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 { skuNameList = append(skuNameList, vendorSku2Jx(v)) } } } if len(result) < mtwmapi.GeneralMaxLimit { break } } } return skuNameList, err } func vendorSku2Jx(appFood *mtwmapi.AppFood) (skuName *partner.SkuNameInfo) { prefix, name, comment, specUnit, unit, specQuality := jxutils.SplitSkuName(appFood.Name) vendorSku := appFood.SkuList[0] weight := vendorSku.Weight if weight <= 0 { weight = jxutils.FormatSkuWeight(specQuality, specUnit) } skuID := int(utils.Str2Int64WithDefault(vendorSku.SkuID, 0)) skuName = &partner.SkuNameInfo{ NameID: skuID, VendorNameID: vendorSku.SkuID, Prefix: prefix, Name: name, Unit: unit, SkuList: []*partner.SkuInfo{ &partner.SkuInfo{ StoreSkuInfo: partner.StoreSkuInfo{ VendorSkuID: vendorSku.SkuID, SkuID: skuID, Stock: int(utils.Str2Int64WithDefault(vendorSku.Stock, partner.UnlimitedStoreSkuStock)), VendorPrice: jxutils.StandardPrice2Int(utils.Str2Float64WithDefault(vendorSku.Price, 0)), Status: mtwmSkuStatus2Jx(appFood.IsSoldOut), }, SkuName: appFood.Name, Comment: comment, SpecQuality: float64(specQuality), SpecUnit: specUnit, Weight: weight, }, }, PictureList: appFood.PictureList, } if appFood.CategoryName != "" { skuName.VendorCatIDList = []string{appFood.CategoryName} if appFood.SecondaryCategoryName != "" { skuName.VendorCatIDList = append(skuName.VendorCatIDList, appFood.SecondaryCategoryName) } } return skuName } func vendorSkuList2Jx(appFoodList []*mtwmapi.AppFood) (skuNameList []*partner.SkuNameInfo) { for _, appFood := range appFoodList { skuNameList = append(skuNameList, vendorSku2Jx(appFood)) } return skuNameList }