package misc import ( "fmt" "math" "time" "git.rosy.net.cn/baseapi" "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/jxutils/weixinmsg" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/globals/refutil" ) const ( EnableCheckStoreAlert = true EnableSendStoreAlert = true IncludeToday = true CheckStoreAlertOneMonthDayNum = 30 CheckStoreAlertOneDayNum = 1 CheckStoreAlertOneWeekDayNum = 7 MonthCheckOnWeekDay = 1 AlertTypePickTimeOrderDaDa = 0 AlertTypeBadCommentOrder = 1 AlertTypeAbsentGoodsOrder = 2 AlertTypeStandardFinishTimeOrderSelfDelivery = 3 AlertTypeStandardPickUpTimeOrderDaDa = 4 ColorRed = "red" ColorYellow = "yellow" ColorUnknown = "unknown" AlertLevelExtraRed = 1 AlertLevelRed = 2 AlertLevelYellow = 3 OneDayName = "单日" OneWeekDayName = "七日" OneMonthDayName = "三十日" YellowAlertInfo = "您的店铺京西菜市-%s,由于%s%s%s%d%%,可能会被系统下线,请及时补救。" RedAlertInfo = "您的店铺京西菜市-%s,由于%s%s%s%d%%,会被系统下线,需要马上补救。" ExtraRedAlertInfo = "您的店铺京西菜市-%s,由于%s%s%s%d%%,会被系统下线,需要马上补救。" NoOrderAlertInfo = "您的店铺京西菜市-%s,由于近%s无订单,会被系统下线,需要马上补救。" RiskOrderAlertInfo = "您的店铺京西菜市-%s,可能有虚假定单,定单号为:%s,可能会被罚款,请及时与运营联系!" ) var ( checkStoreAlertTimeList = []string{ "18:30:00", } AlertTypeNameMap = map[int]string{ AlertTypePickTimeOrderDaDa: "拣货履约率(达达)", AlertTypeBadCommentOrder: "差评率", AlertTypeAbsentGoodsOrder: "缺货率", AlertTypeStandardFinishTimeOrderSelfDelivery: "按时履约率(商家自送)", AlertTypeStandardPickUpTimeOrderDaDa: "10分钟取货完成率(达达)", } AlertTypeExtraNameMap = map[int]string{ AlertTypePickTimeOrderDaDa: "拣货超时订单(达达)", AlertTypeBadCommentOrder: "差评订单", AlertTypeAbsentGoodsOrder: "缺货订单", } storeAlertDataWrapper StoreAlertDataWrapper ) type StoreAlertDataWrapper struct { storeAlertList map[int]*model.StoreAlert } func (s *StoreAlertDataWrapper) InitData() { s.storeAlertList = make(map[int]*model.StoreAlert) } func (s *StoreAlertDataWrapper) ClearData() { s.storeAlertList = nil } func (s *StoreAlertDataWrapper) IsStatusField(valueName string) bool { return valueName == model.FieldYellowStatus || valueName == model.FieldRedStatus || valueName == model.FieldExtraRedStatus } func (s *StoreAlertDataWrapper) SetData(storeID int, valueName string, value int) { data := s.storeAlertList[storeID] if data == nil { data = &model.StoreAlert{} data.StoreID = storeID data.AlertDate = utils.GetCurDate() s.storeAlertList[storeID] = data } if s.IsStatusField(valueName) { srcFieldValue := refutil.GetObjFieldByName(data, valueName).(int) value |= srcFieldValue } refutil.SetObjFieldByName(data, valueName, value) } func (s StoreAlertDataWrapper) InsertStoreAlertList() { for _, value := range s.storeAlertList { dao.InsertStoreAlert(value) } } func ConvertListToMap(listData []*model.StoreCount) (mapData map[int]int) { mapData = make(map[int]int) for _, value := range listData { mapData[value.StoreID] = value.Count } return mapData } func ConvertListToMapEx(listData []*model.StoreOrder) (mapData map[int][]string) { mapData = make(map[int][]string) for _, value := range listData { if mapData[value.StoreID] == nil { mapData[value.StoreID] = []string{} } mapData[value.StoreID] = append(mapData[value.StoreID], value.VendorOrderID) } return mapData } func GetAlertInfo(dayNum, alertLevel int, storeName string, alertType int, logicCondition string, value int) (info string) { if dayNum == CheckStoreAlertOneDayNum { if alertLevel == AlertLevelExtraRed { info = fmt.Sprintf(ExtraRedAlertInfo, storeName, OneDayName, AlertTypeExtraNameMap[alertType], logicCondition, value) } else if alertLevel == AlertLevelRed { info = fmt.Sprintf(RedAlertInfo, storeName, OneDayName, AlertTypeNameMap[alertType], logicCondition, value) } else if alertLevel == AlertLevelYellow { info = fmt.Sprintf(YellowAlertInfo, storeName, OneDayName, AlertTypeNameMap[alertType], logicCondition, value) } } else if dayNum == CheckStoreAlertOneWeekDayNum { if alertLevel == AlertLevelExtraRed { info = fmt.Sprintf(ExtraRedAlertInfo, storeName, OneWeekDayName, AlertTypeExtraNameMap[alertType], logicCondition, value) } else if alertLevel == AlertLevelRed { info = fmt.Sprintf(RedAlertInfo, storeName, OneWeekDayName, AlertTypeNameMap[alertType], logicCondition, value) } else if alertLevel == AlertLevelYellow { info = fmt.Sprintf(YellowAlertInfo, storeName, OneWeekDayName, AlertTypeNameMap[alertType], logicCondition, value) } } else if dayNum == CheckStoreAlertOneMonthDayNum { info = fmt.Sprintf(NoOrderAlertInfo, storeName, OneMonthDayName) } return info } func CheckAlert(alertType int, dayNum int, ratio int, count int) (alertLevel int, logicCondtion string, outValue int) { yellowRatio := -1 redRatio := -1 extraCount := -1 conditionLessEqual := false switch alertType { case AlertTypePickTimeOrderDaDa: if dayNum == CheckStoreAlertOneDayNum { redRatio = 0 } else if dayNum == CheckStoreAlertOneWeekDayNum { yellowRatio = 70 redRatio = 50 extraCount = 5 } conditionLessEqual = true case AlertTypeBadCommentOrder: if dayNum == CheckStoreAlertOneDayNum { redRatio = 100 } else if dayNum == CheckStoreAlertOneWeekDayNum { yellowRatio = 1 redRatio = 3 extraCount = 5 } conditionLessEqual = false case AlertTypeAbsentGoodsOrder: if dayNum == CheckStoreAlertOneDayNum { redRatio = 100 } else if dayNum == CheckStoreAlertOneWeekDayNum { yellowRatio = 3 redRatio = 5 extraCount = 5 } conditionLessEqual = false case AlertTypeStandardFinishTimeOrderSelfDelivery: yellowRatio = 85 redRatio = 70 conditionLessEqual = true case AlertTypeStandardPickUpTimeOrderDaDa: yellowRatio = 85 redRatio = 70 conditionLessEqual = true } if conditionLessEqual { logicCondtion = "<=" if extraCount != -1 && count >= extraCount { alertLevel = AlertLevelExtraRed outValue = extraCount } else if redRatio != -1 && ratio <= redRatio { alertLevel = AlertLevelRed outValue = redRatio } else if yellowRatio != -1 && ratio <= yellowRatio { alertLevel = AlertLevelYellow outValue = yellowRatio } } else { logicCondtion = ">=" if extraCount != -1 && count >= extraCount { alertLevel = AlertLevelExtraRed outValue = extraCount } else if redRatio != -1 && ratio >= redRatio { alertLevel = AlertLevelRed outValue = redRatio } else if yellowRatio != -1 && ratio >= yellowRatio { alertLevel = AlertLevelYellow outValue = yellowRatio } } return alertLevel, logicCondtion, outValue } func SendAlertInfo(storeID int, storeName, alertInfo string) { if EnableSendStoreAlert { baseapi.SugarLogger.Debugf("SendAlertInfo: %d, %s", storeID, alertInfo) weixinmsg.NotifyStoreAlertMessage(storeID, storeName, "门店警告", alertInfo) } } func GetFieldNameByAlertType(alertType, dayNum int) (fieldName string, fieldFlag int) { switch alertType { case AlertTypePickTimeOrderDaDa: if dayNum == CheckStoreAlertOneDayNum { fieldName = model.FieldPickTimeDaDa fieldFlag = model.FlagPickTimeDaDa } else if dayNum == CheckStoreAlertOneWeekDayNum { fieldName = model.FieldPickTimeDaDaOneWeek fieldFlag = model.FlagPickTimeDaDaOneWeek } case AlertTypeBadCommentOrder: if dayNum == CheckStoreAlertOneDayNum { fieldName = model.FieldBadComment fieldFlag = model.FlagBadComment } else if dayNum == CheckStoreAlertOneWeekDayNum { fieldName = model.FieldBadCommentOneWeek fieldFlag = model.FlagBadCommentOneWeek } case AlertTypeAbsentGoodsOrder: if dayNum == CheckStoreAlertOneDayNum { fieldName = model.FieldAbsentGoods fieldFlag = model.FlagAbsentGoods } else if dayNum == CheckStoreAlertOneWeekDayNum { fieldName = model.FieldAbsentGoodsOneWeek fieldFlag = model.FlagAbsentGoodsOneWeek } case AlertTypeStandardFinishTimeOrderSelfDelivery: fieldName = model.FieldStandardFinishTimeSelfDelivery fieldFlag = model.FlagStandardFinishTimeSelfDelivery case AlertTypeStandardPickUpTimeOrderDaDa: fieldName = model.FieldStandardPickUpTimeDaDa fieldFlag = model.FlagStandardPickUpTimeDaDa } return fieldName, fieldFlag } func SendAlertInfoWrapper(storeID int, storeName string, dayNum, alertType, count, totalCount int) { if totalCount > 0 { ratio := int(math.Round(float64(count) * 100 / float64(totalCount))) alertLevel, logicCondtion, outValue := CheckAlert(alertType, dayNum, ratio, count) if alertLevel != 0 { alertInfo := GetAlertInfo(dayNum, alertLevel, storeName, alertType, logicCondtion, outValue) SendAlertInfo(storeID, storeName, alertInfo) fieldName, fieldFlag := GetFieldNameByAlertType(alertType, dayNum) storeAlertDataWrapper.SetData(storeID, fieldName, ratio) if alertLevel == AlertLevelExtraRed { storeAlertDataWrapper.SetData(storeID, model.FieldExtraRedStatus, fieldFlag) } else if alertLevel == AlertLevelRed { storeAlertDataWrapper.SetData(storeID, model.FieldRedStatus, fieldFlag) } else if alertLevel == AlertLevelYellow { storeAlertDataWrapper.SetData(storeID, model.FieldYellowStatus, fieldFlag) } } } } func CheckStoreDayAlert(storeList []*cms.StoreExt, dayNum int) { db := dao.GetDB() //拣货履约订单(达达) pickTimeOrderCountDaDaList, _ := dao.GetStandardPickTimeOrderCountByDaDa(db, dayNum, IncludeToday) pickTimeOrderCountDaDaMapData := ConvertListToMap(pickTimeOrderCountDaDaList) //完成订单(达达) finishOrderCountDaDaList, _ := dao.GetFinishOrderCountByDaDa(db, dayNum, IncludeToday) finishOrderCountDaDaMapData := ConvertListToMap(finishOrderCountDaDaList) //差评订单 badCommentOrderCountList, _ := dao.GetBadCommentOrderCountByDayNum(db, dayNum, IncludeToday) badCommentOrderCountMapData := ConvertListToMap(badCommentOrderCountList) //缺货订单 absentGoodsOrderCountList, _ := dao.GetAbsentGoodsOrderCountByDayNum(db, dayNum, IncludeToday) absentGoodsOrderCountMapData := ConvertListToMap(absentGoodsOrderCountList) //完成订单 finishOrderCountList, _ := dao.GetFinishOrderCountByDayNum(db, dayNum, IncludeToday) finishOrderCountMapData := ConvertListToMap(finishOrderCountList) var standardFinishTimeOrderCountSelfDeliveryList []*model.StoreCount var standardFinishTimeOrderCountSelfDeliveryMapData map[int]int var finishOrderCountSelfDeliveryList []*model.StoreCount var finishOrderCountSelfDeliveryMapData map[int]int var standardPickUpTimeOrderCountDaDaList []*model.StoreCount var standardPickUpTimeOrderCountDaDaMapData map[int]int isOneWeekDay := dayNum == CheckStoreAlertOneWeekDayNum if isOneWeekDay { //按时履约订单(商家自送) standardFinishTimeOrderCountSelfDeliveryList, _ = dao.GetStandardFinishTimeOrderCountBySelfDelivery(db, dayNum, IncludeToday) standardFinishTimeOrderCountSelfDeliveryMapData = ConvertListToMap(standardFinishTimeOrderCountSelfDeliveryList) //完成订单(商家自送) finishOrderCountSelfDeliveryList, _ = dao.GetFinishOrderCountBySelfDelivery(db, dayNum, IncludeToday) finishOrderCountSelfDeliveryMapData = ConvertListToMap(finishOrderCountSelfDeliveryList) //10分钟取货完成订单(达达) standardPickUpTimeOrderCountDaDaList, _ = dao.GetStandardPickUpTimeOrderCountByDaDa(db, dayNum, IncludeToday) standardPickUpTimeOrderCountDaDaMapData = ConvertListToMap(standardPickUpTimeOrderCountDaDaList) } for _, storeInfo := range storeList { storeID := storeInfo.ID storeName := storeInfo.Name count := pickTimeOrderCountDaDaMapData[storeID] totalCount := finishOrderCountDaDaMapData[storeID] SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypePickTimeOrderDaDa, count, totalCount) count = badCommentOrderCountMapData[storeID] totalCount = finishOrderCountMapData[storeID] SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeBadCommentOrder, count, totalCount) count = absentGoodsOrderCountMapData[storeID] SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeAbsentGoodsOrder, count, totalCount) if isOneWeekDay { count = standardFinishTimeOrderCountSelfDeliveryMapData[storeID] totalCount = finishOrderCountSelfDeliveryMapData[storeID] SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeStandardFinishTimeOrderSelfDelivery, count, totalCount) count = standardPickUpTimeOrderCountDaDaMapData[storeID] totalCount = finishOrderCountDaDaMapData[storeID] SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeStandardPickUpTimeOrderDaDa, count, totalCount) } } } func CheckStoreMonthAlert(storeList []*cms.StoreExt) { db := dao.GetDB() storeCountList, _ := dao.GetFinishOrderCountByDayNum(db, CheckStoreAlertOneMonthDayNum, IncludeToday) storeCountMapData := make(map[int]int) for _, value := range storeCountList { storeCountMapData[value.StoreID] = value.Count } for _, storeInfo := range storeList { storeID := storeInfo.ID storeName := storeInfo.Name if _, ok := storeCountMapData[storeID]; !ok { alertInfo := GetAlertInfo(CheckStoreAlertOneMonthDayNum, AlertLevelRed, storeName, -1, "", -1) SendAlertInfo(storeID, storeName, alertInfo) storeAlertDataWrapper.SetData(storeID, model.FieldNoOrderInMonth, 1) storeAlertDataWrapper.SetData(storeID, model.FieldRedStatus, model.FlagNoOrderInMonth) } } } func CheckStoreRiskOrderAlert(storeList []*cms.StoreExt, dayNum int) { db := dao.GetDB() storeOrderList, _ := dao.GetRiskOrderCount(db, dayNum, IncludeToday) storeOrderMapData := ConvertListToMapEx(storeOrderList) for _, storeInfo := range storeList { storeID := storeInfo.ID storeName := storeInfo.Name vendorOrderIDList := storeOrderMapData[storeID] if vendorOrderIDList != nil { vendorOrderIDStr := "" for index, vendorOrderID := range vendorOrderIDList { if index == 0 { vendorOrderIDStr += vendorOrderID } else { vendorOrderIDStr += "," + vendorOrderID } } alertInfo := fmt.Sprintf(RiskOrderAlertInfo, storeName, vendorOrderIDStr) SendAlertInfo(storeID, storeName, alertInfo) storeAlertDataWrapper.SetData(storeID, model.FieldRiskOrderCount, len(vendorOrderIDList)) storeAlertDataWrapper.SetData(storeID, model.FieldRedStatus, model.FlagRiskOrderCount) } } } func GetWeekDay() int { return int(time.Now().Weekday()) } func CheckStoreAlert(ctx *jxcontext.Context, storeIDList []int) { storeAlertDataWrapper.InitData() storeList, _ := GetStoreList(ctx) storeIDMap := jxutils.IntList2Map(storeIDList) storeList = GetFilterStoreListEx(storeList, storeIDMap) if GetWeekDay() == MonthCheckOnWeekDay { CheckStoreMonthAlert(storeList) } CheckStoreDayAlert(storeList, CheckStoreAlertOneDayNum) CheckStoreDayAlert(storeList, CheckStoreAlertOneWeekDayNum) CheckStoreRiskOrderAlert(storeList, CheckStoreAlertOneDayNum) storeAlertDataWrapper.InsertStoreAlertList() storeAlertDataWrapper.ClearData() } func ScheduleCheckStoreAlert() { if EnableCheckStoreAlert { ScheduleTimerFunc("ScheduleCheckStoreAlert", func() { CheckStoreAlert(jxcontext.AdminCtx, nil) }, checkStoreAlertTimeList) } } func GetValueColorByStatus(extraRedStatus, redStatus, yellowStatus, flag int) (color string) { if (extraRedStatus&flag != 0) || (redStatus&flag != 0) { color = ColorRed } else if yellowStatus&flag != 0 { color = ColorYellow } else { color = ColorUnknown } return color } func GetStoreAlertList(storeIDList []int, cityCode int, keyWord string, dateTime time.Time, offset, pageSize int) (storeAlertData model.StoreAlertData, err error) { db := dao.GetDB() storeAlertList, err := dao.GetStoreAlertList(db, storeIDList, cityCode, keyWord, dateTime) if err == nil && len(storeAlertList) > 0 { offset = jxutils.FormalizePageOffset(offset) pageSize = jxutils.FormalizePageSize(pageSize) var pagedStoreAlertList []*model.StoreAlertEx for i := offset; i < offset+pageSize && i < len(storeAlertList); i++ { pagedStoreAlertList = append(pagedStoreAlertList, storeAlertList[i]) } var storeAlertAdvancedList []*model.StoreAlertAdvanced for _, value := range pagedStoreAlertList { storeAlertAdvanced := &model.StoreAlertAdvanced{} storeAlertAdvanced.ID = value.ID storeAlertAdvanced.CreatedTime = value.CreatedTime storeAlertAdvanced.AlertDate = value.AlertDate storeAlertAdvanced.StoreID = value.StoreID storeAlertAdvanced.StoreName = value.StoreName storeAlertAdvanced.CityName = value.CityName storeAlertAdvanced.PickTimeDaDa.Value = fmt.Sprintf("%d%%", value.PickTimeDaDa) storeAlertAdvanced.PickTimeDaDa.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagPickTimeDaDa) storeAlertAdvanced.BadComment.Value = fmt.Sprintf("%d%%", value.BadComment) storeAlertAdvanced.BadComment.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagBadComment) storeAlertAdvanced.AbsentGoods.Value = fmt.Sprintf("%d%%", value.AbsentGoods) storeAlertAdvanced.AbsentGoods.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagAbsentGoods) storeAlertAdvanced.PickTimeDaDaOneWeek.Value = fmt.Sprintf("%d%%", value.PickTimeDaDaOneWeek) storeAlertAdvanced.PickTimeDaDaOneWeek.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagPickTimeDaDaOneWeek) storeAlertAdvanced.BadCommentOneWeek.Value = fmt.Sprintf("%d%%", value.BadCommentOneWeek) storeAlertAdvanced.BadCommentOneWeek.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagBadCommentOneWeek) storeAlertAdvanced.AbsentGoodsOneWeek.Value = fmt.Sprintf("%d%%", value.AbsentGoodsOneWeek) storeAlertAdvanced.AbsentGoodsOneWeek.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagAbsentGoodsOneWeek) storeAlertAdvanced.StandardFinishTimeSelfDelivery.Value = fmt.Sprintf("%d%%", value.StandardFinishTimeSelfDelivery) storeAlertAdvanced.StandardFinishTimeSelfDelivery.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagStandardFinishTimeSelfDelivery) storeAlertAdvanced.StandardPickUpTimeDaDa.Value = fmt.Sprintf("%d%%", value.StandardPickUpTimeDaDa) storeAlertAdvanced.StandardPickUpTimeDaDa.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagStandardPickUpTimeDaDa) if value.NoOrderInMonth == 1 { storeAlertAdvanced.NoOrderInMonth.Value = "是" } else { storeAlertAdvanced.NoOrderInMonth.Value = "否" } storeAlertAdvanced.NoOrderInMonth.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagNoOrderInMonth) storeAlertAdvanced.RiskOrderCount.Value = utils.Int2Str(value.RiskOrderCount) storeAlertAdvanced.RiskOrderCount.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagRiskOrderCount) storeAlertAdvancedList = append(storeAlertAdvancedList, storeAlertAdvanced) } storeAlertData.TotalCount = len(storeAlertList) storeAlertData.StoreAlertList = storeAlertAdvancedList } return storeAlertData, err }