diff --git a/business/jxstore/cms/store_sku_check.go b/business/jxstore/cms/store_sku_check.go index 34dd94871..eed0d6c1f 100644 --- a/business/jxstore/cms/store_sku_check.go +++ b/business/jxstore/cms/store_sku_check.go @@ -5,6 +5,7 @@ import ( "strings" "sync" "time" + "git.rosy.net.cn/baseapi" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxutils" @@ -18,17 +19,17 @@ import ( ) const ( - canWriteTolocal = false - needStatistic = true + canWriteTolocal = false + needStatistic = true isFilterToBeCreateAndNotSale = true - parallelCount = 5 - fileExt = ".xlsx" + parallelCount = 5 + fileExt = ".xlsx" ) var ( - diffFileName = map[bool]string { - true : "export/JXCSAndVendorSkuDiff", - false : "export/JXGYAndVendorSkuDiff", + diffFileName = map[bool]string{ + true: "export/JXCSAndVendorSkuDiff", + false: "export/JXGYAndVendorSkuDiff", } vendorNameList = map[int]string{ model.VendorIDMTWM: model.VendorChineseNames[model.VendorIDMTWM], @@ -86,7 +87,7 @@ type DiffData struct { SkuID string `json:"SkuID"` SyncStatus string `json:"同步状态"` ToBeCreate string `json:"待创建"` - ToBeDel string `json:"待删除"` + ToBeDel string `json:"待删除"` JxSkuName string `json:"京西商品名"` VendorSkuName string `json:"平台商品名"` JxStatus string `json:"京西可售状态"` @@ -94,11 +95,11 @@ type DiffData struct { } type StatisticData struct { - JxVendorStatus string `json:"京西和平台商品状态"` - ToBeCreate string `json:"待创建"` - JxSaleStatus string `json:"京西可售状态"` - Count string `json:"数量"` - Percent string `json:"占比"` + JxVendorStatus string `json:"京西和平台商品状态"` + ToBeCreate string `json:"待创建"` + JxSaleStatus string `json:"京西可售状态"` + Count string `json:"数量"` + Percent string `json:"占比"` } func (d *DiffDataLock) AppendData(vendorID int, diffData DiffData) { @@ -111,14 +112,6 @@ 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) @@ -141,7 +134,7 @@ func GetMultiStoreAllSkuInfo(ctx *jxcontext.Context, vendorMap map[int]bool) { continue } } - if IsMultiStore(vendorID) { + if partner.IsMultiStore(vendorID) { multiHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler) allSkuNameInfoList, err := multiHandler.GetSkus(ctx, 0, "", "") if err != nil { @@ -267,7 +260,7 @@ func CompareJxAndVendor(vendorID int, storeIDStr, vendorStoreID, storeName strin 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) @@ -276,7 +269,7 @@ func CompareJxAndVendor(vendorID int, storeIDStr, vendorStoreID, storeName strin 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) @@ -334,7 +327,7 @@ func CheckSkuDiffBetweenJxAndVendor(ctx *jxcontext.Context, vendorIDList []int, var filterJxSkuInfoMap map[int]*StoreSkuNameExt for _, vendorListValue := range jxStoreInfoListValue.StoreMaps { vendorID := int(utils.MustInterface2Int64(vendorListValue["vendorID"])) - + 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) @@ -344,7 +337,7 @@ func CheckSkuDiffBetweenJxAndVendor(ctx *jxcontext.Context, vendorIDList []int, vendorStoreID := utils.Interface2String(vendorListValue["vendorStoreID"]) baseapi.SugarLogger.Debugf("CheckSkuDiffBetweenJxAndVendor storeID:%d vendorID:%d vendorStoreID:%s vendorListValue:%v", storeID, vendorID, vendorStoreID, vendorListValue) - if IsMultiStore(vendorID) { + if partner.IsMultiStore(vendorID) { singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler) allSkuInfoList := GetMultiStoreAllSkuInfoList(vendorID) skuBareInfoList, err := singleStoreHandler.GetStoreSkusBareInfo(ctx, task, storeID, vendorStoreID, allSkuInfoList) @@ -433,14 +426,14 @@ func AddStatisticSheet(sheetName string, data []DiffData) (sheet *excel.Obj2Exce } } for index, value := range count { - percent[index] = float32(value * 100) / float32(totalCount) + 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 { + sheet = &excel.Obj2ExcelSheetConfig{ Title: sheetName, Data: statisticData, CaptionList: statisticTitleList, diff --git a/business/jxstore/misc/misc.go b/business/jxstore/misc/misc.go index f1e4c563e..1034089ff 100644 --- a/business/jxstore/misc/misc.go +++ b/business/jxstore/misc/misc.go @@ -104,6 +104,7 @@ func Init() { ScheduleTimerFunc("UpdateActStatusByTime", func() { dao.UpdateActStatusByTime(dao.GetDB(), time.Now().Add(-48*time.Hour)) }, updateActStatusTimeList) + ScheduleScoreStore() } ScheduleTimerFunc("AutoSaleStoreSku", func() { cms.AutoSaleStoreSku(jxcontext.AdminCtx, nil, false) diff --git a/business/jxstore/misc/misc2_test.go b/business/jxstore/misc/misc2_test.go index 38d1a9be5..e6627a75a 100644 --- a/business/jxstore/misc/misc2_test.go +++ b/business/jxstore/misc/misc2_test.go @@ -2,8 +2,10 @@ package misc import ( "testing" + + "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" ) func TestStartOrEndOpStore(t *testing.T) { - StartOrEndOpStore(1, true, 0, 0, false, true) + StartOrEndOpStore(jxcontext.AdminCtx, true, nil, nil, 0, 0, false, true) } diff --git a/business/jxstore/misc/store_score.go b/business/jxstore/misc/store_score.go new file mode 100644 index 000000000..e4949b1aa --- /dev/null +++ b/business/jxstore/misc/store_score.go @@ -0,0 +1,780 @@ +package misc + +import ( + "fmt" + "math" + "reflect" + "sync" + "time" + + "git.rosy.net.cn/baseapi" + "git.rosy.net.cn/baseapi/utils" + "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/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/refutil" +) + +const ( + EnableScheduleScoreStore = true + ParallelCount = 1 + + GoldMedalScore = 90 + SilverMedalScore = 80 + BronzeMedalScore = 70 + GoldMedalLevel = 1 + SilverMedalLevel = 2 + BronzeMedalLevel = 3 + + ItemTotalScore = 10 + + StoreOpenTimeNormalTime = 12.0 //小时 + SaleSkuNormalCount = 1000 //数量 + SaleSkuScorePerUnit = float64(ItemTotalScore) / SaleSkuNormalCount //分数 + PromotionSkuNormalCount = 20 //数量 + AveragePickupTimeNormalTime = 10.0 //分钟 + BadCommentOrderNormalRatio = 0.2 //百分比 + UnfinishOrderNormalRatio = 1.0 //百分比 + AbsentGoodsOrderNormalRatio = 1.0 //百分比 + StoreRangeGoodRadius = 2.0 //千米 + StoreRangeBadRadius = 1.0 //千米 + SaleSkuPriceRatio = 90 //千米 + SaleSkuCheckRange = 5.0 //千米 +) + +var ( + scoreStoreTimeList = []string{ + "22:00:00", + } + scoreStoreCheckTimeEnd = "23:30:00" + fullVendorList = map[int]bool{ + model.VendorIDJD: true, + model.VendorIDMTWM: true, + model.VendorIDEBAI: true, + } + storeScoreFieldName = []string{ + model.FieldStoreOpenTime, + model.FieldSaleSkuCount, + model.FieldAveragePickupTime, + model.FieldBadCommentOrder, + model.FieldUnfinishOrder, + model.FieldAbsentGoodsOrder, + model.FieldPromotionSku, + model.FieldFullVendor, + model.FieldStoreRange, + model.FieldSaleSkuPrice, + } + + storeScoreDataWrapper StoreScoreDataWrapper + allStoreSkusWrapper AllStoreSkusWrapper + scoreDate time.Time + isScoring bool +) + +type AllStoreSkusWrapper struct { + allStoreSkus map[int]map[int]int + locker sync.RWMutex +} + +func (a *AllStoreSkusWrapper) InitData() { + a.allStoreSkus = make(map[int]map[int]int) +} + +func (a *AllStoreSkusWrapper) ClearData() { + a.allStoreSkus = nil +} + +func (a *AllStoreSkusWrapper) SetData(storeID int, skuMapData map[int]int) { + a.locker.Lock() + defer a.locker.Unlock() + a.allStoreSkus[storeID] = skuMapData +} + +func (a *AllStoreSkusWrapper) GetData(storeID int) map[int]int { + a.locker.RLock() + defer a.locker.RUnlock() + return a.allStoreSkus[storeID] +} + +type StoreScoreDataWrapper struct { + storeScoreData map[int]*model.StoreScore + dailyBadCommentOrderCount map[int]int + dailyUnFinishOrderCount map[int]int + dailyFinishOrderCount map[int]int + dailyAbsentGoodsOrderCount map[int]int + locker sync.RWMutex +} + +func (s *StoreScoreDataWrapper) InitData() { + s.storeScoreData = make(map[int]*model.StoreScore) + s.dailyBadCommentOrderCount = make(map[int]int) + s.dailyUnFinishOrderCount = make(map[int]int) + s.dailyFinishOrderCount = make(map[int]int) + s.dailyAbsentGoodsOrderCount = make(map[int]int) +} + +func (s *StoreScoreDataWrapper) ClearData() { + s.storeScoreData = nil + s.dailyBadCommentOrderCount = nil + s.dailyUnFinishOrderCount = nil + s.dailyFinishOrderCount = nil + s.dailyAbsentGoodsOrderCount = nil +} + +func (s *StoreScoreDataWrapper) SetData(storeID int, valueName string, value int) { + s.locker.Lock() + defer s.locker.Unlock() + data := s.storeScoreData[storeID] + if data == nil { + data = &model.StoreScore{} + data.StoreID = storeID + data.ScoreDate = scoreDate + s.storeScoreData[storeID] = data + } + valueInfo := reflect.ValueOf(data).Elem() + valueInfo.FieldByName(valueName).SetInt(int64(value)) +} + +func (s *StoreScoreDataWrapper) SetDailyBadCommentOrderCount(storeCountList []*model.StoreCount) { + s.locker.Lock() + defer s.locker.Unlock() + for _, value := range storeCountList { + s.dailyBadCommentOrderCount[value.StoreID] = value.Count + } +} + +func (s *StoreScoreDataWrapper) GetDailyBadCommentOrderCount(storeID int) int { + s.locker.RLock() + defer s.locker.RUnlock() + if count, ok := s.dailyBadCommentOrderCount[storeID]; ok { + return count + } + + return 0 +} + +func (s *StoreScoreDataWrapper) SetDailyUnFinishOrderCount(storeCountList []*model.StoreCount) { + for _, value := range storeCountList { + s.dailyUnFinishOrderCount[value.StoreID] = value.Count + } +} + +func (s *StoreScoreDataWrapper) GetDailyUnFinishOrderCount(storeID int) int { + s.locker.RLock() + defer s.locker.RUnlock() + if count, ok := s.dailyUnFinishOrderCount[storeID]; ok { + return count + } + + return 0 +} + +func (s *StoreScoreDataWrapper) SetDailyFinishOrderCount(storeCountList []*model.StoreCount) { + for _, value := range storeCountList { + s.dailyFinishOrderCount[value.StoreID] = value.Count + } +} + +func (s *StoreScoreDataWrapper) GetDailyFinishOrderCount(storeID int) int { + s.locker.RLock() + defer s.locker.RUnlock() + if count, ok := s.dailyFinishOrderCount[storeID]; ok { + return count + } + + return 0 +} + +func (s *StoreScoreDataWrapper) SetDailyAbsentGoodsOrderCount(storeCountList []*model.StoreCount) { + for _, value := range storeCountList { + s.dailyAbsentGoodsOrderCount[value.StoreID] = value.Count + } +} + +func (s *StoreScoreDataWrapper) GetDailyAbsentGoodsOrderCount(storeID int) int { + s.locker.RLock() + defer s.locker.RUnlock() + if count, ok := s.dailyAbsentGoodsOrderCount[storeID]; ok { + return count + } + + return 0 +} + +func (s *StoreScoreDataWrapper) InsertStoreScore() { + for _, value := range s.storeScoreData { + dao.InsertStoreScore(value) + } +} + +//得到所有门店的可售商品(优化内存,只存商品的价格) +func GetAllStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeList []*cms.StoreExt) { + allStoreSkusWrapper.InitData() + taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + storeInfo := batchItemList[0].(*cms.StoreExt) + storeID := storeInfo.ID + jxSkuInfoData, _ := cms.GetStoreSkus(ctx, storeID, []int{}, true, "", true, map[string]interface{}{}, 0, -1) + jxSkuPriceMapData := make(map[int]int) + for _, value := range jxSkuInfoData.SkuNames { + for _, skuInfo := range value.Skus2 { + saleStatus := jxutils.MergeSkuStatus(skuInfo.SkuStatus, skuInfo.StoreSkuStatus) + if saleStatus == model.SkuStatusNormal { + jxSkuPriceMapData[skuInfo.SkuID] = skuInfo.BindPrice + } + } + } + allStoreSkusWrapper.SetData(storeID, jxSkuPriceMapData) + return retVal, err + } + taskParallel := tasksch.NewParallelTask("得到所有门店商品", tasksch.NewParallelConfig().SetParallelCount(ParallelCount), ctx, taskFunc, storeList) + tasksch.HandleTask(taskParallel, parentTask, true).Run() + taskParallel.GetResult(0) +} + +func GetOpenTime(opTimeList []int16) (opTime float64) { + opTime = 0 + for index, _ := range opTimeList { + if index%2 == 1 { + endTime := opTimeList[index] + startTime := opTimeList[index-1] + diffHour := float64(endTime/100 - startTime/100) + diffMin := float64(endTime%100-startTime%100) / 60 + opTime += diffHour + diffMin + } + } + return opTime +} + +//营业时间12小时及以上满分,总分10分,每少一个小时扣1分 +func ScoreStoreOpenTime(storeInfo *cms.StoreExt) { + storeID := storeInfo.ID + storeStatus := storeInfo.Status + isStoreOpen := storeStatus == model.StoreStatusOpened + finalScore := 0 + if isStoreOpen { + for _, storeMap := range storeInfo.StoreMaps { + isSyncStoreSku := int(utils.MustInterface2Int64(storeMap["isSync"])) + vendorStoreStatus := int(utils.MustInterface2Int64(storeMap["status"])) + isVendorStoreOpen := vendorStoreStatus == model.StoreStatusOpened + opTimeList := storeInfo.GetOpTimeList() + if len(opTimeList) > 0 && isStoreOpen && isVendorStoreOpen && isSyncStoreSku != 0 { + opTime := GetOpenTime(opTimeList) + if opTime >= StoreOpenTimeNormalTime { + finalScore = ItemTotalScore + } else { + decScore := int(math.Round(StoreOpenTimeNormalTime - opTime)) + finalScore = ItemTotalScore - decScore + if finalScore < 0 { + finalScore = 0 + } + } + } + } + } + storeScoreDataWrapper.SetData(storeID, model.FieldStoreOpenTime, finalScore) +} + +//可售商品数量大于1000,总分10分,按比例扣 +func ScoreSaleSkuCount(storeInfo *cms.StoreExt) { + storeID := storeInfo.ID + skusMapData := allStoreSkusWrapper.GetData(storeID) + finalScore := 0 + if len(skusMapData) > 0 { + saleSkuCount := len(skusMapData) + finalScore = int(math.Round(float64(saleSkuCount) * SaleSkuScorePerUnit)) + if finalScore > ItemTotalScore { + finalScore = ItemTotalScore + } + } + storeScoreDataWrapper.SetData(storeID, model.FieldSaleSkuCount, finalScore) +} + +//平均捡货时间小于等于拣货截止时间为10分满分,每超出1分钟,减1分 +func ScoreAveragePickupTime(storeInfo *cms.StoreExt) { + storeID := storeInfo.ID + db := dao.GetDB() + orderList, err := dao.GetDailyFinishOrderList(db, storeID, scoreDate) + orderListCount := len(orderList) + finalScore := 0 + if err == nil && orderListCount > 0 { + totalScore := 0 + for _, value := range orderList { + statusTime := value.StatusTime.Unix() + pickDeadline := value.PickDeadline.Unix() + if statusTime <= pickDeadline { + totalScore += ItemTotalScore + } else { + decScore := int(math.Round(float64(statusTime-pickDeadline) / 60)) + tempScore := ItemTotalScore - decScore + if tempScore < 0 { + tempScore = 0 + } + totalScore += tempScore + } + } + finalScore = totalScore / orderListCount + } + storeScoreDataWrapper.SetData(storeID, model.FieldAveragePickupTime, finalScore) +} + +//差评订单和完成订单比例小于0.2%,得满分10分,每增加0.1%减1分 +func ScoreBadCommentOrder(storeInfo *cms.StoreExt) { + storeID := storeInfo.ID + badCommentOrderCount := storeScoreDataWrapper.GetDailyBadCommentOrderCount(storeID) + finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID) + finalScore := 0 + if finishOrderCount > 0 { + badCommentOrderRatio := float64(badCommentOrderCount) * 100 / float64(finishOrderCount) + if badCommentOrderRatio <= BadCommentOrderNormalRatio { + finalScore = ItemTotalScore + } else { + decScore := int(math.Round((badCommentOrderRatio - BadCommentOrderNormalRatio) / 0.1)) + finalScore = ItemTotalScore - decScore + if finalScore < 0 { + finalScore = 0 + } + } + } + storeScoreDataWrapper.SetData(storeID, model.FieldBadCommentOrder, finalScore) +} + +//未完成订单和完成订单比小于1%,得满分10分,比例每增加5%,分数减1 +func ScoreUnfinishOrder(storeInfo *cms.StoreExt) { + storeID := storeInfo.ID + unFinishOrderCount := storeScoreDataWrapper.GetDailyUnFinishOrderCount(storeID) + finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID) + finalScore := 0 + if finishOrderCount > 0 { + unfinishOrderRatio := float64(unFinishOrderCount) * 100 / float64(finishOrderCount) + if unfinishOrderRatio <= UnfinishOrderNormalRatio { + finalScore = ItemTotalScore + } else { + decScore := int(math.Round((unfinishOrderRatio - UnfinishOrderNormalRatio) / 5)) + finalScore = ItemTotalScore - decScore + if finalScore < 0 { + finalScore = 0 + } + } + } + storeScoreDataWrapper.SetData(storeID, model.FieldUnfinishOrder, finalScore) +} + +//缺货订单和完成订单比小于1%得10分,比例每增加0.1%减1分 +func ScoreAbsentGoodsOrder(storeInfo *cms.StoreExt) { + storeID := storeInfo.ID + absentGoodsOrderCount := storeScoreDataWrapper.GetDailyAbsentGoodsOrderCount(storeID) + finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID) + finalScore := 0 + if finishOrderCount > 0 { + absentGoodsOrderRatio := float64(absentGoodsOrderCount) * 100 / float64(finishOrderCount) + if absentGoodsOrderRatio <= AbsentGoodsOrderNormalRatio { + finalScore = ItemTotalScore + } else { + decScore := int(math.Round((absentGoodsOrderRatio - AbsentGoodsOrderNormalRatio) / 0.1)) + finalScore = ItemTotalScore - decScore + if finalScore < 0 { + finalScore = 0 + } + } + } + storeScoreDataWrapper.SetData(storeID, model.FieldAbsentGoodsOrder, finalScore) +} + +//促销品数量20个以上为满分10分,每少2个扣1分 +func ScorePromotionSku(storeInfo *cms.StoreExt) { + storeID := storeInfo.ID + db := dao.GetDB() + beginTime := time.Now() + endTime := time.Now() + actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, -1, nil, []int{storeID}, nil, beginTime, endTime) + finalScore := 0 + if err == nil && len(actStoreSkuList) > 0 { + actStoreSkuMap := make(map[int]int) + for _, value := range actStoreSkuList { + if value.Type != model.ActSkuFake { + actStoreSkuMap[value.SkuID] = 1 + } + } + promotionSkuCount := len(actStoreSkuMap) + if promotionSkuCount >= PromotionSkuNormalCount { + finalScore = ItemTotalScore + } else { + decScore := (PromotionSkuNormalCount - promotionSkuCount) / 2 + finalScore = ItemTotalScore - decScore + if finalScore < 0 { + finalScore = 0 + } + } + } + storeScoreDataWrapper.SetData(storeID, model.FieldPromotionSku, finalScore) +} + +//经营全平台满分10分,每少一个平台扣2分(一个平台没有得0分) +func ScoreFullVendor(storeInfo *cms.StoreExt) { + fullVendorCount := len(fullVendorList) + finalScore := 0 + storeID := storeInfo.ID + storeStatus := storeInfo.Status + isStoreOpen := storeStatus == model.StoreStatusOpened + count := 0 + for _, storeMap := range storeInfo.StoreMaps { + isSyncStoreSku := int(utils.MustInterface2Int64(storeMap["isSync"])) + vendorStoreStatus := int(utils.MustInterface2Int64(storeMap["status"])) + isVendorStoreOpen := vendorStoreStatus == model.StoreStatusOpened + opTimeList := storeInfo.GetOpTimeList() + if len(opTimeList) > 0 && isStoreOpen && isVendorStoreOpen && isSyncStoreSku != 0 { + count++ + } + } + if count > 0 { + if count == fullVendorCount { + finalScore = ItemTotalScore + } else { + decScore := (fullVendorCount - count) * 2 + finalScore = ItemTotalScore - decScore + } + } + storeScoreDataWrapper.SetData(storeID, model.FieldFullVendor, finalScore) +} + +//经营范围面积大于半径2km的圆得满分10分,低于1km得分0 +func ScoreStoreRange(storeInfo *cms.StoreExt) { + finalScore := 0 + storeID := storeInfo.ID + if storeInfo.DeliveryRangeType == model.DeliveryRangeTypePolygon { + if storeInfo.DeliveryRange != "" { + points := jxutils.CoordinateStr2Points(storeInfo.DeliveryRange) + area := jxutils.CalcPolygonAreaAutonavi(points) + goodArea := math.Pi * StoreRangeGoodRadius * StoreRangeGoodRadius + badArea := math.Pi * StoreRangeBadRadius * StoreRangeBadRadius + if area >= goodArea { + finalScore = ItemTotalScore + } else if area <= badArea { + finalScore = 0 + } else { + diff := goodArea - area + ratio := float64(ItemTotalScore) / (goodArea - badArea) + finalScore = ItemTotalScore - int(math.Round(diff*ratio)) + } + } + } else if storeInfo.DeliveryRangeType == model.DeliveryRangeTypeRadius { + deliveryRadius := utils.Str2Float64WithDefault(storeInfo.DeliveryRange, 0) / 1000 + if deliveryRadius >= StoreRangeGoodRadius { + finalScore = ItemTotalScore + } else if deliveryRadius <= StoreRangeBadRadius { + finalScore = 0 + } else { + diff := StoreRangeGoodRadius - deliveryRadius + ratio := float64(ItemTotalScore) / (StoreRangeGoodRadius - StoreRangeBadRadius) + finalScore = ItemTotalScore - int(math.Round(diff*ratio)) + } + } + storeScoreDataWrapper.SetData(storeID, model.FieldStoreRange, finalScore) +} + +//得到距离某个门店多少KM内的所有门店信息 +func GetRangeStoreList(storeID int, lng, lat, checkRange float64, storeList []*cms.StoreExt) (outStoreList []*cms.StoreExt) { + for _, storeInfo := range storeList { + if storeInfo.ID == storeID { + outStoreList = append(outStoreList, storeInfo) + } else { + distance := jxutils.EarthDistance(lng, lat, storeInfo.FloatLng, storeInfo.FloatLat) + if distance <= checkRange { + outStoreList = append(outStoreList, storeInfo) + } + } + } + + return outStoreList +} + +//得到给定门店列表里的同一SkuID商品的平均价格 +func GetStoreSkusAveragePrice(storeList []*cms.StoreExt) map[int]int { + skusTotalPrice := make(map[int]int) + skusCount := make(map[int]int) + skusAveragePrice := make(map[int]int) + for _, storeInfo := range storeList { + storeID := storeInfo.ID + storeSkuMapData := allStoreSkusWrapper.GetData(storeID) + for skuID, skuPrice := range storeSkuMapData { + skusTotalPrice[skuID] += skuPrice + skusCount[skuID]++ + } + } + for id, totalPrice := range skusTotalPrice { + skusAveragePrice[id] = int(math.Round(float64(totalPrice) / float64(skusCount[id]))) + } + return skusAveragePrice +} + +func GetSkusCountLessEqualAvgPrice(storeID int, skusAveragePrice map[int]int) (count int) { + storeSkuMapData := allStoreSkusWrapper.GetData(storeID) + for skuID, skuPrice := range storeSkuMapData { + skuAvgPrice := skusAveragePrice[skuID] + if skuPrice <= skuAvgPrice { + count++ + } + } + + return count +} + +//可售商品价格在附近5km内门店比较,价格低于等于平均值的商品数占90%以上满分10分,比例每降低10%减1分,100%超标得0分 +func ScoreSaleSkuPrice(storeInfo *cms.StoreExt, storeList []*cms.StoreExt) { + finalScore := 0 + storeID := storeInfo.ID + totalCount := len(allStoreSkusWrapper.GetData(storeID)) + if totalCount > 0 { + rangeStoreList := GetRangeStoreList(storeID, storeInfo.FloatLng, storeInfo.FloatLat, SaleSkuCheckRange, storeList) + skusAveragePrice := GetStoreSkusAveragePrice(rangeStoreList) + count := GetSkusCountLessEqualAvgPrice(storeID, skusAveragePrice) + if count > 0 { + ratio := int(math.Round(float64(count) * 100 / float64(totalCount))) + if ratio >= SaleSkuPriceRatio { + finalScore = ItemTotalScore + } else { + decScore := (SaleSkuPriceRatio - ratio) / 10 + finalScore = ItemTotalScore - decScore + if finalScore < 0 { + finalScore = 0 + } + } + } + } + storeScoreDataWrapper.SetData(storeID, model.FieldSaleSkuPrice, finalScore) +} + +func GetFilterStoreListEx(storeList []*cms.StoreExt, storeIDMap map[int]int) (outStoreList []*cms.StoreExt) { + for _, storeInfo := range storeList { + storeID := storeInfo.ID + if len(storeIDMap) > 0 { + if _, ok := storeIDMap[storeID]; !ok { + continue + } + } + var tempStoreMaps []map[string]interface{} + for _, vendorStoreInfo := range storeInfo.StoreMaps { + vendorID := int(utils.MustInterface2Int64(vendorStoreInfo["vendorID"])) + if _, ok := fullVendorList[vendorID]; !ok { + continue + } + tempStoreMaps = append(tempStoreMaps, vendorStoreInfo) + } + if len(tempStoreMaps) > 0 { + storeInfo.StoreMaps = tempStoreMaps + outStoreList = append(outStoreList, storeInfo) + } + } + + return outStoreList +} + +func ScoreStore(ctx *jxcontext.Context, storeIDList []int) (retVal interface{}, err error) { + isScoring = true + scoreDate = utils.GetCurDate() + var storeList []*cms.StoreExt + taskCount := 5 + taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) { + switch step { + case 0: + baseapi.SugarLogger.Debugf("ScoreStore step0 begin") + storeScoreDataWrapper.InitData() + storeList, err = GetStoreList(ctx) + storeIDMap := jxutils.IntList2Map(storeIDList) + storeList = GetFilterStoreListEx(storeList, storeIDMap) + baseapi.SugarLogger.Debugf("ScoreStore step0 end") + case 1: + baseapi.SugarLogger.Debugf("ScoreStore step1 begin") + GetAllStoreSkus(ctx, task, storeList) + baseapi.SugarLogger.Debugf("ScoreStore step1 end") + case 2: + db := dao.GetDB() + storeCountList, _ := dao.GetDailyBadCommentOrderCount(db, scoreDate) + storeScoreDataWrapper.SetDailyBadCommentOrderCount(storeCountList) + storeCountList, _ = dao.GetDailyUnFinishOrderCount(db, scoreDate) + storeScoreDataWrapper.SetDailyUnFinishOrderCount(storeCountList) + storeCountList, _ = dao.GetDailyFinishOrderCount(db, scoreDate) + storeScoreDataWrapper.SetDailyFinishOrderCount(storeCountList) + storeCountList, _ = dao.GetDailyAbsentGoodsOrderCount(db, scoreDate) + storeScoreDataWrapper.SetDailyAbsentGoodsOrderCount(storeCountList) + case 3: + baseapi.SugarLogger.Debugf("ScoreStore step2 begin") + taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { + storeInfo := batchItemList[0].(*cms.StoreExt) + storeID := storeInfo.ID + baseapi.SugarLogger.Debugf("Begin store id:%d", storeID) + ScoreStoreOpenTime(storeInfo) + ScoreSaleSkuCount(storeInfo) + ScoreAveragePickupTime(storeInfo) + ScoreBadCommentOrder(storeInfo) + ScoreUnfinishOrder(storeInfo) + ScoreAbsentGoodsOrder(storeInfo) + ScorePromotionSku(storeInfo) + ScoreFullVendor(storeInfo) + ScoreStoreRange(storeInfo) + ScoreSaleSkuPrice(storeInfo, storeList) + baseapi.SugarLogger.Debugf("End store id:%d", storeID) + return retVal, err + } + taskParallel := tasksch.NewParallelTask("计算门店得分", tasksch.NewParallelConfig().SetParallelCount(ParallelCount), ctx, taskFunc, storeList) + tasksch.HandleTask(taskParallel, task, true).Run() + taskParallel.GetResult(0) + _, err = taskParallel.GetResult(0) + if err != nil { + baseapi.SugarLogger.Debugf("ScoreStore taskParallel error:%v", err) + } + baseapi.SugarLogger.Debugf("ScoreStore step2 end") + case 4: + baseapi.SugarLogger.Debugf("ScoreStore step3 begin") + storeScoreDataWrapper.InsertStoreScore() + storeScoreDataWrapper.ClearData() + allStoreSkusWrapper.ClearData() + baseapi.SugarLogger.Debugf("ScoreStore step3 end") + isScoring = false + } + return result, err + } + taskSeq := tasksch.NewSeqTask("门店评分-序列任务", ctx, taskSeqFunc, taskCount) + tasksch.HandleTask(taskSeq, nil, true).Run() + + return retVal, err +} + +func ScheduleScoreStore() { + if EnableScheduleScoreStore { + ScheduleTimerFunc("ScheduleScoreStore", func() { + if !isScoring { + ScoreStore(jxcontext.AdminCtx, nil) + } + }, scoreStoreTimeList) + CheckScoreStore() + } +} + +func CheckScoreStore() { + if !isScoring { + curTime := time.Now() + checkTimeStr1 := fmt.Sprintf("%s %s", utils.Time2DateStr(curTime), scoreStoreTimeList[0]) + checkTime1 := utils.Str2Time(checkTimeStr1) + checkTimeStr2 := fmt.Sprintf("%s %s", utils.Time2DateStr(curTime), scoreStoreCheckTimeEnd) + checkTime2 := utils.Str2Time(checkTimeStr2) + if curTime.Unix() >= checkTime1.Unix() && curTime.Unix() <= checkTime2.Unix() { + db := dao.GetDB() + hasStoreScoreData, err := dao.CheckHasStoreScoreData(db, curTime) + if err == nil && !hasStoreScoreData { + ScoreStore(jxcontext.AdminCtx, nil) + } + } + } +} + +func Time2Week(t time.Time) int { + yearDay := t.YearDay() + yearFirstDay := t.AddDate(0, 0, -yearDay+1) + firstDayInWeek := int(yearFirstDay.Weekday()) + + firstWeekDays := 1 + if firstDayInWeek != 0 { + firstWeekDays = 7 - firstDayInWeek + 1 + } + var week int + if yearDay <= firstWeekDays { + week = 1 + } else { + tempWeek := (float64(yearDay) - float64(firstWeekDays)) / float64(7) + week = int(math.Ceil(tempWeek)) + 1 + } + + return week +} + +func SplitToSingleWeekDataList(storeScoreList []*model.StoreScoreEx) (weekDataList [][]*model.StoreScoreEx) { + singelWeekData := []*model.StoreScoreEx{} + weekIndex := 0 + for _, value := range storeScoreList { + if weekIndex == 0 { + weekIndex = Time2Week(value.CreatedAt) + } + if weekIndex == Time2Week(value.CreatedAt) { + singelWeekData = append(singelWeekData, value) + } else { + weekDataList = append(weekDataList, singelWeekData) + singelWeekData = []*model.StoreScoreEx{} + weekIndex = 0 + singelWeekData = append(singelWeekData, value) + } + } + if len(singelWeekData) > 0 { + weekDataList = append(weekDataList, singelWeekData) + } + + return weekDataList +} + +func GetStoreScoreLevel(score int) int { + level := 0 + if score >= GoldMedalScore { + level = GoldMedalLevel + } else if score >= SilverMedalScore { + level = SilverMedalLevel + } else if score >= BronzeMedalScore { + level = BronzeMedalLevel + } + + return level +} + +func GetWeeklyStoreScore(storeID, weekIndex int) (outWeeklyStoreScoreDataList []*model.WeeklyStoreScore, err error) { + db := dao.GetDB() + storeScoreList, err := dao.GetLatestWeeklyStoreScoreList(db, storeID, 5) + if err == nil && len(storeScoreList) > 0 { + weeklyStoreScoreDataList := []*model.WeeklyStoreScore{} + weekDataList := SplitToSingleWeekDataList(storeScoreList) + for weekIndex, weekData := range weekDataList { + weeklyData := &model.WeeklyStoreScore{} + weeklyData.ID = weekIndex + weeklyData.ItemTotalScore = ItemTotalScore + weeklyData.StoreID = storeID + weeklyStoreScoreDataList = append(weeklyStoreScoreDataList, weeklyData) + weekDataCount := len(weekData) + for dayIndex, dayData := range weekData { + for _, fieldName := range storeScoreFieldName { + srcFieldValue := refutil.GetObjFieldByName(dayData, fieldName).(int) + destFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int) + refutil.SetObjFieldByName(weeklyData, fieldName, destFieldValue+srcFieldValue) + } + if weekDataCount == 1 { + weeklyData.BeginTime = dayData.CreatedAt + weeklyData.EndTime = dayData.CreatedAt + } else { + if dayIndex == 0 { + weeklyData.EndTime = dayData.CreatedAt + } else if dayIndex == weekDataCount-1 { + weeklyData.BeginTime = dayData.CreatedAt + } + } + weeklyData.StoreName = dayData.StoreName + } + for _, fieldName := range storeScoreFieldName { + destFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int) + refutil.SetObjFieldByName(weeklyData, fieldName, int(math.Round(float64(destFieldValue)/float64(weekDataCount)))) + } + for _, fieldName := range storeScoreFieldName { + srcFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int) + destFieldValue := refutil.GetObjFieldByName(weeklyData, model.FieldTotalScore).(int) + refutil.SetObjFieldByName(weeklyData, model.FieldTotalScore, destFieldValue+srcFieldValue) + } + weeklyData.Level = GetStoreScoreLevel(weeklyData.TotalScore) + } + if weekIndex == -1 { + outWeeklyStoreScoreDataList = weeklyStoreScoreDataList + } else { + outWeeklyStoreScoreDataList = []*model.WeeklyStoreScore{weeklyStoreScoreDataList[weekIndex]} + } + } + + return outWeeklyStoreScoreDataList, err +} diff --git a/business/jxstore/misc/store_score_test.go b/business/jxstore/misc/store_score_test.go new file mode 100644 index 000000000..01e0a42bb --- /dev/null +++ b/business/jxstore/misc/store_score_test.go @@ -0,0 +1,24 @@ +package misc + +import ( + "testing" + + "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" + "git.rosy.net.cn/jx-callback/globals/api2" + "git.rosy.net.cn/jx-callback/globals/testinit" + + _ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai" + _ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm" + _ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd" + _ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm" + _ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc" +) + +func init() { + testinit.Init() + api2.Init() +} + +func TestScoreStore(t *testing.T) { + ScoreStore(jxcontext.AdminCtx, []int{}) +} diff --git a/business/model/dao/dao_order.go b/business/model/dao/dao_order.go index 1438e7c7d..a365377ed 100644 --- a/business/model/dao/dao_order.go +++ b/business/model/dao/dao_order.go @@ -290,3 +290,71 @@ func GetStoreAfsOrderSkuList(db *DaoDB, storeIDs []int, finishedAtBegin, finishe err = GetRows(db, &afsSkuList, sql, sqlParams...) return afsSkuList, err } + +func GetDailyFinishOrderList(db *DaoDB, storeID int, dateTime time.Time) (orderList []*model.OrderPickupTime, err error) { + sql := ` + SELECT t2.status_time, t1.pick_deadline + FROM goods_order t1 + JOIN order_status t2 ON t1.vendor_order_id = t2.vendor_order_id AND t1.vendor_id = t2.vendor_id + WHERE t1.jx_store_id = ? AND t2.order_type = ? AND t2.status = ? AND DATE(t1.order_finished_at) = DATE(?) + ` + sqlParams := []interface{}{ + storeID, + 1, + model.OrderStatusFinishedPickup, + dateTime, + } + return orderList, GetRows(db, &orderList, sql, sqlParams...) +} + +func GetDailyBadCommentOrderCount(db *DaoDB, dateTime time.Time) (storeCountList []*model.StoreCount, err error) { + sql := ` + SELECT jxstoreid store_id, COUNT(*) count + FROM jx_bad_comments + WHERE DATE(createtime) = DATE(?) + GROUP BY jxstoreid + ` + sqlParams := []interface{}{ + dateTime, + } + err = GetRows(db, &storeCountList, sql, sqlParams) + + return storeCountList, err +} + +func GetDailyUnFinishOrderCount(db *DaoDB, dateTime time.Time) (storeCountList []*model.StoreCount, err error) { + return GetDailyEndOrderCount(db, []int{model.OrderStatusCanceled}, false, dateTime) +} + +func GetDailyFinishOrderCount(db *DaoDB, dateTime time.Time) (storeCountList []*model.StoreCount, err error) { + return GetDailyEndOrderCount(db, []int{model.OrderStatusFinished}, false, dateTime) +} + +func GetDailyAbsentGoodsOrderCount(db *DaoDB, dateTime time.Time) (storeCountList []*model.StoreCount, err error) { + return GetDailyEndOrderCount(db, []int{model.OrderStatusFinished, model.OrderStatusCanceled}, true, dateTime) +} + +func GetDailyEndOrderCount(db *DaoDB, statusList []int, isAbsentOrder bool, dateTime time.Time) (storeCountList []*model.StoreCount, err error) { + sql := ` + SELECT jx_store_id store_id, COUNT(*) count + FROM goods_order + WHERE DATE(order_finished_at) = DATE(?) + ` + sqlParams := []interface{}{ + dateTime, + } + if len(statusList) > 0 { + sql += ` AND status IN (` + GenQuestionMarks(len(statusList)) + `)` + sqlParams = append(sqlParams, statusList) + } + if isAbsentOrder { + sql += ` + AND adjust_count > 0 + ` + } + sql += ` + GROUP BY jx_store_id` + err = GetRow(db, &storeCountList, sql, sqlParams) + + return storeCountList, err +} diff --git a/business/model/dao/store_score.go b/business/model/dao/store_score.go new file mode 100644 index 000000000..604a3b52c --- /dev/null +++ b/business/model/dao/store_score.go @@ -0,0 +1,67 @@ +package dao + +import ( + "time" + + "git.rosy.net.cn/jx-callback/business/model" +) + +func InsertStoreScore(storeScore *model.StoreScore) error { + storeScore.CreatedAt = time.Now() + return CreateEntity(nil, storeScore) +} + +func GetLatestWeeklyStoreScoreList(db *DaoDB, storeID, weekNum int) (storeScoreList []*model.StoreScoreEx, err error) { + sql := ` + SELECT t2.name store_name, t1.* FROM store_score t1 + JOIN store t2 ON t1.store_id = t2.id + WHERE t1.store_id = ? + AND DATE(t1.score_date) >= DATE_SUB( + DATE_SUB( + CURDATE(), + INTERVAL + IF ( + DAYOFWEEK(CURDATE()) - 1 = 0, + 7, + DAYOFWEEK(CURDATE()) - 1 + ) DAY + ), + INTERVAL ? DAY + ) + AND DATE(t1.score_date) <= DATE_SUB( + CURDATE(), + INTERVAL + IF ( + DAYOFWEEK(CURDATE()) - 1 = 0, + 7, + DAYOFWEEK(CURDATE()) - 1 + ) DAY + ) + ORDER BY score_date DESC + ` + if weekNum <= 0 { + weekNum = 1 + } + diffDays := weekNum*7 - 1 + sqlParams := []interface{}{ + storeID, + diffDays, + } + err = GetRows(db, &storeScoreList, sql, sqlParams) + return storeScoreList, err +} + +func CheckHasStoreScoreData(db *DaoDB, dateTime time.Time) (hasStoreScoreData bool, err error) { + sql := ` + SELECT COUNT(*) count + FROM store_score + WHERE DATE(score_date) = DATE(?) + ` + sqlParams := []interface{}{ + dateTime, + } + count := 0 + err = GetRow(db, &count, sql, sqlParams) + hasStoreScoreData = count > 0 + return hasStoreScoreData, err +} diff --git a/business/model/store_score.go b/business/model/store_score.go new file mode 100644 index 000000000..84596ee80 --- /dev/null +++ b/business/model/store_score.go @@ -0,0 +1,60 @@ +package model + +import "time" + +const ( + FieldStoreOpenTime = "StoreOpenTime" + FieldSaleSkuCount = "SaleSkuCount" + FieldAveragePickupTime = "AveragePickupTime" + FieldBadCommentOrder = "BadCommentOrder" + FieldUnfinishOrder = "UnfinishOrder" + FieldAbsentGoodsOrder = "AbsentGoodsOrder" + FieldPromotionSku = "PromotionSku" + FieldFullVendor = "FullVendor" + FieldStoreRange = "StoreRange" + FieldSaleSkuPrice = "SaleSkuPrice" + + FieldTotalScore = "TotalScore" +) + +type StoreScore struct { + ID int `orm:"column(id)" json:"id"` + CreatedAt time.Time `orm:"auto_now_add;type(datetime)" json:"createdAt"` + ScoreDate time.Time `orm:"auto_now_add;type(datetime)" json:"scoreDate"` + StoreID int `orm:"column(store_id)" json:"storeID"` + + StoreOpenTime int `orm:"column(store_open_time)" json:"storeOpenTime"` + SaleSkuCount int `orm:"column(sale_sku_count)" json:"saleSkuCount"` + AveragePickupTime int `orm:"column(average_pickup_time)" json:"averagePickupTime"` + BadCommentOrder int `orm:"column(bad_comment_order)" json:"badCommentOrder"` + UnfinishOrder int `orm:"column(unfinish_order)" json:"unfinishOrder"` + AbsentGoodsOrder int `orm:"column(absent_Goods_order)" json:"absentGoodsOrder"` + PromotionSku int `orm:"column(promotion_sku)" json:"promotionSku"` + FullVendor int `orm:"column(full_vendor)" json:"fullVendor"` + StoreRange int `orm:"column(store_range)" json:"storeRange"` + SaleSkuPrice int `orm:"column(sale_sku_price)" json:"saleSkuPrice"` +} + +type StoreScoreEx struct { + StoreScore + StoreName string `json:"storeName"` +} + +type WeeklyStoreScore struct { + StoreScoreEx + BeginTime time.Time `json:"beginTime"` + EndTime time.Time `json:"endTime"` + TotalScore int `json:"totalScore"` + ItemTotalScore int `json:"itemTotalScore"` + Level int `json:"level"` +} + +type StoreCount struct { + StoreID int `orm:"column(store_id)"` + Count int +} + +type OrderPickupTime struct { + StatusTime time.Time + PickDeadline time.Time +} diff --git a/business/partner/partner.go b/business/partner/partner.go index 8208d7a20..cf94a9148 100644 --- a/business/partner/partner.go +++ b/business/partner/partner.go @@ -263,3 +263,11 @@ func GetSingleStoreVendorIDs() (vendorIDs []int) { } return vendorIDs } + +func IsMultiStore(vendorID int) bool { + if _, ok := GetPurchasePlatformFromVendorID(vendorID).(IMultipleStoresHandler); ok { + return true + } + + return false +} diff --git a/controllers/cms_store.go b/controllers/cms_store.go index f7fe8d61d..95b1c7b1b 100644 --- a/controllers/cms_store.go +++ b/controllers/cms_store.go @@ -3,6 +3,7 @@ package controllers import ( "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxstore/cms" + "git.rosy.net.cn/jx-callback/business/jxstore/misc" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/jxutils/netprinter" "git.rosy.net.cn/jx-callback/business/model" @@ -422,3 +423,36 @@ func (c *StoreController) SyncStoresQualify() { return retVal, "", err }) } + +// @Title 门店评分 +// @Description 门店评分 +// @Param token header string true "认证token" +// @Param storeIDs formData string false "京西门店ID列表" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /ScoreStore [post] +func (c *StoreController) ScoreStore() { + c.callScoreStore(func(params *tStoreScoreStoreParams) (retVal interface{}, errCode string, err error) { + var storeIDList []int + if err = jxutils.Strings2Objs(params.StoreIDs, &storeIDList); err == nil { + misc.ScoreStore(params.Ctx, storeIDList) + } + + return retVal, "", err + }) +} + +// @Title 得到门店近期周平均分数数据 +// @Description 得到门店近期周平均分数数据 +// @Param token header string true "认证token" +// @Param storeID query int true "京西门店ID" +// @Param weekIndex query int true "周索引(起始索引为0, -1为所有周数据)" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /GetWeeklyStoreScore [get] +func (c *StoreController) GetWeeklyStoreScore() { + c.callGetWeeklyStoreScore(func(params *tStoreGetWeeklyStoreScoreParams) (retVal interface{}, errCode string, err error) { + retVal, err = misc.GetWeeklyStoreScore(params.StoreID, params.WeekIndex) + return retVal, "", err + }) +} diff --git a/globals/beegodb/beegodb.go b/globals/beegodb/beegodb.go index 93bd2994e..70da7febd 100644 --- a/globals/beegodb/beegodb.go +++ b/globals/beegodb/beegodb.go @@ -54,7 +54,7 @@ func Init() { orm.RegisterModel(&model.CasbinRule{}) orm.RegisterModel(&model.SensitiveWord{}) - + orm.RegisterModel(&model.StoreScore{}) orm.RegisterModel(&model.FoodRecipe{}, &model.FoodRecipeStep{}, &model.FoodRecipeItem{}, &model.FoodRecipeItemChoice{}, &model.FoodRecipeUser{}) // create table diff --git a/routers/commentsRouter_controllers.go b/routers/commentsRouter_controllers.go index 4208035e1..86bd3bf1f 100644 --- a/routers/commentsRouter_controllers.go +++ b/routers/commentsRouter_controllers.go @@ -475,6 +475,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:FoodRecipeController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:FoodRecipeController"], + beego.ControllerComments{ + Method: "CreateFoodRecipe", + Router: `/CreateFoodRecipe`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:InitDataController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:InitDataController"], beego.ControllerComments{ Method: "BuildSkuFromEbaiStore", @@ -1296,6 +1305,24 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreController"], + beego.ControllerComments{ + Method: "GetWeeklyStoreScore", + Router: `/GetWeeklyStoreScore`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreController"], + beego.ControllerComments{ + Method: "ScoreStore", + Router: `/ScoreStore`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:StoreController"], beego.ControllerComments{ Method: "SyncStoresQualify",