report_push.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. package services
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "github.com/wenzhenxi/gorsa"
  8. "hongze/hongze_task/models"
  9. "hongze/hongze_task/utils"
  10. "io/ioutil"
  11. "net/http"
  12. "net/url"
  13. "strconv"
  14. "time"
  15. )
  16. //func init() {
  17. // report, _ := models.GetReportById(836)
  18. // SendReportToThs(report)
  19. //}
  20. // SendWaitReport 定时向同花顺推送报告(定时任务)
  21. func SendWaitReport(cont context.Context) (err error) {
  22. defer func() {
  23. if err != nil {
  24. //fmt.Println(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "发送消息至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers)
  25. go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "延时任务发送报告至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers)
  26. }
  27. }()
  28. list, err := models.GetWaitReportSendThsDetailList()
  29. if err != nil {
  30. return
  31. }
  32. for _, detail := range list {
  33. //先标记为
  34. _ = models.ModifyReportSendThsDetailStatus(detail.SendId, 0, "")
  35. go SendToThs(detail.SendId, detail.ReportId, detail.ReportType)
  36. }
  37. return
  38. }
  39. // SyncWxGroupEveryDay 每日定时向同花顺同步客户时间
  40. func SyncWxGroupEveryDay(cont context.Context) (err error) {
  41. defer func() {
  42. if err != nil {
  43. fmt.Println(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "同步微信群组信息至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers)
  44. //go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "同步微信群组信息至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers)
  45. }
  46. }()
  47. //查询校验当天数据是否已经生成
  48. _, err = models.GetCompanyEndDate(time.Now().Format(utils.FormatDate))
  49. if err == nil || err.Error() != utils.ErrNoRow() {
  50. err = errors.New(fmt.Sprint(time.Now().Format(utils.FormatDate), "当天数据已经同步"))
  51. return
  52. }
  53. //永续、正式、试用、冻结
  54. list, err := models.GetAllCompanyProduct()
  55. if err != nil {
  56. return
  57. }
  58. timeLoc, _ := time.LoadLocation("Asia/Shanghai")
  59. //需要入库的数据
  60. companyEndDateMap := make(map[string]*models.CompanyEndDate)
  61. //实际需要推送的数据
  62. companyEndDatePushMap := make(map[string]*models.CompanyEndDate)
  63. //微信群组开放编号code
  64. companyProductOpenCode := make(map[string]string)
  65. for _, companyProduct := range list {
  66. key := fmt.Sprint(companyProduct.CompanyId, "_", companyProduct.ProductId)
  67. endDate, _ := time.ParseInLocation(utils.FormatDate, companyProduct.EndDate, timeLoc)
  68. if companyProduct.Status == "冻结" {
  69. endDate = time.Now().AddDate(0, 0, -1)
  70. }
  71. tmpCompanyEndDate := &models.CompanyEndDate{
  72. CompanyId: companyProduct.CompanyId,
  73. ProductId: companyProduct.ProductId,
  74. Status: companyProduct.Status,
  75. EndDate: endDate,
  76. CreateTime: time.Now(),
  77. }
  78. companyEndDateMap[key] = tmpCompanyEndDate
  79. companyEndDatePushMap[key] = tmpCompanyEndDate
  80. companyProductOpenCode[key] = companyProduct.OpenCode
  81. }
  82. startDate := time.Now().AddDate(0, 0, -1).Format(utils.FormatDate)
  83. endDate := time.Now().Format(utils.FormatDate)
  84. endDateList, err := models.GetAllCompanyProductEndDate(startDate, endDate)
  85. for _, endDate := range endDateList {
  86. key := fmt.Sprint(endDate.CompanyId, "_", endDate.ProductId)
  87. if companyEndDate, ok := companyEndDatePushMap[key]; ok {
  88. if companyEndDate.Status == "冻结" {
  89. //获取当天的零点时间
  90. endDateStr := time.Now().AddDate(0, 0, -1).Format(utils.FormatDate)
  91. companyEndDate.EndDate, _ = time.ParseInLocation(utils.FormatDate, endDateStr, timeLoc)
  92. }
  93. if companyEndDate.EndDate.Equal(endDate.EndDate) {
  94. delete(companyEndDatePushMap, key)
  95. }
  96. }
  97. }
  98. for _, companyEndDate := range companyEndDatePushMap {
  99. fmt.Println("待推送数据:", companyEndDate)
  100. key := fmt.Sprint(companyEndDate.CompanyId, "_", companyEndDate.ProductId)
  101. //同步至同花顺
  102. if openCode, ok := companyProductOpenCode[key]; ok {
  103. SyncWxGroup(openCode, companyEndDate.EndDate.Format(utils.FormatDate))
  104. }
  105. }
  106. for _, companyEndDate := range companyEndDateMap {
  107. models.AddCompanyEndDate(companyEndDate)
  108. }
  109. return
  110. }
  111. var permissionMap map[string]string = map[string]string{
  112. "化里化外日评": "原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱",
  113. "股债日评": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢",
  114. "贵金属复盘": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢",
  115. "每日经济数据备忘录": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢",
  116. "宏观商品复盘": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢",
  117. "知白守黑日评": "钢材,铁矿,双焦(焦煤、焦炭)",
  118. "有声有色日度闲篇": "有色(铜、铝),有色(锌、铅),镍+不锈钢",
  119. "EIA原油库存点评": "原油",
  120. "苯乙烯数据点评": "苯乙烯",
  121. "API原油库存点评": "原油",
  122. "铁矿航运数据点评": "铁矿",
  123. "中观需求点评": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢",
  124. "聚酯数据点评": "PTA,MEG",
  125. "钢材周度数据点评": "钢材",
  126. "寻根知本": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢",
  127. "国际宏观": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢",
  128. "能化百家谈": "原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱",
  129. "有色百家谈": "有色(铜、铝),有色(锌、铅),镍+不锈钢",
  130. "黑色百家谈": "钢材,铁矿,双焦(焦煤、焦炭)",
  131. }
  132. //TshResult 同花顺返回信息
  133. type TshResult struct {
  134. ErrorCode int `json:"error" description:"错误状态码"`
  135. Message string `json:"message" description:"提示信息"`
  136. }
  137. //
  138. func SendToThs(sendDetailId, reportId int, reportType string) (err error) {
  139. switch reportType {
  140. case "日度点评":
  141. tmpErr := SendReportToThs(reportId)
  142. if tmpErr != nil {
  143. err = tmpErr
  144. }
  145. case "研报小程序":
  146. tmpErr := SendReportMiniToThs(reportId)
  147. if tmpErr != nil {
  148. err = tmpErr
  149. }
  150. default:
  151. err = errors.New("异常类型")
  152. }
  153. if err != nil {
  154. _ = models.ModifyReportSendThsDetailStatus(sendDetailId, -1, err.Error())
  155. err = nil
  156. return
  157. }
  158. _ = models.ModifyReportSendThsDetailStatus(sendDetailId, 1, "")
  159. return
  160. }
  161. // SendReportToThs 发送报告到同花顺
  162. func SendReportToThs(reportId int) (err error) {
  163. defer func() {
  164. if err != nil {
  165. //fmt.Println(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "发送消息至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers)
  166. go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "发送报告至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers)
  167. }
  168. }()
  169. report, tmpErr := models.GetReportById(reportId)
  170. if tmpErr != nil {
  171. err = tmpErr
  172. return
  173. }
  174. //获取分类信息(标签)
  175. permissionName := report.ClassifyNameSecond
  176. classifyItem, err := models.GetClassifyById(report.ClassifyIdSecond)
  177. if err != nil {
  178. err = errors.New(fmt.Sprint("获取分类失败:", permissionName))
  179. }
  180. //获取权限标签名称
  181. var permissionStr string
  182. if classifyItem != nil {
  183. permissionStr = classifyItem.ClassifyLabel
  184. if permissionStr == "" {
  185. var isOk bool
  186. permissionStr, isOk = permissionMap[permissionName]
  187. if !isOk {
  188. err = errors.New(fmt.Sprint("没有该权限的标签,权限名:", permissionName))
  189. return
  190. }
  191. }
  192. } else {
  193. var isOk bool
  194. permissionStr, isOk = permissionMap[permissionName]
  195. if !isOk {
  196. err = errors.New(fmt.Sprint("没有该权限的标签,权限名:", permissionName))
  197. return
  198. }
  199. }
  200. if permissionStr == "" {
  201. err = errors.New(fmt.Sprint("没有该权限的标签,权限名:", permissionName))
  202. return
  203. }
  204. //fmt.Println("sendDetailId:", sendDetailId)
  205. stageStr := fmt.Sprintf("%v", report.Stage)
  206. createDate, err := time.Parse(utils.FormatDateTime, report.CreateTime)
  207. createDateFrom := createDate.Format("0102")
  208. title := `【第` + stageStr + `期|FICC】` + report.Title + `(` + createDateFrom + ")"
  209. // 跳转地址
  210. jumpBaseUrl := `http://rddpweb.brilliantstart.cn/reportdtl?id=`
  211. //生产环境地址
  212. if utils.RunMode == "release" {
  213. jumpBaseUrl = `https://ficc.hzinsights.com/reportdtl?id=`
  214. }
  215. jumpUrl := fmt.Sprint(jumpBaseUrl, report.Id)
  216. // logo 地址
  217. logoUrl := `https://hongze.oss-cn-shanghai.aliyuncs.com/hzyj.png`
  218. // 简介
  219. abstract := report.Abstract
  220. // 实际推送到同花顺
  221. err = SendThs(title, permissionStr, abstract, jumpUrl, logoUrl, "1")
  222. return
  223. }
  224. // SendThs 发送消息到同花顺
  225. func SendThs(title, labelStr, abstract, jumpBaseUrl, logoUrl, dataType string) (err error) {
  226. defer func() {
  227. if err != nil {
  228. //fmt.Println(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "发送消息至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers)
  229. go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "发送报告至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers)
  230. }
  231. }()
  232. pubKey := utils.THS_PubKey
  233. sendUrl := utils.THS_SendUrl
  234. //fmt.Println("sendUrl:", sendUrl)
  235. //标题字符长度截取,最多50位字符
  236. title = utils.SubStr(title, 50)
  237. utils.FileLog.Info(fmt.Sprintf("title:%s", title))
  238. title, err = gorsa.PublicEncrypt(title, pubKey)
  239. if err != nil {
  240. return
  241. }
  242. //简介字符长度截取,最多50位字符
  243. abstract = utils.SubStr(abstract, 50)
  244. utils.FileLog.Info(fmt.Sprintf("abstract:%s", abstract))
  245. abstract, err = gorsa.PublicEncrypt(abstract, pubKey)
  246. if err != nil {
  247. return
  248. }
  249. utils.FileLog.Info(fmt.Sprintf("labelStr:%s", labelStr))
  250. label, err := gorsa.PublicEncrypt(labelStr, pubKey)
  251. if err != nil {
  252. return
  253. }
  254. jumpUrl, err := gorsa.PublicEncrypt(jumpBaseUrl, pubKey)
  255. if err != nil {
  256. return
  257. }
  258. picUrl, err := gorsa.PublicEncrypt(logoUrl, pubKey)
  259. if err != nil {
  260. return
  261. }
  262. dataTypeEncript, err := gorsa.PublicEncrypt(dataType, pubKey)
  263. if err != nil {
  264. return
  265. }
  266. //开始发送
  267. client := http.Client{}
  268. form := url.Values{}
  269. form.Add("title", title)
  270. form.Add("description", abstract)
  271. form.Add("label", label)
  272. form.Add("url", jumpUrl)
  273. form.Add("icon", picUrl)
  274. form.Add("dataType", dataTypeEncript)
  275. utils.FileLog.Info("SendThs parms:%s", form.Encode())
  276. resp, err := client.PostForm(sendUrl, form)
  277. if err != nil {
  278. return
  279. }
  280. defer resp.Body.Close()
  281. body, _ := ioutil.ReadAll(resp.Body)
  282. //fmt.Println(string(body))
  283. utils.FileLog.Info("ThsResult parms:%s", string(body))
  284. //同花顺接口返回数据
  285. var tshResult TshResult
  286. err = json.Unmarshal(body, &tshResult)
  287. if err != nil {
  288. err = errors.New(fmt.Sprint("同花顺接口返回数据转换成结构体异常,Err:", err))
  289. return
  290. }
  291. if tshResult.ErrorCode != 1 {
  292. err = errors.New(fmt.Sprint("发送数据到同花顺接口异常,result:", string(body)))
  293. return
  294. }
  295. return
  296. }
  297. // SyncWxGroup 同步同花顺 微信群信息
  298. func SyncWxGroup(openCompanyCode, deadline string) (err error) {
  299. defer func() {
  300. if err != nil {
  301. //fmt.Println(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "同步同花顺微信群信息失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers)
  302. go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "同步同花顺微信群信息失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers)
  303. }
  304. }()
  305. pubKey := utils.THS_PubKey
  306. sendUrl := utils.THS_SyncWxGroupUrl
  307. openCompanyCode, err = gorsa.PublicEncrypt(openCompanyCode, pubKey)
  308. if err != nil {
  309. return
  310. }
  311. deadline, err = gorsa.PublicEncrypt(deadline, pubKey)
  312. if err != nil {
  313. return
  314. }
  315. status := `1`
  316. status, err = gorsa.PublicEncrypt(status, pubKey)
  317. if err != nil {
  318. return
  319. }
  320. //开始发送
  321. client := http.Client{}
  322. form := url.Values{}
  323. form.Add("thirdWechatGroupId", openCompanyCode)
  324. form.Add("deadline", deadline)
  325. form.Add("status", status)
  326. utils.FileLog.Info(fmt.Sprintf("SendThs SyncWxGroup parms:%s", form.Encode()))
  327. resp, err := client.PostForm(sendUrl, form)
  328. if err != nil {
  329. return
  330. }
  331. defer resp.Body.Close()
  332. body, _ := ioutil.ReadAll(resp.Body)
  333. fmt.Println(string(body))
  334. utils.FileLog.Info(fmt.Sprintf("SyncWxGroup ThsResult parms:%s", string(body)))
  335. //同花顺接口返回数据
  336. var tshResult TshResult
  337. err = json.Unmarshal(body, &tshResult)
  338. if err != nil {
  339. err = errors.New(fmt.Sprint("同花顺接口返回数据转换成结构体异常,Err:", err))
  340. return
  341. }
  342. if tshResult.ErrorCode != 1 {
  343. err = errors.New(fmt.Sprint("发送数据到同花顺接口异常,result:", string(body)))
  344. return
  345. }
  346. return
  347. }
  348. // SendReportMiniToThs 发送报告小程序到同花顺
  349. func SendReportMiniToThs(reportId int) (err error) {
  350. defer func() {
  351. if err != nil {
  352. //fmt.Println(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "发送消息至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers)
  353. go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "SendReportMiniToThs延时任务发送报告至同花顺失败, ReportId:" + strconv.Itoa(reportId) + ", ErrMsg:"+err.Error(), utils.EmailSendToUsers)
  354. }
  355. }()
  356. report, tmpErr := models.GetReportById(reportId)
  357. if tmpErr != nil {
  358. err = tmpErr
  359. return
  360. }
  361. //小程序跳转地址
  362. jumpBaseUrl := utils.WxYbAppId + `/pages-report/reportDetail?reportId=`
  363. jumpUrl := fmt.Sprint(jumpBaseUrl, report.Id)
  364. logoUrl := `https://hongze.oss-cn-shanghai.aliyuncs.com/hzyj.png`
  365. var permissionStr string
  366. if report.HasChapter == 0 {
  367. // 获取分类信息(标签)
  368. permissionName := report.ClassifyNameSecond
  369. classifyItem, tmpErr := models.GetClassifyById(report.ClassifyIdSecond)
  370. if tmpErr != nil {
  371. err = errors.New(fmt.Sprint("获取分类失败:", permissionName))
  372. return
  373. }
  374. // 获取权限标签名称
  375. if classifyItem != nil {
  376. permissionStr = classifyItem.ClassifyLabel
  377. if permissionStr == "" {
  378. var isOk bool
  379. permissionStr, isOk = permissionMap[permissionName]
  380. if !isOk {
  381. err = errors.New(fmt.Sprint("没有该权限的标签,权限名:", permissionName))
  382. return
  383. }
  384. }
  385. } else {
  386. var isOk bool
  387. permissionStr, isOk = permissionMap[permissionName]
  388. if !isOk {
  389. err = errors.New(fmt.Sprint("没有该权限的标签,权限名:", permissionName))
  390. return
  391. }
  392. }
  393. if permissionStr == "" {
  394. err = errors.New(fmt.Sprint("没有该权限的标签,权限名:", permissionName))
  395. return
  396. }
  397. } else {
  398. // 同php的
  399. permissionStr = "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢"
  400. }
  401. // 实际推送到同花顺
  402. err = SendThs(report.Title, permissionStr, report.Abstract, jumpUrl, logoUrl, "2")
  403. return
  404. }