dwd_f_crm_open_sea.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. package entity
  2. import (
  3. "fmt"
  4. "log"
  5. "strings"
  6. "telemarketingEtl/config"
  7. "time"
  8. "app.yhyue.com/moapp/jybase/date"
  9. "app.yhyue.com/moapp/jybase/mongodb"
  10. "github.com/gogf/gf/v2/frame/g"
  11. "github.com/gogf/gf/v2/os/gctx"
  12. "github.com/gogf/gf/v2/util/gconv"
  13. )
  14. /*
  15. 超级订阅落地页 /front/vipsubscribe/introducePage /jyapp/vipsubscribe/introducePage
  16. 大会员落地页 /big/wx/page/landingPage /jyapp/big/page/landingPage
  17. 产品体系服务 /product/index
  18. 数据导出筛选 /front/dataExport/toSieve /front/wx_dataExport/toSieve /jyapp/front/dataExport/toSieve
  19. 数据导出购买 /front/dataExport/toCreateOrderPage/425b420f564502000756420a4056564451535451430e490f?from=&type=2&source=
  20. 数据流量包 /front/dataPack/createOrder
  21. 超级订阅 /swordfish/page_big_pc/free/svip/buy
  22. 大会员 /big/pc/page/buy_commit
  23. */
  24. /*
  25. 3.公海客户来源:
  26. (1)一级公海:
  27. A. 3天内点击过剑鱼付费产品介绍页(产品-供应商服务体系页、大会员落地页、超级订阅落地页、数据自助导出-筛选条件页)或进入了购买页(超级订阅、大会员购买页、数据自助导出购买页、数据流量包购买页)的客户;
  28. B. 购买了超级订阅产品剩余使用时长不足30天的客户;
  29. C.超时未跟进导致被自动退回至公海的处于“潜在客户”、“意向客户”、“高意向客户”
  30. (2)二级公海:
  31. A.最近30天内活跃天数≥15天的客户;
  32. B.10天≤最近30天内活跃天数<15天的客户;
  33. C.5天≤最近30天内活跃天数<10天的客户;
  34. D.1天≤最近30天内活跃天数<5天的客户;
  35. 备注:判断当日是否活跃的标准为当日是否点击查看了标讯内容。
  36. (3)三级公海:
  37. 最近30天内活跃天数=0天的客户。
  38. (4)回收站:
  39. A.5个自然日内被销售人员手动退回公海的客户;
  40. B.3个自然日内有过“已接听”的通话记录且仍处于“商机线索”状态下的客户。
  41. (5)以上,涉及时间及量的均可配置。
  42. */
  43. func GetOpenSea() {
  44. ctx := gctx.New()
  45. //
  46. session := config.MgoLog.GetMgoConn()
  47. defer config.MgoLog.DestoryMongoConn(session)
  48. t := time.Now()
  49. t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
  50. end := t.Unix()
  51. tA := t.AddDate(0, 0, -g.Cfg().MustGet(ctx, "classOneHighSeas_A").Int())
  52. start := tA.Unix()
  53. oneClassA := map[string]bool{}
  54. //一级公海查询条件
  55. queryOneClassPc := map[string]interface{}{
  56. "date": map[string]interface{}{
  57. "$gte": start,
  58. "$lt": end,
  59. },
  60. "$or": []map[string]interface{}{
  61. map[string]interface{}{
  62. "url": map[string]interface{}{
  63. "$regex": `/front/vipsubscribe/introducePage`,
  64. },
  65. },
  66. map[string]interface{}{
  67. "url": map[string]interface{}{
  68. "$regex": `/big/wx/page/landingPage`,
  69. },
  70. },
  71. map[string]interface{}{
  72. "url": map[string]interface{}{
  73. "$regex": `/product/index`,
  74. },
  75. },
  76. map[string]interface{}{
  77. "url": map[string]interface{}{
  78. "$regex": `/front/dataExport/toSieve`,
  79. },
  80. },
  81. map[string]interface{}{
  82. "url": map[string]interface{}{
  83. "$regex": `/front/dataExport/toCreateOrderPage`,
  84. },
  85. },
  86. map[string]interface{}{
  87. "url": map[string]interface{}{
  88. "$regex": `/front/dataPack/createOrder`,
  89. },
  90. },
  91. map[string]interface{}{
  92. "url": map[string]interface{}{
  93. "$regex": `/swordfish/page_big_pc/free/svip/buy`,
  94. },
  95. },
  96. map[string]interface{}{
  97. "url": map[string]interface{}{
  98. "$regex": `/big/pc/page/buy_commit`,
  99. },
  100. },
  101. map[string]interface{}{
  102. "url": map[string]interface{}{
  103. "$regex": `/front/wx_dataExport/toSieve`,
  104. },
  105. },
  106. },
  107. }
  108. log.Println("queryOneClassPc:", queryOneClassPc)
  109. iter := session.DB("qfw").C("jy_logs").Find(queryOneClassPc).Iter()
  110. count := 0
  111. log.Println("一级公海开始.")
  112. //一级公海
  113. for thisData := map[string]interface{}{}; iter.Next(&thisData); {
  114. userid := gconv.String(thisData["userid"])
  115. if userid == "" {
  116. continue
  117. }
  118. if !mongodb.IsObjectIdHex(userid) {
  119. userid, _ = GetUserIdByPositionId(userid)
  120. }
  121. if userid == "" {
  122. continue
  123. }
  124. clubId := GetClueIdByUserId(userid)
  125. if clubId == "" {
  126. continue
  127. }
  128. //根据userid获取线索id
  129. if oneClassA[clubId] {
  130. continue
  131. }
  132. oneClassA[clubId] = true
  133. count++
  134. if count%100 == 0 {
  135. log.Printf("已完成%d条数据\n", count)
  136. }
  137. thisData = map[string]interface{}{}
  138. }
  139. log.Println("一级公海 pc 结束")
  140. queryOneClassApp := map[string]interface{}{
  141. "date": map[string]interface{}{
  142. "$gte": start,
  143. "$lt": end,
  144. },
  145. "$or": []map[string]interface{}{
  146. map[string]interface{}{
  147. "url": map[string]interface{}{
  148. "$regex": `/jyapp/vipsubscribe/introducePage`,
  149. },
  150. },
  151. map[string]interface{}{
  152. "url": map[string]interface{}{
  153. "$regex": `jyapp/big/page/landingPage`,
  154. },
  155. },
  156. map[string]interface{}{
  157. "url": map[string]interface{}{
  158. "$regex": `/jyapp/front/dataExport/toSieve`,
  159. },
  160. },
  161. },
  162. }
  163. iter2 := session.DB("qfw").C("jyapp_logs").Find(queryOneClassApp).Iter()
  164. count = 0
  165. //一级公海
  166. for thisData := map[string]interface{}{}; iter2.Next(&thisData); {
  167. userid := gconv.String(thisData["userid"])
  168. if userid == "" {
  169. continue
  170. }
  171. if !mongodb.IsObjectIdHex(userid) {
  172. userid, _ = GetUserIdByPositionId(userid)
  173. }
  174. if userid == "" {
  175. continue
  176. }
  177. clubId := GetClueIdByUserId(userid)
  178. if clubId == "" {
  179. continue
  180. }
  181. //根据userid获取线索id
  182. if oneClassA[clubId] {
  183. continue
  184. }
  185. oneClassA[clubId] = true
  186. count++
  187. if count%10 == 0 {
  188. log.Printf("已完成%d条数据\n", count)
  189. }
  190. thisData = map[string]interface{}{}
  191. }
  192. //更新公海
  193. AddOpenSea(oneClassA, 1, "A")
  194. //
  195. oneClassB := map[string]bool{}
  196. vipendtime := t.AddDate(0, 0, -g.Cfg().MustGet(ctx, "classOneHighSeas_B").Int())
  197. classB, ok := config.Mgo.Find("user", map[string]interface{}{
  198. "l_vip_endtime": map[string]interface{}{
  199. "$lt": vipendtime.Unix(),
  200. },
  201. "i_vip_status": map[string]interface{}{
  202. "$gt": 0,
  203. },
  204. "i_appid": 2,
  205. }, nil, `{"_id":1}`, false, -1, -1)
  206. if classB != nil && ok && len(*classB) > 0 {
  207. for _, v := range *classB {
  208. userid := mongodb.BsonIdToSId(v["_id"])
  209. clubId := GetClueIdByUserId(userid)
  210. if clubId == "" {
  211. continue
  212. }
  213. if oneClassA[clubId] {
  214. continue
  215. }
  216. oneClassB[clubId] = true
  217. }
  218. }
  219. AddOpenSea(oneClassB, 1, "B")
  220. oneClassC := GetOneSeaC(oneClassA, oneClassB)
  221. AddOpenSea(oneClassC, 1, "C")
  222. log.Println("一级公海 更新结束。")
  223. //
  224. twoA, twoB, twoC, twoD := TwoOpenSea(oneClassA, oneClassB, oneClassC)
  225. AddOpenSea(twoA, 2, "A")
  226. AddOpenSea(twoB, 2, "B")
  227. AddOpenSea(twoC, 2, "C")
  228. AddOpenSea(twoD, 2, "D")
  229. //三级公海
  230. ThreeOpenSea(oneClassA, oneClassB, oneClassC, twoA, twoB, twoC, twoD)
  231. // AddOpenSea(three, 3, "D")
  232. //
  233. Recycle()
  234. log.Println("end")
  235. }
  236. //二级公海
  237. /*
  238. A.最近30天内活跃天数≥15天的客户;
  239. B.10天≤最近30天内活跃天数<15天的客户;
  240. C.5天≤最近30天内活跃天数<10天的客户;
  241. D.1天≤最近30天内活跃天数<5天的客户;
  242. */
  243. func TwoOpenSea(oneClassA, oneClassB, oneClassC map[string]bool) (aMap, bMap, cMap, dMap map[string]bool) {
  244. clubIdMap := func() map[string]string {
  245. c := 0
  246. mp := map[string]string{}
  247. config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
  248. for _, v := range *l {
  249. c++
  250. if c%5000 == 0 {
  251. log.Println("加载clue_info数据:", c)
  252. }
  253. mp[gconv.String(v["userid"])] = gconv.String(v["id"])
  254. }
  255. return true
  256. }, `SELECT id,userid FROM dwd_f_crm_clue_info WHERE userid !="" and is_assign = 0`)
  257. return mp
  258. }()
  259. log.Println("clue_info数据加载结束:", len(clubIdMap))
  260. //
  261. i_day := g.Cfg().MustGet(ctx, "classTwoHighSeaslastDay").Int()
  262. day := time.Now().AddDate(0, 0, -i_day).Format(date.Date_Full_Layout)
  263. q := fmt.Sprintf("SELECT userid,COUNT(1) as count FROM dwd_f_userbase_visit_info WHERE createtime > '%s' AND contentnum >0 GROUP BY userid ", day)
  264. //
  265. log.Println(q)
  266. stmtOut, err := config.JianyuSubjectdb.DB.Prepare(q)
  267. log.Println("stmtOut.err:", err)
  268. defer func() {
  269. log.Println("stmtOut.Close start")
  270. stmtOut.Close()
  271. log.Println("stmtOut.Close over")
  272. }()
  273. rows, err := stmtOut.Query()
  274. if err != nil {
  275. log.Println("er:", err)
  276. }
  277. defer func() {
  278. log.Println("rows.Close start")
  279. rows.Close()
  280. log.Println("rows.Close over")
  281. }()
  282. aMap = map[string]bool{}
  283. bMap = map[string]bool{}
  284. cMap = map[string]bool{}
  285. dMap = map[string]bool{}
  286. count := 0
  287. for rows.Next() {
  288. var userid string
  289. var ct int
  290. err := rows.Scan(&userid, &ct)
  291. if err != nil {
  292. log.Println("row scan err:", err)
  293. }
  294. count++
  295. if count%5000 == 0 {
  296. log.Println("二级公海查询:", count)
  297. }
  298. // clubId := GetClueIdByUserId(userid)
  299. clubId := clubIdMap[userid]
  300. if clubId == "" {
  301. continue
  302. }
  303. if oneClassA[clubId] || oneClassB[clubId] || oneClassC[clubId] {
  304. continue
  305. }
  306. if ct >= 15 {
  307. aMap[clubId] = true
  308. }
  309. if ct < 15 && ct >= 10 {
  310. bMap[clubId] = true
  311. }
  312. if ct < 10 && ct >= 5 {
  313. cMap[clubId] = true
  314. }
  315. if ct < 5 && ct >= 1 {
  316. dMap[clubId] = true
  317. }
  318. }
  319. // Check for errors during iteration
  320. err = rows.Err()
  321. if err != nil {
  322. log.Println("rows err err:", err)
  323. }
  324. return
  325. }
  326. // 三级公海:
  327. // 最近30天内活跃天数=0天的客户。
  328. func ThreeOpenSea(oneA, oneB, oneC, twoA, twoB, twoC, twoD map[string]bool) map[string]bool {
  329. log.Println("三级公海start")
  330. m := map[string]bool{}
  331. ctx := gctx.New()
  332. t := time.Now()
  333. t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
  334. day := g.Cfg().MustGet(ctx, "classThreeHighSeaslastDay").Int()
  335. t = t.AddDate(0, 0, -day)
  336. count := 0
  337. visitMap := func() map[string]bool {
  338. c := 0
  339. mp := map[string]bool{}
  340. config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
  341. for _, v := range *l {
  342. c++
  343. if c%5000 == 0 {
  344. log.Println("加载dwd_f_userbase_visit_info数据:", c)
  345. }
  346. mp[gconv.String(v["userid"])] = true
  347. }
  348. return true
  349. }, `SELECT COUNT(1),userid FROM dwd_f_userbase_visit_info WHERE createtime > ? AND contentnum >0 GROUP BY userid`, t.Format(date.Date_Full_Layout))
  350. return mp
  351. }()
  352. log.Println("dwd_f_userbase_visit_info数据加载结束:", len(visitMap))
  353. config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
  354. ids := []interface{}{}
  355. for _, v := range *l {
  356. count++
  357. if count%5000 == 0 {
  358. log.Println("三级公海加载:", count)
  359. }
  360. clubId := gconv.String(v["id"])
  361. userid := gconv.String(v["userid"])
  362. // q := fmt.Sprintf("SELECT count(1) FROM dwd_f_userbase_visit_info WHERE createtime > '%s' AND contentnum >0 and userid = '%s'", t.Format(date.Date_Full_Layout), userid)
  363. // if config.JianyuSubjectdb.CountBySql(q) > 0 {
  364. // continue
  365. // }
  366. if visitMap[userid] {
  367. continue
  368. }
  369. if oneA[clubId] || oneB[clubId] || oneC[clubId] || twoA[clubId] || twoB[clubId] || twoC[clubId] || twoD[clubId] {
  370. continue
  371. }
  372. ids = append(ids, clubId)
  373. }
  374. whs := []string{}
  375. for i := 0; i < len(ids); i++ {
  376. whs = append(whs, "?")
  377. }
  378. wh := strings.Join(whs, ",")
  379. config.JianyuSubjectdb.UpdateOrDeleteBySql(`UPDATE dwd_f_crm_clue_info SET level_open = 3,clue_level='D' WHERE id in (`+wh+`)`, ids...)
  380. return true
  381. }, `SELECT id,userid FROM dwd_f_crm_clue_info where is_assign = 0`)
  382. log.Println("三级公海end")
  383. return m
  384. }
  385. // 根据mongodb userid 获取 线索id
  386. func GetClueIdByUserId(userid string) (uuid string) {
  387. if userid == "" {
  388. return
  389. }
  390. data := config.JianyuSubjectdb.SelectBySql(`select id from dwd_f_crm_clue_info where is_assign = 0 and userid=? limit 1`, userid)
  391. if data == nil || len(*data) == 0 {
  392. return
  393. }
  394. return gconv.String((*data)[0]["id"])
  395. }
  396. // m 需要更新的Map key:uuid
  397. // level 公海级别
  398. // clue_level线索级别
  399. func AddOpenSea(m map[string]bool, level int, clue_level string) {
  400. // createtime := time.Now().Format(date.Date_Full_Layout)
  401. if len(m) > 0 {
  402. for k, _ := range m {
  403. config.JianyuSubjectdb.Update("dwd_f_crm_clue_info", map[string]interface{}{"id": k}, map[string]interface{}{
  404. "clue_level": clue_level,
  405. "level_open": level,
  406. })
  407. }
  408. }
  409. }
  410. // 自动退出公海
  411. // 线索状态为“空号停机”自动从线索池删除。
  412. // 空号停机 删除私海, 线索表分配状态改成 -1
  413. // func DeleteOpenSea() {
  414. // config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
  415. // ids := []interface{}{}
  416. // for _, v := range *l {
  417. // id := v["id"]
  418. // ids = append(ids, id)
  419. // }
  420. // whs := []string{}
  421. // for i := 0; i < len(ids); i++ {
  422. // whs = append(whs, "?")
  423. // }
  424. // wh := strings.Join(whs, ",")
  425. // count := config.JianyuSubjectdb.UpdateOrDeleteBySql(`UPDATE dwd_f_crm_clue_info SET is_assign = -1 WHERE id in (`+wh+`)`, ids...)
  426. // if count > 0 {
  427. // return true
  428. // }
  429. // return true
  430. // }, `select id from dwd_f_crm_clue_info where trailstatus = ?`, "02")
  431. // }
  432. //自动退回公海
  433. /*
  434. 1.处于“待签署客户”和“成交客户”状态下的客户不自动退回公海;
  435. 2.“高意向客户”超过30天未更新跟进记录自动退回公海;
  436. 3.“意向客户”超过30天未更新跟进记录自动退回公海;
  437. 4.“潜在客户”超过60天未更新跟进记录自动退回公海;
  438. 5.“沉睡客户”超过90天未更新跟进记录自动退回公海;
  439. 6.“商机线索”超过2天未更新跟进记录自动退回公海;
  440. 7.“无意向客户”自动退回公海;
  441. */
  442. // func ReturnOpenSea() {
  443. // ctx := gctx.New()
  444. // t := time.Now()
  445. // t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
  446. // //高意向客户
  447. // highIntentionCustomer := g.Cfg().MustGet(ctx, "highIntentionCustomer").Int() //30
  448. // //意向客户
  449. // intentionCustomer := g.Cfg().MustGet(ctx, "intentionCustomer").Int() //30
  450. // //潜在客户
  451. // latentCustomer := g.Cfg().MustGet(ctx, "latentCustomer").Int() //60
  452. // //沉睡客户
  453. // sleepCustomer := g.Cfg().MustGet(ctx, "sleepCustomer").Int() //90
  454. // //商机线索
  455. // businessLeads := g.Cfg().MustGet(ctx, "businessLeads").Int() //2
  456. // //无意向客户
  457. // // noIdeaCustomer := g.Cfg().MustGet(ctx, "noIdeaCustomer").Int() //
  458. // codeMap := dwd_d_crm_trailstatus_code()
  459. // now := time.Now().Format(date.Date_Full_Layout)
  460. // //判断节假日
  461. // statusMap := map[string]int{
  462. // "06": highIntentionCustomer,
  463. // "05": intentionCustomer,
  464. // "04": latentCustomer,
  465. // "03": sleepCustomer,
  466. // "01": businessLeads,
  467. // }
  468. // for status, statusInt := range statusMap {
  469. // count, counts := 0, 0
  470. // for {
  471. // count++
  472. // currentTime := t.AddDate(0, 0, -count)
  473. // if currentTime.Weekday() == time.Sunday || currentTime.Weekday() == time.Saturday {
  474. // isok := false
  475. // for k, v := range config.DateMap {
  476. // if currentTime.Format(date.Date_Short_Layout) == k && v == 2 {
  477. // isok = true
  478. // }
  479. // }
  480. // if isok {
  481. // counts++
  482. // }
  483. // } else {
  484. // isok := true
  485. // for k, v := range config.DateMap {
  486. // if currentTime.Format(date.Date_Short_Layout) == k && v == 1 {
  487. // isok = false
  488. // }
  489. // }
  490. // if isok {
  491. // counts++
  492. // }
  493. // }
  494. // if counts >= statusInt {
  495. // break
  496. // }
  497. // }
  498. // statusMap[status] = count
  499. // }
  500. // //
  501. // //2.“高意向客户”超过30天未更新跟进记录自动退回公海;
  502. // for trailstatus, _ := range map[string]string{
  503. // "06": "",
  504. // "05": "",
  505. // "04": "",
  506. // "03": "",
  507. // "01": "",
  508. // "00": "",
  509. // } {
  510. // sql := `SELECT a.clue_id,a.position_id,a.seatNumber FROM dwd_f_crm_private_sea a
  511. // LEFT JOIN dwd_f_crm_clue_info b ON a.clue_id=b.id
  512. // WHERE a.position_id is not null and b.trailstatus =?`
  513. // argsSelect := []interface{}{trailstatus}
  514. // intime := ""
  515. // if trailstatus != "00" {
  516. // sql += " AND a.comeintime <?"
  517. // nt := t.AddDate(0, 0, -statusMap[trailstatus])
  518. // // nt, _ := nexttime.(time.Time)
  519. // intime = nt.Format(date.Date_Full_Layout)
  520. // argsSelect = append(argsSelect, intime)
  521. // }
  522. // log.Println(sql)
  523. // log.Println(argsSelect)
  524. // //
  525. // config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
  526. // //1新增 2私海手动退回 3私海高意向客户自动退回 4私海意向客户退回 5私海潜在客户退回 6私海沉睡客户退回 7私海商机线索退回 8私海无意向客户退回
  527. // comeinsource := GetComeSource()[trailstatus]
  528. // ids := []interface{}{}
  529. // args := []interface{}{}
  530. // changeArgs1 := []interface{}{}
  531. // changeArgs2 := []interface{}{}
  532. // changeArgs3 := []interface{}{}
  533. // changeArgs4 := []interface{}{}
  534. // for _, v := range *l {
  535. // id := v["clue_id"] //
  536. // position_id := v["position_id"]
  537. // seatNumber := gconv.String(v["seatNumber"])
  538. // args2 := []interface{}{id}
  539. // //获取跟进内容
  540. // sql2 := `SELECT COUNT(1) FROM dwd_f_crm_trail_content WHERE clue_id = ? and position_id = ?`
  541. // if intime != "" {
  542. // sql2 += ` and createtime > ?`
  543. // args2 = append(args2, intime)
  544. // args2 = append(args2, position_id)
  545. // }
  546. // //保留未跟进线索
  547. // if config.JianyuSubjectdb.CountBySql(sql2, args2...) > 0 {
  548. // log.Println("不满足线索过滤", id)
  549. // continue
  550. // }
  551. // ids = append(ids, id)
  552. // //
  553. // args = append(args, id, now, comeinsource)
  554. // changeArgs1 = append(changeArgs1, id, position_id, "trailstatus", "线索状态变更", codeMap[trailstatus], "流失", now, -1)
  555. // changeArgs2 = append(changeArgs2, id, position_id, "position_id", "所属人变更", GetPositionName(seatNumber), "/", now, -1)
  556. // changeArgs3 = append(changeArgs3, id, position_id, "退出任务车", "未更新跟进记录自动退回公海", now, -1)
  557. // changeArgs4 = append(changeArgs3, id, position_id, "退回公海", "未更新跟进记录自动退回公海", now, -1)
  558. // }
  559. // whs := []string{}
  560. // for i := 0; i < len(ids); i++ {
  561. // whs = append(whs, "?")
  562. // }
  563. // wh := strings.Join(whs, ",")
  564. // //退出私海
  565. // if len(ids) > 0 {
  566. // config.JianyuSubjectdb.UpdateOrDeleteBySql(`delete from dwd_f_crm_private_sea where clue_id in (`+wh+`)`, ids...)
  567. // //改线索表 职位id 坐席号 弄成空 分配状态改成未分配
  568. // up1 := config.JianyuSubjectdb.UpdateOrDeleteBySql(`UPDATE dwd_f_crm_clue_info SET seatNumber ='',position_id=0,is_assign=0 WHERE id in (`+wh+`)`, ids...)
  569. // if up1 == -1 {
  570. // log.Println("修改记录失败", `UPDATE dwd_f_crm_clue_info SET seatNumber ='',position_id=0,is_assign=0 WHERE id in (`+wh+`)`, ids)
  571. // }
  572. // }
  573. // //进入公海
  574. // if len(args) > 0 {
  575. // config.JianyuSubjectdb.InsertIgnoreBatch("dwd_f_crm_clue_info", []string{"clue_id", "comeintime", "comeinsource"}, args)
  576. // }
  577. // // 添加线索修改记录
  578. // //线索状态变更记录
  579. // if len(changeArgs1) > 0 {
  580. // i1, _ := 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)
  581. // if i1 <= 0 {
  582. // log.Println("i1失败", changeArgs1)
  583. // }
  584. // }
  585. // if len(changeArgs1) > 0 {
  586. // i2, _ := 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)
  587. // if i2 <= 0 {
  588. // log.Println("i2失败", changeArgs2)
  589. // }
  590. // }
  591. // if len(changeArgs1) > 0 {
  592. // i3, _ := config.JianyuSubjectdb.InsertBatch("dwd_f_crm_clue_change_record", []string{"clue_id", "position_id", "change_type", "new_value", "createtime", "operator_id"}, changeArgs3)
  593. // if i3 <= 0 {
  594. // log.Println("i3失败", changeArgs3)
  595. // }
  596. // }
  597. // if len(changeArgs1) > 0 {
  598. // i4, _ := config.JianyuSubjectdb.InsertBatch("dwd_f_crm_clue_change_record", []string{"clue_id", "position_id", "change_type", "new_value", "createtime", "operator_id"}, changeArgs4)
  599. // if i4 <= 0 {
  600. // log.Println("i4失败", changeArgs4)
  601. // }
  602. // }
  603. // return true
  604. // }, sql, argsSelect...)
  605. // }
  606. // log.Println("return sea end")
  607. // }
  608. // 2私海手动退回 3私海高意向客户自动退回 4私海意向客户退回 5私海潜在客户退回 6私海沉睡客户退回 7私海商机线索退回 8私海无意向客户退回
  609. func GetComeSource() map[string]int {
  610. return map[string]int{
  611. "06": 3,
  612. "05": 4,
  613. "04": 5,
  614. "03": 6,
  615. "01": 7,
  616. "00": 8,
  617. }
  618. }
  619. func GetOneSeaC(oneClassA, oneClassB map[string]bool) map[string]bool {
  620. m := map[string]bool{}
  621. config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
  622. for _, v := range *l {
  623. clueid := gconv.String(v["id"])
  624. if oneClassA[clueid] || oneClassB[clueid] {
  625. continue
  626. }
  627. m[clueid] = true
  628. }
  629. return true
  630. }, `select id from dwd_f_crm_clue_info where is_assign = 0 and comeinsource_open in(3,4,5)`)
  631. return m
  632. }
  633. func dwd_d_crm_trailstatus_code() map[string]string {
  634. m := map[string]string{}
  635. data := config.JianyuSubjectdb.SelectBySql(`SELECT CODE,NAME FROM dwd_d_crm_trailstatus_code;`)
  636. for _, v := range *data {
  637. code := gconv.String(v["CODE"])
  638. name := gconv.String(v["NAME"])
  639. m[code] = name
  640. }
  641. return m
  642. }
  643. func GetPositionName(seatNumber string) string {
  644. data := config.JianyuSubjectdb.SelectBySql(`select name from jy_salesperson_info where status = 0 and position != 0 and seatNumber = ? limit 1`, seatNumber)
  645. if data != nil && len(*data) > 0 {
  646. return gconv.String((*data)[0]["name"])
  647. }
  648. return ""
  649. }
  650. // (4)回收站:
  651. // A.5个自然日内被销售人员手动退回公海的客户;
  652. // B.3个自然日内有过“已接听”的通话记录且仍处于“商机线索”状态下的客户。
  653. func Recycle() {
  654. log.Println("回收站开始")
  655. ctx := gctx.New()
  656. t := time.Now()
  657. t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
  658. handReturn := g.Cfg().MustGet(ctx, "handReturn").Int()
  659. tA := t.AddDate(0, 0, -handReturn)
  660. recycleB := g.Cfg().MustGet(ctx, "recycleB").Int()
  661. tB := t.AddDate(0, 0, -recycleB)
  662. for sql, clue_level := range map[string]interface{}{
  663. fmt.Sprintf(`select id from dwd_f_crm_clue_info where (comeinsource_open=2 or comeinsource_open=8) and is_assign = 0 and comeintime_open > "%s" ;`, tA.Format(date.Date_Full_Layout)): "A",
  664. fmt.Sprintf(`SELECT a.uid,b.phone,c.createTime,a.id FROM dwd_f_crm_clue_info a
  665. LEFT JOIN dwd_f_userbase_contacts b ON b.baseinfo_id=a.uid
  666. LEFT JOIN Call_Accounting.voice_record c ON c.CalledNo = b.phone
  667. WHERE a.is_assign = 0 AND a.trailstatus=01 AND a.uid !="" AND b.phone IS NOT NULL AND c.State="dealing" AND c.createTime >"%s"
  668. `, tB.Format(date.Date_Full_Layout)): "B",
  669. } {
  670. func(sql string) {
  671. config.JianyuSubjectdb.SelectByBath(500, func(l *[]map[string]interface{}) bool {
  672. ids := []interface{}{}
  673. for _, v := range *l {
  674. id := v["id"]
  675. //不包括管理员退回
  676. if clue_level == "A" {
  677. rData := config.JianyuSubjectdb.FindOne("dwd_f_crm_clue_change_record", map[string]interface{}{"clue_id": id, "change_type": "退回公海"}, "", "createtime desc")
  678. if rData != nil && len(*rData) > 0 {
  679. position_id := gconv.Int64((*rData)["position_id"])
  680. operator_id := gconv.Int64((*rData)["operator_id"])
  681. if position_id != operator_id && operator_id != -1 {
  682. continue
  683. }
  684. }
  685. }
  686. ids = append(ids, id)
  687. }
  688. whs := []string{}
  689. for i := 0; i < len(ids); i++ {
  690. whs = append(whs, "?")
  691. }
  692. wh := strings.Join(whs, ",")
  693. config.JianyuSubjectdb.UpdateOrDeleteBySql(`UPDATE dwd_f_crm_clue_info SET level_open = 4,clue_level = "`+fmt.Sprint(clue_level)+`" WHERE id in (`+wh+`)`, ids...)
  694. return true
  695. }, sql)
  696. }(sql)
  697. }
  698. log.Println("回收站结束")
  699. }
  700. /*
  701. dwd_f_crm_clue_info.uid trailstatus==01
  702. dwd_f_userbase_contacts.baseinfo_id ==dwd_f_crm_clue_info.uid
  703. >> dwd_f_userbase_contacts.phone== Call_Accounting.voice_record.CalledNo &&State=="dealing"
  704. */