|
@@ -4,7 +4,6 @@ import (
|
|
"fmt"
|
|
"fmt"
|
|
"log"
|
|
"log"
|
|
"strings"
|
|
"strings"
|
|
- "sync"
|
|
|
|
"telemarketingEtl/config"
|
|
"telemarketingEtl/config"
|
|
"telemarketingEtl/util"
|
|
"telemarketingEtl/util"
|
|
"time"
|
|
"time"
|
|
@@ -48,17 +47,6 @@ B.3个自然日内有过“已接听”的通话记录且仍处于“商机线
|
|
|
|
|
|
*/
|
|
*/
|
|
|
|
|
|
-var (
|
|
|
|
- oPool chan bool
|
|
|
|
- oWait = &sync.WaitGroup{}
|
|
|
|
-)
|
|
|
|
-
|
|
|
|
-func init() {
|
|
|
|
- ctx := gctx.New()
|
|
|
|
- poolSize := g.Cfg().MustGet(ctx, "poolSize").Int()
|
|
|
|
- oPool = make(chan bool, poolSize)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
func GetOpenSea() {
|
|
func GetOpenSea() {
|
|
ctx := gctx.New()
|
|
ctx := gctx.New()
|
|
//
|
|
//
|
|
@@ -134,21 +122,21 @@ func GetOpenSea() {
|
|
|
|
|
|
userid := gconv.String(thisData["userid"])
|
|
userid := gconv.String(thisData["userid"])
|
|
if userid == "" {
|
|
if userid == "" {
|
|
- return
|
|
|
|
|
|
+ continue
|
|
}
|
|
}
|
|
if !mongodb.IsObjectIdHex(userid) {
|
|
if !mongodb.IsObjectIdHex(userid) {
|
|
userid = GetUserIdByPositionId(userid)
|
|
userid = GetUserIdByPositionId(userid)
|
|
}
|
|
}
|
|
if userid == "" {
|
|
if userid == "" {
|
|
- return
|
|
|
|
|
|
+ continue
|
|
}
|
|
}
|
|
//根据userid获取线索id
|
|
//根据userid获取线索id
|
|
if oneClassA[userid] {
|
|
if oneClassA[userid] {
|
|
- return
|
|
|
|
|
|
+ continue
|
|
}
|
|
}
|
|
uuid := GetClueIdByUserId(userid)
|
|
uuid := GetClueIdByUserId(userid)
|
|
if uuid == "" {
|
|
if uuid == "" {
|
|
- return
|
|
|
|
|
|
+ continue
|
|
}
|
|
}
|
|
oneClassA[uuid] = true
|
|
oneClassA[uuid] = true
|
|
|
|
|
|
@@ -190,23 +178,23 @@ func GetOpenSea() {
|
|
|
|
|
|
userid := gconv.String(thisData["userid"])
|
|
userid := gconv.String(thisData["userid"])
|
|
if userid == "" {
|
|
if userid == "" {
|
|
- return
|
|
|
|
|
|
+ continue
|
|
}
|
|
}
|
|
if !mongodb.IsObjectIdHex(userid) {
|
|
if !mongodb.IsObjectIdHex(userid) {
|
|
userid = GetUserIdByPositionId(userid)
|
|
userid = GetUserIdByPositionId(userid)
|
|
}
|
|
}
|
|
if userid == "" {
|
|
if userid == "" {
|
|
- return
|
|
|
|
|
|
+ continue
|
|
}
|
|
}
|
|
//根据userid获取线索id
|
|
//根据userid获取线索id
|
|
if oneClassA[userid] {
|
|
if oneClassA[userid] {
|
|
- return
|
|
|
|
|
|
+ continue
|
|
}
|
|
}
|
|
- uuid := GetClueIdByUserId(userid)
|
|
|
|
- if uuid == "" {
|
|
|
|
- return
|
|
|
|
|
|
+ clubId := GetClueIdByUserId(userid)
|
|
|
|
+ if clubId == "" {
|
|
|
|
+ continue
|
|
}
|
|
}
|
|
- oneClassA[uuid] = true
|
|
|
|
|
|
+ oneClassA[clubId] = true
|
|
|
|
|
|
count++
|
|
count++
|
|
if count%10 == 0 {
|
|
if count%10 == 0 {
|
|
@@ -234,8 +222,8 @@ func GetOpenSea() {
|
|
if oneClassA[userid] {
|
|
if oneClassA[userid] {
|
|
continue
|
|
continue
|
|
}
|
|
}
|
|
- uuid := GetClueIdByUserId(userid)
|
|
|
|
- oneClassB[uuid] = true
|
|
|
|
|
|
+ clubId := GetClueIdByUserId(userid)
|
|
|
|
+ oneClassB[clubId] = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
AddOpenSea(oneClassB, 1, "B")
|
|
AddOpenSea(oneClassB, 1, "B")
|
|
@@ -248,7 +236,7 @@ func GetOpenSea() {
|
|
AddOpenSea(twoC, 2, "C")
|
|
AddOpenSea(twoC, 2, "C")
|
|
AddOpenSea(twoD, 2, "D")
|
|
AddOpenSea(twoD, 2, "D")
|
|
//三级公海
|
|
//三级公海
|
|
- ThreeOpenSea()
|
|
|
|
|
|
+ ThreeOpenSea(oneClassA, oneClassB, oneClassC, twoA, twoB, twoC, twoD)
|
|
//
|
|
//
|
|
log.Println("end")
|
|
log.Println("end")
|
|
}
|
|
}
|
|
@@ -294,21 +282,21 @@ func TwoOpenSea(oneClassA, oneClassB, oneClassC map[string]bool) (aMap, bMap, cM
|
|
if err != nil {
|
|
if err != nil {
|
|
log.Println("row scan err:", err)
|
|
log.Println("row scan err:", err)
|
|
}
|
|
}
|
|
- uuid := GetClueIdByUserId(userid)
|
|
|
|
- if oneClassA[uuid] || oneClassB[uuid] || oneClassC[uuid] {
|
|
|
|
|
|
+ clubId := GetClueIdByUserId(userid)
|
|
|
|
+ if oneClassA[clubId] || oneClassB[clubId] || oneClassC[clubId] {
|
|
continue
|
|
continue
|
|
}
|
|
}
|
|
if ct >= 15 {
|
|
if ct >= 15 {
|
|
- aMap[uuid] = true
|
|
|
|
|
|
+ aMap[clubId] = true
|
|
}
|
|
}
|
|
if ct < 15 && ct >= 10 {
|
|
if ct < 15 && ct >= 10 {
|
|
- bMap[uuid] = true
|
|
|
|
|
|
+ bMap[clubId] = true
|
|
}
|
|
}
|
|
if ct < 10 && ct >= 5 {
|
|
if ct < 10 && ct >= 5 {
|
|
- cMap[uuid] = true
|
|
|
|
|
|
+ cMap[clubId] = true
|
|
}
|
|
}
|
|
if ct < 5 && ct >= 1 {
|
|
if ct < 5 && ct >= 1 {
|
|
- dMap[uuid] = true
|
|
|
|
|
|
+ dMap[clubId] = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Check for errors during iteration
|
|
// Check for errors during iteration
|
|
@@ -321,14 +309,14 @@ func TwoOpenSea(oneClassA, oneClassB, oneClassC map[string]bool) (aMap, bMap, cM
|
|
|
|
|
|
// 三级公海:
|
|
// 三级公海:
|
|
// 最近30天内活跃天数=0天的客户。
|
|
// 最近30天内活跃天数=0天的客户。
|
|
-func ThreeOpenSea() {
|
|
|
|
|
|
+func ThreeOpenSea(oneA, oneB, oneC, twoA, twoB, twoC, twoD map[string]bool) {
|
|
ctx := gctx.New()
|
|
ctx := gctx.New()
|
|
t := time.Now()
|
|
t := time.Now()
|
|
t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
|
|
t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
|
|
day := g.Cfg().MustGet(ctx, "classThreeHighSeaslastDay").Int()
|
|
day := g.Cfg().MustGet(ctx, "classThreeHighSeaslastDay").Int()
|
|
- t.AddDate(0, 0, day)
|
|
|
|
|
|
+ t = t.AddDate(0, 0, -day)
|
|
start := util.GetObjectId(t.Unix())
|
|
start := util.GetObjectId(t.Unix())
|
|
- // createtime := time.Now().Format(date.Date_Full_Layout)
|
|
|
|
|
|
+ log.Println(t.Format(date.Date_Full_Layout), "~~")
|
|
|
|
|
|
config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
|
|
config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
|
|
for _, v := range *l {
|
|
for _, v := range *l {
|
|
@@ -339,15 +327,16 @@ func ThreeOpenSea() {
|
|
"$gte": start,
|
|
"$gte": start,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
- // uuid := gconv.String(v["uid"])
|
|
|
|
id := gconv.Int64(v["id"])
|
|
id := gconv.Int64(v["id"])
|
|
|
|
+ clubId := gconv.String(v["id"])
|
|
if r, ok := config.MgoLog.Find("subscribepay_logs", query, nil, `{"_id":1}`, false, 0, 1); ok && r != nil && len(*r) == 0 {
|
|
if r, ok := config.MgoLog.Find("subscribepay_logs", query, nil, `{"_id":1}`, false, 0, 1); ok && r != nil && len(*r) == 0 {
|
|
|
|
+ if oneA[clubId] || oneB[clubId] || oneC[clubId] || twoA[clubId] || twoB[clubId] || twoC[clubId] || twoD[clubId] {
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
config.JianyuSubjectdb.Update("dwd_f_crm_open_sea", map[string]interface{}{"clue_id": id}, map[string]interface{}{
|
|
config.JianyuSubjectdb.Update("dwd_f_crm_open_sea", map[string]interface{}{"clue_id": id}, map[string]interface{}{
|
|
- // "comeintime": createtime,
|
|
|
|
"LEVEL": 3,
|
|
"LEVEL": 3,
|
|
"clue_level": "D",
|
|
"clue_level": "D",
|
|
})
|
|
})
|
|
-
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
return true
|
|
@@ -383,6 +372,7 @@ func AddOpenSea(m map[string]bool, level int, clue_level string) {
|
|
|
|
|
|
// 自动退出公海
|
|
// 自动退出公海
|
|
// 线索状态为“空号停机”自动从线索池删除。
|
|
// 线索状态为“空号停机”自动从线索池删除。
|
|
|
|
+// 空号停机 删除私海, 线索表分配状态改成 -1
|
|
func DeleteOpenSea() {
|
|
func DeleteOpenSea() {
|
|
config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
|
|
config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
|
|
ids := []interface{}{}
|
|
ids := []interface{}{}
|
|
@@ -395,7 +385,7 @@ func DeleteOpenSea() {
|
|
whs = append(whs, "?")
|
|
whs = append(whs, "?")
|
|
}
|
|
}
|
|
wh := strings.Join(whs, ",")
|
|
wh := strings.Join(whs, ",")
|
|
- count := config.JianyuSubjectdb.UpdateOrDeleteBySql(`delete from dwd_f_crm_clue_info where id in (`+wh+`)`, ids...)
|
|
|
|
|
|
+ count := config.JianyuSubjectdb.UpdateOrDeleteBySql(`UPDATE dwd_f_crm_clue_info SET is_assign = -1 WHERE id in (`+wh+`)`, ids...)
|
|
if count > 0 {
|
|
if count > 0 {
|
|
return true
|
|
return true
|
|
}
|
|
}
|
|
@@ -418,17 +408,22 @@ func ReturnOpenSea() {
|
|
t := time.Now()
|
|
t := time.Now()
|
|
t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
|
|
t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
|
|
//高意向客户
|
|
//高意向客户
|
|
- highIntentionCustomer := g.Cfg().MustGet(ctx, "highIntentionCustomer").Int()
|
|
|
|
|
|
+ highIntentionCustomer := g.Cfg().MustGet(ctx, "highIntentionCustomer").Int() //30
|
|
//意向客户
|
|
//意向客户
|
|
- intentionCustomer := g.Cfg().MustGet(ctx, "intentionCustomer").Int()
|
|
|
|
|
|
+ intentionCustomer := g.Cfg().MustGet(ctx, "intentionCustomer").Int() //30
|
|
//潜在客户
|
|
//潜在客户
|
|
- latentCustomer := g.Cfg().MustGet(ctx, "latentCustomer").Int()
|
|
|
|
|
|
+ latentCustomer := g.Cfg().MustGet(ctx, "latentCustomer").Int() //60
|
|
//沉睡客户
|
|
//沉睡客户
|
|
- sleepCustomer := g.Cfg().MustGet(ctx, "sleepCustomer").Int()
|
|
|
|
|
|
+ sleepCustomer := g.Cfg().MustGet(ctx, "sleepCustomer").Int() //90
|
|
//商机线索
|
|
//商机线索
|
|
- businessLeads := g.Cfg().MustGet(ctx, "businessLeads").Int()
|
|
|
|
|
|
+ businessLeads := g.Cfg().MustGet(ctx, "businessLeads").Int() //2
|
|
//无意向客户
|
|
//无意向客户
|
|
- noIdeaCustomer := g.Cfg().MustGet(ctx, "noIdeaCustomer").Int()
|
|
|
|
|
|
+ // noIdeaCustomer := g.Cfg().MustGet(ctx, "noIdeaCustomer").Int() //
|
|
|
|
+
|
|
|
|
+ codeMap := dwd_d_crm_trailstatus_code()
|
|
|
|
+
|
|
|
|
+ now := time.Now().Format(date.Date_Full_Layout)
|
|
|
|
+
|
|
//2.“高意向客户”超过30天未更新跟进记录自动退回公海;
|
|
//2.“高意向客户”超过30天未更新跟进记录自动退回公海;
|
|
for trailstatus, nexttime := range map[string]interface{}{
|
|
for trailstatus, nexttime := range map[string]interface{}{
|
|
"06": t.AddDate(0, 0, -highIntentionCustomer),
|
|
"06": t.AddDate(0, 0, -highIntentionCustomer),
|
|
@@ -436,18 +431,39 @@ func ReturnOpenSea() {
|
|
"04": t.AddDate(0, 0, -latentCustomer),
|
|
"04": t.AddDate(0, 0, -latentCustomer),
|
|
"03": t.AddDate(0, 0, -sleepCustomer),
|
|
"03": t.AddDate(0, 0, -sleepCustomer),
|
|
"01": t.AddDate(0, 0, -businessLeads),
|
|
"01": t.AddDate(0, 0, -businessLeads),
|
|
- "00": t.AddDate(0, 0, -noIdeaCustomer),
|
|
|
|
|
|
+ "00": t,
|
|
} {
|
|
} {
|
|
|
|
+ sql := `SELECT MAX(c.next_time) nexttime, b.id FROM dwd_f_crm_private_sea a
|
|
|
|
+ LEFT JOIN dwd_f_crm_clue_info b ON a.clue_id=b.id
|
|
|
|
+ LEFT JOIN dwd_f_crm_trail_content c ON b.id =c.clue_id
|
|
|
|
+ WHERE b.trailstatus =?`
|
|
|
|
+ argsSelect := []interface{}{trailstatus}
|
|
|
|
+ if trailstatus != "00" {
|
|
|
|
+ sql += " AND c.next_time >? "
|
|
|
|
+ argsSelect = append(argsSelect, nexttime)
|
|
|
|
+ }
|
|
|
|
+ sql += " GROUP BY b.id"
|
|
config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
|
|
config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
|
|
//1新增 2私海手动退回 3私海高意向客户自动退回 4私海意向客户退回 5私海潜在客户退回 6私海沉睡客户退回 7私海商机线索退回 8私海无意向客户退回
|
|
//1新增 2私海手动退回 3私海高意向客户自动退回 4私海意向客户退回 5私海潜在客户退回 6私海沉睡客户退回 7私海商机线索退回 8私海无意向客户退回
|
|
comeinsource := GetComeSource()[trailstatus]
|
|
comeinsource := GetComeSource()[trailstatus]
|
|
ids := []interface{}{}
|
|
ids := []interface{}{}
|
|
args := []interface{}{}
|
|
args := []interface{}{}
|
|
|
|
+ changeArgs1 := []interface{}{}
|
|
|
|
+ changeArgs2 := []interface{}{}
|
|
|
|
+ changeArgs3 := []interface{}{}
|
|
|
|
+ changeArgs4 := []interface{}{}
|
|
for _, v := range *l {
|
|
for _, v := range *l {
|
|
id := v["id"]
|
|
id := v["id"]
|
|
|
|
+ position_id := v["position_id"]
|
|
|
|
+ seatNumber := gconv.String(v["seatNumber"])
|
|
ids = append(ids, id)
|
|
ids = append(ids, id)
|
|
//
|
|
//
|
|
- args = append(args, id, time.Now().Format(date.Date_Full_Layout), comeinsource)
|
|
|
|
|
|
+ args = append(args, id, now, comeinsource)
|
|
|
|
+ changeArgs1 = append(changeArgs1, id, position_id, "trailstatus", "线索状态变更", codeMap[trailstatus], "流失", now, -1)
|
|
|
|
+ changeArgs2 = append(changeArgs2, id, position_id, "position_id", "所属人变更", GetPositionName(seatNumber), "/", now, -1)
|
|
|
|
+ changeArgs3 = append(changeArgs3, id, position_id, "退出任务车", "未更新跟进记录自动退回公海", now, -1)
|
|
|
|
+ changeArgs3 = append(changeArgs3, id, position_id, "退回公海", "未更新跟进记录自动退回公海", now, -1)
|
|
|
|
+
|
|
}
|
|
}
|
|
whs := []string{}
|
|
whs := []string{}
|
|
for i := 0; i < len(ids); i++ {
|
|
for i := 0; i < len(ids); i++ {
|
|
@@ -458,15 +474,21 @@ func ReturnOpenSea() {
|
|
count := config.JianyuSubjectdb.UpdateOrDeleteBySql(`delete from dwd_f_crm_private_sea where clue_id in (`+wh+`)`, ids...)
|
|
count := config.JianyuSubjectdb.UpdateOrDeleteBySql(`delete from dwd_f_crm_private_sea where clue_id in (`+wh+`)`, ids...)
|
|
//进入公海
|
|
//进入公海
|
|
config.JianyuSubjectdb.InsertIgnoreBatch("dwd_f_crm_open_sea", []string{"clue_id", "comeintime", "comeinsource"}, args)
|
|
config.JianyuSubjectdb.InsertIgnoreBatch("dwd_f_crm_open_sea", []string{"clue_id", "comeintime", "comeinsource"}, args)
|
|
- //
|
|
|
|
|
|
+ //改线索表 职位id 坐席号 弄成空 分配状态改成未分配
|
|
|
|
+ config.JianyuSubjectdb.UpdateOrDeleteBySql(`UPDATE dwd_f_crm_clue_info SET seatNumber ='',position_id=0,is_assign=0 WHERE id in (`+wh+`)`, ids...)
|
|
|
|
+
|
|
|
|
+ // 添加线索修改记录
|
|
|
|
+
|
|
|
|
+ //线索状态变更记录
|
|
|
|
+ config.JianyuSubjectdb.InsertBatch("dwd_f_crm_clue_change_record", []string{"clue_id", "position_id", "change_field", "change_type", "old_value", "new_value", "createtime", "operator_id"}, changeArgs1)
|
|
|
|
+ config.JianyuSubjectdb.InsertBatch("dwd_f_crm_clue_change_record", []string{"clue_id", "position_id", "change_field", "change_type", "old_value", "new_value", "createtime", "operator_id"}, changeArgs2)
|
|
|
|
+ config.JianyuSubjectdb.InsertBatch("dwd_f_crm_clue_change_record", []string{"clue_id", "position_id", "change_type", "new_value", "createtime", "operator_id"}, changeArgs3)
|
|
|
|
+ config.JianyuSubjectdb.InsertBatch("dwd_f_crm_clue_change_record", []string{"clue_id", "position_id", "change_type", "new_value", "createtime", "operator_id"}, changeArgs4)
|
|
if count > 0 {
|
|
if count > 0 {
|
|
return true
|
|
return true
|
|
}
|
|
}
|
|
return true
|
|
return true
|
|
- }, `SELECT MAX(c.next_time) nexttime, b.id FROM dwd_f_crm_private_sea a
|
|
|
|
- LEFT JOIN dwd_f_crm_clue_info b ON a.clue_id=b.id
|
|
|
|
- LEFT JOIN dwd_f_crm_trail_content c ON b.id =c.clue_id
|
|
|
|
- WHERE b.trailstatus =? AND c.next_time >? GROUP BY b.id`, trailstatus, nexttime)
|
|
|
|
|
|
+ }, sql, argsSelect...)
|
|
}
|
|
}
|
|
log.Println("return sea end")
|
|
log.Println("return sea end")
|
|
}
|
|
}
|
|
@@ -493,3 +515,22 @@ func GetOneSeaC() map[string]bool {
|
|
}, `select clue_id from dwd_f_crm_open_sea where comeinsource in(2,3,4)`)
|
|
}, `select clue_id from dwd_f_crm_open_sea where comeinsource in(2,3,4)`)
|
|
return m
|
|
return m
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+func dwd_d_crm_trailstatus_code() map[string]string {
|
|
|
|
+ m := map[string]string{}
|
|
|
|
+ data := config.JianyuSubjectdb.SelectBySql(`SELECT CODE,NAME FROM dwd_d_crm_trailstatus_code;`)
|
|
|
|
+ for _, v := range *data {
|
|
|
|
+ code := gconv.String(v["CODE"])
|
|
|
|
+ name := gconv.String(v["NAME"])
|
|
|
|
+ m[code] = name
|
|
|
|
+ }
|
|
|
|
+ return m
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func GetPositionName(seatNumber string) string {
|
|
|
|
+ data := config.JianyuSubjectdb.SelectBySql(`select name from jy_salesperson_info where status = 0 and position != 0 and seatNumber = ? limit 1`, seatNumber)
|
|
|
|
+ if data != nil && len(*data) > 0 {
|
|
|
|
+ return gconv.String((*data)[0]["name"])
|
|
|
|
+ }
|
|
|
|
+ return ""
|
|
|
|
+}
|