ctr_contract_cron.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. package service
  2. import (
  3. "dashoo.cn/micro/app/service"
  4. "dashoo.cn/opms_libary/plugin/dingtalk"
  5. "dashoo.cn/opms_libary/plugin/dingtalk/message/corpconversation"
  6. "database/sql"
  7. "fmt"
  8. "github.com/360EntSecGroup-Skylar/excelize"
  9. "github.com/gogf/gf/frame/g"
  10. "github.com/gogf/gf/os/glog"
  11. "github.com/gogf/gf/os/gtime"
  12. "github.com/gogf/gf/util/gconv"
  13. "github.com/robfig/cron"
  14. "os"
  15. )
  16. // 初始化,创建每10分钟执行一次的定时任务
  17. func init() {
  18. // 定时任务
  19. c := cron.New()
  20. spec1 := "0 0 20 * * 0" // 每周日晚八点
  21. spec2 := "0 0 20 1 * ?" // 每月1号晚八点
  22. if err := c.AddJob(spec1, CollectionCron{}); err != nil {
  23. glog.Error(err)
  24. }
  25. if err := c.AddJob(spec2, ContractCron{}); err != nil {
  26. glog.Error(err)
  27. }
  28. c.Start()
  29. }
  30. // CollectionCron 回款定义
  31. type CollectionCron struct {
  32. }
  33. // ContractCron 合同任务定义
  34. type ContractCron struct {
  35. }
  36. // Run 计划回款到期提醒
  37. func (c CollectionCron) Run() {
  38. tenant := g.Config().GetString("micro_srv.tenant")
  39. if tenant == "" {
  40. glog.Error("租户码未设置,请前往配置")
  41. return
  42. }
  43. // 当前时间
  44. now := gtime.Now()
  45. collections, err := g.DB(tenant).Model("ctr_contract_collection_plan p").InnerJoin("ctr_contract c", "c.id=p.contract_id").Where(fmt.Sprintf("(p.contract_status='10' OR p.contract_status='20') AND p.plan_datetime>='%v'", now.Format("Y-m-d 00:00:00"))).Fields("p.*,c.incharge_id,c.incharge_name").FindAll()
  46. if err != nil && err != sql.ErrNoRows {
  47. glog.Error(err)
  48. return
  49. }
  50. data := make(map[int][]map[string]string)
  51. for _, collection := range collections {
  52. // 校验当前时间
  53. remindTime := collection["cashed_datetime"].GTime()
  54. if isMatchDate(remindTime, 5) || isMatchDate(remindTime, 15) || isMatchDate(remindTime, 30) || isMatchDate(remindTime, 60) || isMatchDate(remindTime, 90) {
  55. id := gconv.Int(collection["incharge_id"])
  56. if _, ok := data[id]; !ok {
  57. data[id] = make([]map[string]string, 0)
  58. }
  59. d := map[string]string{
  60. "contract_code": gconv.String(collection["contract_code"]),
  61. "cashed_datetime": collection["cashed_datetime"].GTime().Format("Y-m-d"),
  62. "cust_name": gconv.String(collection["cust_name"]),
  63. "plan_amount": fmt.Sprintf("%.2f", collection["plan_amount"].Float64()),
  64. }
  65. data[id] = append(data[id], d)
  66. }
  67. }
  68. if len(data) > 0 {
  69. for id, collections := range data {
  70. f := excelize.NewFile()
  71. // Create a new sheet.
  72. sheet := f.NewSheet("Sheet1")
  73. // 表头
  74. f.SetCellValue("Sheet1", Div(1)+"1", "合同编号")
  75. f.SetCellValue("Sheet1", Div(2)+"1", "计划回款时间")
  76. f.SetCellValue("Sheet1", Div(3)+"1", "客户名称")
  77. f.SetCellValue("Sheet1", Div(4)+"1", "回款金额")
  78. for index, collection := range collections {
  79. f.SetCellValue("Sheet1", Div(1)+gconv.String(index+2), collection["contract_code"])
  80. f.SetCellValue("Sheet1", Div(2)+gconv.String(index+2), collection["cashed_datetime"])
  81. f.SetCellValue("Sheet1", Div(3)+gconv.String(index+2), collection["cust_name"])
  82. f.SetCellValue("Sheet1", Div(4)+gconv.String(index+2), collection["plan_amount"])
  83. }
  84. // Set active sheet of the workbook.
  85. f.SetActiveSheet(sheet)
  86. // Save xlsx file by the given path.
  87. file := "./temp/计划回款到期合同.xlsx"
  88. _, err = createPath("./temp")
  89. if err != nil {
  90. glog.Error(err)
  91. return
  92. }
  93. if err = f.SaveAs(file); err != nil {
  94. glog.Error(err)
  95. return
  96. }
  97. fileId, err := uploadFile(file)
  98. if err != nil {
  99. glog.Error(err)
  100. return
  101. }
  102. notifyMessage("计划回款到期提醒", gconv.String(id), fileId)
  103. // 删除已存在的文件
  104. err = os.Remove(file)
  105. if err != nil {
  106. glog.Error(err)
  107. return
  108. }
  109. }
  110. }
  111. }
  112. // Run 售后运维到期提醒
  113. func (c ContractCron) Run() {
  114. tenant := g.Config().GetString("micro_srv.tenant")
  115. if tenant == "" {
  116. glog.Error("租户码未设置,请前往配置")
  117. return
  118. }
  119. // 当前时间
  120. date := gtime.Now().AddDate(1, 0, 0)
  121. // 获取数据
  122. contracts, err := g.DB(tenant).Model("ctr_contract").Where(fmt.Sprintf("appro_status='30' AND contract_end_time LIKE '%v%%'", date.Format("Y-m"))).Order("contract_end_time ASC").FindAll()
  123. if err != nil && err != sql.ErrNoRows {
  124. glog.Error(err)
  125. return
  126. }
  127. data := make(map[int][]map[string]string)
  128. for _, contract := range contracts {
  129. id := gconv.Int(contract["incharge_id"])
  130. if _, ok := data[id]; !ok {
  131. data[id] = make([]map[string]string, 0)
  132. }
  133. d := map[string]string{
  134. "contract_code": gconv.String(contract["contract_code"]),
  135. "contract_end_time": contract["contract_end_time"].GTime().Format("Y-m-d"),
  136. "cust_name": gconv.String(contract["cust_name"]),
  137. "contract_amount": fmt.Sprintf("%.2f", contract["contract_amount"].Float64()),
  138. }
  139. data[id] = append(data[id], d)
  140. }
  141. if len(data) > 0 {
  142. for id, collections := range data {
  143. f := excelize.NewFile()
  144. // Create a new sheet.
  145. sheet := f.NewSheet("Sheet1")
  146. // 表头
  147. f.SetCellValue("Sheet1", Div(1)+"1", "合同编号")
  148. f.SetCellValue("Sheet1", Div(2)+"1", "合同结束时间")
  149. f.SetCellValue("Sheet1", Div(3)+"1", "客户名称")
  150. f.SetCellValue("Sheet1", Div(4)+"1", "合同总金额")
  151. for index, collection := range collections {
  152. f.SetCellValue("Sheet1", Div(1)+gconv.String(index+2), collection["contract_code"])
  153. f.SetCellValue("Sheet1", Div(2)+gconv.String(index+2), collection["contract_end_time"])
  154. f.SetCellValue("Sheet1", Div(3)+gconv.String(index+2), collection["cust_name"])
  155. f.SetCellValue("Sheet1", Div(4)+gconv.String(index+2), collection["contract_amount"])
  156. }
  157. // Set active sheet of the workbook.
  158. f.SetActiveSheet(sheet)
  159. // Save xlsx file by the given path.
  160. file := "./temp/售后运维到期提醒.xlsx"
  161. _, err = createPath("./temp")
  162. if err != nil {
  163. glog.Error(err)
  164. return
  165. }
  166. if err = f.SaveAs(file); err != nil {
  167. glog.Error(err)
  168. return
  169. }
  170. fileId, err := uploadFile(file)
  171. if err != nil {
  172. glog.Error(err)
  173. return
  174. }
  175. notifyMessage("售后运维到期提醒", gconv.String(id), fileId)
  176. // 删除已存在的文件
  177. err = os.Remove(file)
  178. if err != nil {
  179. glog.Error(err)
  180. return
  181. }
  182. }
  183. }
  184. }
  185. func uploadFile(file string) (string, error) {
  186. var request corpconversation.UploadConversationFileRequest
  187. request.Type = "file"
  188. request.FileData = "media"
  189. request.FilePath = file
  190. c := dingtalk.Client.GetCorpConversation()
  191. resp, err := c.UploadConversationFile(&request)
  192. if err != nil {
  193. fmt.Println(err)
  194. return "", err
  195. }
  196. return resp.MediaId, nil
  197. }
  198. // notifyMessage 发送消息通知
  199. func notifyMessage(title, ids, message string) {
  200. msg := g.MapStrStr{
  201. "msgTitle": title,
  202. "msgContent": message,
  203. "msgType": "40", // 文件处理
  204. "recvUserIds": ids,
  205. "msgStatus": "10",
  206. "sendType": "30",
  207. }
  208. if err := service.CreateSystemMessage(msg); err != nil {
  209. glog.Error("消息提醒异常:", err)
  210. }
  211. }
  212. func isMatchDate(date *gtime.Time, days int) bool {
  213. begin := gtime.Now().AddDate(0, 0, days)
  214. end := gtime.Now().AddDate(0, 0, days+7)
  215. return begin.Format("Y-m-d 00:00:00") <= date.Format("Y-m-d H:i:s") && date.Format("Y-m-d H:i:s") <= end.Format("Y-m-d 23:59:59")
  216. }
  217. // 判断文件夹是否存在
  218. func pathExists(path string) (bool, error) {
  219. _, err := os.Stat(path)
  220. if err == nil {
  221. return true, nil
  222. }
  223. if os.IsNotExist(err) {
  224. return false, nil
  225. }
  226. return false, err
  227. }
  228. func createPath(path string) (bool, error) {
  229. exist, err := pathExists(path)
  230. if err != nil {
  231. return false, err
  232. }
  233. if exist {
  234. return true, nil
  235. } else {
  236. // 创建文件夹
  237. err := os.MkdirAll(path, os.ModePerm)
  238. if err != nil {
  239. return false, err
  240. } else {
  241. return true, err
  242. }
  243. }
  244. }
  245. // Div 数字转字母
  246. func Div(Num int) string {
  247. var (
  248. Str string = ""
  249. k int
  250. temp []int //保存转化后每一位数据的值,然后通过索引的方式匹配A-Z
  251. )
  252. //用来匹配的字符A-Z
  253. Slice := []string{"", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
  254. "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
  255. if Num > 26 { //数据大于26需要进行拆分
  256. for {
  257. k = Num % 26 //从个位开始拆分,如果求余为0,说明末尾为26,也就是Z,如果是转化为26进制数,则末尾是可以为0的,这里必须为A-Z中的一个
  258. if k == 0 {
  259. temp = append(temp, 26)
  260. k = 26
  261. } else {
  262. temp = append(temp, k)
  263. }
  264. Num = (Num - k) / 26 //减去Num最后一位数的值,因为已经记录在temp中
  265. if Num <= 26 { //小于等于26直接进行匹配,不需要进行数据拆分
  266. temp = append(temp, Num)
  267. break
  268. }
  269. }
  270. } else {
  271. return Slice[Num]
  272. }
  273. for _, value := range temp {
  274. Str = Slice[value] + Str //因为数据切分后存储顺序是反的,所以Str要放在后面
  275. }
  276. return Str
  277. }