门店评分

This commit is contained in:
Rosy-zhudan
2019-09-03 14:48:37 +08:00
parent b12d7dad77
commit ad1bcd36ff
5 changed files with 320 additions and 0 deletions

View File

@@ -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)
}
}