package yonghui import ( "errors" "fmt" "io" "math" "mime/multipart" "unicode" "git.rosy.net.cn/baseapi" "git.rosy.net.cn/baseapi/utils" "github.com/360EntSecGroup-Skylar/excelize" "git.rosy.net.cn/baseapi/platformapi/jdapi" "git.rosy.net.cn/baseapi/platformapi/weimobapi" "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/dao" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" ) type SheetParam struct { SkuIDCol int SkuPriceCol int OrgSkuIdCol int OrgSkuPriceCol int SkuRow int } var ( sheetMap = map[string]*SheetParam{ "蔬菜": &SheetParam{ SkuIDCol: 0, SkuPriceCol: 14, OrgSkuIdCol: 5, OrgSkuPriceCol: 8, SkuRow: 2, }, "水果": &SheetParam{ SkuIDCol: 0, SkuPriceCol: 14, OrgSkuIdCol: 5, OrgSkuPriceCol: 8, SkuRow: 2, }, "肉禽": &SheetParam{ SkuIDCol: 0, SkuPriceCol: 12, OrgSkuIdCol: 4, OrgSkuPriceCol: 7, SkuRow: 1, }, "净配": &SheetParam{ SkuIDCol: 0, SkuPriceCol: 12, OrgSkuIdCol: 4, OrgSkuPriceCol: 7, SkuRow: 1, }, "水产": &SheetParam{ SkuIDCol: 1, SkuPriceCol: 15, OrgSkuIdCol: 6, OrgSkuPriceCol: 9, SkuRow: 1, }, "干货": &SheetParam{ SkuIDCol: 0, SkuPriceCol: 13, OrgSkuIdCol: 4, OrgSkuPriceCol: 7, SkuRow: 2, }, "MINI肉禽价格": &SheetParam{ SkuIDCol: 1, SkuPriceCol: 5, OrgSkuIdCol: -1, OrgSkuPriceCol: -1, SkuRow: 1, }, } ) const ( parallelCount = 5 UpdateGoodsShelfStatusCount = 50 //微盟下架商品api限制一次50个 ) func LoadExcelByYongHui(ctx *jxcontext.Context, files []*multipart.FileHeader, isAsync, isContinueWhenError bool) (hint string, err error) { if len(files) == 0 { return "", errors.New("没有文件上传!") } fileHeader := files[0] file, err := fileHeader.Open() hint, err = LoadExcelBinByYongHui(ctx, file, true, true) file.Close() return hint, err } func LoadExcelBinByYongHui(ctx *jxcontext.Context, reader io.Reader, isAsync, isContinueWhenError bool) (hint string, err error) { var ( skuMap = make(map[string]float64) errMsg string costPrice float64 //成本价 goodsList []*weimobapi.GoodsInfo goodsIDListForPutAway []interface{} ) db := dao.GetDB() taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { switch step { case 0: //读取excel文件 xlsx, err := excelize.OpenReader(reader) if err != nil { return "", err } for k := range sheetMap { sheetParam := sheetMap[k] rows, _ := xlsx.GetRows(k) for rowNum, row := range rows { if rowNum < sheetParam.SkuRow { continue } GetCellIntoMap(sheetParam.SkuIDCol, sheetParam.SkuPriceCol, sheetParam.OrgSkuIdCol, sheetParam.OrgSkuPriceCol, skuMap, row, k, rowNum) if len(skuMap) < 1 { errMsg += fmt.Sprintf("读取Excel数据失败,Excel格式排版可能发生了变化!sheetName: [%v]\n", k) } } if errMsg != "" { return "", errors.New(errMsg) } } case 1: //获取微盟所有商品 goodsList, err = GetWeiMobGoodsList() if err != nil { baseapi.SugarLogger.Errorf("GetWeiMobGoodsList error:%v", err) } taskFunc2 := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { v := batchItemList[0].(*weimobapi.GoodsInfo) goodsDetail, err := api.WeimobAPI.QueryGoodsDetail(v.GoodsID) if err != nil { baseapi.SugarLogger.Errorf("QueryGoodsDetail error:%v", err) } v.GoodsDetailInfo = goodsDetail return retVal, err } taskParallel2 := tasksch.NewParallelTask("获取微盟商品", tasksch.NewParallelConfig().SetParallelCount(parallelCount), ctx, taskFunc2, goodsList) tasksch.HandleTask(taskParallel2, task, true).Run() _, err = taskParallel2.GetResult(0) //找出excel上有,微盟没有的,有就列出报错,不进行更新 goodsInfoAndDetailMap := GetGoodsInfoAndDetailMap(goodsList) for k, _ := range skuMap { //表示excel上有,微盟上没有 if goodsInfoAndDetailMap[k] == nil { errMsg += fmt.Sprintf("在微盟上未找到该商品!excel商品ID : [%v]\n", k) } } // if errMsg != "" { // return "", errors.New(errMsg) // } case 2: //找出微盟上有,excel上没有的,有就更新,没有就下架 taskFunc3 := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { goods := batchItemList[0].(*weimobapi.GoodsInfo) goodsDetail := goods.GoodsDetailInfo spuCode := goodsDetail.OuterGoodsCode if spuCode != "" { //如果微盟商品里找得到excel中的商品 if skuMap[spuCode] != 0 { //获取京西库商品 skuList, _ := dao.GetSkus(db, nil, []int{int(utils.Str2Int64(goodsDetail.SkuMap.SingleSku.OuterSkuCode))}, nil, nil) if len(skuList) == 0 { return "", errors.New(fmt.Sprintf("在京西库中未找到该商品!name_id : [%v]\n", goodsDetail.SkuMap.SingleSku.OuterSkuCode)) } else { if skuList[0].Unit == "份" { if goodsDetail.SkuMap.SingleSku.B2CSku.Weight == 0 { costPrice = skuMap[spuCode] } else { costPrice = Float64Round(0.5 / goodsDetail.SkuMap.SingleSku.B2CSku.Weight * skuMap[spuCode]) } } else { costPrice = skuMap[spuCode] } // if errMsg == "" { _, _, err = updateWeiMobGoods(costPrice, skuMap[spuCode], goodsDetail) // } } } else { //下架微盟商品 retVal = []int64{goodsDetail.GoodsID} } } return retVal, err } taskParallel3 := tasksch.NewParallelTask("根据获取的微盟所有商品并更新", tasksch.NewParallelConfig().SetParallelCount(parallelCount).SetIsContinueWhenError(isContinueWhenError), ctx, taskFunc3, goodsList) tasksch.HandleTask(taskParallel3, task, true).Run() goodsIDListForPutAwayInterface, err2 := taskParallel3.GetResult(0) if err = err2; err != nil { return "", err } goodsIDListForPutAway = goodsIDListForPutAwayInterface case 3: // 批量下架微盟商品 // if errMsg == "" { taskFunc4 := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { int64Slice := []int64{} for _, v := range batchItemList { int64Slice = append(int64Slice, v.(int64)) } PutAwayWeiMobSku(int64Slice) return retVal, err } taskParallel4 := tasksch.NewParallelTask("下架微盟商品", tasksch.NewParallelConfig().SetParallelCount(parallelCount).SetBatchSize(UpdateGoodsShelfStatusCount), ctx, taskFunc4, goodsIDListForPutAway) tasksch.HandleTask(taskParallel4, task, true).Run() _, err = taskParallel4.GetResult(0) // } } if errMsg != "" { return result, errors.New(errMsg) } return result, err } taskSeq := tasksch.NewSeqTask2("读取永辉Excel文件修改微盟商品价格可售状态-序列任务", ctx, isContinueWhenError, taskSeqFunc, 4) tasksch.HandleTask(taskSeq, nil, true).Run() if !isAsync { _, err = taskSeq.GetResult(0) hint = "1" } else { hint = taskSeq.GetID() } return hint, err } func PutAwayWeiMobSku(goodsIDListForPutAway []int64) (err error) { if globals.EnableStoreWrite { err = api.WeimobAPI.UpdateGoodsShelfStatus(goodsIDListForPutAway, false) } if err != nil { baseapi.SugarLogger.Errorf("UpdateGoodsShelfStatus error:%v", err) } return err } func GetGoodsInfoAndDetailMap(goodsList []*weimobapi.GoodsInfo) (goodsMap map[string]*weimobapi.GoodsInfo) { goodsMap = make(map[string]*weimobapi.GoodsInfo) for _, v := range goodsList { goodsMap[v.GoodsDetailInfo.OuterGoodsCode] = v } return goodsMap } func updateWeiMobGoods(costPrice, salePrice float64, goodsDetail *weimobapi.GoodsDetailInfo) (goodsID int64, skuMap map[string]int64, err error) { var ( categoryList []*weimobapi.CategoryList skuListInfo = goodsDetail.SkuList[0] skuListParam []*weimobapi.SkuList categoryID int deliveryTypeListSlice []int64 ) //查询配送方式 deliveryTypeList, err := api.WeimobAPI.FindDeliveryTypeList(goodsDetail.GoodsID) if err != nil { baseapi.SugarLogger.Errorf("FindDeliveryTypeList error:%v", err) } for _, deliveryType := range deliveryTypeList { if deliveryType.Selected { deliveryTypeListSlice = append(deliveryTypeListSlice, deliveryType.DeliveryID) } } //查询运费模板 freightTemplateListInfo, err := api.WeimobAPI.FindFreightTemplateList(goodsDetail.GoodsID) if err != nil { baseapi.SugarLogger.Errorf("FindFreightTemplateList error:%v", err) } //寻找分类子ID categoryList = goodsDetail.CategoryList if len(categoryList) > 0 { categoryID = categoryList[len(categoryList)-1].CategoryID } else { return 0, nil, errors.New(fmt.Sprintf("未查询到此商品的分类信息!goodsID : [%v] ,", goodsDetail.GoodsID)) } b2CSku := &weimobapi.B2CSku{ Weight: skuListInfo.B2CSku.Weight, Volume: skuListInfo.B2CSku.Volume, } b2CGoods := &weimobapi.B2CGoods{ B2CGoodsType: goodsDetail.B2CGoods.B2CGoodsType, DeliveryTypeIDList: deliveryTypeListSlice, FreightTemplateID: freightTemplateListInfo.DefaultFreightTemplate.TemplateID, } skuList := &weimobapi.SkuList{ SalePrice: salePrice, CostPrice: costPrice, SkuID: skuListInfo.SkuID, EditStockNum: 9999 - skuListInfo.AvailableStockNum, OuterSkuCode: skuListInfo.OuterSkuCode, B2CSku: b2CSku, } skuListParam = append(skuListParam, skuList) goods := &weimobapi.Goods{ B2CGoods: b2CGoods, SkuList: skuListParam, Title: goodsDetail.Title, IsMultiSku: goodsDetail.IsMultiSku, IsPutAway: weimobapi.GoodsTypeNormal, GoodsImageURL: goodsDetail.GoodsImageURL, GoodsID: goodsDetail.GoodsID, CategoryID: categoryID, OuterGoodsCode: goodsDetail.OuterGoodsCode, PointDeductRatio: goodsDetail.PointDeductRatio, } updateGoodsParam := &weimobapi.UpdateGoodsParam{ Goods: goods, } if globals.EnableStoreWrite { goodsID, skuMap, err = api.WeimobAPI.UpdateGoods3(updateGoodsParam) } return goodsID, skuMap, err } func GetWeiMobGoodsList() (goodsList []*weimobapi.GoodsInfo, err error) { param := &weimobapi.QueryGoodsListParam{ PageNum: 1, PageSize: jdapi.MaxSkuIDsCount4QueryListBySkuIds, } for { goodsInfoList, _, err := api.WeimobAPI.QueryGoodsList(param) if err != nil { return nil, err } if len(goodsInfoList) > 0 { goodsList = append(goodsList, goodsInfoList...) } if len(goodsInfoList) < param.PageSize { break } param.PageNum++ } return goodsList, err } func IsChineseChar(str string) bool { for _, r := range str { if unicode.Is(unicode.Scripts["Han"], r) { return true } } return false } func GetCellIntoMap(skuIDCol, skuPriceCol, orgSkuIDCol, orgSkuPriceCol int, skuMap map[string]float64, row []string, sheetName string, rowNum int) { var ( skuID string orgSkuID string skuPrice float64 orgSkuPrice float64 ) for k, cell := range row { if !IsChineseChar(cell) && cell != "" { if k == skuIDCol && skuIDCol >= 0 { skuID = cell } if k == skuPriceCol && skuPriceCol >= 0 { skuPrice = Float64Round(utils.Str2Float64WithDefault(cell, 0)) } if k == orgSkuIDCol && orgSkuIDCol >= 0 { orgSkuID = "0" + cell } if k == orgSkuPriceCol && orgSkuPriceCol >= 0 { orgSkuPrice = Float64Round(utils.Str2Float64WithDefault(cell, 0)) } } } if skuMap[skuID] != 0 && skuMap[skuID] != skuPrice { if skuPrice > skuMap[skuID] { skuMap[skuID] = skuPrice } // fmt.Sprintf("读取excel表格出错!有商品ID重复且价格不同,sheetName : [%v] ,行数 : [%v] , 商品编码 :[%v] , 价格:[%v]\n", sheetName, rowNum, skuID, skuPrice) } else { skuMap[skuID] = skuPrice } if skuMap[orgSkuID] != 0 && skuMap[orgSkuID] != orgSkuPrice { if orgSkuPrice > skuMap[orgSkuID] { skuMap[orgSkuID] = orgSkuPrice } // fmt.Sprintf("读取excel表格出错!有商品ID重复且价格不同,sheetName : [%v] ,行数 : [%v], 商品编码 :[%v] , 价格:[%v]\n", sheetName, rowNum, orgSkuID, orgSkuPrice) } else if orgSkuPriceCol >= 0 && orgSkuIDCol >= 0 { skuMap[orgSkuID] = orgSkuPrice } delete(skuMap, "") } func Float64Round(f float64) (flt float64) { return math.Round(f*100) / 100 }