更新门店评分

This commit is contained in:
Rosy-zhudan
2019-09-05 17:24:52 +08:00
parent 9e5d152a48
commit c7d883b51c
4 changed files with 181 additions and 122 deletions

View File

@@ -2,6 +2,7 @@ package misc
import (
"math"
"reflect"
"sync"
"time"
@@ -24,8 +25,9 @@ const (
AveragePickupTimeNormalTime = 10.0 //分钟
BadCommentOrderNormalRatio = 0.2
UnfinishOrderNormalRatio = 1.0
StoreRangeGoodRadius = 2000 //米
StoreRangeBadRadius = 1000 //米
StoreRangeGoodRadius = 2.0 //
StoreRangeBadRadius = 1.0 //
SaleSkuPriceRatio = 90 //百分比
)
var (
@@ -46,28 +48,32 @@ type StoreScoreDataWrapper struct {
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)
}
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
s.storeScoreData[storeID] = data
}
valueInfo := reflect.ValueOf(data).Elem()
valueInfo.FieldByName(valueName).SetInt(int64(value))
}
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
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
@@ -79,27 +85,23 @@ func ScoreStoreOpenTime(storeList []*cms.StoreExt) {
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 {
finalScore := 0
opTime := GetOpenTime(opTimeList)
if opTime >= StoreOpenTimeNormalTime {
storeScoreData.StoreOpenTime = ItemScore
finalScore = ItemScore
} else {
decScore := int(math.Round(StoreOpenTimeNormalTime - opTime))
storeScoreData.StoreOpenTime = ItemScore - decScore
if storeScoreData.StoreOpenTime < 0 {
storeScoreData.StoreOpenTime = 0
finalScore = ItemScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
storeScoreDataWrapper.SetData(storeID, "StoreOpenTime", finalScore)
}
}
}
@@ -109,25 +111,23 @@ func ScoreStoreOpenTime(storeList []*cms.StoreExt) {
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++
jxSkuInfoData, err := cms.GetStoreSkus(ctx, storeID, []int{}, true, "", true, map[string]interface{}{}, 0, -1)
if err == nil && len(jxSkuInfoData.SkuNames) > 0 {
finalScore := 0
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))
if storeScoreData.SaleSkuCount > ItemScore {
storeScoreData.SaleSkuCount = ItemScore
finalScore = int(math.Round(float64(saleSkuCount) * SaleSkuScorePerUnit))
if finalScore > ItemScore {
finalScore = ItemScore
}
storeScoreDataWrapper.SetData(storeID, "SaleSkuCount", finalScore)
}
}
}
@@ -136,15 +136,10 @@ func ScoreSaleSkuCount(ctx *jxcontext.Context, storeList []*cms.StoreExt) {
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 {
orderListCount := len(orderList)
if err == nil && orderListCount > 0 {
totalScore := 0
for _, value := range orderList {
statusTime := value.StatusTime.Unix()
@@ -160,7 +155,8 @@ func ScoreAveragePickupTime(storeList []*cms.StoreExt) {
totalScore += tempScore
}
}
storeScoreData.AveragePickupTime = totalScore / len(orderList)
finalScore := totalScore / orderListCount
storeScoreDataWrapper.SetData(storeID, "AveragePickupTime", finalScore)
}
}
}
@@ -169,24 +165,22 @@ func ScoreAveragePickupTime(storeList []*cms.StoreExt) {
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
if finishOrderCount > 0 {
finalScore := 0
badCommentOrderRatio := float64(badCommentOrderCount) * 100 / float64(finishOrderCount)
if badCommentOrderRatio <= BadCommentOrderNormalRatio {
finalScore = ItemScore
} else {
decScore := int(math.Round((badCommentOrderRatio - BadCommentOrderNormalRatio) / 0.1))
finalScore = ItemScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
storeScoreDataWrapper.SetData(storeID, "BadCommentOrder", finalScore)
}
}
}
@@ -195,24 +189,22 @@ func ScoreBadCommentOrder(storeList []*cms.StoreExt) {
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
if finishOrderCount > 0 {
finalScore := 0
unfinishOrderRatio := float64(unFinishOrderCount) * 100 / float64(finishOrderCount)
if unfinishOrderRatio <= UnfinishOrderNormalRatio {
finalScore = ItemScore
} else {
decScore := int(math.Round((unfinishOrderRatio - UnfinishOrderNormalRatio) / 5))
finalScore = ItemScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
storeScoreDataWrapper.SetData(storeID, "UnfinishOrder", finalScore)
}
}
}
@@ -226,17 +218,12 @@ func ScoreAbsentGoodsOrder(storeList []*cms.StoreExt) {
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 {
if err == nil && len(actStoreSkuList) > 0 {
finalScore := 0
actStoreSkuMap := make(map[int]int)
for _, value := range actStoreSkuList {
if value.Type != model.ActSkuFake {
@@ -245,14 +232,15 @@ func ScorePromotionSku(storeList []*cms.StoreExt) {
}
promotionSkuCount := len(actStoreSkuMap)
if promotionSkuCount >= PromotionSkuNormalCount {
storeScoreData.PromotionSku = ItemScore
finalScore = ItemScore
} else {
decScore := (PromotionSkuNormalCount - promotionSkuCount) / 2
storeScoreData.PromotionSku = ItemScore - decScore
if storeScoreData.PromotionSku < 0 {
storeScoreData.PromotionSku = 0
finalScore = ItemScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
storeScoreDataWrapper.SetData(storeID, "PromotionSku", finalScore)
}
}
}
@@ -261,15 +249,10 @@ func ScorePromotionSku(storeList []*cms.StoreExt) {
func ScoreFullVendor(storeList []*cms.StoreExt) {
fullVendorCount := len(fullVendorList)
for _, storeInfo := range storeList {
finalScore := 0
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"]))
@@ -280,11 +263,12 @@ func ScoreFullVendor(storeList []*cms.StoreExt) {
}
}
if count == fullVendorCount {
storeScoreData.FullVendor = ItemScore
finalScore = ItemScore
} else {
decScore := (fullVendorCount - count) * 2
storeScoreData.FullVendor = ItemScore - decScore
finalScore = ItemScore - decScore
}
storeScoreDataWrapper.SetData(storeID, "FullVendor", finalScore)
}
}
@@ -302,42 +286,39 @@ func CalcPolygonArea(points [][2]float64) (area float64) {
//经营范围面积大于半径2km的圆得满分10分低于1km得分0
func ScoreStoreRange(storeList []*cms.StoreExt) {
for _, storeInfo := range storeList {
finalScore := 0
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
finalScore = ItemScore
} else if area <= badArea {
storeScoreData.StoreRange = 0
finalScore = 0
} else {
diff := float64(goodArea - area)
diff := goodArea - area
ratio := float64(ItemScore) / (goodArea - badArea)
storeScoreData.StoreRange = ItemScore - int(math.Round(diff*ratio))
finalScore = ItemScore - int(math.Round(diff*ratio))
}
} else if storeInfo.DeliveryRangeType == model.DeliveryRangeTypeRadius {
deliveryRadius := utils.Str2Int64WithDefault(storeInfo.DeliveryRange, 0)
deliveryRadius := utils.Str2Float64WithDefault(storeInfo.DeliveryRange, 0)
if deliveryRadius >= StoreRangeGoodRadius {
storeScoreData.StoreRange = ItemScore
finalScore = ItemScore
} else if deliveryRadius <= StoreRangeBadRadius {
storeScoreData.StoreRange = 0
finalScore = 0
} else {
diff := float64(StoreRangeGoodRadius - deliveryRadius)
diff := StoreRangeGoodRadius - deliveryRadius
ratio := float64(ItemScore) / (StoreRangeGoodRadius - StoreRangeBadRadius)
storeScoreData.StoreRange = ItemScore - int(math.Round(diff*ratio))
finalScore = ItemScore - int(math.Round(diff*ratio))
}
}
storeScoreDataWrapper.SetData(storeID, "StoreRange", finalScore)
}
}
//得到距离某个门店多少KM内的所有门店信息
func GetRangeStoreList(storeID int, lng, lat, checkDist float64, storeList []*cms.StoreExt) (outStoreList []*cms.StoreExt) {
for _, storeInfo := range storeList {
if storeInfo.ID == storeID {
@@ -353,6 +334,7 @@ func GetRangeStoreList(storeID int, lng, lat, checkDist float64, storeList []*cm
return outStoreList
}
//得到所有门店的商品
func GetAllStoreSkus(ctx *jxcontext.Context, storeList []*cms.StoreExt) {
allStoreSkus = make(map[int]map[int]*cms.StoreSkuNameExt)
for _, storeInfo := range storeList {
@@ -375,21 +357,64 @@ func ClearAllStoreSkus() {
allStoreSkus = nil
}
//得到所有门店的商品map[int]*cms.StoreSkuNamesInfo
//得到距离某个门店5KM内的所有门店信息
//得到给定门店列表里的同一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
for _, value := range allStoreSkus[storeID] {
skuID := value.Skus2[0].SkuID
skuPrice := value.Skus2[0].BindPrice
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) {
for _, value := range allStoreSkus[storeID] {
skuID := value.Skus2[0].SkuID
skuPrice := value.Skus2[0].BindPrice
skuAvgPrice := skusAveragePrice[skuID]
if skuPrice <= skuAvgPrice {
count++
}
}
return count
}
//可售商品价格在附近5km内门店比较价格低于等于平均值的商品数占90%以上满分10分比例每降低10%减1分100%超标得0分
func ScoreSaleSkuPrice(ctx *jxcontext.Context, storeList []*cms.StoreExt) {
GetAllStoreSkus(ctx, storeList)
for _, storeInfo := range storeList {
finalScore := 0
storeID := storeInfo.ID
storeScoreData := storeScoreDataWrapper.GetData(storeID)
if storeScoreData == nil {
storeScoreData = &model.StoreScore{}
storeScoreData.StoreID = storeID
storeScoreDataWrapper.AppendData(storeScoreData)
totalCount := len(allStoreSkus[storeID])
if totalCount > 0 {
rangeStoreList := GetRangeStoreList(storeID, storeInfo.FloatLng, storeInfo.FloatLat, 5, storeList)
skusAveragePrice := GetStoreSkusAveragePrice(rangeStoreList)
count := GetSkusCountLessEqualAvgPrice(storeID, skusAveragePrice)
ratio := int(math.Round(float64(count) * 100 / float64(totalCount)))
if ratio >= SaleSkuPriceRatio {
finalScore = ItemScore
} else {
decScore := (SaleSkuPriceRatio - ratio) / 10
finalScore = ItemScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
storeScoreDataWrapper.SetData(storeID, "SaleSkuPrice", finalScore)
}
//rangeStoreList := GetRangeStoreList(storeID, storeInfo.FloatLng, storeInfo.FloatLat, 5, storeList)
}
ClearAllStoreSkus()
}
func GetFilterStoreListEx(storeList []*cms.StoreExt, storeIDMap map[int]int) (outStoreList []*cms.StoreExt) {

View File

@@ -2,9 +2,16 @@ 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/jxutils/jxcontext"
_ "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() {

View File

@@ -316,3 +316,21 @@ func (c *TempOpController) CheckSkuDiffBetweenJxAndVendor() {
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 *TempOpController) ScoreStore() {
c.callScoreStore(func(params *tTempopScoreStoreParams) (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
})
}

View File

@@ -1674,6 +1674,15 @@ func init() {
Filters: nil,
Params: nil})
beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:TempOpController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:TempOpController"],
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:TempOpController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:TempOpController"],
beego.ControllerComments{
Method: "TestIt",