task.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. package task
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/json"
  6. "fmt"
  7. "git.listensoft.net/tool/jspkit/common"
  8. "git.listensoft.net/tool/jspkit/common/lxhttp"
  9. "git.listensoft.net/tool/jspkit/common/models"
  10. "git.listensoft.net/tool/jspkit/common/variable"
  11. "git.listensoft.net/tool/jspkit/logger"
  12. "git.listensoft.net/tool/jspkit/login"
  13. "git.listensoft.net/tool/jspkit/taxerr"
  14. "github.com/spf13/viper"
  15. "github.com/tidwall/gjson"
  16. "os"
  17. "path/filepath"
  18. "strconv"
  19. "strings"
  20. "time"
  21. )
  22. const taxMaxTime = 20 * time.Minute //超时默认20分钟
  23. // GetContent 根据地区定制Content 设置超时时间
  24. func GetContent(childCtx context.Context, address string, pdfTel string, ticker *time.Ticker) (childCtx1 context.Context) {
  25. if address == "shandong" || address == "neimenggu" || address == "jiangsu" { // 针对20分钟不够用的地区
  26. childCtx1, _ = context.WithTimeout(childCtx, 30*time.Minute)
  27. } else if address == "sichuan" || address == "chongqing" || address == "shanxi" || (address == "anhui") {
  28. childCtx1, _ = context.WithTimeout(childCtx, 40*time.Minute)
  29. } else if address == "fujian" || address == "beijing" || address == "qinghai" || address == "xiamen" {
  30. childCtx1, _ = context.WithTimeout(childCtx, 40*time.Minute)
  31. } else {
  32. childCtx1, _ = context.WithTimeout(childCtx, taxMaxTime)
  33. }
  34. if pdfTel != "" {
  35. //childCtx1, _ = context.WithTimeout(childCtx, 120*time.Minute) //四川的pdf采集 一个小时不够
  36. ticker = time.NewTicker(4 * time.Minute) // 每四分钟加五分钟的锁
  37. go func() {
  38. for t := range ticker.C { // 阻塞等待接收ticker发出的时间信号
  39. common.AddTelLockerX2(pdfTel, "300")
  40. logger.Info("Tick at:", t)
  41. }
  42. }()
  43. }
  44. return
  45. }
  46. // GetTaxTask 获取任务
  47. func GetTaxTask(robotName string) (list []models.TaxTask, err error) {
  48. client := lxhttp.NewHttpClient()
  49. defer client.CloseIdleConnections()
  50. param := map[string]string{
  51. "robotName": robotName,
  52. }
  53. bys, err2 := lxhttp.POSTJson(client, variable.TaxTaskURL+"/api/v1/getRobotQueue", param, map[string]string{})
  54. if err2 != nil {
  55. return
  56. }
  57. data := gjson.GetBytes(bys, "data").String()
  58. list = []models.TaxTask{}
  59. err = json.Unmarshal([]byte(data), &list)
  60. return
  61. }
  62. // EndQueue 释放机器人
  63. func EndQueue(robotName string) {
  64. client := lxhttp.NewHttpClient()
  65. defer client.CloseIdleConnections()
  66. param := map[string]string{
  67. "robotName": robotName,
  68. }
  69. bys, err2 := lxhttp.POSTJson(client, variable.TaxTaskURL+"/api/v1/endQueue", param, map[string]string{}) // https://task.listensoft.net
  70. if err2 != nil {
  71. return
  72. }
  73. logger.Info("endQueue - ", string(bys))
  74. }
  75. // GetRobotName 获取当前机器人名称
  76. func GetRobotName() string {
  77. //环境变量中读取名称
  78. envRobotName := os.Getenv("robotName")
  79. logger.Info("envRobotName:", envRobotName)
  80. if envRobotName != "" {
  81. return envRobotName
  82. }
  83. //config中读取文件
  84. confRobotName := viper.GetString("robotName")
  85. logger.Info("confRobotName:", confRobotName)
  86. if confRobotName != "" { //如果是测试环境 固定一个 robotName 方便调试 一直获取一个任务
  87. return confRobotName
  88. }
  89. //读取不到默认文件夹名称
  90. dir, _ := os.Getwd()
  91. _, file := filepath.Split(dir)
  92. logger.Info("fileDIrRobotName:", file)
  93. return file
  94. }
  95. // 结束任务
  96. func EndTask(ctx context.Context, tasks []models.TaxTask) {
  97. clientURL := variable.TaxTaskURL + "/api/v1/endTaskTax"
  98. for k, v := range tasks {
  99. symbolToRemove := ","
  100. // 使用Trim函数删除字符串两端的指定符号
  101. tasks[k].Result.BusinessImg = strings.Trim(v.Result.BusinessImg, symbolToRemove)
  102. }
  103. for _, task := range tasks {
  104. if (strings.Contains(task.Result.BusinessLog, "您当前认证等级不够") || strings.Contains(task.Result.BusinessLog, "认证等级无法访问该功能")) && task.LoginType == "新版登录" {
  105. task.Result.BusinessStatus = variable.TaxFail
  106. task.Result.BusinessLog = common.HandleError(ctx, taxerr.TaxRzDkErr).Error()
  107. login.RemoveLogin(models.CompanyInfo{Tel: strings.Split(task.Tel, "#")[0], Area: task.Address})
  108. }
  109. // 检查 如果截图lv《申报清册_有遗漏》 状态不是有遗漏 这边强制改成有遗漏 遇到别的情况再额外处理
  110. if task.TaskName == variable.TaxJcShenBao &&
  111. (task.Result.BusinessStatus != variable.TaxSuccessdOmit && task.Result.BusinessStatus != variable.TaxFail) &&
  112. strings.Contains(task.Result.BusinessImg, "申报清册_有遗漏") {
  113. task.Result.BusinessStatus = variable.TaxSuccessdOmit
  114. task.Result.BusinessLog = "申报清册有遗漏,请看截图" + task.Result.BusinessLog
  115. }
  116. if task.ReqNo == "" {
  117. logger.Info("跳过用于解锁的空任务:", task)
  118. continue
  119. }
  120. task.Result.ReqNo = task.ReqNo //reqNo 返回
  121. if task.Result.Status == 0 { //如果没有状态 申报检查会带状态过来
  122. task.Result.Status = variable.TaxSuccess //默认任务成功
  123. }
  124. if !task.Result.BusinessStatus.Check() { //没有状态的话
  125. task.Result.BusinessStatus = variable.TaxFail //失败
  126. task.Result.BusinessLog = common.HandleError(ctx, taxerr.NewWebStuckTitle(false)).Error() //提示不支持的任务
  127. }
  128. //if task.Result.BusinessStatus.Success() { //如果是成功的话
  129. // task.Result.BusinessLog = "成功" //提示不支持的任务
  130. //}
  131. //if task.TaskName == variable.TaxCjInInvoice && strings.Contains(task.Result.BusinessLog, "请勾选认证后再次发起采集") {
  132. // task.Result.BusinessStatus = variable.TaxSuccessNeedPay
  133. //}
  134. if strings.Contains(string(task.TaskName), `kk`) && task.Result.BusinessStatus != variable.TaxTiJiaoJinSan {
  135. if task.Result.BusinessStatus != variable.TaxSuccessPaid && task.Result.BusinessStatus != variable.TaxSuccessdPaid {
  136. task.Result.BusinessStatus = variable.TaxFail
  137. } else {
  138. if task.TaskName != variable.TaxKkShebao { //社保的扣款任务要保留原状态作为 系统扣款 和 非系统扣款
  139. task.Result.BusinessStatus = variable.TaxSuccess
  140. }
  141. }
  142. }
  143. bys, _ := json.Marshal(task.Result)
  144. logger.Info("结束任务:", string(bys))
  145. for i := 0; i < 6; i++ {
  146. logger.Info(time.Now(), fmt.Sprintf("-----------第%s次尝试endTaskTax", strconv.Itoa(i)))
  147. res, err := lxhttp.HttpClientPost(lxhttp.NewHttpClient(), clientURL, "application/json", bytes.NewReader(bys))
  148. if err != nil || strings.Contains(string(res), "Sorry") {
  149. logger.Error("任务结束请求错误:" + err.Error())
  150. time.Sleep(time.Second * 10)
  151. continue
  152. } else {
  153. logger.Info(time.Now(), fmt.Sprintf("-----------第%s次endTaskTax成功", strconv.Itoa(i)))
  154. logger.Info("任务结束发送到服务器返回结果:", string(res))
  155. break
  156. }
  157. }
  158. }
  159. }
  160. // =================================== 历史数据采集相关 ======================================
  161. // 校验凭证出现的所有科目是否都在中间课余表中
  162. func CheckSubjectCodes(midSubjects []models.HisSubject, Vouchers []models.HisVoucher) bool {
  163. var Map1 map[string]bool // 凭证的所有科目
  164. Map1 = make(map[string]bool, len(midSubjects))
  165. var Map2 map[string]bool // 中间课余表的所有科目
  166. Map2 = make(map[string]bool, len(midSubjects))
  167. for _, v1 := range Vouchers {
  168. for _, v2 := range v1.Items {
  169. if !Map1[v2.SubjectCode] {
  170. Map1[v2.SubjectCode] = true
  171. }
  172. }
  173. }
  174. for _, v := range midSubjects {
  175. if !Map2[v.SubjectCode] {
  176. Map2[v.SubjectCode] = true
  177. }
  178. }
  179. for v := range Map1 {
  180. if !Map2[v] {
  181. for _, v1 := range Vouchers {
  182. for _, v2 := range v1.Items {
  183. if v == v2.SubjectCode {
  184. logger.Info(v1.VoucherNo, v1.Period)
  185. break
  186. }
  187. }
  188. }
  189. logger.Info(v)
  190. return false
  191. }
  192. }
  193. return true
  194. }
  195. // 返回错误信息
  196. func CheckSubjectCodesError(midSubjects []models.HisSubject, Vouchers []models.HisVoucher) (bool, string) {
  197. var Map1 map[string]bool // 凭证的所有科目
  198. Map1 = make(map[string]bool, len(midSubjects))
  199. var Map2 map[string]bool // 中间课余表的所有科目
  200. Map2 = make(map[string]bool, len(midSubjects))
  201. for _, v1 := range Vouchers {
  202. for _, v2 := range v1.Items {
  203. if !Map1[v2.SubjectCode] {
  204. Map1[v2.SubjectCode] = true
  205. }
  206. }
  207. }
  208. for _, v := range midSubjects {
  209. if !Map2[v.SubjectCode] {
  210. Map2[v.SubjectCode] = true
  211. }
  212. }
  213. for v := range Map1 {
  214. if !Map2[v] {
  215. msg := ""
  216. for _, v1 := range Vouchers {
  217. for _, v2 := range v1.Items {
  218. if v == v2.SubjectCode {
  219. msg = fmt.Sprintf("%s期%s凭证出现缺失%s科目", v1.Period, v1.VoucherNo, v)
  220. logger.Info(v1.VoucherNo, v1.Period)
  221. break
  222. }
  223. }
  224. }
  225. logger.Info(v)
  226. return false, msg
  227. }
  228. }
  229. return true, ""
  230. }
  231. func Unlocking(start time.Time, tasks []models.TaxTask) {
  232. reqs := []string{}
  233. for _, v := range tasks {
  234. reqs = append(reqs, strings.Split(v.ReqNo, "&")...)
  235. }
  236. req := strings.Join(reqs, "*")
  237. UnTels := make(map[string]bool, 1000)
  238. if len(tasks) < 1 {
  239. return
  240. }
  241. //工商的任务不在这里解锁了(避免影响到这个手机号下的税局申报任务,因为如果不加锁的话120秒是可能不够工商申报的,并发的话税局任务会一直挂掉)
  242. //如果想要工商任务快一点(客户嫌慢的话),工商任务拿到的时候自己加锁,加锁时长要大于等待验证码的时间(确保收到验证码后解锁 解的是自己加的锁),然后收到验证码的时候解锁
  243. for _, task := range tasks {
  244. if task.TaskName == variable.TaxCjGsnb || task.TaskName == variable.TaxSbGsnb {
  245. return
  246. }
  247. }
  248. // 采集pdf除外 因为超了20分钟就不解锁了 pdf统一上锁3600
  249. if (tasks[0].Address == "jiangsu" || tasks[0].Address == "henan") && tasks[0].TaskName != variable.TaxCjInvoicePdf { //&& (tasks[0].LoginType == "政务网登录" || tasks[0].LoginType == "免验证码登录")
  250. checkPass := true
  251. info, _ := GetEacComInfo(tasks[0])
  252. if info.Dlfs == "新版登录" && strings.Contains(tasks[0].Result.BusinessLog, "验证码接收失败") {
  253. logger.Info("结束该手机号剩余任务:" + info.Tel)
  254. common.CancelLeftTasks(info.Tel)
  255. }
  256. for _, task := range tasks {
  257. if strings.Contains(task.Result.BusinessLog, "超限") { //strings.Contains(task.Result.BusinessLog, "锁定") ||
  258. checkPass = false
  259. }
  260. }
  261. if tasks[0].Address == "henan" && checkPass {
  262. if !time.Now().After(start.Add(12 * time.Minute)) { //不超过7分钟的解锁
  263. tel := strings.Split(tasks[0].Tel, `#`)[0]
  264. if time.Since(start).Seconds() < 45 {
  265. itv := common.FloatToIntStr((45 - time.Since(start).Seconds()) / 1)
  266. logger.Info("加锁:" + tel + " " + itv)
  267. common.AddTelLockerX2(tel, itv)
  268. return
  269. }
  270. logger.Info("解锁:" + tel)
  271. common.AddTelLockerX2Req(tel, "-1", req)
  272. } else if tasks[0].TaskName == variable.TaxCjInvoicePdf { //pdf的任务,如果没有任务在执行也解锁
  273. tel := strings.Split(tasks[0].Tel, `#`)[0]
  274. status, err := common.GetTelTaskStatus(tel)
  275. if err != nil {
  276. logger.Info("获取手机号任务状态失败")
  277. return
  278. }
  279. if !status {
  280. logger.Info("解锁:" + tel)
  281. common.AddTelLockerX2Req(tel, "-1", req)
  282. }
  283. return
  284. }
  285. }
  286. if tasks[0].Address == "jiangsu" && !time.Now().After(start.Add(18*time.Minute)) && checkPass {
  287. tel := strings.Split(tasks[0].Tel, `#`)[0]
  288. if time.Since(start).Seconds() < 45 {
  289. itv := common.FloatToIntStr((45 - time.Since(start).Seconds()) / 1)
  290. logger.Info("加锁:" + tel + " " + itv)
  291. common.AddTelLockerX2(tel, itv)
  292. return
  293. }
  294. logger.Info("解锁:" + tel)
  295. common.AddTelLockerX2Req(tel, "-1", req)
  296. }
  297. return
  298. }
  299. for _, task := range tasks {
  300. info, _ := GetEacComInfo(task)
  301. //address := info.Area
  302. // 新版登录 收不到验证码撤销掉剩余的任务,避免一直发导致超限
  303. if info.Dlfs == "新版登录" && strings.Contains(task.Result.BusinessLog, "验证码接收失败") {
  304. logger.Info("结束该手机号剩余任务:" + info.Tel)
  305. common.CancelLeftTasks(info.Tel)
  306. }
  307. //
  308. {
  309. //// 新版=统一解锁
  310. //if (info.Dlfs == "新版登录" || info.Dlfs == "代理登录") && info.Tel != "" && !(strings.Contains(task.Result.BusinessLog, "超限") || strings.Contains(task.Result.BusinessLog, "发送短信过于频繁")) {
  311. // if !UnTels[info.Tel] {
  312. // UnTels[info.Tel] = true
  313. // }
  314. //}
  315. //// zrridno统一解锁
  316. //if address == Hebei || address == Hainan || address == Yunnan || address == Shandong || address == Beijing || address == Xizang || address == "zhejiang" || address == "guangdong" || address == "jilin" {
  317. // if info.Dlfs == "新版登录" {
  318. // if !UnTels[info.Tel] {
  319. // UnTels[info.Tel] = true
  320. // }
  321. // } else {
  322. // if !UnTels[info.Zzridno] {
  323. // UnTels[info.Zzridno] = true
  324. // }
  325. // }
  326. //}
  327. //// zrrxm解锁
  328. //if address == "ningxia" {
  329. // if !UnTels[info.Zzrxm] {
  330. // UnTels[info.Zzrxm] = true
  331. // }
  332. //}
  333. //// 所有登陆方式都需要解锁的地区
  334. //if address == Shanxi || address == Jiangxi || address == Guangxi || address == Neimenggu || address == Xinjiang || address == Shenzhen || address == Henan || address == Anhui || address == Shaanxi || address == Hunan || address == Qingdao || address == Sichuan || address == Guizhou || address == Gansu || address == Dalian {
  335. // if !UnTels[info.Tel] {
  336. // UnTels[info.Tel] = true
  337. // }
  338. //}
  339. ////if (address == "tianjin" || address == "guangdong" || address == "zhejiang" || address == "hubei") && info.Dlfs == "新版登录" {
  340. //// if !UnTels[info.Zzridno+"_"+info.Area] {
  341. //// UnTels[info.Zzridno+"_"+info.Area] = true
  342. //// }
  343. ////}
  344. //// 针对发送超限
  345. //if strings.Contains(task.Result.BusinessLog, "超限") || strings.Contains(task.Result.BusinessLog, "发送短信过于频繁") {
  346. // common.AddTelLockerX2(info.Tel, "600")
  347. //}
  348. //// 针对新疆
  349. //if strings.Contains(task.Result.BusinessLog, "因上条短信验证码未正常使用,无法重新获取验证码,请您在5分钟后上条短信失效后") {
  350. // common.AddTelLockerX2(info.Tel, "300")
  351. //}
  352. }
  353. // 现在直接用手机号解锁,因为不管用什么加锁都会加到tel字段上
  354. if info.Tel != "" {
  355. UnTels[info.Tel] = true
  356. }
  357. // 频繁加锁
  358. if strings.Contains(task.Result.BusinessLog, "短信发送申请过于频繁") || strings.Contains(task.Result.BusinessLog, "超限") || strings.Contains(task.Result.BusinessLog, "发送短信过于频繁") || strings.Contains(task.Result.BusinessLog, "因上条短信验证码未正常使用,无法重新获取验证码,请您在5分钟后上条短信失效后") {
  359. UnTels[info.Tel] = false
  360. common.AddTelLockerX2(info.Tel, "300") // 直接覆盖一个5分钟的锁
  361. }
  362. }
  363. for k := range UnTels {
  364. haspdf := false
  365. for _, v := range tasks {
  366. if v.TaskName == variable.TaxCjInvoicePdf {
  367. haspdf = true
  368. break
  369. }
  370. }
  371. if time.Since(start).Seconds() < 1195 || haspdf {
  372. logger.Info("开始时间:", start.Format("2006-01-02 15:04:05"), ";结束时间:", time.Now().Format("2006-01-02 15:04:05"), ";任务时长:", time.Since(start).Seconds())
  373. logger.Info("解锁:" + k)
  374. common.AddTelLockerX2Req(k, "-1", req)
  375. }
  376. //if strings.Contains(k, "anhui") {
  377. // logger.Info("安徽暂时全解锁:" + k)
  378. // common.AddTelLockerX2Req(k, "-1", req)
  379. //}
  380. }
  381. }