package cms import ( "fmt" "git.rosy.net.cn/baseapi/platformapi/dingdingapi" "git.rosy.net.cn/jx-callback/business/jxutils/ddmsg" "github.com/astaxie/beego" "strconv" "strings" "sync" "time" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/baseapi" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxutils" "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/partner" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api/apimanager" ) const ( canWriteTolocal = false needStatistic = false isFilterToBeCreateAndNotSale = true parallelCount = 5 fileExt = ".xlsx" ) //错误类型 const ( DatAanalyse1 = "京西门店未关注,应删除对应的平台门店商品" DatAanalyse2 = "平台商品库未创建成功(可能无经营许可等) " DatAanalyse3 = "商品名不同 " DatAanalyse4 = "商品可售状态不同 " DatAanalyse5 = "京西商品库没有,平台商品库有 " DatAanalyse6 = "京西商品库有,平台商品库没有" DatAanalyse7 = "同步状态异常" DatAanalyse8 = "平台门店未关注或平台门店商品库存为0,应添加对应的平台门店商品" DatAanalyse9 = "平台门店价格与京西商品库价格不一致" DatAanalyse10 = "平台商品的VendorSkuID与京西的VendorSkuID不一致" ) var ( diffFileName = map[bool]string{ true: "export/JXCSAndVendorSkuDiff", false: "export/JXGYAndVendorSkuDiff", } vendorNameList = map[int]string{ model.VendorIDMTWM: model.VendorChineseNames[model.VendorIDMTWM], model.VendorIDEBAI: model.VendorChineseNames[model.VendorIDEBAI], model.VendorIDJD: model.VendorChineseNames[model.VendorIDJD], } titleList = []string{ "京西门店ID", "平台门店ID", "门店名", "SkuID", "京西美团外卖ID", "京西饿百ID", "同步状态", "待创建", "待删除", "京西商品名", "平台商品名", "京西可售状态", "平台可售状态", "京西价格", "平台价格", "数据分析", } deoptTitleList = []string{ "SkuID", "京西商品名", "平台商品名", "京西可售状态", "平台可售状态", "数据分析", } statisticTitleList = []string{ "京西和平台商品状态", "待创建", "京西可售状态", "数量", "占比", } statisticDataList = [][]string{ {"京西有,平台无", "是", "下架"}, {"京西有,平台无", "是", "上架"}, {"京西有,平台无", "否", "下架"}, {"京西有,平台无", "否", "上架"}, {"京西无,平台有", "N/A", "N/A"}, {"京西有,平台有", "是", "下架"}, {"京西有,平台有", "是", "上架"}, {"京西有,平台有", "否", "下架"}, {"京西有,平台有", "否", "上架"}, } diffData DiffDataLock depotDiffData DeoptDiffDataLock multiStoreAllSkuInfoMap map[int]map[string]map[int]*partner.SkuNameInfo multiStoreAllSkuInfoList map[int]map[string][]*partner.StoreSkuInfo skuNameInfoList []*partner.SkuNameInfo filterVendorDepotUnSaleSkuIds []int filterJxDepotUnSaleSkuIds []int ) type DiffDataLock struct { diffDataMap map[int][]DiffData locker sync.RWMutex } type DeoptDiffDataLock struct { diffDataMap map[int][]DepotDiffData locker sync.RWMutex } type DepotDiffData struct { SkuID string `json:"SkuID"` JxSkuName string `json:"京西商品名"` VendorSkuName string `json:"平台商品名"` JxStatus string `json:"京西可售状态"` VendorStatus string `json:"平台可售状态"` DatAanalyse string `json:"数据分析"` } type DiffData struct { JxStoreID string `json:"京西门店ID"` VendorStoreID string `json:"平台门店ID"` VendorStoreName string `json:"门店名"` SkuID string `json:"SkuID"` MtwmID string `json:"京西美团外卖ID"` EbaiID string `json:"京西饿百ID"` SyncStatus string `json:"同步状态"` ToBeCreate string `json:"待创建"` ToBeDel string `json:"待删除"` JxSkuName string `json:"京西商品名"` VendorSkuName string `json:"平台商品名"` JxStatus string `json:"京西可售状态"` VendorStatus string `json:"平台可售状态"` JxSkuPrice string `json:"京西价格"` /*哇,不能小写,不然会搞事情*/ VendorPrice string `json:"平台价格"` DatAanalyse string `json:"数据分析"` } type StatisticData struct { JxVendorStatus string `json:"京西和平台商品状态"` ToBeCreate string `json:"待创建"` JxSaleStatus string `json:"京西可售状态"` Count string `json:"数量"` Percent string `json:"占比"` } func (d *DeoptDiffDataLock) AppendData2(vendorID int, depotDiffData DepotDiffData) { d.locker.Lock() defer d.locker.Unlock() d.diffDataMap[vendorID] = append(d.diffDataMap[vendorID], depotDiffData) } func (d *DeoptDiffDataLock) InitData2() { d.diffDataMap = make(map[int][]DepotDiffData) } func (d *DiffDataLock) AppendData(vendorID int, diffData DiffData) { d.locker.Lock() defer d.locker.Unlock() d.diffDataMap[vendorID] = append(d.diffDataMap[vendorID], diffData) } func (d *DiffDataLock) InitData() { d.diffDataMap = make(map[int][]DiffData) } func InitMultiStoreData() { multiStoreAllSkuInfoMap = make(map[int]map[string]map[int]*partner.SkuNameInfo) multiStoreAllSkuInfoList = make(map[int]map[string][]*partner.StoreSkuInfo) } func GetMultiStoreAllSkuInfoMap(vendorID int, vendorOrgCode string) (retVal map[int]*partner.SkuNameInfo) { if multiStoreAllSkuInfoMap[vendorID] != nil { retVal = multiStoreAllSkuInfoMap[vendorID][vendorOrgCode] } return retVal } func GetMultiStoreAllSkuInfoList(vendorID int, vendorOrgCode string) (retVal []*partner.StoreSkuInfo) { if multiStoreAllSkuInfoList[vendorID] != nil { retVal = multiStoreAllSkuInfoList[vendorID][vendorOrgCode] } return retVal } //过滤掉平台下架的 func StoreSkuFullList2BareFilter(storeSkuFull []*partner.SkuNameInfo) (bareStoreSkuList []*partner.StoreSkuInfo) { for _, v := range storeSkuFull { for _, v2 := range v.SkuList { if v2.Status > model.SkuStatusDontSale { bareStoreSkuList = append(bareStoreSkuList, &v2.StoreSkuInfo) } } } return bareStoreSkuList } func GetMultiStoreAllSkuInfo(ctx *jxcontext.Context, vendorMap map[int]bool) { InitMultiStoreData() filterVendorDepotUnSaleSkuIds = filterVendorDepotUnSaleSkuIds[0:0] for vendorID, _ := range vendorNameList { //filter for vendorID if len(vendorMap) > 0 { if _, ok := vendorMap[vendorID]; !ok { continue } } if partner.IsMultiStore(vendorID) { multiHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler) for _, vendorOrgCode := range apimanager.CurAPIManager.GetAppOrgCodeList(vendorID) { allSkuNameInfoList, err := multiHandler.GetSkus(ctx, vendorOrgCode, 0, "") skuNameInfoList = allSkuNameInfoList if err != nil { baseapi.SugarLogger.Errorf("GetMultiStoreAllSkuInfo error:%v", err) } else { if multiStoreAllSkuInfoList[vendorID] != nil { multiStoreAllSkuInfoList[vendorID][vendorOrgCode] = StoreSkuFullList2BareFilter(allSkuNameInfoList) //map[平台ID:[]StoreSkuInfo1,StoreSkuInfo2...] } else { multiStoreAllSkuInfoList = make(map[int]map[string][]*partner.StoreSkuInfo) multiStoreAllSkuInfoList[vendorID] = make(map[string][]*partner.StoreSkuInfo) multiStoreAllSkuInfoList[vendorID][vendorOrgCode] = StoreSkuFullList2BareFilter(allSkuNameInfoList) //map[平台ID:[]StoreSkuInfo1,StoreSkuInfo2...] } tempMap := make(map[int]*partner.SkuNameInfo) for _, value := range allSkuNameInfoList { for _, skuInfo := range value.SkuList { //表示平台商品库未下架的 if skuInfo.Status > model.SkuStatusDontSale { filterVendorDepotUnSaleSkuIds = append(filterVendorDepotUnSaleSkuIds, skuInfo.SkuID) tempMap[skuInfo.SkuID] = value } } } multiStoreAllSkuInfoMap[vendorID] = make(map[string]map[int]*partner.SkuNameInfo) multiStoreAllSkuInfoMap[vendorID][vendorOrgCode] = tempMap //map[平台ID][map[skuID1:SkuNameInfo1,skuID2:SkuNameInfo2]...] } } } } } func GetFilterJxSkuInfoMap(jxSkuInfoList []*dao.StoreSkuNameExt) map[int]*dao.StoreSkuNameExt { filterJxSkuInfoMap := make(map[int]*dao.StoreSkuNameExt) for _, value := range jxSkuInfoList { for _, skuInfo := range value.Skus { filterJxSkuInfoMap[skuInfo.SkuID] = value } } return filterJxSkuInfoMap } func GetFilterVendorSkuInfoMap(vendorSkuInfoList []*partner.SkuNameInfo) map[int]*partner.SkuNameInfo { filterVendorSkuInfoMap := make(map[int]*partner.SkuNameInfo) for _, value := range vendorSkuInfoList { for _, skuInfo := range value.SkuList { filterVendorSkuInfoMap[skuInfo.SkuID] = value } } return filterVendorSkuInfoMap } func GetFilterJxSkuInfoMap2(jxSkuInfoList []*model.SkuAndName) map[int]*model.SkuAndName { filterVendorSkuInfoMap := make(map[int]*model.SkuAndName) for _, value := range jxSkuInfoList { filterVendorSkuInfoMap[value.ID] = value } return filterVendorSkuInfoMap } func GetFilterMultiStoreSkuInfoMap(vendorID int, vendorOrgCode string, skuInfoList []*partner.StoreSkuInfo) map[int]*partner.SkuNameInfo { allSkuInfoMap := GetMultiStoreAllSkuInfoMap(vendorID, vendorOrgCode) filterSkuInfoMap := make(map[int]*partner.SkuNameInfo) for _, value := range skuInfoList { if value.Stock > 0 { filterSkuInfoMap[value.SkuID] = allSkuInfoMap[value.SkuID] } } return filterSkuInfoMap } func GetFilterStoreList(storeList []*StoreExt, vendorMap, storeIDMap map[int]bool) (outStoreList []*StoreExt) { for _, storeInfo := range storeList { storeID := storeInfo.ID //filter for storeID if len(storeIDMap) > 0 { if _, ok := storeIDMap[storeID]; !ok { continue } } if storeInfo.StoreMaps != nil { var tempStoreMaps []*model.StoreMap for _, vendorStoreInfo := range storeInfo.StoreMaps { vendorID := vendorStoreInfo.VendorID isSyncStoreSku := int(vendorStoreInfo.IsSync) if isSyncStoreSku == 0 { continue } //filter for vendorID if len(vendorMap) > 0 { if _, ok := vendorMap[vendorID]; !ok { continue } } if _, ok := vendorNameList[vendorID]; !ok { continue } tempStoreMaps = append(tempStoreMaps, vendorStoreInfo) } if len(tempStoreMaps) > 0 { storeInfo.StoreMaps = tempStoreMaps outStoreList = append(outStoreList, storeInfo) } } } return outStoreList } func GetSkuSaleStatusName(status int) string { return model.SkuStatusName[status] } func GetBoolName(flag bool) string { if flag { return "是" } else { return "否" } } func IsSkuCanSale(saleStatus int) bool { return saleStatus == model.SkuStatusNormal } //京西平台和其他平台商品的对比 //storeIDStr 京西商家id ,vendorStoreID 平台商家id ,isJd 京东比较的标记 0不是,1是 func CompareJxAndVendor(vendorID int, storeIDStr, vendorStoreID, storeName string, filterJxSkuInfoMap map[int]*dao.StoreSkuNameExt, filterVendorSkuInfoMap map[int]*partner.SkuNameInfo, isJd int) { //utils.Writelog("进入 CompareJxAndVendor 方法") for skuID, jxSkuInfo := range filterJxSkuInfoMap { skuIDStr := utils.Int2Str(skuID) /*写京西skuIDStr*/ //utils.Writelog("skuIDStr" + skuIDStr) var jxSkuDetailName string //多规格商品不用比较数量单位 if jxSkuInfo.IsSpu == 0 { //jxSkuDetailName : 前缀 ([荐]) + 分类名(xxx水饺) + 数量单位(约..g/份) + 注释 (补充..) jxSkuDetailName = jxutils.ComposeSkuNameOriginal(jxSkuInfo.SkuName.Prefix, jxSkuInfo.SkuName.Name, jxSkuInfo.Skus[0].Comment, jxSkuInfo.SkuName.Unit, jxSkuInfo.Skus[0].SkuSpecQuality, jxSkuInfo.Skus[0].SkuSpecUnit, 0) } else { //jxSkuDetailName : 前缀 ([荐]) + 分类名(xxx水饺) + 数量单位(约..g/份) + 注释 (补充..) jxSkuDetailName = jxutils.ComposeSkuNameOriginal(jxSkuInfo.SkuName.Prefix, jxSkuInfo.SkuName.Name, jxSkuInfo.Skus[0].Comment, "", jxSkuInfo.Skus[0].SkuSpecQuality, "", 0) } //utils.Writelog("jxSkuDetailName:" + jxSkuDetailName) //jxSkuSaleStatus : 商品状态 ,skustatus 优先级高于 StoreSkuStatus jxSkuSaleStatus := jxutils.MergeSkuStatus(jxSkuInfo.Skus[0].SkuStatus, jxSkuInfo.Skus[0].StoreSkuStatus) jxSkuSaleStatusName := GetSkuSaleStatusName(jxSkuSaleStatus + 3) /*京西价格*/ jxSkuPrice := fmt.Sprintf("%.2f", float64(jxSkuInfo.Skus[0].JxPrice)/float64(100)) /*饿了吗编码*/ ebaiid := jxSkuInfo.Skus[0].EbaiID /*美团编码*/ mtwmid := jxSkuInfo.Skus[0].MtwmID //jxSkuPrice := strconv.Itoa(jxSkuInfo.Skus[0].JxPrice) vendorSkuInfo := filterVendorSkuInfoMap[skuID] var status int8 if vendorID == model.VendorIDMTWM { status = jxSkuInfo.Skus[0].MtwmSyncStatus } else if vendorID == model.VendorIDEBAI { status = jxSkuInfo.Skus[0].EbaiSyncStatus } else if vendorID == model.VendorIDJD { status = jxSkuInfo.Skus[0].JdSyncStatus } syncStatus := utils.Int2Str(int(status)) toBeCreate := GetBoolName(model.IsSyncStatusNeedCreate(status)) toBeDel := GetBoolName(model.IsSyncStatusNeedDelete(status)) if vendorSkuInfo != nil { vendorSkuDetailName := vendorSkuInfo.SkuList[0].SkuName vendorSkuSaleStatusName := GetSkuSaleStatusName(vendorSkuInfo.SkuList[0].Status + 3) /* 供货商价格 */ vendorPrice := fmt.Sprintf("%.2f", float64(vendorSkuInfo.SkuList[0].StoreSkuInfo.VendorPrice)/float64(100)) var IdMark bool if isJd == 0 { IdMark = skuIDStr != ebaiid && skuIDStr != mtwmid } else { IdMark = false } isSaleStatusDiff := jxSkuSaleStatusName != vendorSkuSaleStatusName isNameDiff := jxSkuDetailName != vendorSkuDetailName /*比较价格*/ isPriceDiff := vendorPrice != jxSkuPrice //utils.Writelog("isSaleStatusDiff:" + strconv.FormatBool(isSaleStatusDiff)) //utils.Writelog("isNameDiff:" + strconv.FormatBool(isNameDiff)) if jxSkuDetailName != "" && vendorSkuDetailName != "" && strings.Contains(jxSkuDetailName, vendorSkuDetailName) { isNameDiff = false } if isSaleStatusDiff || isNameDiff || isPriceDiff { reason := "" if isNameDiff { reason += DatAanalyse3 } if isSaleStatusDiff { reason += DatAanalyse4 } if isPriceDiff { reason += DatAanalyse9 } if IdMark { reason += DatAanalyse10 } if status != model.SkuStatusDontSale { reason += DatAanalyse7 } outPutData := DiffData{storeIDStr, vendorStoreID, storeName, skuIDStr, mtwmid, ebaiid, syncStatus, toBeCreate, toBeDel, jxSkuDetailName, vendorSkuDetailName, jxSkuSaleStatusName, vendorSkuSaleStatusName, jxSkuPrice, vendorPrice, reason} diffData.AppendData(vendorID, outPutData) } if !isSaleStatusDiff && !isNameDiff { if status != model.SkuStatusDontSale { outPutData := DiffData{storeIDStr, vendorStoreID, storeName, skuIDStr, mtwmid, ebaiid, syncStatus, toBeCreate, toBeDel, jxSkuDetailName, vendorSkuDetailName, jxSkuSaleStatusName, vendorSkuSaleStatusName, jxSkuPrice, vendorPrice, DatAanalyse7} diffData.AppendData(vendorID, outPutData) } } } else { if isFilterToBeCreateAndNotSale && model.IsSyncStatusNeedCreate(status) && !IsSkuCanSale(jxSkuSaleStatus) { continue } reason := "" if status == model.SkuStatusDontSale { reason = DatAanalyse8 } else { reason = DatAanalyse2 } if status != model.SkuStatusDontSale { reason += DatAanalyse7 } outPutData := DiffData{storeIDStr, vendorStoreID, storeName, skuIDStr, mtwmid, ebaiid, syncStatus, toBeCreate, toBeDel, jxSkuDetailName, "", jxSkuSaleStatusName, "", jxSkuPrice, "", reason} diffData.AppendData(vendorID, outPutData) } } for skuID, vendorSkuInfo := range filterVendorSkuInfoMap { if vendorSkuInfo != nil { if len(vendorSkuInfo.SkuList) > 0 { skuIDStr := utils.Int2Str(skuID) vendorSkuDetailName := vendorSkuInfo.SkuList[0].SkuName vendorSkuSaleStatusName := GetSkuSaleStatusName(vendorSkuInfo.SkuList[0].Status + 3) /* 供货商价格 */ vendorPrice := fmt.Sprintf("%.2f", float64(vendorSkuInfo.SkuList[0].StoreSkuInfo.VendorPrice)/float64(100)) /* 供货商价格 */ jxSkuInfo := filterJxSkuInfoMap[skuID] /*平台有,京西没有*/ if jxSkuInfo == nil { outPutData := DiffData{storeIDStr, vendorStoreID, "", "", storeName, skuIDStr, "", "", "", "", vendorSkuDetailName, "", vendorSkuSaleStatusName, "", vendorPrice, DatAanalyse1} diffData.AppendData(vendorID, outPutData) } } else { globals.SugarLogger.Warnf("CompareJxAndVendor vendorSkuInfo.SkuList:%d is nil", skuID) } } else { globals.SugarLogger.Warnf("CompareJxAndVendor skuID:%d is nil", skuID) } } } func FilterJxDepotUnSaleSkuID() { db := dao.GetDB() filterJxDepotUnSaleSkuIds = filterJxDepotUnSaleSkuIds[0:0] skuList, _ := dao.GetSkus(db, filterVendorDepotUnSaleSkuIds, []int{}, []int{}, []int{}, nil) filterJxSkuInfoMap2 := GetFilterJxSkuInfoMap2(skuList) for skuid, jxSkuInfo := range filterJxSkuInfoMap2 { //过滤掉平台库下架,且京西库下架的商品,为下面比较门店商品用 if jxSkuInfo.Status != model.SkuStatusDontSale { filterJxDepotUnSaleSkuIds = append(filterJxDepotUnSaleSkuIds, skuid) } } } func CompareJxAndMultiVenderDepot(ctx *jxcontext.Context, vendorMap map[int]bool) { db := dao.GetDB() for vendorID, _ := range vendorNameList { //filter for vendorID if len(vendorMap) > 0 { if _, ok := vendorMap[vendorID]; !ok { continue } } if partner.IsMultiStore(vendorID) { FilterJxDepotUnSaleSkuID() filterVendorSkuInfoMap := GetFilterVendorSkuInfoMap(skuNameInfoList) skuNameInfoList = skuNameInfoList[0:0] skuList, _ := dao.GetSkus(db, []int{}, []int{}, []int{}, []int{}, nil) filterJxSkuInfoMap2 := GetFilterJxSkuInfoMap2(skuList) for skuid, jxSkuInfo := range filterJxSkuInfoMap2 { var jxSkuDetailName string //多规格商品不用比较数量单位 if jxSkuInfo.IsSpu == 0 { jxSkuDetailName = jxutils.ComposeSkuNameOriginal(jxSkuInfo.Prefix, jxSkuInfo.Name, jxSkuInfo.Comment, jxSkuInfo.Unit, jxSkuInfo.SpecQuality, jxSkuInfo.SpecUnit, 0) } else { jxSkuDetailName = jxutils.ComposeSkuNameOriginal(jxSkuInfo.Prefix, jxSkuInfo.Name, jxSkuInfo.Comment, "", jxSkuInfo.SpecQuality, "", 0) } vendorSkuInfoMap := filterVendorSkuInfoMap[skuid] jxSkuSaleStatus := jxSkuInfo.Status jxSkuSaleStatusName := GetSkuSaleStatusName(jxSkuSaleStatus) skuIDStr := utils.Int2Str(skuid) if vendorSkuInfoMap != nil { vendorSkuSaleStatusName := GetSkuSaleStatusName(vendorSkuInfoMap.SkuList[0].Status) vendorSkuDetailName := vendorSkuInfoMap.SkuList[0].SkuName isSaleStatusDiff := jxSkuSaleStatusName != vendorSkuSaleStatusName isNameDiff := strings.Compare(jxSkuDetailName, vendorSkuDetailName) != 0 if isNameDiff || isSaleStatusDiff { reason := "" if isNameDiff { reason += DatAanalyse3 } if isSaleStatusDiff { reason += DatAanalyse4 } outPutData := DepotDiffData{skuIDStr, jxSkuDetailName, vendorSkuDetailName, jxSkuSaleStatusName, vendorSkuSaleStatusName, reason} depotDiffData.AppendData2(vendorID, outPutData) } } else { outPutData := DepotDiffData{skuIDStr, jxSkuDetailName, "", jxSkuSaleStatusName, "", DatAanalyse6} depotDiffData.AppendData2(vendorID, outPutData) } } for skuID, vendorSkuInfo := range filterVendorSkuInfoMap { if vendorSkuInfo != nil { if len(vendorSkuInfo.SkuList) > 0 { skuIDStr := utils.Int2Str(skuID) vendorSkuDetailName := vendorSkuInfo.SkuList[0].SkuName vendorSkuSaleStatusName := GetSkuSaleStatusName(vendorSkuInfo.SkuList[0].Status + 3) jxSkuInfo := filterJxSkuInfoMap2[skuID] if jxSkuInfo == nil { outPutData := DepotDiffData{skuIDStr, "", vendorSkuDetailName, "", vendorSkuSaleStatusName, DatAanalyse5} depotDiffData.AppendData2(vendorID, outPutData) } } else { globals.SugarLogger.Warnf("CompareJxAndMultiVenderDepot vendorSkuInfo.SkuList:%d is nil", skuID) } } else { globals.SugarLogger.Warnf("CompareJxAndMultiVenderDepot skuID:%d is nil", skuID) } } } } } func StoreOpenAll(ctx *jxcontext.Context) { db := dao.GetDB() StoreLists, err := dao.GetStoreList(db, nil, nil, []int{1}, nil, "") if err != nil { globals.SugarLogger.Debugf("商店列表获取失败") } var StoreMapLists []*model.StoreMap for _, StoreList := range StoreLists { if StoreMapLists, err = dao.GetStoresMapList(db, []int{0, 1, 3}, []int{StoreList.ID}, nil, 1, -1, "", ""); err != nil { globals.SugarLogger.Debugf("商店列表获取失败") } if len(StoreMapLists) > 0 { /*将map查询的结果全部放进数组*/ for _, StoreMapList := range StoreMapLists { /*二元运算符*/ StoreMapList.SyncStatus = StoreMapList.SyncStatus | model.SyncFlagModifiedMask StoreMapList.UpdatedAt = time.Now() StoreMapList.LastOperator = ctx.GetUserName() dao.UpdateEntity(db, StoreMapList, "SyncStatus", "UpdatedAt", "LastOperator") //} /*同步*/ if _, err = CurVendorSync.SyncStore(ctx, db, StoreMapList.VendorID, StoreList.ID, false, ctx.GetUserName()); err != nil { globals.SugarLogger.Debugf("同步失败") } } } if StoreMapLists, err = dao.GetStoresMapList(db, []int{9}, []int{StoreList.ID}, nil, 1, -1, "", ""); err != nil { globals.SugarLogger.Debugf("商店列表获取失败") } if len(StoreMapLists) == 0 { /*遍历,绑定*/ Map := &model.StoreMap{} Map.VendorStoreID = strconv.Itoa(StoreList.ID) Map.AutoPickup = 1 Map.DeliveryCompetition = 1 Map.PricePercentage = 100 Map.IsSync = 1 Map.PricePercentagePack = "京西100-100" Map.DeliveryFeeDeductionSill = 0 Map.DeliveryFeeDeductionFee = 0 Map.IsOrder = 0 if _, err := AddStoreVendorMap(ctx, db, 9, "", StoreList.ID, Map); err != nil { globals.SugarLogger.Debugf("AddStoreVendorMap调用出错,StoreID是" + strconv.Itoa(StoreList.ID)) } } /*改配送范围*/ //deliverrangetype 3 //deliverrange 3000 StoreList.DeliveryRange = "3000" StoreList.DeliveryRangeType = 3 StoreList.UpdatedAt = time.Now() StoreList.LastOperator = ctx.GetUserName() dao.UpdateEntity(db, StoreList, "DeliveryRange", "DeliveryRangeType", "LastOperator", "UpdatedAt") } } func TestDiff(ctx *jxcontext.Context, vendorIDList []int, storeIDList []int) { baseapi.SugarLogger.Debugf("CheckSkuDiffBetweenJxAndVendor start time: %v", time.Now()) startProcessTime := time.Now().Unix() vendorMap := make(map[int]bool) for _, vendorID := range vendorIDList { vendorMap[vendorID] = true //map[平台ID:true] } storeIDMap := make(map[int]bool) for _, storeID := range storeIDList { storeIDMap[storeID] = true //map[门店ID:true] } /************************************************update**************************************************/ //自己存值 a := func() { for vendorID, _ := range vendorNameList { //filter for vendorID if len(vendorMap) > 0 { if _, ok := vendorMap[vendorID]; !ok { continue } } if partner.IsMultiStore(vendorID) { multiHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler) for _, vendorOrgCode := range apimanager.CurAPIManager.GetAppOrgCodeList(vendorID) { allSkuNameInfoList, err := multiHandler.GetSkus(ctx, vendorOrgCode, 0, "") //获取单个表格对比的物品信息列表 skuNameInfoList = allSkuNameInfoList if err != nil { fmt.Println("allSkuNameInfoList赋值错误,error信息" + err.Error()) continue } //*partner.StoreSkuInfo skuNameList []*SkuNameInfo var bareStoreSkuList []*partner.StoreSkuInfo for _, v := range allSkuNameInfoList { for _, v2 := range v.SkuList { if v2.Status > model.SkuStatusDontSale { for _, v2 := range v.SkuList { bareStoreSkuList = append(bareStoreSkuList, &v2.StoreSkuInfo) } } } } //if multiStoreAllSkuInfoList[vendorID][vendorOrgCode] != nil && bareStoreSkuList != nil { if multiStoreAllSkuInfoList[vendorID] != nil && bareStoreSkuList != nil { multiStoreAllSkuInfoList[vendorID][vendorOrgCode] = bareStoreSkuList //}else if multiStoreAllSkuInfoList[vendorID][vendorOrgCode] == nil{ } else if multiStoreAllSkuInfoList[vendorID] == nil { multiStoreAllSkuInfoList = make(map[int]map[string][]*partner.StoreSkuInfo) multiStoreAllSkuInfoList[vendorID] = make(map[string][]*partner.StoreSkuInfo) multiStoreAllSkuInfoList[vendorID][vendorOrgCode] = bareStoreSkuList } tempMap := make(map[int]*partner.SkuNameInfo) for _, value := range allSkuNameInfoList { for _, skuInfo := range value.SkuList { //表示平台商品库未下架的 if skuInfo.Status > model.SkuStatusDontSale { filterVendorDepotUnSaleSkuIds = append(filterVendorDepotUnSaleSkuIds, skuInfo.SkuID) tempMap[skuInfo.SkuID] = value } } } //商品信息 if multiStoreAllSkuInfoMap[vendorID] == nil { multiStoreAllSkuInfoMap = make(map[int]map[string]map[int]*partner.SkuNameInfo) multiStoreAllSkuInfoMap[vendorID] = make(map[string]map[int]*partner.SkuNameInfo) //multiStoreAllSkuInfoMap[vendorID][vendorOrgCode] = make(map[int]*partner.SkuNameInfo) multiStoreAllSkuInfoMap[vendorID][vendorOrgCode] = tempMap } else { multiStoreAllSkuInfoMap[vendorID][vendorOrgCode] = tempMap } } } } } /************************************************update****************************************************/ //1.获取京西本地所有门店信息 store、place、user表联查 jxStoreInfoList //2.过滤所有门店信息,只留下传进来的vendorMap,storeIDMap中对应的平台和门台信息 filterStoreList //3.判断是否多平台门店,两种情况两种处理 b := func() { jxStoreInfoList, err := GetStores(ctx, "", map[string]interface{}{}, 0, -1, utils.DefaultTimeValue, utils.DefaultTimeValue, 0, 0) if err != nil { baseapi.SugarLogger.Errorf("CheckSkuDiffBetweenJxAndVendor GetStores error:%v", err) } else { //获取总共几个门店任务 filterStoreList := GetFilterStoreList(jxStoreInfoList.Stores, vendorMap, storeIDMap) diffData.InitData() jxStoreInfoListValue := filterStoreList[0] storeID := jxStoreInfoListValue.ID storeIDStr := utils.Int2Str(storeID) storeName := jxStoreInfoListValue.Name jxSkuInfoDataSingle := &dao.StoreSkuNamesInfo{} jxSkuInfoDataMulti := &dao.StoreSkuNamesInfo{} if jxStoreInfoListValue.StoreMaps != nil { var multiFlag = false var singleFlag = false var filterJxSkuInfoMapSingle map[int]*dao.StoreSkuNameExt var filterJxSkuInfoMapMulti map[int]*dao.StoreSkuNameExt for _, vendorListValue := range jxStoreInfoListValue.StoreMaps { vendorID := vendorListValue.VendorID if partner.IsMultiStore(vendorID) { if multiFlag == false { jxSkuInfoDataMulti, _ = GetStoreSkus(ctx, storeID, filterJxDepotUnSaleSkuIds, true, "", true, false, map[string]interface{}{}, 0, -1) /*重新计算价格*/ SetJxPrice(jxSkuInfoDataMulti, storeID) filterJxSkuInfoMapMulti = GetFilterJxSkuInfoMap(jxSkuInfoDataMulti.SkuNames) //map[京西商品ID:StoreSkuNameExt] multiFlag = true } } else { if singleFlag == false { jxSkuInfoDataSingle, _ = GetStoreSkus(ctx, storeID, nil, true, "", true, false, map[string]interface{}{}, 0, -1) filterJxSkuInfoMapSingle = GetFilterJxSkuInfoMap(jxSkuInfoDataSingle.SkuNames) //map[京西商品ID:StoreSkuNameExt] singleFlag = true } } vendorStoreID := vendorListValue.VendorStoreID baseapi.SugarLogger.Debugf("CheckSkuDiffBetweenJxAndVendor storeID:%d vendorID:%d vendorStoreID:%s vendorListValue:%v", storeID, vendorID, vendorStoreID, vendorListValue) if partner.IsMultiStore(vendorID) { singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler) allSkuInfoList := GetMultiStoreAllSkuInfoList(vendorID, vendorListValue.VendorOrgCode) skuBareInfoList, err := singleStoreHandler.GetStoreSkusBareInfo(ctx, vendorListValue.VendorOrgCode, nil, storeID, vendorStoreID, allSkuInfoList) if err != nil { baseapi.SugarLogger.Infof("CheckSkuDiffBetweenJxAndVendor GetStoreSkusBareInfo error:%v", err) } else if len(skuBareInfoList) > 0 { //获取京东的商品 filterSkuInfoMap := GetFilterMultiStoreSkuInfoMap(vendorID, vendorListValue.VendorOrgCode, skuBareInfoList) //map[京东商品ID:SkuNameInfo] CompareJxAndVendor(vendorID, storeIDStr, vendorStoreID, storeName, filterJxSkuInfoMapMulti, filterSkuInfoMap, 1) } } else { singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler) vendorSkuInfoList, err := singleStoreHandler.GetStoreSkusFullInfo(ctx, nil, storeID, vendorStoreID, nil) if err != nil { baseapi.SugarLogger.Infof("CheckSkuDiffBetweenJxAndVendor GetStoreSkusFullInfo error:%v", err) } else if len(vendorSkuInfoList) > 0 { //获取京东的商品 filterVendorSkuInfoMap := GetFilterVendorSkuInfoMap(vendorSkuInfoList) //map[平台商品ID:SkuNameInfo] CompareJxAndVendor(vendorID, storeIDStr, vendorStoreID, storeName, filterJxSkuInfoMapSingle, filterVendorSkuInfoMap, 0) } } } } } } /********************************第三步****************************/ c := func(data map[int][]DiffData, depotData map[int][]DepotDiffData) { var sheetList []*excel.Obj2ExcelSheetConfig for key, value := range data { sheetName := vendorNameList[key] if partner.IsMultiStore(key) { excelConfDepot := &excel.Obj2ExcelSheetConfig{ Title: sheetName + "商品库与京西商品库对比", Data: depotData[key], CaptionList: deoptTitleList, } sheetList = append(sheetList, excelConfDepot) } excelConf := &excel.Obj2ExcelSheetConfig{ Title: sheetName, Data: value, CaptionList: titleList, } sheetList = append(sheetList, excelConf) if needStatistic { statisticSheet := AddStatisticSheet(sheetName, value) sheetList = append(sheetList, statisticSheet) } baseapi.SugarLogger.Debugf("WriteToExcel:append:%s count:%d", sheetName, len(value)) } if len(sheetList) > 0 { excelBin := excel.Obj2Excel(sheetList) sheetList = nil timeStr := utils.Int64ToStr(time.Now().Unix()) diffFullFileName := diffFileName[IsJXCS()] + timeStr + fileExt if canWriteTolocal { jxutils.WriteFile(diffFullFileName, excelBin) } baseapi.SugarLogger.Debugf("WriteToExcel:save %s success", diffFullFileName) //上传 downloadURL, err := jxutils.UploadExportContent(excelBin, diffFullFileName) if err != nil { baseapi.SugarLogger.Errorf("WriteToExcel:upload %s failed error:%v", diffFullFileName, err) } else { baseapi.SugarLogger.Debugf("WriteToExcel:upload %s success, downloadURL: %s", diffFullFileName, downloadURL) /*************发送钉钉消息**************/ ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "", "异步任务完成", "京西平台对比数据上传成功:Excel下载地址是 "+downloadURL) } } else { baseapi.SugarLogger.Debug("WriteToExcel:No diff data!!!") } //} endProcessTime := time.Now().Unix() diff := endProcessTime - startProcessTime baseapi.SugarLogger.Debugf("CheckSkuDiffBetweenJxAndVendor end time: %v", time.Now()) baseapi.SugarLogger.Debugf("CheckSkuDiffBetweenJxAndVendor cost time: %d sec", diff) } apiover := make(chan int, 1) compover := make(chan int, 1) over := false /********************************第三步****************************/ /*异步任务*/ /************************************************************************************/ go func() { defer func() { if recover() != nil { beego.Info("执行任务失败") panic("API调用失败") } }() a() depotDiffData.InitData2() CompareJxAndMultiVenderDepot(ctx, vendorMap) apiover <- 0 }() /*a等待a现成执行完*/ go func() { for !over { select { case <-apiover: /*第二步 为了获取 filterJxDepotUnSaleSkuIds*/ go func() { defer func() { if recover() != nil { beego.Info("比较任务失败") panic("比较任务失败") } }() b() compover <- 0 //比较任务完成 }() /*第二步*/ case <-compover: go func() { defer func() { if recover() != nil { beego.Info("写入任务失败") panic("写入任务失败") } }() c(diffData.diffDataMap, depotDiffData.diffDataMap) fmt.Println("任务执行完成") over = true }() break } } }() /************************************************************************************/ } //入口函数,校验本地商品京西和其他平台的差异 func CheckSkuDiffBetweenJxAndVendor(ctx *jxcontext.Context, vendorIDList []int, storeIDList []int) { startProcessTime := time.Now().Unix() baseapi.SugarLogger.Debugf("CheckSkuDiffBetweenJxAndVendor start time: %v", time.Now()) vendorMap := make(map[int]bool) for _, vendorID := range vendorIDList { vendorMap[vendorID] = true //map[平台ID:true] } storeIDMap := make(map[int]bool) for _, storeID := range storeIDList { storeIDMap[storeID] = true //map[门店ID:true] } taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { switch step { case 0: //获取所有多门店平台的商品信息 //1.循环传进来的平台id,如果是多门店的平台,查询该门店京东到家平台的所有商品 //2.为multiStoreAllSkuInfoList 和 multiStoreAllSkuInfoMap 赋值 GetMultiStoreAllSkuInfo(ctx, vendorMap) case 1: //对比京西库和多门店平台的库的信息 depotDiffData.InitData2() CompareJxAndMultiVenderDepot(ctx, vendorMap) case 2: //1.获取京西本地所有门店信息 store、place、user表联查 jxStoreInfoList //2.过滤所有门店信息,只留下传进来的vendorMap,storeIDMap中对应的平台和门台信息 filterStoreList //3.判断是否多平台门店,两种情况两种处理 jxStoreInfoList, err := GetStores(ctx, "", map[string]interface{}{}, 0, -1, utils.DefaultTimeValue, utils.DefaultTimeValue, 0, 0) if err != nil { baseapi.SugarLogger.Errorf("CheckSkuDiffBetweenJxAndVendor GetStores error:%v", err) } else { filterStoreList := GetFilterStoreList(jxStoreInfoList.Stores, vendorMap, storeIDMap) diffData.InitData() //循环门店store taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { jxStoreInfoListValue := batchItemList[0].(*StoreExt) storeID := jxStoreInfoListValue.ID storeIDStr := utils.Int2Str(storeID) storeName := jxStoreInfoListValue.Name jxSkuInfoDataSingle := &dao.StoreSkuNamesInfo{} jxSkuInfoDataMulti := &dao.StoreSkuNamesInfo{} if jxStoreInfoListValue.StoreMaps != nil { var multiFlag = false var singleFlag = false var filterJxSkuInfoMapSingle map[int]*dao.StoreSkuNameExt var filterJxSkuInfoMapMulti map[int]*dao.StoreSkuNameExt for _, vendorListValue := range jxStoreInfoListValue.StoreMaps { vendorID := vendorListValue.VendorID if partner.IsMultiStore(vendorID) { if multiFlag == false { jxSkuInfoDataMulti, _ = GetStoreSkus(ctx, storeID, filterJxDepotUnSaleSkuIds, true, "", true, false, map[string]interface{}{}, 0, -1) filterJxSkuInfoMapMulti = GetFilterJxSkuInfoMap(jxSkuInfoDataMulti.SkuNames) //map[京西商品ID:StoreSkuNameExt] multiFlag = true } } else { if singleFlag == false { jxSkuInfoDataSingle, _ = GetStoreSkus(ctx, storeID, nil, true, "", true, false, map[string]interface{}{}, 0, -1) filterJxSkuInfoMapSingle = GetFilterJxSkuInfoMap(jxSkuInfoDataSingle.SkuNames) //map[京西商品ID:StoreSkuNameExt] singleFlag = true } } vendorStoreID := vendorListValue.VendorStoreID baseapi.SugarLogger.Debugf("CheckSkuDiffBetweenJxAndVendor storeID:%d vendorID:%d vendorStoreID:%s vendorListValue:%v", storeID, vendorID, vendorStoreID, vendorListValue) if partner.IsMultiStore(vendorID) { singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler) allSkuInfoList := GetMultiStoreAllSkuInfoList(vendorID, vendorListValue.VendorOrgCode) skuBareInfoList, err := singleStoreHandler.GetStoreSkusBareInfo(ctx, vendorListValue.VendorOrgCode, task, storeID, vendorStoreID, allSkuInfoList) if err != nil { baseapi.SugarLogger.Infof("CheckSkuDiffBetweenJxAndVendor GetStoreSkusBareInfo error:%v", err) } else if len(skuBareInfoList) > 0 { filterSkuInfoMap := GetFilterMultiStoreSkuInfoMap(vendorID, vendorListValue.VendorOrgCode, skuBareInfoList) //map[京东商品ID:SkuNameInfo] CompareJxAndVendor(vendorID, storeIDStr, vendorStoreID, storeName, filterJxSkuInfoMapMulti, filterSkuInfoMap, 1) } } else { singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler) vendorSkuInfoList, err := singleStoreHandler.GetStoreSkusFullInfo(ctx, task, storeID, vendorStoreID, nil) if err != nil { baseapi.SugarLogger.Infof("CheckSkuDiffBetweenJxAndVendor GetStoreSkusFullInfo error:%v", err) } else if len(vendorSkuInfoList) > 0 { filterVendorSkuInfoMap := GetFilterVendorSkuInfoMap(vendorSkuInfoList) //map[平台商品ID:SkuNameInfo] CompareJxAndVendor(vendorID, storeIDStr, vendorStoreID, storeName, filterJxSkuInfoMapSingle, filterVendorSkuInfoMap, 0) } } } } return retVal, err } taskParallel := tasksch.NewParallelTask("京西和平台商品差异对比-门店商品对比", tasksch.NewParallelConfig().SetParallelCount(parallelCount), ctx, taskFunc, filterStoreList) tasksch.HandleTask(taskParallel, task, true).Run() _, err = taskParallel.GetResult(0) if err != nil { baseapi.SugarLogger.Debugf("CheckSkuDiffBetweenJxAndVendor taskParallel error:%v", err) } } case 3: WriteToExcel(task, diffData.diffDataMap, depotDiffData.diffDataMap) endProcessTime := time.Now().Unix() diff := endProcessTime - startProcessTime baseapi.SugarLogger.Debugf("CheckSkuDiffBetweenJxAndVendor end time: %v", time.Now()) baseapi.SugarLogger.Debugf("CheckSkuDiffBetweenJxAndVendor cost time: %d sec", diff) } return result, err } taskSeq := tasksch.NewSeqTask("京西和平台商品差异对比-序列任务", ctx, taskSeqFunc, 4) tasksch.HandleTask(taskSeq, nil, true).Run() } func IsJXCS() bool { return globals.IsMainProductEnv() } func AddStatisticSheet(sheetName string, data []DiffData) (sheet *excel.Obj2ExcelSheetConfig) { statisticData := make([]StatisticData, 9) var count [9]int var percent [9]float32 totalCount := len(data) for _, rowData := range data { if rowData.JxSkuName != "" && rowData.VendorSkuName == "" { if rowData.ToBeCreate == "是" { if rowData.JxStatus == "下架" { count[0]++ } else if rowData.JxStatus == "上架" { count[1]++ } } else if rowData.ToBeCreate == "否" { if rowData.JxStatus == "下架" { count[2]++ } else if rowData.JxStatus == "上架" { count[3]++ } } } else if rowData.JxSkuName == "" && rowData.VendorSkuName != "" { if rowData.ToBeCreate == "" && rowData.JxStatus == "" { count[4]++ } } else if rowData.JxSkuName != "" && rowData.VendorSkuName != "" { if rowData.ToBeCreate == "是" { if rowData.JxStatus == "下架" { count[5]++ } else if rowData.JxStatus == "上架" { count[6]++ } } else if rowData.ToBeCreate == "否" { if rowData.JxStatus == "下架" { count[7]++ } else if rowData.JxStatus == "上架" { count[8]++ } } } } for index, value := range count { percent[index] = float32(value*100) / float32(totalCount) countStr := utils.Int2Str(value) percentStr := fmt.Sprintf("%.2f%%", percent[index]) subStatisticData := statisticDataList[index] statisticData[index] = StatisticData{subStatisticData[0], subStatisticData[1], subStatisticData[2], countStr, percentStr} } sheetName = sheetName + "统计" sheet = &excel.Obj2ExcelSheetConfig{ Title: sheetName, Data: statisticData, CaptionList: statisticTitleList, } return sheet } func WriteToExcel(task *tasksch.SeqTask, data map[int][]DiffData, depotData map[int][]DepotDiffData) { var sheetList []*excel.Obj2ExcelSheetConfig for key, value := range data { sheetName := vendorNameList[key] if partner.IsMultiStore(key) { excelConfDepot := &excel.Obj2ExcelSheetConfig{ Title: sheetName + "商品库与京西商品库对比", Data: depotData[key], CaptionList: deoptTitleList, } sheetList = append(sheetList, excelConfDepot) } excelConf := &excel.Obj2ExcelSheetConfig{ Title: sheetName, Data: value, CaptionList: titleList, } sheetList = append(sheetList, excelConf) if needStatistic { statisticSheet := AddStatisticSheet(sheetName, value) sheetList = append(sheetList, statisticSheet) } baseapi.SugarLogger.Debugf("WriteToExcel:append:%s count:%d", sheetName, len(value)) } if len(sheetList) > 0 { excelBin := excel.Obj2Excel(sheetList) sheetList = nil timeStr := utils.Int64ToStr(time.Now().Unix()) diffFullFileName := diffFileName[IsJXCS()] + timeStr + fileExt if canWriteTolocal { jxutils.WriteFile(diffFullFileName, excelBin) } baseapi.SugarLogger.Debugf("WriteToExcel:save %s success", diffFullFileName) //上传 downloadURL, err := jxutils.UploadExportContent(excelBin, diffFullFileName) if err != nil { baseapi.SugarLogger.Errorf("WriteToExcel:upload %s failed error:%v", diffFullFileName, err) } else { noticeMsg := fmt.Sprintf("[详情点我]%s/billshow/?normal=true&path=%s \n", globals.BackstageHost, downloadURL) task.SetNoticeMsg(noticeMsg) baseapi.SugarLogger.Debugf("WriteToExcel:upload %s success, downloadURL:%s", diffFullFileName, downloadURL) } } else { baseapi.SugarLogger.Debug("WriteToExcel:No diff data!!!") } } func SetJxPrice(jxSkuInfoDataMulti *dao.StoreSkuNamesInfo, storeId int) (err error) { db := dao.GetDB() storeDetail, err := dao.GetStoreDetail(dao.GetDB(), storeId, model.VendorIDJX) if err != nil { dao.Rollback(db) return err } /*重新计算京西价格*/ for _, values := range jxSkuInfoDataMulti.SkuNames { for _, value := range values.Skus { value.JxPrice = jxutils.CaculatePriceByPricePack(storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage), value.JxPrice) } } /*重新计算京西价格*/ return nil }