package mtwm import ( "encoding/json" "fmt" "math" "regexp" "strings" "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" ) const ( updateTypeStock = iota updateTypeStatus updateTypePrice ) const ( defVendorCatID = 200001903 // 生菜 specialStoreID = "8171010" // specialStoreID = "2523687" ) var ( sensitiveWordRegexp = regexp.MustCompile(`包含敏感词:(\[.*\])`) ) func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) (batchSize int) { switch funcID { case partner.FuncUpdateStoreSkusStock, partner.FuncUpdateStoreSkusStatus, partner.FuncUpdateStoreSkusPrice: batchSize = mtwmapi.MaxStoreSkuBatchSize case partner.FuncDeleteStoreSkus: batchSize = mtwmapi.MaxBatchDeleteSize case partner.FuncCreateStoreSkus: batchSize = 1 // 可考虑用批量操作 case partner.FuncUpdateStoreSkus: batchSize = 1 // mtwmapi.MaxStoreSkuBatchSize case partner.FuncGetStoreSkusFullInfo: batchSize = 1 case partner.FuncCreateActs: batchSize = mtwmapi.MaxRetailDiscountCreateBatchSize case partner.FuncCancelActs: batchSize = mtwmapi.MaxRetailDiscountDeleteBatchSize } return batchSize } func getStoreVendorOrgCode(storeID int) (vendorOrgCode string) { if storeMap, _ := dao.GetStoreDetail(dao.GetDB(), storeID, model.VendorIDMTWM, ""); storeMap != nil { return storeMap.VendorOrgCode } return vendorOrgCode } // 门店分类 func (p *PurchaseHandler) GetStoreAllCategories(ctx *jxcontext.Context, storeID int, vendorStoreID string) (cats []*partner.BareCategoryInfo, err error) { remoteCats, err := getAPI(getStoreVendorOrgCode(storeID), storeID, vendorStoreID).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.Code, Name: rCat.Name, Level: rCat.Level, Seq: rCat.Sequence, Children: convertVendorCatList(rCat.Children), } if cat.VendorCatID == "" { cat.VendorCatID = rCat.Name } 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 catCode2Str(catCode int) (catCodeStr string) { if catCode > 0 { catCodeStr = utils.Int2Str(catCode) } return catCodeStr } func tryCatName2Code(originName string) (catCodeStr string) { if intValue := utils.Str2Int64WithDefault(originName, 0); intValue > 0 { catCodeStr = utils.Int64ToStr(intValue) if catCodeStr != originName { catCodeStr = "" } } return catCodeStr } func (p *PurchaseHandler) CreateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) { level := 1 if storeCat.ParentCatName != "" { level = 2 } originName := "" catName := storeCat.Name catCode := storeCat.ID subCatName := "" subCatCode := 0 if storeCat.CatSyncStatus&model.SyncFlagNewMask == 0 { // 修改一级分类 originName = storeCat.VendorCatID } if level == 2 { // 二级分类 // 创建二级分类 originName = storeCat.ParentVendorCatID catName = storeCat.ParentCatName catCode = storeCat.ParentID subCatName = storeCat.Name subCatCode = storeCat.ID if storeCat.CatSyncStatus&model.SyncFlagNewMask == 0 { // 修改二级分类 originName = storeCat.VendorCatID catName = storeCat.Name catCode = storeCat.ID subCatName = "" subCatCode = 0 } } if catName == "" { panic("catName is empty") } catName = utils.FilterEmoji(catName) subCatName = utils.FilterEmoji(subCatName) if globals.EnableMtwmStoreWrite { param4Update := &mtwmapi.Param4UpdateCat{ CategoryCodeOrigin: tryCatName2Code(originName), CategoryNameOrigin: originName, CategoryCode: catCode2Str(catCode), SecondaryCategoryCode: catCode2Str(subCatCode), SecondaryCategoryName: subCatName, Sequence: storeCat.Seq, } api := getAPI(storeCat.VendorOrgCode, storeID, vendorStoreID) err = api.RetailCatUpdate(vendorStoreID, catName, param4Update) if storeCat.CatSyncStatus&model.SyncFlagNewMask == 0 && p.IsErrCategoryNotExist(err) && originName != "" { // 修改分类名,但分类不存在 storeCat.CatSyncStatus |= model.SyncFlagNewMask err = p.CreateStoreCategory(ctx, storeID, vendorStoreID, storeCat) } // 门店内存在重复的分类:【柑桔柚类】 【底料】,请先删除重复分类后再操作。 if err != nil && strings.Contains(err.Error(), "门店内存在重复的分类:") { for _, v := range deleteRepeatCat(err.Error()) { if len(v) > 0 { if err2 := api.RetailCatDelete(vendorStoreID, "", v, model.YES); err != nil { globals.SugarLogger.Errorf("RetailCatDelete delete err : [%v]", err2) } } } } } if err == nil { // storeCat.VendorCatID = utils.FilterEmoji(storeCat.Name) storeCat.VendorCatID = utils.Int2Str(storeCat.ID) } return err } // deleteRepeatCat 门店内存在重复的分类:【柑桔柚类】 【底料】 【火锅】,请先删除重复分类后再操作。 func deleteRepeatCat(param string) []string { firstIndex := strings.Index(param, "【") lastIndex := strings.LastIndex(param, "】") newParam := param[firstIndex:lastIndex] deleteCat := make([]string, 0, 0) for _, v := range strings.Split(newParam, "【") { if strings.TrimSpace(v) == "" { continue } else if strings.Contains(v, "【") { for _, v2 := range strings.Split(v, "【") { if strings.TrimSpace(v) == "" { continue } if strings.TrimSpace(v2) != "" { deleteCat = append(deleteCat, v2) } } } else if strings.Contains(v, "】") { for _, v3 := range strings.Split(v, "】") { if strings.TrimSpace(v3) == "" { continue } if strings.TrimSpace(v3) != "" { deleteCat = append(deleteCat, v3) } } } else { deleteCat = append(deleteCat, v) } } return deleteCat } 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) { if false { if globals.EnableMtwmStoreWrite { err = getAPI(getStoreVendorOrgCode(storeID), storeID, vendorStoreID).RetailCatDelete(vendorStoreID, tryCatName2Code(vendorCatID), vendorCatID, model.NO) } } else { var catCodes []string if catCode := tryCatName2Code(vendorCatID); catCode != "" { catCodes = []string{catCode} } if globals.EnableMtwmStoreWrite { if level == 1 { err = getAPI(getStoreVendorOrgCode(storeID), storeID, vendorStoreID).RetailCatSkuBatchDelete2(ctx.GetTrackInfo(), vendorStoreID, catCodes, []string{vendorCatID}, nil, nil, nil) } else { err = getAPI(getStoreVendorOrgCode(storeID), storeID, vendorStoreID).RetailCatSkuBatchDelete2(ctx.GetTrackInfo(), vendorStoreID, nil, nil, catCodes, []string{vendorCatID}, nil) } } } return err } // GetCategoryAttrList 根据末级类目id获取类目属性列表 func GetCategoryAttrList(appOrgCode string, tagID int) (categoryAttrListResult []*mtwmapi.CategoryAttrListResult, err error) { if resp, err := getAPI(appOrgCode, 0, "").CategoryAttrList(int64(tagID)); err == nil { return resp, nil } return nil, err } //GetCategoryAttrValueList 查询特殊属性的属性值列表 func GetCategoryAttrValueList(appOrgCode, keyword string, attrID int) (categoryAttrValueListResult []*mtwmapi.CategoryAttrValueListResult, err error) { if attrID != utils.Str2Int(mtwmapi.SpecialAttrBrand) && attrID != utils.Str2Int(mtwmapi.SpecialAttrProducer) || len(keyword) == 0 || len(appOrgCode) == 0 { return nil, nil } if resp, err := getAPI(appOrgCode, 0, "").CategoryAttrValueList(int64(attrID), keyword); err == nil { return resp, nil } return nil, nil } // GetRetailRecommendTag 根据商品UPC或名称或类目ID查询平台推荐类目及类目属性信息 func GetRetailRecommendTag(appOrgCode, appPoiCode, name string, tagID, tagType int) (*mtwmapi.RetailRecommendTagResp, error) { if resp, err := getAPI(appOrgCode, 0, "").RetailRecommendTag(name, appPoiCode, tagID, tagType); err == nil { return resp, nil } else { return nil, err } } //批量更新商品进货价 func BatchSetRestockingPrice(ctx *jxcontext.Context, storeID int, vendorStoreID string, param []*mtwmapi.SpuData) error { if err := getAPI(getStoreVendorOrgCode(storeID), storeID, "").BatchSetRestockingPrice(ctx.GetTrackInfo(), vendorStoreID, param); err != nil { return err } return nil } // 门店商品 // 多门店平台不需要实现这个接口 func (p *PurchaseHandler) IsErrSkuExist(err error) (isExist bool) { return false } func (p *PurchaseHandler) IsErrSkuNotExist(err error) (isNotExist bool) { return mtwmapi.IsErrSkuNotExist(err) } // func duplicateStoreSkuList(storeSkuList []*dao.StoreSkuSyncInfo, index int) (newStoreSkuList []*dao.StoreSkuSyncInfo) { // newStoreSkuList = make([]*dao.StoreSkuSyncInfo, len(storeSkuList)) // for k, v := range storeSkuList { // tmp := *v // tmp.SkuName = fmt.Sprintf("%s.%d", tmp.SkuName, index) // tmp.SkuID = index*1000000 + tmp.SkuID // newStoreSkuList[k] = &tmp // } // return newStoreSkuList // } 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) // if err == nil && vendorStoreID == specialStoreID { // for i := 0; i < 2; i++ { // p.createOrUpdateStoreSkus(ctx, storeID, vendorStoreID, duplicateStoreSkuList(storeSkuList, i+1), true) // } // } return failedList, err } 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) // if err == nil && vendorStoreID == specialStoreID { // for i := 0; i < 2; i++ { // p.createOrUpdateStoreSkus(ctx, storeID, vendorStoreID, duplicateStoreSkuList(storeSkuList, i+1), true) // } // } return failedList, err } // 对于多门店平台来说,storeSkuList中只有SkuID与VendorSkuID有意义 func (p *PurchaseHandler) createOrUpdateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo, isCreate bool) (failedList []*partner.StoreSkuInfoWithErr, err error) { var syncType string foodDataList := make([]map[string]interface{}, len(storeSkuList)) if isCreate { syncType = "创建商品" } else { syncType = "更新商品" } for i, storeSku := range storeSkuList { isNeedUpdatePrice := isCreate //storeSku.SkuSyncStatus&(model.SyncFlagPriceMask|model.SyncFlagNewMask) != 0 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 if isNeedUpdatePrice { foodData["price"] = jxutils.IntPrice2Standard(storeSku.VendorPrice) } if storeSku.MinOrderCount != 0 { foodData["min_order_count"] = storeSku.MinOrderCount } else { foodData["min_order_count"] = 1 } foodData["unit"] = storeSku.Unit //todo 增加商品必填属性 attr := SwitchAttr(getAPI(getStoreVendorOrgCode(storeID), storeID, vendorStoreID), vendorStoreID, storeSku.VendorVendorCatID, storeSku.NameID, storeSku.Name) if attr != "" { foodData["common_attr_value"] = attr } catCode := tryCatName2Code(storeSku.VendorCatID) if catCode != "" { foodData["category_code"] = catCode } else { foodData["category_name"] = storeSku.VendorCatID } foodData["is_sold_out"] = skuStatusJX2Mtwm(storeSku.MergedStatus) if true { // vendorStoreID == specialStoreID { img2 := storeSku.Img2 img3 := storeSku.Img3 img4 := storeSku.Img4 img5 := storeSku.Img5 if img2 == "" { img2 = storeSku.Img } if img3 == "" { img3 = storeSku.Img } if img4 == "" { img4 = storeSku.Img } if img5 == "" { img5 = storeSku.Img } if storeSku.ImgMix != "" && ((storeSku.BrandID == storeSku.ExBrandID && storeSku.ExBrandID != 0) || storeSku.ExBrandID == 0) { foodData["picture"] = strings.Join(jxutils.BatchString2Slice(storeSku.ImgMix, img2, img3, img4, img5), ",") } else { foodData["picture"] = strings.Join(jxutils.BatchString2Slice(storeSku.Img, img2, img3, img4, img5), ",") } } else { foodData["picture"] = strings.Join(jxutils.BatchString2Slice(storeSku.Img, storeSku.Img2), ",") } if storeSku.DescImg != "" { foodData["picture_contents"] = storeSku.DescImg } // 周期性可售时间段 if storeSku.StatusSaleBegin != model.NO && storeSku.StatusSaleEnd != model.NO { saleStart := utils.Int2Str(int(storeSku.StatusSaleBegin)) saleEnd := utils.Int2Str(int(storeSku.StatusSaleEnd)) for { if len(saleStart) != 4 { saleStart = "0" + saleStart } if len(saleEnd) != 4 { saleEnd += "0" + saleEnd } if len(saleEnd) == 4 && len(saleStart) == 4 { break } } saleStart = fmt.Sprintf("%s:%s", saleStart[:2], saleStart[2:]) saleEnd = fmt.Sprintf("%s:%s", saleEnd[:2], saleEnd[2:]) availableTimes := fmt.Sprintf("%s-%s", saleStart, saleEnd) available, _ := json.Marshal(map[string]string{"monday": availableTimes, "tuesday": availableTimes, "wednesday": availableTimes, "thursday": availableTimes, "friday": availableTimes, "saturday": availableTimes, "sunday": availableTimes}) foodData["available_times"] = string(available) } foodData["sequence"] = storeSku.GetSeq() 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) if isNeedUpdatePrice { skus[0]["price"] = foodData["price"] } skus[0]["stock"] = stockCount2Mtwm(model.MaxStoreSkuStockQty) if storeSku.Upc != "" { skus[0]["upc"] = storeSku.Upc } // 暂时取消打包费 //skus[0]["ladder_box_num"] = storeSku.LadderBoxNum //boxPirce := 0 //if storeSku.MtLadderBoxPrice != 0 { // boxPirce = storeSku.MtLadderBoxPrice //} else { // boxPirce = storeSku.LadderBoxPrice //} //skus[0]["ladder_box_price"] = jxutils.IntPrice2Standard(int64(boxPirce)) skus[0]["ladder_box_num"] = 0 skus[0]["ladder_box_price"] = 0 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"])) if err = getAPI(getStoreVendorOrgCode(storeID), storeID, vendorStoreID).RetailInitData(ctx.GetTrackInfo(), vendorStoreID, utils.Int2Str(storeSkuList[0].SkuID), foodDataList[0]); err != nil { failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDMTWM], syncType) } } else if len(foodDataList) > 0 { failedFoodList, err2 := getAPI(getStoreVendorOrgCode(storeID), storeID, vendorStoreID).RetailBatchInitData(ctx.GetTrackInfo(), vendorStoreID, foodDataList) if err = err2; err == nil { if err = putils.GenPartialFailedErr(failedFoodList, len(failedFoodList)); err != nil { failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], syncType) // successList = putils.UnselectStoreSkuSyncListByVendorSkuIDs(storeSkuList, getAppFoodCodeList(failedFoodList)) } } else if err2 != nil && len(failedFoodList) == 0 { if errExt, ok := err2.(*utils.ErrorWithCode); ok { err = utils.UnmarshalUseNumber([]byte(errExt.ErrMsg()), &failedFoodList) failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], syncType) } } } } for _, storeSku := range storeSkuList { storeSku.VendorSkuID = utils.Int2Str(storeSku.SkuID) } if len(failedList) > 0 { err = nil } return failedList, err } func getAppFoodCodeList(l []*mtwmapi.AppFoodResult) (vendorSkuIDs []string) { if len(l) > 0 { vendorSkuIDs = make([]string, len(l)) for k, v := range l { vendorSkuIDs[k] = v.AppFoodCode } } return vendorSkuIDs } func (p *PurchaseHandler) DeleteStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) { if globals.EnableMtwmStoreWrite { if len(storeSkuList) == 1 { err = getAPI(storeSkuList[0].VendorOrgCode, storeID, vendorStoreID).RetailDelete(ctx.GetTrackInfo(), vendorStoreID, storeSkuList[0].VendorSkuID) failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDMTWM], "删除商品") } else { // todo 部分失败 err = getAPI(getStoreVendorOrgCode(storeID), storeID, vendorStoreID).RetailCatSkuBatchDelete2(ctx.GetTrackInfo(), vendorStoreID, nil, nil, nil, nil, partner.BareStoreSkuInfoList(storeSkuList).GetVendorSkuIDList()) if err != nil { if errExt, ok := err.(*utils.ErrorWithCode); ok { myMap := make(map[string][]*mtwmapi.AppFoodResult) json.Unmarshal([]byte(errExt.ErrMsg()), &myMap) failedList = SelectStoreSkuListByFoodList(storeSkuList, myMap["retail_error_list"], storeID, model.VendorChineseNames[model.VendorIDMTWM], "批量删除商品") } } } } if len(failedList) > 0 { err = nil } return failedList, err } // CommonAttrValue 类目对应属性值 type CommonAttrValue struct { AttrID int `json:"attr_id"` //普通属性Id AttrName string `json:"attr_name"` //普通属性名称 ValueList []ValueList `json:"valueList"` } type ValueList struct { ValueID int `json:"value_id"` //普通属性值Id,当属性值录入方式为文本时,该参数无需上传;若该普通属性可扩展则支持自定义 1.负值 2.同一个商品的同一个普通属性内唯一 Value string `json:"value"` //普通属性值名称(与普通属性值Id一一对应),支持自定义。 } func SwitchAttr(apiObj *mtwmapi.API, vendorStoreID string, vendorCatID int64, nameID int, name string) (attrs string) { var ( db *dao.DaoDB tempCatID int64 attrValue CommonAttrValue attrValues []CommonAttrValue ) if nameID != 0 { //是否为纯创建 if tData, err := dao.GetSkuNames(db, []int{nameID}, nil, "", false); err == nil && len(tData) > 0 { if tData[0].MtAttribute != "[]" && tData[0].MtAttribute != "{}" && tData[0].MtAttribute != "" { return tData[0].MtAttribute } } } if vendorCatID == 0 { //创建商品时无分类,使用推荐分类 if comTag, err := apiObj.RetailRecommendTag(name, vendorStoreID, 0, mtwmapi.TypeCategory); err == nil && comTag.TagID != 0 { tempCatID = int64(comTag.TagID) } } else { tempCatID = vendorCatID } //根据类目id获取类目属性列表 if attrList, err := apiObj.CategoryAttrList(tempCatID); err == nil && len(attrList) > 0 { for _, v := range attrList { if v.Need == mtwmapi.NeedYes { attrValue = CommonAttrValue{ AttrID: utils.Str2Int(v.AttrID), AttrName: v.AttrName, } if v.AttrID == mtwmapi.SpecialAttrBrand || v.AttrID == mtwmapi.SpecialAttrProducer { //单独获取特殊属性 data, err1 := apiObj.CategoryAttrValueList(utils.Str2Int64(v.AttrID), name) if len(data) > 0 { attrValue.ValueList = []ValueList{{ //默认取推荐第一个 ValueID: utils.Str2Int(data[0].ValueID), Value: data[0].Value, }} } if err1 != nil || len(data) == 0 { attrValue.ValueList = []ValueList{{ //兜底处理 Value: "其他", }} } } else { if len(v.ValueList) > 0 { attrValue.ValueList = []ValueList{{ ValueID: utils.Str2Int(v.ValueList[0].ValueID), Value: v.ValueList[0].Value, }} } else { //兜底处理 attrValue.ValueList = []ValueList{{ Value: "其他", }} } } attrValues = append(attrValues, attrValue) } } temp, _ := json.Marshal(attrValues) attrs = string(temp) } else { switch vendorCatID { //兜底处理 case 200002727: attrs = mtwmapi.MtwmSkuAttr200002727 case 200001555: attrs = mtwmapi.MtwmSkuAttr200001555 case 200002728: attrs = mtwmapi.MtwmSkuAttr200002728 case 200001519, 200000592: attrs = mtwmapi.MtwmSkuAttr200000592 case 200002704, 200002731: attrs = mtwmapi.MtwmSkuAttr200002731 case 200002716: attrs = mtwmapi.MtwmSkuAttr200002716 case 200002667, 200002713, 200002670: attrs = mtwmapi.MtwmSkuAttr200002670 case 200002680: attrs = mtwmapi.MtwmSkuAttr200002680 default: attrs = "" } } //更新进数据库 dao.UpdateSkuNameMtAttr(db, int64(nameID), attrs) return attrs } 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) } else { skuInfo.Skus = nil } skuList = append(skuList, skuInfo) } return skuList } func (p *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo, status int) (failedList []*partner.StoreSkuInfoWithErr, err error) { skuList := storeSku2Mtwm(storeSkuList, updateTypeStatus) mtwmStatus := skuStatusJX2Mtwm(status) if globals.EnableMtwmStoreWrite { failedFoodList, err2 := getAPI(vendorOrgCode, storeID, vendorStoreID).RetailSellStatus(ctx.GetTrackInfo(), vendorStoreID, skuList, mtwmStatus) if err = err2; err == nil { if len(failedFoodList) > 0 { failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], "更新商品状态") // successList = putils.UnselectStoreSkuListByVendorSkuIDs(storeSkuList, getAppFoodCodeList(failedFoodList)) } } else if err2 != nil && len(failedFoodList) == 0 { if errExt, ok := err2.(*utils.ErrorWithCode); ok { err = utils.UnmarshalUseNumber([]byte(errExt.ErrMsg()), &failedFoodList) failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], "更新商品状态") } } } if len(failedList) > 0 { err = nil } return failedList, err } func (p *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) { priceList := storeSku2Mtwm(storeSkuList, updateTypePrice) if globals.EnableMtwmStoreWrite { failedFoodList, err2 := getAPI(vendorOrgCode, storeID, vendorStoreID).RetailSkuPrice(ctx.GetTrackInfo(), vendorStoreID, priceList) if err = err2; err == nil { if len(failedFoodList) > 0 { failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], "更新商品价格") } } else if err2 != nil && len(failedFoodList) == 0 { if errExt, ok := err2.(*utils.ErrorWithCode); ok { err = utils.UnmarshalUseNumber([]byte(errExt.ErrMsg()), &failedFoodList) failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], "更新商品价格") } } } if len(failedList) > 0 { err = nil } return failedList, err } func (p *PurchaseHandler) UpdateStoreSkusStock(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) { stockList := storeSku2Mtwm(storeSkuList, updateTypeStock) if globals.EnableMtwmStoreWrite { failedFoodList, err2 := getAPI(vendorOrgCode, storeID, vendorStoreID).RetailSkuStock(ctx.GetTrackInfo(), vendorStoreID, stockList) if err = err2; err == nil { if len(failedFoodList) > 0 { failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], "更新商品库存") } //if err = putils.GenPartialFailedErr(failedFoodList, len(failedFoodList)); err != nil { // successList = putils.UnselectStoreSkuListByVendorSkuIDs(storeSkuList, getAppFoodCodeList(failedFoodList)) // } } else if err2 != nil && len(failedFoodList) == 0 { if errExt, ok := err2.(*utils.ErrorWithCode); ok { err = utils.UnmarshalUseNumber([]byte(errExt.ErrMsg()), &failedFoodList) failedList = SelectStoreSkuListByFoodList(storeSkuList, failedFoodList, storeID, model.VendorChineseNames[model.VendorIDMTWM], "更新商品库存") } } } if len(failedList) > 0 { err = nil } return failedList, 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 := getAPI(storeSkuList[0].VendorOrgCode, storeID, vendorStoreID).RetailGet(vendorStoreID, utils.Int2Str(storeSkuList[0].SkuID)) if err != nil { return nil, err } if skuName := vendorSku2Jx(skuInfo); skuName != nil { skuNameList = append(skuNameList, skuName) } } else { var storeSkuMap map[string]*partner.StoreSkuInfo if storeSkuList != nil { storeSkuMap = putils.StoreSkuList2MapByVendorSkuID(storeSkuList) } mtapi := getAPI(getStoreVendorOrgCode(storeID), storeID, vendorStoreID) for { // todo 待优化获取速度 result, err := mtapi.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 { if skuName := vendorSku2Jx(v); skuName != nil { skuNameList = append(skuNameList, skuName) } } } } if len(result) < mtwmapi.GeneralMaxLimit { break } } } return skuNameList, err } func vendorSku2Jx(appFood *mtwmapi.AppFood) (skuName *partner.SkuNameInfo) { if len(appFood.SkuList) == 0 { return nil } prefix, name, comment, specUnit, unit, specQuality := jxutils.SplitSkuName(appFood.Name) vendorSku := appFood.SkuList[0] weight := int(utils.Str2Int64WithDefault(vendorSku.Weight, 0)) if weight <= 0 { weight = jxutils.FormatSkuWeight(specQuality, specUnit) } skuID := int(utils.Str2Int64WithDefault(vendorSku.SkuId, 0)) skuName = &partner.SkuNameInfo{ NameID: int(utils.Str2Int64WithDefault(appFood.AppFoodCode, 0)), VendorNameID: appFood.AppFoodCode, UPC: appFood.SkuList[0].Upc, Prefix: prefix, Name: name, Unit: unit, Status: mtwmSkuStatus2Jx(appFood.IsSoldOut), //此处为之前一个bug 如果吧状态放到切片内层 对于内层函数中映射无法关联 永远获取到的初始值为0 SkuList: []*partner.SkuInfo{ &partner.SkuInfo{ StoreSkuInfo: partner.StoreSkuInfo{ VendorSkuID: vendorSku.SkuId, SkuID: skuID, IsSpecialty: appFood.IsSpecialty, 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 != "" { // todo, 因为当前我们用的是分类名操作这种方式,所以要返回分类名(而不是分类code) 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 { if skuName := vendorSku2Jx(appFood); skuName != nil { skuNameList = append(skuNameList, skuName) } } return skuNameList } func (p *PurchaseHandler) GetSensitiveWordRegexp() *regexp.Regexp { return sensitiveWordRegexp } //美团api返回 func SelectStoreSkuListByFoodList(storeSkuList interface{}, foodList []*mtwmapi.AppFoodResult, storeID int, vendorName, syncType string) (selectedStoreSkuList []*partner.StoreSkuInfoWithErr) { foodMap := make(map[string]string) if len(foodList) > 0 { for _, v := range foodList { foodMap[v.AppFoodCode] = v.ErrorMsg } if storeSkuLists, ok := storeSkuList.([]*partner.StoreSkuInfo); ok { for _, v := range storeSkuLists { if foodMap[v.VendorSkuID] != "" { foodFailed := &partner.StoreSkuInfoWithErr{ StoreSkuInfo: v, ErrMsg: foodMap[v.VendorSkuID], StoreID: storeID, VendoreName: vendorName, SyncType: syncType, } selectedStoreSkuList = append(selectedStoreSkuList, foodFailed) } } } if storeSkuLists, ok := storeSkuList.([]*dao.StoreSkuSyncInfo); ok { for _, v := range storeSkuLists { if foodMap[v.VendorSkuID] != "" { storeSkuInfo := &partner.StoreSkuInfo{ SkuID: v.SkuID, VendorSkuID: v.VendorSkuID, NameID: v.NameID, VendorNameID: v.VendorNameID, VendorPrice: v.VendorPrice, Status: v.Status, } foodFailed := &partner.StoreSkuInfoWithErr{ StoreSkuInfo: storeSkuInfo, ErrMsg: foodMap[v.VendorSkuID], StoreID: storeID, VendoreName: vendorName, SyncType: syncType, } selectedStoreSkuList = append(selectedStoreSkuList, foodFailed) } } } } return selectedStoreSkuList } 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 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 == -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 (p *PurchaseHandler) GetSkuCategoryIdByName(vendorOrgCode, skuName string) (vendorCategoryId string, err error) { return "", err } type SetBoxPrice struct { StoreId int `json:"store_id"` // 门店id SkuId int `json:"sku_id"` // 商品id BoxPrice float64 `json:"box_price"` // 打包价格 } func UpdateBoxPrice(ctx *jxcontext.Context, db *dao.DaoDB, list []*SetBoxPrice) error { storeDetail, err := dao.GetStoreDetail(db, list[0].StoreId, model.VendorIDMTWM, "") if err != nil { return err } //storeSkuList, err := dao.GetStoresSkusInfo(db, []int{list[0].StoreId}, nil) //if err != nil { // return err //} api := getAPI(storeDetail.VendorOrgCode, list[0].StoreId, storeDetail.VendorStoreID) foodDataList := make([]map[string]interface{}, 0) for _, v := range list { foodDataList = append(foodDataList, map[string]interface{}{ "app_spu_code": utils.Int2Str(v.SkuId), "skus": []map[string]interface{}{ { "sku_id": utils.Int2Str(v.SkuId), "ladder_box_num": "1", "ladder_box_price": utils.Float64ToStr(v.BoxPrice), }, }, }) } count := utils.Float64TwoInt(math.Ceil(float64(len(foodDataList)) / float64(50))) for i := 1; i <= count; i++ { if i == count { _, _ = api.RetailBatchInitData(ctx.GetTrackInfo(), storeDetail.VendorStoreID, foodDataList[(i-1)*50:]) } else { _, _ = api.RetailBatchInitData(ctx.GetTrackInfo(), storeDetail.VendorStoreID, foodDataList[(i-1)*50:i*50]) } } return nil }