From ad1bcd36ff372a1f3adb20935dc708056c0abf35 Mon Sep 17 00:00:00 2001 From: Rosy-zhudan Date: Tue, 3 Sep 2019 14:48:37 +0800 Subject: [PATCH] =?UTF-8?q?=E9=97=A8=E5=BA=97=E8=AF=84=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- business/jxstore/misc/store_score.go | 268 +++++++++++++++++++++++++++ business/model/dao/store_score.go | 23 +++ business/model/store_score.go | 20 ++ business/partner/partner.go | 8 + globals/beegodb/beegodb.go | 1 + 5 files changed, 320 insertions(+) create mode 100644 business/jxstore/misc/store_score.go create mode 100644 business/model/dao/store_score.go create mode 100644 business/model/store_score.go diff --git a/business/jxstore/misc/store_score.go b/business/jxstore/misc/store_score.go new file mode 100644 index 000000000..3f614ad8f --- /dev/null +++ b/business/jxstore/misc/store_score.go @@ -0,0 +1,268 @@ +package misc + +import ( + "math" + "sync" + "time" + + "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/model" + "git.rosy.net.cn/jx-callback/business/model/dao" +) + +const ( + ItemScore = 10 + TotalScore = 100 + + StoreOpenTimeNormalScore = 12.0 + SaleSkuNormalCount = 1000 + SaleSkuScorePerUnit = float64(ItemScore) / SaleSkuNormalCount + PromotionSkuNormalCount = 20 +) + +var ( + storeScoreDataWrapper StoreScoreDataWrapper + fullVendorList = map[int]bool{ + model.VendorIDJD: true, + model.VendorIDMTWM: true, + model.VendorIDEBAI: true, + } +) + +type StoreScoreDataWrapper struct { + storeScoreData map[int]*model.StoreScore + locker sync.RWMutex +} + +func (s *StoreScoreDataWrapper) AppendData(data *model.StoreScore) { + s.locker.Lock() + defer s.locker.Unlock() + s.storeScoreData[data.StoreID] = data +} + +func (s *StoreScoreDataWrapper) GetData(storeID int) *model.StoreScore { + s.locker.RLock() + defer s.locker.RUnlock() + return s.storeScoreData[storeID] +} + +func (s *StoreScoreDataWrapper) InitData() { + s.storeScoreData = make(map[int]*model.StoreScore) +} + +/* 分日评分和周评分两种,周评分为最近一周的平均值 +1 营业时间12小时及以上满分,总分10分,每少一个小时扣1分 +2 可售商品数量大于1000,总分10分,按比例扣 +3 平均捡货时间10分钟内为满分10分,每超1分钟扣1分 +4 差评订单和完成订单比例小于0.2%,得满分10分,每增加0.1,%减1分 +5 未完成订单和完成订单比小于1%,得满分10分,比例每增加5%,分数减1 +6 缺货订单和完成订单比小于1%得10分,比例每增加0.1%减1分 +7 促销品数量20个以上为满分10分,每少2个扣1分 +8 经营全平台满分10分,每少一个平台扣2分(???一个都没有,是否为0) +9 经营范围面积大于半径2km的圆得满分10分,低于1km得分0 +10 可售商品价格在附近5km内门店比较,价格低于等于平均值的商品数占90%以上满分10分,比例每降低10%减1分,100%超标得0分 +*/ + +func GetOpenTime(opTimeList []int16) (opTime float64) { + opTime = 0 + for index, _ := range opTimeList { + if index%2 == 1 { + diff := opTimeList[index] - opTimeList[index-1] + opTime += float64(diff) / 100 + } + } + return opTime +} + +func ScoreStoreOpenTime(storeList []*cms.StoreExt) { + for _, storeInfo := range storeList { + storeID := storeInfo.ID + storeStatus := storeInfo.Status + isStoreOpen := storeStatus == model.StoreStatusOpened + storeScoreData := storeScoreDataWrapper.GetData(storeID) + if storeScoreData == nil { + storeScoreData = &model.StoreScore{} + storeScoreData.StoreID = storeID + storeScoreDataWrapper.AppendData(storeScoreData) + } + for _, storeMap := range storeInfo.StoreMaps { + vendorStoreStatus := int(utils.MustInterface2Int64(storeMap["status"])) + isVendorStoreOpen := vendorStoreStatus == model.StoreStatusOpened + opTimeList := storeInfo.GetOpTimeList() + if len(opTimeList) > 0 && isStoreOpen && isVendorStoreOpen { + opTime := GetOpenTime(opTimeList) + if opTime >= StoreOpenTimeNormalScore { + storeScoreData.StoreOpenTime = ItemScore + } else { + decScore := int(math.Round(StoreOpenTimeNormalScore - opTime)) + storeScoreData.StoreOpenTime = ItemScore - decScore + if storeScoreData.StoreOpenTime < 0 { + storeScoreData.StoreOpenTime = 0 + } + } + } + } + } +} + +func ScoreSaleSkuCount(ctx *jxcontext.Context, storeList []*cms.StoreExt) { + for _, storeInfo := range storeList { + storeID := storeInfo.ID + storeScoreData := storeScoreDataWrapper.GetData(storeID) + if storeScoreData == nil { + storeScoreData = &model.StoreScore{} + storeScoreData.StoreID = storeID + storeScoreDataWrapper.AppendData(storeScoreData) + } + jxSkuInfoData, _ := cms.GetStoreSkus(ctx, storeID, []int{}, true, "", true, map[string]interface{}{}, 0, -1) + saleSkuCount := 0 + for _, value := range jxSkuInfoData.SkuNames { + for _, skuInfo := range value.Skus2 { + saleStatus := jxutils.MergeSkuStatus(skuInfo.SkuStatus, skuInfo.StoreSkuStatus) + if saleStatus == model.SkuStatusNormal { + saleSkuCount++ + } + } + } + storeScoreData.SaleSkuCount = int(math.Round(float64(saleSkuCount) * SaleSkuScorePerUnit)) + } +} + +func ScoreAveragePickupTime() { + +} + +func ScoreBadReviewOrder() { + +} + +func ScoreUnfinishOrder() { + +} + +func ScoreLackStockOrder() { + +} + +func ScorePromotionSku(storeList []*cms.StoreExt) { + for _, storeInfo := range storeList { + storeID := storeInfo.ID + storeScoreData := storeScoreDataWrapper.GetData(storeID) + if storeScoreData == nil { + storeScoreData = &model.StoreScore{} + storeScoreData.StoreID = storeID + storeScoreDataWrapper.AppendData(storeScoreData) + } + db := dao.GetDB() + beginTime := time.Now() + endTime := time.Now() + actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, -1, []int{}, []int{storeID}, []int{}, beginTime, endTime) + if err == nil { + actStoreSkuMap := make(map[int]int) + for _, value := range actStoreSkuList { + actStoreSkuMap[value.SkuID] = 1 + } + promotionSkuCount := len(actStoreSkuMap) + if promotionSkuCount >= PromotionSkuNormalCount { + storeScoreData.PromotionSku = ItemScore + } else { + decScore := (PromotionSkuNormalCount - promotionSkuCount) / 2 + storeScoreData.PromotionSku = ItemScore - decScore + if storeScoreData.PromotionSku < 0 { + storeScoreData.PromotionSku = 0 + } + } + } + } +} + +func ScoreFullVendor(storeList []*cms.StoreExt) { + fullVendorCount := len(fullVendorList) + for _, storeInfo := range storeList { + storeID := storeInfo.ID + storeStatus := storeInfo.Status + isStoreOpen := storeStatus == model.StoreStatusOpened + storeScoreData := storeScoreDataWrapper.GetData(storeID) + if storeScoreData == nil { + storeScoreData = &model.StoreScore{} + storeScoreData.StoreID = storeID + storeScoreDataWrapper.AppendData(storeScoreData) + } + count := 0 + for _, storeMap := range storeInfo.StoreMaps { + vendorStoreStatus := int(utils.MustInterface2Int64(storeMap["status"])) + isVendorStoreOpen := vendorStoreStatus == model.StoreStatusOpened + opTimeList := storeInfo.GetOpTimeList() + if len(opTimeList) > 0 && isStoreOpen && isVendorStoreOpen { + count++ + } + } + if count == fullVendorCount { + storeScoreData.FullVendor = ItemScore + } else { + decScore := (fullVendorCount - count) * 2 + storeScoreData.FullVendor = ItemScore - decScore + } + } +} + +func ScoreStoreRange() { + +} + +func ScoreSaleSkuPrice() { + +} + +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 + } + } + for _, vendorStoreInfo := range storeInfo.StoreMaps { + vendorID := int(utils.MustInterface2Int64(vendorStoreInfo["vendorID"])) + if _, ok := fullVendorList[vendorID]; !ok { + continue + } + outStoreList = append(outStoreList, storeInfo) + } + } + + return outStoreList +} + +func ScoreStore(ctx *jxcontext.Context, storeIDList []int) (retVal interface{}, err error) { + storeScoreDataWrapper.InitData() + storeList, err := GetStoreList(ctx) + storeIDMap := jxutils.IntList2Map(storeIDList) + storeList = GetFilterStoreListEx(storeList, storeIDMap) + + ScoreStoreOpenTime(storeList) + ScoreSaleSkuCount(ctx, storeList) + InsertStoreScore() + + return retVal, err +} + +func InsertStoreScore() { + for _, value := range storeScoreDataWrapper.storeScoreData { + scores := make(map[string]int) + scores["storeOpenTime"] = value.StoreOpenTime + scores["saleSkuCount"] = value.SaleSkuCount + scores["averagePickupTime"] = value.AveragePickupTime + scores["badReviewOrder"] = value.BadReviewOrder + scores["unfinishOrder"] = value.UnfinishOrder + scores["lackStockOrder"] = value.LackStockOrder + scores["promotionSku"] = value.PromotionSku + scores["fullVendor"] = value.FullVendor + scores["storeRange"] = value.StoreRange + scores["saleSkuPrice"] = value.SaleSkuPrice + dao.InsertStoreScore(value.StoreID, scores) + } +} diff --git a/business/model/dao/store_score.go b/business/model/dao/store_score.go new file mode 100644 index 000000000..71aea890e --- /dev/null +++ b/business/model/dao/store_score.go @@ -0,0 +1,23 @@ +package dao + +import ( + "time" + + "git.rosy.net.cn/jx-callback/business/model" +) + +func InsertStoreScore(storeID int, scores map[string]int) error { + storeScore := &model.StoreScore{CreatedAt: time.Now(), StoreID: storeID} + storeScore.StoreOpenTime = scores["storeOpenTime"] + storeScore.SaleSkuCount = scores["saleSkuCount"] + storeScore.AveragePickupTime = scores["averagePickupTime"] + storeScore.BadReviewOrder = scores["badReviewOrder"] + storeScore.UnfinishOrder = scores["unfinishOrder"] + storeScore.LackStockOrder = scores["lackStockOrder"] + storeScore.PromotionSku = scores["promotionSku"] + storeScore.FullVendor = scores["fullVendor"] + storeScore.StoreRange = scores["storeRange"] + storeScore.SaleSkuPrice = scores["saleSkuPrice"] + + return CreateEntity(nil, storeScore) +} diff --git a/business/model/store_score.go b/business/model/store_score.go new file mode 100644 index 000000000..0277557d7 --- /dev/null +++ b/business/model/store_score.go @@ -0,0 +1,20 @@ +package model + +import "time" + +type StoreScore struct { + ID int `orm:"column(id)" json:"id"` + CreatedAt time.Time `orm:"auto_now_add;type(datetime)" json:"createdAt"` + 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"` + BadReviewOrder int `orm:"column(bad_review_order)" json:"badReviewOrder"` + UnfinishOrder int `orm:"column(unfinish_order)" json:"unfinishOrder"` + LackStockOrder int `orm:"column(lack_stock_order)" json:"lackStockOrder"` + 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"` +} diff --git a/business/partner/partner.go b/business/partner/partner.go index 803ceb747..6e106b42b 100644 --- a/business/partner/partner.go +++ b/business/partner/partner.go @@ -242,3 +242,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/globals/beegodb/beegodb.go b/globals/beegodb/beegodb.go index 5b0b17614..fde70fb6a 100644 --- a/globals/beegodb/beegodb.go +++ b/globals/beegodb/beegodb.go @@ -54,6 +54,7 @@ func Init() { orm.RegisterModel(&model.CasbinRule{}) orm.RegisterModel(&model.SensitiveWord{}) + orm.RegisterModel(&model.StoreScore{}) // create table orm.RunSyncdb("default", false, true) }