package cms import ( "time" "fmt" "sync" "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/model" "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/business/partner/putils" "git.rosy.net.cn/baseapi" "git.rosy.net.cn/jx-callback/business/jxutils/tasksch" "git.rosy.net.cn/jx-callback/business/jxutils/excel" "git.rosy.net.cn/jx-callback/globals" ) const ( canWriteTolocal = false parallelCount = 5 fileExt = ".xlsx" diffFileName = "export/京西和平台商品差异" ) var ( vendorNameList = map[int]string { model.VendorIDMTWM: "美团", model.VendorIDEBAI: "饿百", model.VendorIDJD: "京东", } titleList = []string { "京西门店ID", "平台门店ID", "门店名", "SkuID", "京西商品名", "平台商品名", "京西可售状态", "平台可售状态", } diffData DiffDataLock jdAllSkuInfoMap map[int]*partner.SkuNameInfo jdAllSkuInfoList []*partner.StoreSkuInfo ) type DiffDataLock struct { diffDataMap map[int][]DiffData locker sync.RWMutex } type DiffData struct { JxStoreID string `json:"京西门店ID"` VendorStoreID string `json:"平台门店ID"` VendorStoreName string `json:"门店名"` SkuID string `json:"SkuID"` JxSkuName string `json:"京西商品名"` VendorSkuName string `json:"平台商品名"` JxStatus string `json:"京西可售状态"` VendorStatus string `json:"平台可售状态"` } 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 GetFilterJxSkuInfoMap(jxSkuInfoList []*StoreSkuNameExt) map[int]*StoreSkuNameExt { filterJxSkuInfoMap := make(map[int]*StoreSkuNameExt) for _, value := range jxSkuInfoList { for _, skuInfo := range value.Skus2 { 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 GetFilterJdSkuInfoMap(jdSkuInfoList []*partner.StoreSkuInfo) map[int]*partner.StoreSkuInfo { filterJdSkuInfoMap := make(map[int]*partner.StoreSkuInfo) for _, value := range jdSkuInfoList { if value.Stock > 0 { filterJdSkuInfoMap[value.SkuID] = value } } return filterJdSkuInfoMap } func GetJdAllSkuInfo() { if _, ok := vendorNameList[model.VendorIDJD]; ok { if jdAllSkuInfoMap == nil { jdAllSkuInfoMap = make(map[int]*partner.SkuNameInfo) ctx := jxcontext.AdminCtx vendorID := model.VendorIDJD if multiHandler, ok := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler); ok { jdAllSkuNameInfoList, err := multiHandler.GetSkus(ctx, 0, "", "") if err != nil { baseapi.SugarLogger.Errorf("GetJdAllSkuInfo error:%v", err) } else { jdAllSkuInfoList = putils.StoreSkuFullList2Bare(jdAllSkuNameInfoList) for _, value := range jdAllSkuNameInfoList { for _, skuInfo := range value.SkuList { jdAllSkuInfoMap[skuInfo.SkuID] = value } } } } } } } func GetSkuStatusName(status int) string { if status == model.SkuStatusNormal { return "可售" } else if status == model.SkuStatusDontSale { return "不可售" } else if status == model.SkuStatusDeleted { return "删除" } return "" } func CompareJxAndJd(vendorID int, storeIDStr, vendorStoreID, storeName string, filterJxSkuInfoMap map[int]*StoreSkuNameExt, filterJdSkuInfoMap map[int]*partner.StoreSkuInfo) { for skuID, jxSkuInfo := range filterJxSkuInfoMap { skuIDStr := utils.Int2Str(skuID) jxSkuDetailName := jxutils.ComposeSkuName(jxSkuInfo.SkuName.Prefix, jxSkuInfo.SkuName.Name, jxSkuInfo.Skus2[0].Comment, jxSkuInfo.SkuName.Unit, jxSkuInfo.Skus2[0].SkuSpecQuality, jxSkuInfo.Skus2[0].SkuSpecUnit, 0) jxSkuStatus := jxutils.MergeSkuStatus(jxSkuInfo.Skus2[0].SkuStatus, jxSkuInfo.Skus2[0].StoreSkuStatus) jxSkuStatusName := GetSkuStatusName(jxSkuStatus) vendorSkuInfo := filterJdSkuInfoMap[skuID] if vendorSkuInfo != nil { vendorSkuInfo := jdAllSkuInfoMap[vendorSkuInfo.SkuID] vendorSkuDetailName := vendorSkuInfo.SkuList[0].SkuName vendorSkuStatusName := GetSkuStatusName(vendorSkuInfo.SkuList[0].Status) if jxSkuStatusName != vendorSkuStatusName || jxSkuDetailName != vendorSkuDetailName { outPutData := DiffData{storeIDStr, vendorStoreID, storeName, skuIDStr, jxSkuDetailName, vendorSkuDetailName, jxSkuStatusName, vendorSkuStatusName} diffData.AppendData(vendorID, outPutData) } } else { outPutData := DiffData{storeIDStr, vendorStoreID, storeName, skuIDStr, jxSkuDetailName, "", jxSkuStatusName, ""} diffData.AppendData(vendorID, outPutData) } } for skuID, _ := range filterJdSkuInfoMap { skuIDStr := utils.Int2Str(skuID) vendorSkuInfo := jdAllSkuInfoMap[skuID] vendorSkuDetailName := vendorSkuInfo.SkuList[0].SkuName vendorSkuStatusName := GetSkuStatusName(vendorSkuInfo.SkuList[0].Status) jxSkuInfo := filterJxSkuInfoMap[skuID] if jxSkuInfo == nil { outPutData := DiffData{storeIDStr, vendorStoreID, storeName, skuIDStr, "", vendorSkuDetailName, "", vendorSkuStatusName} diffData.AppendData(vendorID, outPutData) } } } func CompareJxAndVendor(vendorID int, storeIDStr, vendorStoreID, storeName string, filterJxSkuInfoMap map[int]*StoreSkuNameExt, filterVendorSkuInfoMap map[int]*partner.SkuNameInfo) { for skuID, jxSkuInfo := range filterJxSkuInfoMap { skuIDStr := utils.Int2Str(skuID) jxSkuDetailName := jxutils.ComposeSkuName(jxSkuInfo.SkuName.Prefix, jxSkuInfo.SkuName.Name, jxSkuInfo.Skus2[0].Comment, jxSkuInfo.SkuName.Unit, jxSkuInfo.Skus2[0].SkuSpecQuality, jxSkuInfo.Skus2[0].SkuSpecUnit, 0) jxSkuStatus := jxutils.MergeSkuStatus(jxSkuInfo.Skus2[0].SkuStatus, jxSkuInfo.Skus2[0].StoreSkuStatus) jxSkuStatusName := GetSkuStatusName(jxSkuStatus) vendorSkuInfo := filterVendorSkuInfoMap[skuID] if vendorSkuInfo != nil { vendorSkuDetailName := vendorSkuInfo.SkuList[0].SkuName vendorSkuStatusName := GetSkuStatusName(vendorSkuInfo.SkuList[0].Status) if jxSkuStatusName != vendorSkuStatusName || jxSkuDetailName != vendorSkuDetailName { outPutData := DiffData{storeIDStr, vendorStoreID, storeName, skuIDStr, jxSkuDetailName, vendorSkuDetailName, jxSkuStatusName, vendorSkuStatusName} diffData.AppendData(vendorID, outPutData) } } else { outPutData := DiffData{storeIDStr, vendorStoreID, storeName, skuIDStr, jxSkuDetailName, "", jxSkuStatusName, ""} diffData.AppendData(vendorID, outPutData) } } for skuID, vendorSkuInfo := range filterVendorSkuInfoMap { skuIDStr := utils.Int2Str(skuID) vendorSkuDetailName := vendorSkuInfo.SkuList[0].SkuName vendorSkuStatusName := GetSkuStatusName(vendorSkuInfo.SkuList[0].Status) jxSkuInfo := filterJxSkuInfoMap[skuID] if jxSkuInfo == nil { outPutData := DiffData{storeIDStr, vendorStoreID, storeName, skuIDStr, "", vendorSkuDetailName, "", vendorSkuStatusName} diffData.AppendData(vendorID, outPutData) } } } func CheckSkuDiffBetweenJxAndVendor(vendorIDList []int, storeIDList []int) { startProcessTime := time.Now().Unix() vendorMap := make(map[int]bool) for _, vendorID := range vendorIDList { vendorMap[vendorID] = true } storeIDMap := make(map[int]bool) for _, storeID := range storeIDList { storeIDMap[storeID] = true } baseapi.SugarLogger.Debugf("CheckSkuDiffBetweenJxAndVendor start time: %v", time.Now()) ctx := jxcontext.AdminCtx 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 { GetJdAllSkuInfo() diffData.InitData() 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) { jxStoreInfoListValue := batchItemList[0].(*StoreExt) storeID := jxStoreInfoListValue.ID //filter for storeID if len(storeIDMap) > 0 { if _, ok := storeIDMap[storeID]; !ok { return retVal, err } } storeIDStr := utils.Int2Str(storeID) storeName := jxStoreInfoListValue.Name if jxStoreInfoListValue.StoreMaps != nil { isGetJxSkuInfoData := false for _, vendorListValue := range jxStoreInfoListValue.StoreMaps { vendorID := int(utils.MustInterface2Int64(vendorListValue["vendorID"])) //filter for vendorID if len(vendorMap) > 0 { if _, ok := vendorMap[vendorID]; !ok { continue } } if _, ok := vendorNameList[vendorID]; ok { var filterJxSkuInfoMap map[int]*StoreSkuNameExt if isGetJxSkuInfoData == false {//only get once jx sku info list every store id isGetJxSkuInfoData = true jxSkuInfoData, _ := GetStoreSkus(ctx, storeID, []int{}, true, "", true, map[string]interface{}{}, 0, -1) filterJxSkuInfoMap = GetFilterJxSkuInfoMap(jxSkuInfoData.SkuNames) } vendorStoreID := utils.Interface2String(vendorListValue["vendorStoreID"]) baseapi.SugarLogger.Debugf("CheckSkuDiffBetweenJxAndVendor storeID:%d vendorID:%d vendorStoreID:%s vendorListValue:%v", storeID, vendorID, vendorStoreID, vendorListValue) if vendorID == model.VendorIDJD { singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler) jdSkuInfoList, err := singleStoreHandler.GetStoreSkusBareInfo(ctx, nil, storeID, vendorStoreID, jdAllSkuInfoList) if err != nil { baseapi.SugarLogger.Errorf("CheckSkuDiffBetweenJxAndVendor GetStoreSkusBareInfo error:%v", err) } else if len(jdSkuInfoList) > 0 { filterJdSkuInfoMap := GetFilterJdSkuInfoMap(jdSkuInfoList) CompareJxAndJd(vendorID, storeIDStr, vendorStoreID, storeName, filterJxSkuInfoMap, filterJdSkuInfoMap) } } else { singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler) vendorSkuInfoList, err := singleStoreHandler.GetStoreSkusFullInfo(ctx, nil, storeID, vendorStoreID, nil) if err != nil { baseapi.SugarLogger.Errorf("CheckSkuDiffBetweenJxAndVendor GetStoreSkusFullInfo error:%v", err) } else if len(vendorSkuInfoList) > 0 { filterVendorSkuInfoMap := GetFilterVendorSkuInfoMap(vendorSkuInfoList) CompareJxAndVendor(vendorID, storeIDStr, vendorStoreID, storeName, filterJxSkuInfoMap, filterVendorSkuInfoMap) } } } } } return retVal, err } taskParallel := tasksch.NewParallelTask("CheckSkuDiffBetweenJxAndVendor", tasksch.NewParallelConfig().SetParallelCount(parallelCount), ctx, taskFunc, jxStoreInfoList.Stores) tasksch.HandleTask(taskParallel, task, false).Run() _, err = taskParallel.GetResult(0) if err != nil { baseapi.SugarLogger.Debugf("CheckSkuDiffBetweenJxAndVendor taskParallel error:%v", err) } case 1: WriteToExcel(task, diffData.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("CheckSkuDiffBetweenJxAndVendor SeqTask", ctx, taskSeqFunc, 2) tasksch.HandleTask(taskSeq, nil, false).Run() } } func WriteToExcel(task *tasksch.SeqTask, data map[int][]DiffData) { var sheetList []*excel.Obj2ExcelSheetConfig for key, value := range data { sheetName := vendorNameList[key] excelConf := &excel.Obj2ExcelSheetConfig{ Title: sheetName, Data: value, CaptionList: titleList, } sheetList = append(sheetList, excelConf) baseapi.SugarLogger.Debugf("WriteToExcel:append:%s count:%d", sheetName, len(value)) } if len(sheetList) > 0 { excelBin := excel.Obj2Excel(sheetList) timeStr := utils.Int64ToStr(time.Now().Unix()) diffFullFileName := diffFileName + 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!!!") } }