门店评分

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

View File

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

View File

@@ -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"`
}

View File

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

View File

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