business_cron.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. package proj
  2. import (
  3. "context"
  4. projDao "dashoo.cn/micro/app/dao/proj"
  5. model "dashoo.cn/micro/app/model/proj"
  6. "dashoo.cn/micro/app/service"
  7. "database/sql"
  8. "fmt"
  9. "github.com/360EntSecGroup-Skylar/excelize"
  10. "github.com/gogf/gf/container/gset"
  11. "github.com/gogf/gf/frame/g"
  12. "github.com/gogf/gf/os/gcron"
  13. "github.com/gogf/gf/os/glog"
  14. "github.com/gogf/gf/os/gtime"
  15. "github.com/gogf/gf/text/gstr"
  16. "github.com/gogf/gf/util/gconv"
  17. "github.com/smallnest/rpcx/share"
  18. "strings"
  19. "time"
  20. )
  21. // 初始化,创建每10分钟执行一次的定时任务
  22. func init() {
  23. // 定时任务
  24. spec := "0 0 9 * * *" // 每天凌晨9点执行
  25. gcron.AddSingleton(spec, businessFollowRun)
  26. //定时任务
  27. specs := "0 0 0 * * 1 *" //每周一一点
  28. gcron.AddSingleton(specs, businesspeopleUpReminder)
  29. }
  30. // businessFollowRun 项目跟进超时任务逻辑
  31. func businessFollowRun() {
  32. tenant := g.Config().GetString("micro_srv.tenant")
  33. if tenant == "" {
  34. glog.Error("定时任务租户码未设置,请前往配置")
  35. return
  36. }
  37. // 从配置中获取消息提醒设置
  38. configs, err := g.DB(tenant).Model("sys_config").Where("config_key IN ('SalesDirector','SalesAssociate', 'ProductLineManager')").FindAll()
  39. if err != nil && err != sql.ErrNoRows {
  40. glog.Error(err)
  41. return
  42. }
  43. // 销售总监用户Id,销售助理用户Id,产品线经理用户Id
  44. salesDirector, salesAssociate, productLineManager := []string{}, []string{}, []string{}
  45. for _, config := range configs {
  46. if config["config_key"].String() == "SalesDirector" {
  47. salesDirector = strings.Split(config["config_value"].String(), ",")
  48. } else if config["config_key"].String() == "SalesAssociate" {
  49. salesAssociate = strings.Split(config["config_value"].String(), ",")
  50. } else if config["config_key"].String() == "ProductLineManager" {
  51. productLineManager = strings.Split(config["config_value"].String(), ",")
  52. }
  53. }
  54. if len(salesDirector) > 0 {
  55. go businessFollowOverdueSalesDirector(tenant, salesDirector)
  56. }
  57. if len(salesAssociate) > 0 {
  58. go businessFollowOverdueSalesAssociate(tenant, salesAssociate)
  59. }
  60. if len(productLineManager) > 0 {
  61. businessFollowOverdueProductLineManager(tenant, productLineManager)
  62. }
  63. go businessFollowOverdueSalesEngineer(tenant)
  64. }
  65. type FollowOverdue struct {
  66. SaleId int64 `json:"saleId"`
  67. Count int64 `json:"count"`
  68. BusNames string `json:"busNames"`
  69. }
  70. // 超期3天提醒销售总监
  71. func businessFollowOverdueSalesDirector(tenant string, userIds []string) {
  72. now := gtime.Now().StartOfDay()
  73. LastWeekDay := now.AddDate(0, 0, -10)
  74. LastTwoWeekDay := now.AddDate(0, 0, -17)
  75. LastMonthDay := now.AddDate(0, -1, -3)
  76. businessA, businessB, businessC := new(FollowOverdue), new(FollowOverdue), new(FollowOverdue)
  77. err := projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusA).
  78. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekDay).
  79. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(&businessA)
  80. if err != nil {
  81. g.Log().Error("获取A类超期3天未跟进项目", err)
  82. }
  83. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusB).
  84. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekDay).
  85. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(&businessB)
  86. if err != nil {
  87. g.Log().Error("获取B类超期3天未跟进项目", err)
  88. }
  89. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusC).
  90. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthDay).
  91. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(&businessC)
  92. if err != nil {
  93. g.Log().Error("获取C类超期3天未跟进项目", err)
  94. }
  95. var msg string
  96. if businessA.Count > 0 {
  97. msg += fmt.Sprintf("**您有超期3天未跟进A类项目%v个:** %v \n\n", businessA.Count, "\n1. "+strings.Replace(businessA.BusNames, ",", "\n1. ", -1))
  98. }
  99. if businessB.Count > 0 {
  100. if msg != "" {
  101. msg = "\n" + msg
  102. }
  103. msg += fmt.Sprintf("**您有超期3天未跟进B类项目%v个:** %v \n\n", businessB.Count, "\n1. "+strings.Replace(businessB.BusNames, ",", "\n1. ", -1))
  104. }
  105. if businessC.Count > 0 {
  106. if msg != "" {
  107. msg = "\n" + msg
  108. }
  109. msg += fmt.Sprintf("**您有超期3天未跟进C类项目%v个:** %v \n\n", businessC.Count, "\n1. "+strings.Replace(businessC.BusNames, ",", "\n1. ", -1))
  110. }
  111. if msg != "" {
  112. businessNotifyMessage(userIds, gstr.TrimRightStr(msg, ","))
  113. }
  114. }
  115. // 超期1天后,超期3天 提醒销售助理
  116. func businessFollowOverdueSalesAssociate(tenant string, userIds []string) {
  117. now := gtime.Now().StartOfDay()
  118. LastWeekDay := now.AddDate(0, 0, -8)
  119. LastTwoWeekDay := now.AddDate(0, 0, -15)
  120. LastMonthDay := now.AddDate(0, -1, -1)
  121. LastWeekTridDay := now.AddDate(0, 0, -10)
  122. LastTwoWeekTridDay := now.AddDate(0, 0, -17)
  123. LastMonthTridDay := now.AddDate(0, -1, -3)
  124. businessATrid, businessBTrid, businessCTrid := new(FollowOverdue), new(FollowOverdue), new(FollowOverdue)
  125. businessA, businessB, businessC := new(FollowOverdue), new(FollowOverdue), new(FollowOverdue)
  126. err := projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusA).
  127. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekDay).
  128. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(&businessATrid)
  129. if err != nil {
  130. g.Log().Error("获取A类超期3天未跟进项目", err)
  131. }
  132. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusB).
  133. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekDay).
  134. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(businessBTrid)
  135. if err != nil {
  136. g.Log().Error("获取B类超期3天未跟进项目", err)
  137. }
  138. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusC).
  139. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthDay).
  140. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(businessCTrid)
  141. if err != nil {
  142. g.Log().Error("获取C类超期3天未跟进项目", err)
  143. }
  144. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusA).
  145. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekDay).WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekTridDay).
  146. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(businessA)
  147. if err != nil {
  148. g.Log().Error("获取A类超期1天未跟进项目", err)
  149. }
  150. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusB).
  151. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekDay).WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekTridDay).
  152. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(businessB)
  153. if err != nil {
  154. g.Log().Error("获取B类超期1天未跟进项目", err)
  155. }
  156. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusC).
  157. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthDay).WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthTridDay).
  158. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(businessC)
  159. if err != nil {
  160. g.Log().Error("获取C类超期1天未跟进项目", err)
  161. }
  162. var msg string
  163. if businessATrid.Count > 0 {
  164. msg += fmt.Sprintf("**您有超期3天未跟进A类项目%v个:** %v \n\n", businessATrid.Count, "\n1. "+strings.Replace(businessATrid.BusNames, ",", "\n1. ", -1))
  165. }
  166. if businessBTrid.Count > 0 {
  167. if msg != "" {
  168. msg = "\n " + msg
  169. }
  170. msg += fmt.Sprintf("**您有超期3天未跟进B类项目%v个:** %v \n\n", businessBTrid.Count, "\n1. "+strings.Replace(businessBTrid.BusNames, ",", "\n1. ", -1))
  171. }
  172. if businessCTrid.Count > 0 {
  173. if msg != "" {
  174. msg = "\n " + msg
  175. }
  176. msg += fmt.Sprintf("**您有超期3天未跟进C类项目%v个:** %v \n\n", businessCTrid.Count, "\n1. "+strings.Replace(businessCTrid.BusNames, ",", "\n1. ", -1))
  177. }
  178. if businessA.Count > 0 {
  179. if msg != "" {
  180. msg = "\n " + msg
  181. }
  182. msg += fmt.Sprintf("**您有超期1天未跟进A类项目%v个:** %v \n\n", businessA.Count, "\n1. "+strings.Replace(businessA.BusNames, ",", "\n1. ", -1))
  183. }
  184. if businessB.Count > 0 {
  185. if msg != "" {
  186. msg = "\n " + msg
  187. }
  188. msg += fmt.Sprintf("**您有超期1天未跟进B类项目%v个:** %v \n\n", businessB.Count, "\n1. "+strings.Replace(businessB.BusNames, ",", "\n1. ", -1))
  189. }
  190. if businessC.Count > 0 {
  191. if msg != "" {
  192. msg = "\n " + msg
  193. }
  194. msg += fmt.Sprintf("**您有超期1天未跟进C类项目%v个:** %v \n\n", businessC.Count, "\n1. "+strings.Replace(businessC.BusNames, ",", "\n1. ", -1))
  195. }
  196. if msg != "" {
  197. businessNotifyMessage(userIds, gstr.TrimRightStr(msg, ","))
  198. }
  199. }
  200. // 在到达超期时间前3天进行提醒、当天进行提醒,这两次提醒只提醒销售工程师, 超期1天后提醒
  201. func businessFollowOverdueProductLineManager(tenant string, userIds []string) {
  202. now := gtime.Now().StartOfDay()
  203. // 超期一天
  204. LastWeekOneDay := now.AddDate(0, 0, -8)
  205. LastTwoWeekOneDay := now.AddDate(0, 0, -15)
  206. LastMonthOneDay := now.AddDate(0, -1, -1)
  207. // 超期当天
  208. LastWeekCurrentDay := now.AddDate(0, 0, -7)
  209. LastTwoWeekCurrentDay := now.AddDate(0, 0, -14)
  210. LastMonthCurrentDay := now.AddDate(0, -1, 0)
  211. // 在到达超期时间前3天进行提醒
  212. LastWeekBeforeTridDay := now.AddDate(0, 0, -4)
  213. LastTwoWeekBeforeTridDay := now.AddDate(0, 0, -11)
  214. LastMonthBeforeTridDay := now.AddDate(0, -1, 3)
  215. for _, userId := range userIds {
  216. LastWeekOne, LastTwoWeekOne, LastMonthOne := new(FollowOverdue), new(FollowOverdue), new(FollowOverdue)
  217. LastWeekCurrent, LastTwoWeekCurrent, LastMonthCurrent := new(FollowOverdue), new(FollowOverdue), new(FollowOverdue)
  218. LastWeekBeforeTrid, LastTwoWeekBeforeTrid, LastMonthBeforeTrid := new(FollowOverdue), new(FollowOverdue), new(FollowOverdue)
  219. dataScope, err := service.GetUserDataScope(gconv.Int(userId))
  220. if err != nil {
  221. g.Log().Error(fmt.Sprintf("定时任务项目超期提醒用户数据权限查询失败:userId-%v,", userId), err)
  222. continue
  223. }
  224. ctx := context.WithValue(context.TODO(), "contextService", g.Map{"dataScope": dataScope})
  225. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusA).
  226. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekOneDay).DataScope(ctx, "sale_id").
  227. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastWeekOne)
  228. if err != nil {
  229. g.Log().Error("获取A类超期一天未跟进项目", err)
  230. }
  231. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusB).
  232. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekOneDay).DataScope(ctx, "sale_id").
  233. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastTwoWeekOne)
  234. if err != nil {
  235. g.Log().Error("获取B类超期一天未跟进项目", err)
  236. }
  237. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusC).
  238. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthOneDay).DataScope(ctx, "sale_id").
  239. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastMonthOne)
  240. if err != nil {
  241. g.Log().Error("获取C类超期一天未跟进项目", err)
  242. }
  243. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusA).
  244. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekCurrentDay).
  245. WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekOneDay).DataScope(ctx, "sale_id").
  246. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastWeekCurrent)
  247. if err != nil {
  248. g.Log().Error("获取A类超期当天未跟进项目", err)
  249. }
  250. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusB).
  251. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekCurrentDay).
  252. WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekOneDay).DataScope(ctx, "sale_id").
  253. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastTwoWeekCurrent)
  254. if err != nil {
  255. g.Log().Error("获取B类超期当天未跟进项目", err)
  256. }
  257. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusC).
  258. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthCurrentDay).
  259. WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthOneDay).DataScope(ctx, "sale_id").
  260. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastMonthCurrent)
  261. if err != nil {
  262. g.Log().Error("获取C类超期当天未跟进项目", err)
  263. }
  264. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusA).
  265. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekBeforeTridDay).
  266. WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekCurrentDay).DataScope(ctx, "sale_id").
  267. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastWeekBeforeTrid)
  268. if err != nil {
  269. g.Log().Error("获取A类超期当天未跟进项目", err)
  270. }
  271. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusB).
  272. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekBeforeTridDay).
  273. WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekCurrentDay).DataScope(ctx, "sale_id").
  274. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastTwoWeekBeforeTrid)
  275. if err != nil {
  276. g.Log().Error("获取B类超期当天未跟进项目", err)
  277. }
  278. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusC).
  279. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthBeforeTridDay).
  280. WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthCurrentDay).DataScope(ctx, "sale_id").
  281. Fields("count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastMonthBeforeTrid)
  282. if err != nil {
  283. g.Log().Error("获取C类超期当天未跟进项目", err)
  284. }
  285. var msg string
  286. if LastWeekOne.Count != 0 {
  287. msg += fmt.Sprintf("**您有超期1天未跟进A类项目%v个:** %v \n\n", LastWeekOne.Count, "\n1. "+strings.Replace(LastWeekOne.BusNames, ",", "\n1. ", -1))
  288. }
  289. if LastTwoWeekOne.Count != 0 {
  290. if msg != "" {
  291. msg = "\n" + msg
  292. }
  293. msg += fmt.Sprintf("**您有超期1天未跟进B类项目%v个:** %v \n\n", LastTwoWeekOne.Count, "\n1. "+strings.Replace(LastTwoWeekOne.BusNames, ",", "\n1. ", -1))
  294. }
  295. if LastMonthOne.Count != 0 {
  296. if msg != "" {
  297. msg = "\n" + msg
  298. }
  299. msg += fmt.Sprintf("**您有超期1天未跟进C类项目%v个:** %v \n\n", LastMonthOne.Count, "\n1. "+strings.Replace(LastMonthOne.BusNames, ",", "\n1. ", -1))
  300. }
  301. if LastWeekCurrent.Count != 0 {
  302. if msg != "" {
  303. msg = "\n" + msg
  304. }
  305. msg += fmt.Sprintf("**您今天有超期未跟进A类项目%v个:** %v \n\n", LastWeekCurrent.Count, "\n1. "+strings.Replace(LastWeekCurrent.BusNames, ",", "\n1. ", -1))
  306. }
  307. if LastTwoWeekCurrent.Count != 0 {
  308. if msg != "" {
  309. msg = "\n" + msg
  310. }
  311. msg += fmt.Sprintf("**您今天有超期未跟进B类项目%v个:** %v \n\n", LastTwoWeekCurrent.Count, "\n1. "+strings.Replace(LastTwoWeekCurrent.BusNames, ",", "\n1. ", -1))
  312. }
  313. if LastMonthCurrent.Count != 0 {
  314. if msg != "" {
  315. msg = "\n" + msg
  316. }
  317. msg += fmt.Sprintf("**您今天有超期未跟进C类项目%v个:** %v \n\n", LastMonthCurrent.Count, "\n1. "+strings.Replace(LastMonthCurrent.BusNames, ",", "\n1. ", -1))
  318. }
  319. if LastWeekBeforeTrid.Count != 0 {
  320. if msg != "" {
  321. msg = "\n" + msg
  322. }
  323. msg += fmt.Sprintf("**您3天后有超期未跟进A类项目%v个:** %v \n\n", LastWeekBeforeTrid.Count, "\n1. "+strings.Replace(LastWeekBeforeTrid.BusNames, ",", "\n1. ", -1))
  324. }
  325. if LastTwoWeekBeforeTrid.Count != 0 {
  326. if msg != "" {
  327. msg = "\n" + msg
  328. }
  329. msg += fmt.Sprintf("**您3天后有超期未跟进B类项目%v个:** %v \n\n", LastTwoWeekBeforeTrid.Count, "\n1. "+strings.Replace(LastTwoWeekBeforeTrid.BusNames, ",", "\n1. ", -1))
  330. }
  331. if LastMonthBeforeTrid.Count != 0 {
  332. if msg != "" {
  333. msg = "\n" + msg
  334. }
  335. msg += fmt.Sprintf("**您3天后有超期未跟进C类项目%v个:** %v \n\n", LastMonthBeforeTrid.Count, "\n1. "+strings.Replace(LastMonthBeforeTrid.BusNames, ",", "\n1. ", -1))
  336. }
  337. if msg != "" {
  338. businessNotifyMessage([]string{userId}, gstr.TrimRightStr(msg, ","))
  339. }
  340. }
  341. }
  342. // 在到达超期时间前3天进行提醒、当天进行提醒,这两次提醒只提醒销售工程师, 超期1天后提醒
  343. func businessFollowOverdueSalesEngineer(tenant string) {
  344. now := gtime.Now().StartOfDay()
  345. // 超期一天
  346. LastWeekOneDay := now.AddDate(0, 0, -8)
  347. LastTwoWeekOneDay := now.AddDate(0, 0, -15)
  348. LastMonthOneDay := now.AddDate(0, -1, -1)
  349. // 超期当天
  350. LastWeekCurrentDay := now.AddDate(0, 0, -7)
  351. LastTwoWeekCurrentDay := now.AddDate(0, 0, -14)
  352. LastMonthCurrentDay := now.AddDate(0, -1, 0)
  353. // 在到达超期时间前3天进行提醒
  354. LastWeekBeforeTridDay := now.AddDate(0, 0, -4)
  355. LastTwoWeekBeforeTridDay := now.AddDate(0, 0, -11)
  356. LastMonthBeforeTridDay := now.AddDate(0, -1, 3)
  357. LastWeekOneCount, LastTwoWeekOneCount, LastMonthOneCount := make([]FollowOverdue, 0), make([]FollowOverdue, 0), make([]FollowOverdue, 0)
  358. LastWeekCurrentCount, LastTwoWeekCurrentCount, LastMonthCurrentCount := make([]FollowOverdue, 0), make([]FollowOverdue, 0), make([]FollowOverdue, 0)
  359. LastWeekBeforeTridCount, LastTwoWeekBeforeTridCount, LastMonthBeforeTridCount := make([]FollowOverdue, 0), make([]FollowOverdue, 0), make([]FollowOverdue, 0)
  360. err := projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusA).
  361. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekOneDay).Group("sale_id").OrderAsc("sale_id").
  362. Fields("sale_id, count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastWeekOneCount)
  363. if err != nil {
  364. g.Log().Error("获取A类超期一天未跟进项目", err)
  365. }
  366. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusB).
  367. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekOneDay).Group("sale_id").OrderAsc("sale_id").
  368. Fields("sale_id, count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastTwoWeekOneCount)
  369. if err != nil {
  370. g.Log().Error("获取B类超期一天未跟进项目", err)
  371. }
  372. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusC).
  373. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthOneDay).Group("sale_id").OrderAsc("sale_id").
  374. Fields("sale_id, count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastMonthOneCount)
  375. if err != nil {
  376. g.Log().Error("获取C类超期一天未跟进项目", err)
  377. }
  378. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusA).
  379. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekCurrentDay).
  380. WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekOneDay).Group("sale_id").OrderAsc("sale_id").
  381. Fields("sale_id, count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastWeekCurrentCount)
  382. if err != nil {
  383. g.Log().Error("获取A类超期当天未跟进项目", err)
  384. }
  385. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusB).
  386. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekCurrentDay).
  387. WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekOneDay).Group("sale_id").OrderAsc("sale_id").
  388. Fields("sale_id, count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastTwoWeekCurrentCount)
  389. if err != nil {
  390. g.Log().Error("获取B类超期当天未跟进项目", err)
  391. }
  392. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusC).
  393. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthCurrentDay).
  394. WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthOneDay).Group("sale_id").OrderAsc("sale_id").
  395. Fields("sale_id, count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastMonthCurrentCount)
  396. if err != nil {
  397. g.Log().Error("获取C类超期当天未跟进项目", err)
  398. }
  399. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusA).
  400. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekBeforeTridDay).
  401. WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekCurrentDay).Group("sale_id").OrderAsc("sale_id").
  402. Fields("sale_id, count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastWeekBeforeTridCount)
  403. if err != nil {
  404. g.Log().Error("获取A类超期当天未跟进项目", err)
  405. }
  406. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusB).
  407. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekBeforeTridDay).
  408. WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekCurrentDay).Group("sale_id").OrderAsc("sale_id").
  409. Fields("sale_id, count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastTwoWeekBeforeTridCount)
  410. if err != nil {
  411. g.Log().Error("获取B类超期当天未跟进项目", err)
  412. }
  413. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusC).
  414. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthBeforeTridDay).
  415. WhereGTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthCurrentDay).Group("sale_id").OrderAsc("sale_id").
  416. Fields("sale_id, count(id) as count, group_concat(nbo_name) as busNames").Scan(&LastMonthBeforeTridCount)
  417. if err != nil {
  418. g.Log().Error("获取C类超期当天未跟进项目", err)
  419. }
  420. allSaleIds := gset.NewIntSet(true)
  421. saleIds, LastWeekOneCountMap := handleSalesEngineerData(LastWeekOneCount)
  422. allSaleIds = allSaleIds.Union(saleIds)
  423. saleIds, LastTwoWeekOneCountMap := handleSalesEngineerData(LastTwoWeekOneCount)
  424. allSaleIds = allSaleIds.Union(saleIds)
  425. saleIds, LastMonthOneCountMap := handleSalesEngineerData(LastMonthOneCount)
  426. allSaleIds = allSaleIds.Union(saleIds)
  427. saleIds, LastWeekCurrentCountMap := handleSalesEngineerData(LastWeekCurrentCount)
  428. allSaleIds = allSaleIds.Union(saleIds)
  429. saleIds, LastTwoWeekCurrentCountMap := handleSalesEngineerData(LastTwoWeekCurrentCount)
  430. allSaleIds = allSaleIds.Union(saleIds)
  431. saleIds, LastMonthCurrentCountMap := handleSalesEngineerData(LastMonthCurrentCount)
  432. allSaleIds = allSaleIds.Union(saleIds)
  433. saleIds, LastWeekBeforeTridCountMap := handleSalesEngineerData(LastWeekBeforeTridCount)
  434. allSaleIds = allSaleIds.Union(saleIds)
  435. saleIds, LastTwoWeekBeforeTridCountMap := handleSalesEngineerData(LastTwoWeekBeforeTridCount)
  436. allSaleIds = allSaleIds.Union(saleIds)
  437. saleIds, LastMonthBeforeTridCountMap := handleSalesEngineerData(LastMonthBeforeTridCount)
  438. allSaleIds = allSaleIds.Union(saleIds)
  439. for _, saleId := range allSaleIds.Slice() {
  440. var msg string
  441. if LastWeekOneCountMap[saleId].Count != 0 {
  442. msg += fmt.Sprintf("**您有超期1天未跟进A类项目%v个:** %v \n\n", LastWeekOneCountMap[saleId].Count, "\n1. "+strings.Replace(LastWeekOneCountMap[saleId].BusNames, ",", "\n1. ", -1))
  443. }
  444. if LastTwoWeekOneCountMap[saleId].Count != 0 {
  445. if msg != "" {
  446. msg = "\n" + msg
  447. }
  448. msg += fmt.Sprintf("**您有超期1天未跟进B类项目%v个:** %v \n\n", LastTwoWeekOneCountMap[saleId].Count, "\n1. "+strings.Replace(LastTwoWeekOneCountMap[saleId].BusNames, ",", "\n1. ", -1))
  449. }
  450. if LastMonthOneCountMap[saleId].Count != 0 {
  451. if msg != "" {
  452. msg = "\n" + msg
  453. }
  454. msg += fmt.Sprintf("**您有超期1天未跟进C类项目%v个:** %v \n\n", LastMonthOneCountMap[saleId].Count, "\n1. "+strings.Replace(LastMonthOneCountMap[saleId].BusNames, ",", "\n1. ", -1))
  455. }
  456. if LastWeekCurrentCountMap[saleId].Count != 0 {
  457. if msg != "" {
  458. msg = "\n" + msg
  459. }
  460. msg += fmt.Sprintf("**您今天有超期未跟进A类项目%v个:** %v \n\n", LastWeekCurrentCountMap[saleId].Count, "\n1. "+strings.Replace(LastWeekCurrentCountMap[saleId].BusNames, ",", "\n1. ", -1))
  461. }
  462. if LastTwoWeekCurrentCountMap[saleId].Count != 0 {
  463. if msg != "" {
  464. msg = "\n" + msg
  465. }
  466. msg += fmt.Sprintf("**您今天有超期未跟进B类项目%v个:** %v \n\n", LastTwoWeekCurrentCountMap[saleId].Count, "\n1. "+strings.Replace(LastTwoWeekCurrentCountMap[saleId].BusNames, ",", "\n1. ", -1))
  467. }
  468. if LastMonthCurrentCountMap[saleId].Count != 0 {
  469. if msg != "" {
  470. msg = "\n" + msg
  471. }
  472. msg += fmt.Sprintf("**您今天有超期未跟进C类项目%v个:** %v \n\n", LastMonthCurrentCountMap[saleId].Count, "\n1. "+strings.Replace(LastMonthCurrentCountMap[saleId].BusNames, ",", "\n1. ", -1))
  473. }
  474. if LastWeekBeforeTridCountMap[saleId].Count != 0 {
  475. if msg != "" {
  476. msg = "\n" + msg
  477. }
  478. msg += fmt.Sprintf("**您3天后有超期未跟进A类项目%v个:** %v \n\n", LastWeekBeforeTridCountMap[saleId].Count, "\n1. "+strings.Replace(LastWeekBeforeTridCountMap[saleId].BusNames, ",", "\n1. ", -1))
  479. }
  480. if LastTwoWeekBeforeTridCountMap[saleId].Count != 0 {
  481. if msg != "" {
  482. msg = "\n" + msg
  483. }
  484. msg += fmt.Sprintf("**您3天后有超期未跟进B类项目%v个:** %v \n\n", LastTwoWeekBeforeTridCountMap[saleId].Count, "\n1. "+strings.Replace(LastTwoWeekBeforeTridCountMap[saleId].BusNames, ",", "\n1. ", -1))
  485. }
  486. if LastMonthBeforeTridCountMap[saleId].Count != 0 {
  487. if msg != "" {
  488. msg = "\n" + msg
  489. }
  490. msg += fmt.Sprintf("**您3天后有超期未跟进C类项目%v个:** %v \n\n", LastMonthBeforeTridCountMap[saleId].Count, "\n1. "+strings.Replace(LastMonthBeforeTridCountMap[saleId].BusNames, ",", "\n1. ", -1))
  491. }
  492. if msg != "" {
  493. businessNotifyMessage([]string{gconv.String(saleId)}, gstr.TrimRightStr(msg, ","))
  494. }
  495. }
  496. }
  497. func handleSalesEngineerData(countData []FollowOverdue) (saleIds *gset.IntSet, data map[int]FollowOverdue) {
  498. saleIds = gset.NewIntSet(true)
  499. data = make(map[int]FollowOverdue)
  500. for _, v := range countData {
  501. saleId := gconv.Int(v.SaleId)
  502. saleIds.Add(saleId)
  503. data[saleId] = v
  504. }
  505. return
  506. }
  507. // 项目跟进的消息通知
  508. func businessNotifyMessage(userIds []string, message string) {
  509. ids := strings.Join(userIds, ",")
  510. // 调用统一的消息通知方式
  511. notifyMessage(ids, message)
  512. }
  513. // notifyMessage 发送消息通知
  514. func notifyMessage(ids, message string) {
  515. msg := g.MapStrStr{
  516. "msgTitle": "项目跟进超期提醒",
  517. "msgContent": message,
  518. "msgType": "20",
  519. "recvUserIds": ids,
  520. "msgStatus": "10",
  521. "sendType": "10,30",
  522. }
  523. if err := service.CreateSystemMessage(msg); err != nil {
  524. glog.Error("消息提醒异常:", err)
  525. }
  526. }
  527. // 项目每周进行一次超期三天未跟进统计表,每周给销售助理发一次邮件
  528. func businesspeopleUpReminder() {
  529. tenant := g.Config().GetString("micro_srv.tenant")
  530. if tenant == "" {
  531. glog.Error("定时任务租户码未设置,请前往配置")
  532. return
  533. }
  534. // 从配置中获取消息提醒设置
  535. configs, err := g.DB(tenant).Model("sys_config").Where("config_key IN ('SalesDirector','SalesAssociate')").FindAll()
  536. if err != nil && err != sql.ErrNoRows {
  537. glog.Error(err)
  538. return
  539. }
  540. // 销售助理用户Id
  541. salesAssociate := []string{}
  542. for _, config := range configs {
  543. if config["config_key"].String() == "SalesAssociate" {
  544. salesAssociate = strings.Split(config["config_value"].String(), ",")
  545. }
  546. }
  547. var list []*model.ProjBusinessRes
  548. var listA []*model.ProjBusinessRes
  549. var listB []*model.ProjBusinessRes
  550. var listC []*model.ProjBusinessRes
  551. now := gtime.Now().StartOfDay()
  552. LastWeekDay := now.AddDate(0, 0, -8)
  553. LastTwoWeekDay := now.AddDate(0, 0, -15)
  554. LastMonthDay := now.AddDate(0, -1, -1)
  555. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusA).
  556. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastWeekDay).OrderDesc("id").Scan(&listA)
  557. if err != nil {
  558. g.Log().Error("获取A类超期3天未跟进项目", err)
  559. }
  560. if len(listA) > 0 {
  561. list = append(list, listA...)
  562. }
  563. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusB).
  564. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastTwoWeekDay).OrderDesc("id").Scan(&listB)
  565. if err != nil {
  566. g.Log().Error("获取B类超期3天未跟进项目", err)
  567. }
  568. if len(listB) > 0 {
  569. list = append(list, listB...)
  570. }
  571. err = projDao.NewProjBusinessDao(tenant).Where(projDao.ProjBusiness.C.NboType, StatusC).
  572. WhereLTE(projDao.ProjBusiness.C.FinalFollowTime, LastMonthDay).OrderDesc("id").Scan(&listC)
  573. if err != nil {
  574. g.Log().Error("获取C类超期3天未跟进项目", err)
  575. }
  576. if len(listC) > 0 {
  577. list = append(list, listC...)
  578. }
  579. if err != nil {
  580. g.Log().Error("获取未跟进项目", err)
  581. }
  582. ctx := context.WithValue(context.TODO(), share.ReqMetaDataKey, map[string]string{"tenant": tenant})
  583. rsp, err := service.GetDictDataByType(ctx, "proj_nbo_type")
  584. if err != nil {
  585. g.Log().Error("项目类别数据字典", err)
  586. }
  587. if err != nil {
  588. g.Log().Error("获取未跟进项目", err)
  589. return
  590. }
  591. var msg string
  592. if len(list) > 0 {
  593. msg += fmt.Sprintf("您有超期3天未跟进项目%v个,请登录系统查看", len(list))
  594. }
  595. f := excelize.NewFile()
  596. f.MergeCell("Sheet1", "A1", "D1")
  597. style, _ := f.NewStyle(`{"alignment":{"horizontal":"center"}}`)
  598. f.SetCellValue("Sheet1", "A1", "超期三天未跟进项目")
  599. f.SetCellStyle("sheet1", "A1", "D1", style)
  600. f.SetColWidth("Sheet1", "A", "K", 20)
  601. f.SetCellValue("Sheet1", "A2", "序号")
  602. f.SetCellValue("Sheet1", "B2", "项目名称")
  603. f.SetCellValue("Sheet1", "C2", "项目类别")
  604. f.SetCellValue("Sheet1", "D2", "最新跟进时间")
  605. line := 2
  606. if len(list) > 0 {
  607. for _, v := range list {
  608. line++
  609. f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), gconv.String(line-2))
  610. f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), v.NboName)
  611. if len(rsp) > 0 {
  612. f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), rsp[v.NboType])
  613. } else {
  614. f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), v.NboType)
  615. }
  616. f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), v.FinalFollowTime)
  617. }
  618. }
  619. dir := g.Config().GetString("file.cronstatic")
  620. filename := "项目跟进" + gconv.String(time.Now().UnixNano()) + ".xlsx"
  621. path := dir + filename
  622. if err = f.SaveAs(path); err != nil {
  623. g.Log().Error("Excel保存失败", err)
  624. }
  625. if len(salesAssociate) > 0 {
  626. for _, val := range salesAssociate {
  627. if val == "" {
  628. continue
  629. }
  630. msgs := g.MapStrStr{
  631. "msgTitle": "超期3天未跟进项目提醒",
  632. "msgContent": msg,
  633. "recvUserIds": "1",
  634. "recvUser": "系统管理员",
  635. "opnUrl": path,
  636. }
  637. if err = service.GSendMail(msgs); err != nil {
  638. g.Log().Error("SendMail() error = %v", err)
  639. }
  640. }
  641. }
  642. }