门店评分
This commit is contained in:
@@ -2,8 +2,9 @@ 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, []int{}, []int{}, 0, 0, false, true)
|
||||
}
|
||||
|
||||
@@ -17,19 +17,28 @@ const (
|
||||
ItemScore = 10
|
||||
TotalScore = 100
|
||||
|
||||
StoreOpenTimeNormalScore = 12.0
|
||||
SaleSkuNormalCount = 1000
|
||||
SaleSkuScorePerUnit = float64(ItemScore) / SaleSkuNormalCount
|
||||
PromotionSkuNormalCount = 20
|
||||
StoreOpenTimeNormalTime = 12.0 //小时
|
||||
SaleSkuNormalCount = 1000
|
||||
SaleSkuScorePerUnit = float64(ItemScore) / SaleSkuNormalCount
|
||||
PromotionSkuNormalCount = 20
|
||||
AveragePickupTimeNormalTime = 10.0 //分钟
|
||||
BadCommentOrderNormalRatio = 0.2
|
||||
UnfinishOrderNormalRatio = 1.0
|
||||
StoreRangeGoodRadius = 2000 //米
|
||||
StoreRangeBadRadius = 1000 //米
|
||||
)
|
||||
|
||||
var (
|
||||
scoreStoreTimeList = []string{
|
||||
"23:30:00",
|
||||
}
|
||||
storeScoreDataWrapper StoreScoreDataWrapper
|
||||
fullVendorList = map[int]bool{
|
||||
model.VendorIDJD: true,
|
||||
model.VendorIDMTWM: true,
|
||||
model.VendorIDEBAI: true,
|
||||
}
|
||||
allStoreSkus map[int]map[int]*cms.StoreSkuNameExt
|
||||
)
|
||||
|
||||
type StoreScoreDataWrapper struct {
|
||||
@@ -53,19 +62,6 @@ 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 {
|
||||
@@ -77,6 +73,7 @@ func GetOpenTime(opTimeList []int16) (opTime float64) {
|
||||
return opTime
|
||||
}
|
||||
|
||||
//营业时间12小时及以上满分,总分10分,每少一个小时扣1分
|
||||
func ScoreStoreOpenTime(storeList []*cms.StoreExt) {
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
@@ -94,10 +91,10 @@ func ScoreStoreOpenTime(storeList []*cms.StoreExt) {
|
||||
opTimeList := storeInfo.GetOpTimeList()
|
||||
if len(opTimeList) > 0 && isStoreOpen && isVendorStoreOpen {
|
||||
opTime := GetOpenTime(opTimeList)
|
||||
if opTime >= StoreOpenTimeNormalScore {
|
||||
if opTime >= StoreOpenTimeNormalTime {
|
||||
storeScoreData.StoreOpenTime = ItemScore
|
||||
} else {
|
||||
decScore := int(math.Round(StoreOpenTimeNormalScore - opTime))
|
||||
decScore := int(math.Round(StoreOpenTimeNormalTime - opTime))
|
||||
storeScoreData.StoreOpenTime = ItemScore - decScore
|
||||
if storeScoreData.StoreOpenTime < 0 {
|
||||
storeScoreData.StoreOpenTime = 0
|
||||
@@ -108,6 +105,7 @@ func ScoreStoreOpenTime(storeList []*cms.StoreExt) {
|
||||
}
|
||||
}
|
||||
|
||||
//可售商品数量大于1000,总分10分,按比例扣
|
||||
func ScoreSaleSkuCount(ctx *jxcontext.Context, storeList []*cms.StoreExt) {
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
@@ -128,25 +126,103 @@ func ScoreSaleSkuCount(ctx *jxcontext.Context, storeList []*cms.StoreExt) {
|
||||
}
|
||||
}
|
||||
storeScoreData.SaleSkuCount = int(math.Round(float64(saleSkuCount) * SaleSkuScorePerUnit))
|
||||
if storeScoreData.SaleSkuCount > ItemScore {
|
||||
storeScoreData.SaleSkuCount = ItemScore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ScoreAveragePickupTime() {
|
||||
|
||||
}
|
||||
|
||||
func ScoreBadReviewOrder() {
|
||||
|
||||
}
|
||||
|
||||
func ScoreUnfinishOrder() {
|
||||
|
||||
}
|
||||
|
||||
func ScoreLackStockOrder() {
|
||||
//平均捡货时间小于等于拣货截止时间为10分满分,每超出1分钟,减1分
|
||||
func ScoreAveragePickupTime(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()
|
||||
orderList, err := dao.GetDailyFinishOrderList(db, storeID)
|
||||
if err == nil {
|
||||
totalScore := 0
|
||||
for _, value := range orderList {
|
||||
statusTime := value.StatusTime.Unix()
|
||||
pickDeadline := value.PickDeadline.Unix()
|
||||
if statusTime <= pickDeadline {
|
||||
totalScore += ItemScore
|
||||
} else {
|
||||
decScore := int(math.Round(float64(statusTime-pickDeadline) / 60))
|
||||
tempScore := ItemScore - decScore
|
||||
if tempScore < 0 {
|
||||
tempScore = 0
|
||||
}
|
||||
totalScore += tempScore
|
||||
}
|
||||
}
|
||||
storeScoreData.AveragePickupTime = totalScore / len(orderList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//差评订单和完成订单比例小于0.2%,得满分10分,每增加0.1%减1分
|
||||
func ScoreBadCommentOrder(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()
|
||||
badCommentOrderCount, _ := dao.GetDailyBadCommentOrderCount(db, storeID)
|
||||
finishOrderCount, _ := dao.GetDailyFinishOrderCount(db, storeID)
|
||||
badCommentOrderRatio := float64(badCommentOrderCount) * 100 / float64(finishOrderCount)
|
||||
if badCommentOrderRatio <= BadCommentOrderNormalRatio {
|
||||
storeScoreData.BadCommentOrder = ItemScore
|
||||
} else {
|
||||
decScore := int(math.Round((badCommentOrderRatio - BadCommentOrderNormalRatio) / 0.1))
|
||||
storeScoreData.BadCommentOrder = ItemScore - decScore
|
||||
if storeScoreData.BadCommentOrder < 0 {
|
||||
storeScoreData.BadCommentOrder = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//未完成订单和完成订单比小于1%,得满分10分,比例每增加5%,分数减1
|
||||
func ScoreUnfinishOrder(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()
|
||||
unFinishOrderCount, _ := dao.GetDailyUnFinishOrderCount(db, storeID)
|
||||
finishOrderCount, _ := dao.GetDailyFinishOrderCount(db, storeID)
|
||||
unfinishOrderRatio := float64(unFinishOrderCount) * 100 / float64(finishOrderCount)
|
||||
if unfinishOrderRatio <= UnfinishOrderNormalRatio {
|
||||
storeScoreData.UnfinishOrder = ItemScore
|
||||
} else {
|
||||
decScore := int(math.Round((unfinishOrderRatio - UnfinishOrderNormalRatio) / 5))
|
||||
storeScoreData.UnfinishOrder = ItemScore - decScore
|
||||
if storeScoreData.UnfinishOrder < 0 {
|
||||
storeScoreData.UnfinishOrder = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//缺货订单和完成订单比小于1%得10分,比例每增加0.1%减1分
|
||||
func ScoreAbsentGoodsOrder(storeList []*cms.StoreExt) {
|
||||
|
||||
}
|
||||
|
||||
//促销品数量20个以上为满分10分,每少2个扣1分
|
||||
func ScorePromotionSku(storeList []*cms.StoreExt) {
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
@@ -163,7 +239,9 @@ func ScorePromotionSku(storeList []*cms.StoreExt) {
|
||||
if err == nil {
|
||||
actStoreSkuMap := make(map[int]int)
|
||||
for _, value := range actStoreSkuList {
|
||||
actStoreSkuMap[value.SkuID] = 1
|
||||
if value.Type != model.ActSkuFake {
|
||||
actStoreSkuMap[value.SkuID] = 1
|
||||
}
|
||||
}
|
||||
promotionSkuCount := len(actStoreSkuMap)
|
||||
if promotionSkuCount >= PromotionSkuNormalCount {
|
||||
@@ -179,6 +257,7 @@ func ScorePromotionSku(storeList []*cms.StoreExt) {
|
||||
}
|
||||
}
|
||||
|
||||
//经营全平台满分10分,每少一个平台扣2分(???一个都没有,是否为0)
|
||||
func ScoreFullVendor(storeList []*cms.StoreExt) {
|
||||
fullVendorCount := len(fullVendorList)
|
||||
for _, storeInfo := range storeList {
|
||||
@@ -209,12 +288,108 @@ func ScoreFullVendor(storeList []*cms.StoreExt) {
|
||||
}
|
||||
}
|
||||
|
||||
func ScoreStoreRange() {
|
||||
func CalcPolygonArea(points [][2]float64) (area float64) {
|
||||
count := len(points)
|
||||
for i := 0; i < count-1; i++ {
|
||||
area += (points[i][0] - points[i+1][0]) * (points[i][1] + points[i+1][1])
|
||||
}
|
||||
area += (points[count-1][0] - points[0][0]) * (points[count-1][1] + points[0][1])
|
||||
area = math.Abs(area) / 2
|
||||
|
||||
return area
|
||||
}
|
||||
|
||||
func ScoreSaleSkuPrice() {
|
||||
//经营范围面积大于半径2km的圆得满分10分,低于1km得分0
|
||||
func ScoreStoreRange(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)
|
||||
}
|
||||
if storeInfo.DeliveryRangeType == model.DeliveryRangeTypePolygon {
|
||||
points := jxutils.CoordinateStr2Points(storeInfo.DeliveryRange)
|
||||
area := CalcPolygonArea(points)
|
||||
goodArea := math.Pi * StoreRangeGoodRadius * StoreRangeGoodRadius
|
||||
badArea := math.Pi * StoreRangeBadRadius * StoreRangeBadRadius
|
||||
if area >= goodArea {
|
||||
storeScoreData.StoreRange = ItemScore
|
||||
} else if area <= badArea {
|
||||
storeScoreData.StoreRange = 0
|
||||
} else {
|
||||
diff := float64(goodArea - area)
|
||||
ratio := float64(ItemScore) / (goodArea - badArea)
|
||||
storeScoreData.StoreRange = ItemScore - int(math.Round(diff*ratio))
|
||||
}
|
||||
} else if storeInfo.DeliveryRangeType == model.DeliveryRangeTypeRadius {
|
||||
deliveryRadius := utils.Str2Int64WithDefault(storeInfo.DeliveryRange, 0)
|
||||
if deliveryRadius >= StoreRangeGoodRadius {
|
||||
storeScoreData.StoreRange = ItemScore
|
||||
} else if deliveryRadius <= StoreRangeBadRadius {
|
||||
storeScoreData.StoreRange = 0
|
||||
} else {
|
||||
diff := float64(StoreRangeGoodRadius - deliveryRadius)
|
||||
ratio := float64(ItemScore) / (StoreRangeGoodRadius - StoreRangeBadRadius)
|
||||
storeScoreData.StoreRange = ItemScore - int(math.Round(diff*ratio))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetRangeStoreList(storeID int, lng, lat, checkDist 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 <= checkDist {
|
||||
outStoreList = append(outStoreList, storeInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outStoreList
|
||||
}
|
||||
|
||||
func GetAllStoreSkus(ctx *jxcontext.Context, storeList []*cms.StoreExt) {
|
||||
allStoreSkus = make(map[int]map[int]*cms.StoreSkuNameExt)
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
jxSkuInfoData, _ := cms.GetStoreSkus(ctx, storeID, []int{}, true, "", true, map[string]interface{}{}, 0, -1)
|
||||
jxSkuMapData := make(map[int]*cms.StoreSkuNameExt)
|
||||
for _, value := range jxSkuInfoData.SkuNames {
|
||||
for _, skuInfo := range value.Skus2 {
|
||||
saleStatus := jxutils.MergeSkuStatus(skuInfo.SkuStatus, skuInfo.StoreSkuStatus)
|
||||
if saleStatus == model.SkuStatusNormal {
|
||||
jxSkuMapData[skuInfo.SkuID] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
allStoreSkus[storeID] = jxSkuMapData
|
||||
}
|
||||
}
|
||||
|
||||
func ClearAllStoreSkus() {
|
||||
allStoreSkus = nil
|
||||
}
|
||||
|
||||
//得到所有门店的商品,map[int]*cms.StoreSkuNamesInfo
|
||||
//得到距离某个门店5KM内的所有门店信息
|
||||
//可售商品价格在附近5km内门店比较,价格低于等于平均值的商品数占90%以上满分10分,比例每降低10%减1分,100%超标得0分
|
||||
func ScoreSaleSkuPrice(ctx *jxcontext.Context, storeList []*cms.StoreExt) {
|
||||
GetAllStoreSkus(ctx, storeList)
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
storeScoreData := storeScoreDataWrapper.GetData(storeID)
|
||||
if storeScoreData == nil {
|
||||
storeScoreData = &model.StoreScore{}
|
||||
storeScoreData.StoreID = storeID
|
||||
storeScoreDataWrapper.AppendData(storeScoreData)
|
||||
}
|
||||
//rangeStoreList := GetRangeStoreList(storeID, storeInfo.FloatLng, storeInfo.FloatLat, 5, storeList)
|
||||
}
|
||||
}
|
||||
|
||||
func GetFilterStoreListEx(storeList []*cms.StoreExt, storeIDMap map[int]int) (outStoreList []*cms.StoreExt) {
|
||||
@@ -245,6 +420,14 @@ func ScoreStore(ctx *jxcontext.Context, storeIDList []int) (retVal interface{},
|
||||
|
||||
ScoreStoreOpenTime(storeList)
|
||||
ScoreSaleSkuCount(ctx, storeList)
|
||||
ScoreAveragePickupTime(storeList)
|
||||
ScoreBadCommentOrder(storeList)
|
||||
ScoreUnfinishOrder(storeList)
|
||||
ScoreAbsentGoodsOrder(storeList)
|
||||
ScorePromotionSku(storeList)
|
||||
ScoreFullVendor(storeList)
|
||||
ScoreStoreRange(storeList)
|
||||
ScoreSaleSkuPrice(ctx, storeList)
|
||||
InsertStoreScore()
|
||||
|
||||
return retVal, err
|
||||
@@ -252,17 +435,12 @@ func ScoreStore(ctx *jxcontext.Context, storeIDList []int) (retVal interface{},
|
||||
|
||||
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)
|
||||
dao.InsertStoreScore(value)
|
||||
}
|
||||
}
|
||||
|
||||
func ScheduleScoreStore() {
|
||||
ScheduleTimerFunc("ScheduleScoreStore", func() {
|
||||
ScoreStore(jxcontext.AdminCtx, []int{})
|
||||
}, scoreStoreTimeList)
|
||||
}
|
||||
|
||||
17
business/jxstore/misc/store_score_test.go
Normal file
17
business/jxstore/misc/store_score_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api2.Init()
|
||||
}
|
||||
|
||||
func TestScoreStore(t *testing.T) {
|
||||
ScoreStore(jxcontext.AdminCtx, []int{})
|
||||
}
|
||||
Reference in New Issue
Block a user