package yonghui import ( "errors" "fmt" "io" "math" "mime/multipart" "strings" "sync" "time" "git.rosy.net.cn/baseapi" "git.rosy.net.cn/baseapi/utils" "github.com/360EntSecGroup-Skylar/excelize" "git.rosy.net.cn/baseapi/platformapi/dingdingapi" "git.rosy.net.cn/baseapi/platformapi/jdapi" "git.rosy.net.cn/baseapi/platformapi/weimobapi" "git.rosy.net.cn/jx-callback/business/jxstore/cms" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/jxutils/ddmsg" "git.rosy.net.cn/jx-callback/business/jxutils/excel" "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" ) type SheetParam struct { SkuIDCol int SkuPriceCol int SkuNameCol int OrgSkuIdCol int OrgSkuPriceCol int OrgSkuNameCol int SkuRow int } type DataStoreSkusSuccessLock struct { dataStoreSkusSuccessList []DataStoreSkusSuccess locker sync.RWMutex } type DataSuccessLock struct { dataSuccessList []DataSuccess locker sync.RWMutex } type DataFailedLock struct { dataFailedList []DataFailed locker sync.RWMutex } type DataStoreSkusSuccess struct { StoreID int `json:"门店ID"` NameID int `json:"商品编码"` Name string `json:"商品名称"` Unit string `json:"单位"` OrgPrice float64 `json:"原价"` NowPrice float64 `json:"现价"` MixPrice float64 `json:"涨跌"` } type DataSuccess struct { NameID string `json:"商品编码"` Name string `json:"商品名称"` Unit string `json:"单位"` OrgPrice float64 `json:"原价"` NowPrice float64 `json:"现价"` MixPrice float64 `json:"涨跌"` } type DataFailed struct { GoodsID string `json:"商品ID"` GoodsName string `json:"商品名称"` Comment string `json:"备注"` } type Data struct { GoodsID string `json:"商品编码"` GoodsName string `json:"商品名称"` GoodsNum int `json:"订货数量"` } type ExcelParam struct { SpuCode string Name string Price float64 } type OrderList struct { Name string `json:"name"` Phone string `json:"phone"` OrderNo int64 `json:"orderNo"` } type WeimobOrderSkusExcelResult struct { DownloadUrlFine string `json:"downloadUrlFine,omitempty"` DownloadUrlHairy string `json:"downloadUrlHairy,omitempty"` } var ( sheetMap = map[string]*SheetParam{ "蔬菜": &SheetParam{ SkuIDCol: 0, SkuPriceCol: 14, SkuNameCol: 1, OrgSkuIdCol: 5, OrgSkuPriceCol: 8, OrgSkuNameCol: 6, SkuRow: 2, }, "水果": &SheetParam{ SkuIDCol: 0, SkuPriceCol: 14, SkuNameCol: 1, OrgSkuIdCol: 5, OrgSkuPriceCol: 8, OrgSkuNameCol: 6, SkuRow: 2, }, "肉禽": &SheetParam{ SkuIDCol: 0, SkuPriceCol: 12, SkuNameCol: 1, OrgSkuIdCol: 4, OrgSkuPriceCol: 7, OrgSkuNameCol: 5, SkuRow: 1, }, "净配": &SheetParam{ SkuIDCol: 0, SkuPriceCol: 14, SkuNameCol: 1, OrgSkuIdCol: 4, OrgSkuPriceCol: 7, OrgSkuNameCol: 5, SkuRow: 1, }, "水产": &SheetParam{ SkuIDCol: 1, SkuPriceCol: 15, SkuNameCol: 2, OrgSkuIdCol: 6, OrgSkuPriceCol: 9, OrgSkuNameCol: 7, SkuRow: 1, }, "干货": &SheetParam{ SkuIDCol: 0, SkuPriceCol: 13, SkuNameCol: 1, OrgSkuIdCol: 4, OrgSkuPriceCol: 7, OrgSkuNameCol: 5, SkuRow: 2, }, "MINI肉禽价格": &SheetParam{ SkuIDCol: 1, SkuPriceCol: 5, SkuNameCol: 2, OrgSkuIdCol: -1, OrgSkuPriceCol: -1, OrgSkuNameCol: -1, SkuRow: 1, }, } titleListStoreSkusSuccess = []string{ "门店ID", "商品编码", "商品名称", "单位", "原价", "现价", "涨跌", } titleListSuccess = []string{ "商品编码", "商品名称", "单位", "原价", "现价", "涨跌", } titleListFailed = []string{ "商品ID", "商品名称", "备注", } titleList = []string{ "商品编码", "商品名称", "订货数量", } dataSuccess DataSuccessLock dataFailed DataFailedLock dataStoreSkusSuccess DataStoreSkusSuccessLock ) const ( parallelCount = 5 UpdateGoodsShelfStatusCount = 50 //微盟下架商品api限制一次50个 ) func (d *DataSuccessLock) AppendData(dataSuccess DataSuccess) { d.locker.Lock() defer d.locker.Unlock() d.dataSuccessList = append(d.dataSuccessList, dataSuccess) } func (d *DataFailedLock) AppendData2(dataFailed DataFailed) { d.locker.Lock() defer d.locker.Unlock() d.dataFailedList = append(d.dataFailedList, dataFailed) } func (d *DataStoreSkusSuccessLock) AppendData3(dataStoreSkusSuccess DataStoreSkusSuccess) { d.locker.Lock() defer d.locker.Unlock() d.dataStoreSkusSuccessList = append(d.dataStoreSkusSuccessList, dataStoreSkusSuccess) } 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]*ExcelParam) costPrice float64 //成本价 goodsList []*weimobapi.GoodsInfo goodsIDListForPutAway []interface{} isCompare bool isExecute = false ) db := dao.GetDB() taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { var errMsg string 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 { errMsg += GetCellIntoMap(sheetParam, skuMap, row, k, rowNum) } } //修改分组名 // 分类名格式为:可定XX日 // XX为上传永辉 提供的 价格表时间 +2天 if errMsg == "" { isExecute = true } else { return "", fmt.Errorf(errMsg) } if isExecute { isCompare, err = UpdateClassifyAndGetLastClassify() } case 1: //获取微盟所有商品 param := &weimobapi.QueryGoodsListParam{ PageNum: 1, PageSize: jdapi.MaxSkuIDsCount4QueryListBySkuIds, } goodsList, err = GetWeiMobGoodsList(param) 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 { outPutData := DataFailed{ GoodsID: k, GoodsName: skuMap[k].Name, Comment: "在微盟上未找到该商品", } dataFailed.AppendData2(outPutData) } } 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] != nil { //获取京西库商品 skuList, _ := dao.GetSkus(db, nil, []int{int(utils.Str2Int64(goodsDetail.SkuMap.SingleSku.OuterSkuCode))}, nil, nil, nil) if len(skuList) == 0 { outPutData := DataFailed{ GoodsID: spuCode, GoodsName: skuMap[spuCode].Name, Comment: "在京西库中未找到该商品", } dataFailed.AppendData2(outPutData) } else { if skuList[0].Unit == "份" { if goodsDetail.SkuMap.SingleSku.B2CSku.Weight == 0 { costPrice = skuMap[spuCode].Price } else { costPrice = Float64Round(0.5 / goodsDetail.SkuMap.SingleSku.B2CSku.Weight * skuMap[spuCode].Price) } } else { costPrice = skuMap[spuCode].Price } if isExecute { _, _, _ = updateWeiMobGoods(costPrice, skuMap[spuCode].Price, skuList[0].Unit, isCompare, goodsDetail) } } } else { //下架微盟商品 retVal = []int64{goodsDetail.GoodsID} } } return retVal, err } taskParallel3 := tasksch.NewParallelTask("根据获取的微盟所有商品并更新", tasksch.NewParallelConfig().SetParallelCount(parallelCount), 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: // 批量下架微盟商品 taskFunc4 := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { int64Slice := []int64{} for _, v := range batchItemList { int64Slice = append(int64Slice, v.(int64)) } if isExecute { 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) case 4: WriteToExcel(task, dataSuccess.dataSuccessList, dataFailed.dataFailedList) } return result, err } taskSeq := tasksch.NewSeqTask2("读取永辉Excel文件修改微盟商品价格可售状态-序列任务", ctx, isContinueWhenError, taskSeqFunc, 5) 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, unit string, isCompare bool, 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 newSkuTitle string ) //查询配送方式 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)) } //商品分组(原有的分组IDs) selectedClassifyList := goodsDetail.SelectedClassifyList selectedClassifyListIDMap := make(map[int64]int64) if len(selectedClassifyList) > 0 { for _, v := range selectedClassifyList { for _, v := range v.ChildrenClassify { selectedClassifyListIDMap[v.ClassifyID] = v.ClassifyID } } } //上次上传价格和这次上传价格对比 // 4、微盟商品。两个重要分组 // 降价超0.2元,与前一日数据对比,需要将此类商品增加分类到这里,不改变原分类 // 涨价超0.2元,与前一日数据对比,需要将此类商品增加分类到这里,不改变原分类 // 其他商品,取消 这两个分类 // 同一天第二次上传的处理,需要注意是与前一天价格的对比,不是当天的价格对比。 // 5. 涨价和跌价值保留2位小数 // 需要在每个商品中增加↑0.01或↓0.02。 // 显示在商品最前的括号里,如果没有括号,需要增加。都用小写的括号,大写括号需要删除。 // 包装菜需要增加“精”,其他不需要加字,比如: // (精↓2.11)新土豆1kg/袋 // (↓2.11)新土豆1kg //salePrice 这次上传的价格 goodsDetail.SkuMap.SingleSku.SalePrice 上次上传的价格 priceMix 两次上传价格差 priceMixRound 保留两位后的价格差 if !isCompare { priceMix := salePrice - goodsDetail.SkuMap.SingleSku.SalePrice if priceMix > 0.2 { delete(selectedClassifyListIDMap, 1064198248) delete(selectedClassifyListIDMap, 1065246248) selectedClassifyListIDMap[1064198248] = 1064198248 } else if priceMix < -0.2 { delete(selectedClassifyListIDMap, 1064198248) delete(selectedClassifyListIDMap, 1065246248) selectedClassifyListIDMap[1065246248] = 1065246248 } else { delete(selectedClassifyListIDMap, 1064198248) delete(selectedClassifyListIDMap, 1065246248) } priceMixRound := Float64Round(priceMix) newSkuTitle = GetNewSkuTitle(priceMixRound, goodsDetail.Title, goodsDetail.OuterGoodsCode) } else { newSkuTitle = goodsDetail.Title } 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: newSkuTitle, IsMultiSku: goodsDetail.IsMultiSku, IsPutAway: weimobapi.GoodsTypeNormal, GoodsImageURL: goodsDetail.GoodsImageURL, GoodsID: goodsDetail.GoodsID, CategoryID: categoryID, OuterGoodsCode: goodsDetail.OuterGoodsCode, PointDeductRatio: goodsDetail.PointDeductRatio, SelectedClassifyIDList: Map2Int64Slice(selectedClassifyListIDMap), } updateGoodsParam := &weimobapi.UpdateGoodsParam{ Goods: goods, } if globals.EnableStoreWrite { goodsID, skuMap, err = api.WeimobAPI.UpdateGoods3(updateGoodsParam) if err != nil { if errExt, ok := err.(*utils.ErrorWithCode); ok { outPutData := DataFailed{ GoodsID: goodsDetail.OuterGoodsCode, GoodsName: goodsDetail.Title, Comment: errExt.ErrMsg(), } dataFailed.AppendData2(outPutData) } } else { outPutData := DataSuccess{ NameID: goodsDetail.OuterGoodsCode, Name: newSkuTitle, Unit: unit, OrgPrice: goodsDetail.SkuMap.SingleSku.SalePrice, NowPrice: salePrice, MixPrice: Float64Round(salePrice - goodsDetail.SkuMap.SingleSku.SalePrice), } dataSuccess.AppendData(outPutData) } } return goodsID, skuMap, err } func GetWeiMobGoodsList(param *weimobapi.QueryGoodsListParam) (goodsList []*weimobapi.GoodsInfo, err error) { 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 GetCellIntoMap(sheetParam *SheetParam, skuMap map[string]*ExcelParam, row []string, sheetName string, rowNum int) (errMsg string) { var ( skuID string orgSkuID string skuPrice float64 orgSkuPrice float64 skuName string orgSkuName string skuIDCol = sheetParam.SkuIDCol skuPriceCol = sheetParam.SkuPriceCol skuNameCol = sheetParam.SkuNameCol orgSkuIDCol = sheetParam.OrgSkuIdCol orgSkuPriceCol = sheetParam.OrgSkuPriceCol orgSkuNameCol = sheetParam.OrgSkuNameCol ) for k, cell := range row { if cell != "" { if k == skuIDCol && skuIDCol >= 0 { skuID = cell } if k == skuPriceCol && skuPriceCol >= 0 { if rowNum == sheetParam.SkuRow-1 { if !strings.Contains(cell, "今日供价") && !strings.Contains(cell, "单价") { errMsg += fmt.Sprintf("sheet页:[%v],Excel排版发生变化!第[%v]列今日供价附近可能增加或减少了一列,请确认!", sheetName, k+1) } } skuPrice = Float64Round(utils.Str2Float64WithDefault(cell, 0)) } if k == orgSkuIDCol && orgSkuIDCol >= 0 { orgSkuID = "0" + cell } if k == orgSkuPriceCol && orgSkuPriceCol >= 0 { if rowNum == sheetParam.SkuRow-1 { if !strings.Contains(cell, "进价") { errMsg += fmt.Sprintf("sheet页:[%v],Excel排版发生变化!第[%v]列进价附近可能增加或减少了一列,请确认!", sheetName, k+1) } } orgSkuPrice = Float64Round(utils.Str2Float64WithDefault(cell, 0)) } if k == skuNameCol && skuNameCol >= 0 { skuName = cell } if k == orgSkuNameCol && orgSkuNameCol >= 0 { orgSkuName = cell } } } if rowNum >= sheetParam.SkuRow { if rowNum == sheetParam.SkuRow { if cms.IsChineseChar(skuID) { errMsg += fmt.Sprintf("sheet页:[%v],Excel排版发生变化!第[%v]行附近可能增加了一行,请确认!", sheetName, rowNum) } } if len(skuMap) > 0 { if skuMap[skuID] != nil { if skuMap[skuID].Price != 0 && skuMap[skuID].Price != skuPrice && skuPrice != 0 { if skuPrice > skuMap[skuID].Price { BuildSkuMap(skuID, skuName, skuPrice, skuMap) } } else { BuildSkuMap(skuID, skuName, skuPrice, skuMap) } } else if skuPrice != 0 { BuildSkuMap(skuID, skuName, skuPrice, skuMap) } if skuMap[orgSkuID] != nil { if skuMap[orgSkuID].Price != 0 && skuMap[orgSkuID].Price != orgSkuPrice && orgSkuPrice != 0 { if orgSkuPrice > skuMap[orgSkuID].Price { BuildSkuMap(orgSkuID, orgSkuName, orgSkuPrice, skuMap) } } else if orgSkuPriceCol >= 0 && orgSkuIDCol >= 0 && orgSkuNameCol >= 0 { BuildSkuMap(orgSkuID, orgSkuName, orgSkuPrice, skuMap) } } else if orgSkuPrice != 0 { BuildSkuMap(orgSkuID, orgSkuName, orgSkuPrice, skuMap) } } else { BuildSkuMap(skuID, skuName, skuPrice, skuMap) BuildSkuMap(orgSkuID, orgSkuName, orgSkuPrice, skuMap) } delete(skuMap, "") } else { for i := rowNum; i < sheetParam.SkuRow; i++ { if !cms.IsChineseChar(skuID) { errMsg += fmt.Sprintf("sheet页:[%v],Excel排版发生变化!第[%v]行附近可能减少了一行,请确认!", sheetName, rowNum) } } } return errMsg } func BuildSkuMap(id, name string, price float64, skuMap map[string]*ExcelParam) { excelParam := &ExcelParam{ SpuCode: id, Price: price, Name: name, } skuMap[id] = excelParam } func Float64Round(f float64) (flt float64) { return math.Round(f*100) / 100 } func Map2Int64Slice(m map[int64]int64) (result []int64) { for _, v := range m { result = append(result, v) } return result } func UpdateClassifyAndGetLastClassify() (isCompare bool, err error) { var lastTitle string classfiyList, err := api.WeimobAPI.QueryClassifyInfoList() if len(classfiyList) > 0 { for _, v := range classfiyList { if v.ClassifyID == 1065244148 { lastTitle = v.Title } } } title := "可定" now := time.Now() afterDay := now.AddDate(0, 0, 2).Day() title += utils.Int2Str(afterDay) + "日" if lastTitle == title { return true, err } else { err = api.WeimobAPI.UpdateClassify(1065244148, title, "") return false, err } } func GetNewSkuTitle(priceMixRound float64, orgTitle, outerGoodsCode string) (name string) { var prefix = "" title1 := strings.ReplaceAll(orgTitle, "(", "(") title := strings.ReplaceAll(title1, ")", ")") if outerGoodsCode[0:1] != "0" { prefix += "(精" if priceMixRound > 0 { prefix += "↑" } else if priceMixRound < 0 { prefix += "↓" } else { prefix += ")" return GetReplaceNewTitle(title, prefix) } } else { if priceMixRound > 0 { prefix += "(↑" } else if priceMixRound < 0 { prefix += "(↓" } else { return GetReplaceNewTitle(title, prefix) } } prefix += utils.Float64ToStr(math.Abs(priceMixRound)) + ")" return GetReplaceNewTitle(title, prefix) } func GetReplaceNewTitle(title, prefix string) (newTitle string) { if title[0:1] == "(" { return strings.Replace(title, title[0:strings.Index(title, ")")+1], prefix, 1) } else { return prefix + title } } func WriteToExcel(task *tasksch.SeqTask, dataSuccess []DataSuccess, dataFailed []DataFailed) (err error) { var sheetList1 []*excel.Obj2ExcelSheetConfig var sheetList2 []*excel.Obj2ExcelSheetConfig var downloadURL1, downloadURL2, fileName1, fileName2 string excelConf1 := &excel.Obj2ExcelSheetConfig{ Title: "sheet1", Data: dataSuccess, CaptionList: titleListSuccess, } sheetList1 = append(sheetList1, excelConf1) excelConf2 := &excel.Obj2ExcelSheetConfig{ Title: "sheet1", Data: dataFailed, CaptionList: titleListFailed, } sheetList2 = append(sheetList2, excelConf2) if excelConf1 != nil { downloadURL1, fileName1, err = jxutils.UploadExeclAndPushMsg(sheetList1, "微盟已更新商品") } else { baseapi.SugarLogger.Debug("WriteToExcel: dataSuccess is nil!") } if excelConf2 != nil { downloadURL2, fileName2, err = jxutils.UploadExeclAndPushMsg(sheetList2, "缺少商品_微盟") } else { baseapi.SugarLogger.Debug("WriteToExcel: dataFailed is nil!") } if err != nil { baseapi.SugarLogger.Errorf("WriteToExcel:upload %s , %s failed error:%v", fileName1, fileName2, err) } else { noticeMsg := fmt.Sprintf("[详情点我]path1=%s, path2=%s \n", downloadURL1, downloadURL2) task.SetNoticeMsg(noticeMsg) baseapi.SugarLogger.Debugf("WriteToExcel:upload %s ,%s success, downloadURL1:%s ,downloadURL2:%s", fileName1, fileName2, downloadURL1, downloadURL2) } return err } func UpdateJxPriceByWeimob(ctx *jxcontext.Context, storeIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) { var ( storeSkuBindInfoList []interface{} skuBindInfos []*cms.StoreSkuBindInfo nameID int ) db := dao.GetDB() dataFailed.dataFailedList = dataFailed.dataFailedList[0:0] dataStoreSkusSuccess.dataStoreSkusSuccessList = dataStoreSkusSuccess.dataStoreSkusSuccessList[0:0] //获取微盟所有商品 param := &weimobapi.QueryGoodsListParam{ PageNum: 1, PageSize: jdapi.MaxSkuIDsCount4QueryListBySkuIds, } goodsList, err := GetWeiMobGoodsList(param) if err != nil { baseapi.SugarLogger.Errorf("GetWeiMobGoodsList error:%v", err) } taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { switch step { case 0: taskFunc := 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) } goodsID := goodsDetail.OuterGoodsCode unitPrice := int(utils.Float64TwoInt64(goodsDetail.SkuMap.SingleSku.CostPrice * 100)) if goodsDetail.SkuMap.SingleSku.OuterSkuCode != "" { nameID = int(utils.Str2Int64(goodsDetail.SkuMap.SingleSku.OuterSkuCode)) } else { outPutData := DataFailed{ GoodsID: goodsID, GoodsName: goodsDetail.Title, Comment: "微盟上没有该商品的商品编码", } dataFailed.AppendData2(outPutData) nameID = -1 } skuList, err := dao.GetStoreSkusByNameIDs(db, storeIDs, nameID) if len(skuList) > 0 { if goodsDetail.OuterGoodsCode != "" { if goodsDetail.IsPutAway == weimobapi.GoodsTypeNormal { storeSkuBindInfo := &cms.StoreSkuBindInfo{ NameID: nameID, UnitPrice: unitPrice, } retVal = []*cms.StoreSkuBindInfo{storeSkuBindInfo} for _, v := range skuList { outPutData := DataStoreSkusSuccess{ StoreID: v.StoreID, NameID: nameID, Name: v.Name, Unit: v.Unit, OrgPrice: utils.Str2Float64(utils.Int64ToStr(v.UnitPrice)) / 100, NowPrice: goodsDetail.SkuMap.SingleSku.CostPrice, MixPrice: Float64Round((utils.Str2Float64(utils.Int64ToStr(v.UnitPrice)) / 100) - goodsDetail.SkuMap.SingleSku.CostPrice), } dataStoreSkusSuccess.AppendData3(outPutData) } } else { //如果微盟为下架 outPutData := DataFailed{ GoodsID: goodsID, GoodsName: goodsDetail.Title, Comment: "微盟已下架", } dataFailed.AppendData2(outPutData) } } else { outPutData := DataFailed{ GoodsID: goodsID, GoodsName: goodsDetail.Title, Comment: "微盟上没有该商品的spu编码", } dataFailed.AppendData2(outPutData) } } else { outPutData := DataFailed{ GoodsID: goodsID, GoodsName: goodsDetail.Title, Comment: "京西未关注该商品", } dataFailed.AppendData2(outPutData) } return retVal, err } taskParallel := tasksch.NewParallelTask("获取微盟商品", tasksch.NewParallelConfig().SetParallelCount(parallelCount), ctx, taskFunc, goodsList) tasksch.HandleTask(taskParallel, task, true).Run() storeSkuBindInfoList, err = taskParallel.GetResult(0) case 1: for _, v := range storeSkuBindInfoList { skuBindInfos = append(skuBindInfos, v.(*cms.StoreSkuBindInfo)) } cms.UpdateStoresSkus(ctx, 0, storeIDs, skuBindInfos, false, false, isAsync, isContinueWhenError) case 2: WriteToExcel3(task, dataStoreSkusSuccess.dataStoreSkusSuccessList, dataFailed.dataFailedList) } return result, err } taskSeq := tasksch.NewSeqTask2("根据微盟商品更新京西价", ctx, isContinueWhenError, taskSeqFunc, 3) tasksch.HandleTask(taskSeq, nil, true).Run() if !isAsync { _, err = taskSeq.GetResult(0) hint = "1" } else { hint = taskSeq.GetID() } return hint, err } func WriteToExcel3(task *tasksch.SeqTask, dataSuccess []DataStoreSkusSuccess, dataFailed []DataFailed) (err error) { var sheetList1 []*excel.Obj2ExcelSheetConfig var sheetList2 []*excel.Obj2ExcelSheetConfig var downloadURL1, downloadURL2, fileName1, fileName2 string excelConf1 := &excel.Obj2ExcelSheetConfig{ Title: "sheet1", Data: dataSuccess, CaptionList: titleListStoreSkusSuccess, } sheetList1 = append(sheetList1, excelConf1) excelConf2 := &excel.Obj2ExcelSheetConfig{ Title: "sheet1", Data: dataFailed, CaptionList: titleListFailed, } sheetList2 = append(sheetList2, excelConf2) if excelConf1 != nil { downloadURL1, fileName1, err = jxutils.UploadExeclAndPushMsg(sheetList1, "京西已更新商品") } else { baseapi.SugarLogger.Debug("WriteToExcel: dataSuccess is nil!") } if excelConf2 != nil { downloadURL2, fileName2, err = jxutils.UploadExeclAndPushMsg(sheetList2, "缺少商品_京西") } else { baseapi.SugarLogger.Debug("WriteToExcel: dataFailed is nil!") } if err != nil { baseapi.SugarLogger.Errorf("WriteToExcel:upload %s , %s failed error:%v", fileName1, fileName2, err) } else { noticeMsg := fmt.Sprintf("[详情点我]path1=%s, path2=%s \n", downloadURL1, downloadURL2) task.SetNoticeMsg(noticeMsg) baseapi.SugarLogger.Debugf("WriteToExcel:upload %s ,%s success, downloadURL1:%s ,downloadURL2:%s", fileName1, fileName2, downloadURL1, downloadURL2) } return err } func GetWeimobOrders(ctx *jxcontext.Context, fromTime, toTime string, params map[string]interface{}) (result []*OrderList, err error) { if fromTime != "" && toTime != "" { fromTimeParam := utils.Str2Time(fromTime).UnixNano() / 1e6 toTimeParam := utils.Str2Time(toTime).UnixNano() / 1e6 if params["keyword"] != nil { if jxutils.GetPossibleVendorIDFromVendorOrderID(params["keyword"].(string)) > model.VendorIDUnknown { resultList, err := GetSingleOrderResultList(params) result = append(result, resultList...) return result, err } else { orderList, err := GetWeimobOrdersList(fromTimeParam, toTimeParam, params["keyword"].(string)) return orderList, err } } else { orderList, err := GetWeimobOrdersList(fromTimeParam, toTimeParam, "") return orderList, err } } if fromTime == "" && toTime == "" && params["keyword"] != nil { if jxutils.GetPossibleVendorIDFromVendorOrderID(params["keyword"].(string)) > model.VendorIDUnknown { resultList, err := GetSingleOrderResultList(params) result = append(result, resultList...) return result, err } else { orderList, err := GetWeimobOrdersList(0, 0, params["keyword"].(string)) return orderList, err } } return result, err } func GetWeimobOrdersList(fromTimeParam, toTimeParam int64, keyword string) (aList []*OrderList, err error) { var queryParameter *weimobapi.MerchantOrderListQueryParameter if fromTimeParam == 0 && toTimeParam == 0 { queryParameter = &weimobapi.MerchantOrderListQueryParameter{ CreateStartTime: time.Now().AddDate(0, -2, 0).UnixNano() / 1e6, CreateEndTime: time.Now().UnixNano() / 1e6, } } else { queryParameter = &weimobapi.MerchantOrderListQueryParameter{ CreateStartTime: fromTimeParam, CreateEndTime: toTimeParam, } } param := &weimobapi.QueryOrdersListParam{ PageNum: 1, PageSize: weimobapi.QueryOrdersListPageSize, QueryParameter: queryParameter, } for { orderList, _, err2 := api.WeimobAPI.QueryOrdersList(param) err = err2 if len(orderList) > 0 { if keyword != "" { for _, v := range orderList { if ContainsKeyword(v, keyword) { var aOrder = &OrderList{ Name: v.ReceiverName, OrderNo: v.OrderNo, Phone: v.ReceiverMobile, } aList = append(aList, aOrder) } } } else { for _, v := range orderList { var aOrder = &OrderList{ Name: v.ReceiverName, OrderNo: v.OrderNo, Phone: v.ReceiverMobile, } aList = append(aList, aOrder) } } } if len(orderList) < param.PageSize { break } param.PageNum++ } return aList, err } func GetWeimobOrderDetail(orderNo int64) (order *weimobapi.OrderDetail, err error) { order, err = api.WeimobAPI.QueryOrderDetail2(orderNo, false) if err != nil { return nil, err } return order, err } func GetSingleOrderResultList(params map[string]interface{}) (result []*OrderList, err error) { weimobOrderID := params["keyword"].(string) orderSingle, err := GetWeimobOrderDetail(utils.Str2Int64(weimobOrderID)) orderList := &OrderList{ Name: orderSingle.DeliveryDetail.LogisticsDeliveryDetail.ReceiverName, Phone: orderSingle.DeliveryDetail.LogisticsDeliveryDetail.ReceiverMobile, OrderNo: orderSingle.OrderNo, } result = append(result, orderList) return result, err } func ContainsKeyword(v *weimobapi.OrderInfo, keyword string) bool { return strings.Contains(v.ReceiverName, keyword) || strings.Contains(utils.Int64ToStr(v.OrderNo), keyword) || strings.Contains(v.ReceiverMobile, keyword) } func GetWeimobOrdersExcel(ctx *jxcontext.Context, OrderNo string) (result *WeimobOrderSkusExcelResult, err error) { var ( DataFineList []*Data //精品 DataHairyList []*Data //毛菜 ) orderSingle, err := GetWeimobOrderDetail(utils.Str2Int64(OrderNo)) if err != nil { return result, err } if len(orderSingle.ItemList) > 0 { itemList := orderSingle.ItemList for _, v := range itemList { if v.GoodsCode != "" { var goodsTile string if v.GoodsTitle[0:1] == "(" { goodsTile = v.GoodsTitle[strings.Index(v.GoodsTitle, ")")+1 : len(v.GoodsTitle)] } else { goodsTile = v.GoodsTitle } if v.GoodsCode[0:1] == "0" { DataHairy := &Data{ GoodsID: v.GoodsCode[1:len(v.GoodsCode)], GoodsName: goodsTile, GoodsNum: v.SkuNum, } DataHairyList = append(DataHairyList, DataHairy) } else { DataFine := &Data{ GoodsID: v.GoodsCode, GoodsName: goodsTile, GoodsNum: v.SkuNum, } DataFineList = append(DataFineList, DataFine) } } else { return result, errors.New(fmt.Sprintf("此订单中该商品无spu编码,请检查!订单号:[%v] ,商品名: [%v]", OrderNo, v.GoodsTitle)) } } } else { return result, errors.New(fmt.Sprintf("此订单中无商品信息,请检查!订单号:[%v]", OrderNo)) } downloadURL1, downloadURL2, err := WriteToExcel2(ctx, DataFineList, DataHairyList) result = &WeimobOrderSkusExcelResult{ DownloadUrlFine: downloadURL1, DownloadUrlHairy: downloadURL2, } return result, err } func WriteToExcel2(ctx *jxcontext.Context, DataFineList, DataHairyList []*Data) (downloadURL1, downloadURL2 string, err error) { var ( sheetList1 []*excel.Obj2ExcelSheetConfig sheetList2 []*excel.Obj2ExcelSheetConfig fileName1, fileName2 string noticeMsg string ) excelConf1 := &excel.Obj2ExcelSheetConfig{ Title: "sheet1", Data: DataFineList, CaptionList: titleList, } sheetList1 = append(sheetList1, excelConf1) excelConf2 := &excel.Obj2ExcelSheetConfig{ Title: "sheet1", Data: DataHairyList, CaptionList: titleList, } sheetList2 = append(sheetList2, excelConf2) noticeMsg += "[详情点我]" if len(DataFineList) > 0 { downloadURL1, fileName1, err = jxutils.UploadExeclAndPushMsg(sheetList1, "京西采购_精品") noticeMsg += "path1=" + downloadURL1 + " " } else { baseapi.SugarLogger.Debug("WriteToExcel: DataFineList is nil!") } if len(DataHairyList) > 0 { downloadURL2, fileName2, err = jxutils.UploadExeclAndPushMsg(sheetList2, "京西采购_毛菜") noticeMsg += "path2=" + downloadURL2 } else { baseapi.SugarLogger.Debug("WriteToExcel: DataHairyList is nil!") } if err != nil { baseapi.SugarLogger.Errorf("WriteToExcel:upload %s , %s failed error:%v", fileName1, fileName2, err) } else { if authInfo, err := ctx.GetV2AuthInfo(); err == nil { ddmsg.SendUserMessage(dingdingapi.MsgTyeText, authInfo.UserID, "导出微盟订单商品成功", noticeMsg) baseapi.SugarLogger.Debugf("WriteToExcel:upload %s ,%s success, downloadURL1:%s ,downloadURL2:%s", fileName1, fileName2, downloadURL1, downloadURL2) } } return downloadURL1, downloadURL2, err }