package cms import ( "fmt" "strings" "sync" "time" "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/business/partner/putils" "git.rosy.net.cn/jx-callback/globals" ) const ( canWriteTolocal = false isFilterToBeCreateAndNotSale = !false parallelCount = 5 fileExt = ".xlsx" ) 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", "同步状态", "待创建", "待删除", "京西商品名", "平台商品名", "京西可售状态", "平台可售状态", } diffData DiffDataLock multiStoreAllSkuInfoMap map[int]map[int]*partner.SkuNameInfo multiStoreAllSkuInfoList map[int][]*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"` SyncStatus string `json:"同步状态"` ToBeCreate string `json:"待创建"` ToBeDel string `json:"待删除"` 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 IsMultiStore(vendorID int) bool { if _, ok := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler); ok { return true } return false } func InitMultiStoreData() { multiStoreAllSkuInfoMap = make(map[int]map[int]*partner.SkuNameInfo) multiStoreAllSkuInfoList = make(map[int][]*partner.StoreSkuInfo) } func GetMultiStoreAllSkuInfoMap(vendorID int) map[int]*partner.SkuNameInfo { return multiStoreAllSkuInfoMap[vendorID] } func GetMultiStoreAllSkuInfoList(vendorID int) []*partner.StoreSkuInfo { return multiStoreAllSkuInfoList[vendorID] } func GetMultiStoreAllSkuInfo(ctx *jxcontext.Context) { InitMultiStoreData() for vendorID, _ := range vendorNameList { if IsMultiStore(vendorID) { multiHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler) allSkuNameInfoList, err := multiHandler.GetSkus(ctx, 0, "", "") if err != nil { baseapi.SugarLogger.Errorf("GetMultiStoreAllSkuInfo error:%v", err) } else { multiStoreAllSkuInfoList[vendorID] = putils.StoreSkuFullList2Bare(allSkuNameInfoList) tempMap := make(map[int]*partner.SkuNameInfo) for _, value := range allSkuNameInfoList { for _, skuInfo := range value.SkuList { tempMap[skuInfo.SkuID] = value } } multiStoreAllSkuInfoMap[vendorID] = tempMap } } } } 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 GetFilterMultiStoreSkuInfoMap(vendorID int, skuInfoList []*partner.StoreSkuInfo) map[int]*partner.SkuNameInfo { allSkuInfoMap := GetMultiStoreAllSkuInfoMap(vendorID) filterSkuInfoMap := make(map[int]*partner.SkuNameInfo) for _, value := range skuInfoList { if value.Stock > 0 { filterSkuInfoMap[value.SkuID] = allSkuInfoMap[value.SkuID] } } return filterSkuInfoMap } 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 } 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) jxSkuSaleStatus := jxutils.MergeSkuStatus(jxSkuInfo.Skus2[0].SkuStatus, jxSkuInfo.Skus2[0].StoreSkuStatus) jxSkuSaleStatusName := GetSkuSaleStatusName(jxSkuSaleStatus) vendorSkuInfo := filterVendorSkuInfoMap[skuID] var status int8 if vendorID == model.VendorIDMTWM { status = jxSkuInfo.Skus2[0].MtwmSyncStatus } else if vendorID == model.VendorIDEBAI { status = jxSkuInfo.Skus2[0].EbaiSyncStatus } else if vendorID == model.VendorIDJD { status = jxSkuInfo.Skus2[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) isSaleStatusDiff := jxSkuSaleStatusName != vendorSkuSaleStatusName isNameDiff := jxSkuDetailName != vendorSkuDetailName if jxSkuDetailName != "" && vendorSkuDetailName != "" && strings.Contains(jxSkuDetailName, vendorSkuDetailName) { isNameDiff = false } if isSaleStatusDiff || isNameDiff { outPutData := DiffData{storeIDStr, vendorStoreID, storeName, skuIDStr, syncStatus, toBeCreate, toBeDel, jxSkuDetailName, vendorSkuDetailName, jxSkuSaleStatusName, vendorSkuSaleStatusName} diffData.AppendData(vendorID, outPutData) } } else { if isFilterToBeCreateAndNotSale && model.IsSyncStatusNeedCreate(status) && !IsSkuCanSale(jxSkuSaleStatus) { continue } outPutData := DiffData{storeIDStr, vendorStoreID, storeName, skuIDStr, syncStatus, toBeCreate, toBeDel, jxSkuDetailName, "", jxSkuSaleStatusName, ""} diffData.AppendData(vendorID, outPutData) } } for skuID, vendorSkuInfo := range filterVendorSkuInfoMap { skuIDStr := utils.Int2Str(skuID) vendorSkuDetailName := vendorSkuInfo.SkuList[0].SkuName vendorSkuSaleStatusName := GetSkuSaleStatusName(vendorSkuInfo.SkuList[0].Status) jxSkuInfo := filterJxSkuInfoMap[skuID] if jxSkuInfo == nil { outPutData := DiffData{storeIDStr, vendorStoreID, storeName, skuIDStr, "", "", "", "", vendorSkuDetailName, "", vendorSkuSaleStatusName} diffData.AppendData(vendorID, outPutData) } } } 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 } storeIDMap := make(map[int]bool) for _, storeID := range storeIDList { storeIDMap[storeID] = true } taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { switch step { case 0: 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 { GetMultiStoreAllSkuInfo(ctx) diffData.InitData() 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 var filterJxSkuInfoMap map[int]*StoreSkuNameExt for _, vendorListValue := range jxStoreInfoListValue.StoreMaps { vendorID := int(utils.MustInterface2Int64(vendorListValue["vendorID"])) isSyncStoreSku := int(utils.MustInterface2Int64(vendorListValue["isSync"])) if isSyncStoreSku == 0 { continue } //filter for vendorID if len(vendorMap) > 0 { if _, ok := vendorMap[vendorID]; !ok { continue } } if _, ok := vendorNameList[vendorID]; ok { 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 IsMultiStore(vendorID) { singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler) allSkuInfoList := GetMultiStoreAllSkuInfoList(vendorID) skuBareInfoList, err := singleStoreHandler.GetStoreSkusBareInfo(ctx, task, storeID, vendorStoreID, allSkuInfoList) if err != nil { baseapi.SugarLogger.Errorf("CheckSkuDiffBetweenJxAndVendor GetStoreSkusBareInfo error:%v", err) } else if len(skuBareInfoList) > 0 { filterSkuInfoMap := GetFilterMultiStoreSkuInfoMap(vendorID, skuBareInfoList) CompareJxAndVendor(vendorID, storeIDStr, vendorStoreID, storeName, filterJxSkuInfoMap, filterSkuInfoMap) } } else { singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler) vendorSkuInfoList, err := singleStoreHandler.GetStoreSkusFullInfo(ctx, task, 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, true).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, true).Run() } func IsJXCS() bool { return globals.IsMainProductEnv() } 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[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!!!") } }