package task import ( "bytes" "context" "encoding/json" "fmt" "git.listensoft.net/tool/jspkit/common" "git.listensoft.net/tool/jspkit/common/lxhttp" "git.listensoft.net/tool/jspkit/common/models" "git.listensoft.net/tool/jspkit/common/variable" "git.listensoft.net/tool/jspkit/logger" "git.listensoft.net/tool/jspkit/taxerr" "github.com/spf13/viper" "github.com/tidwall/gjson" "os" "path/filepath" "strconv" "strings" "time" ) const taxMaxTime = 20 * time.Minute //超时默认20分钟 // GetContent 根据地区定制Content 设置超时时间 func GetContent(childCtx context.Context, address string, pdfTel string, ticker *time.Ticker) (childCtx1 context.Context) { if address == "shandong" || address == "neimenggu" || address == "jiangsu" { // 针对20分钟不够用的地区 childCtx1, _ = context.WithTimeout(childCtx, 30*time.Minute) } else if address == "sichuan" || address == "chongqing" || address == "shanxi" || (address == "anhui") { childCtx1, _ = context.WithTimeout(childCtx, 40*time.Minute) } else if address == "fujian" || address == "beijing" || address == "qinghai" || address == "xiamen" { childCtx1, _ = context.WithTimeout(childCtx, 40*time.Minute) } else { childCtx1, _ = context.WithTimeout(childCtx, taxMaxTime) } if pdfTel != "" { //childCtx1, _ = context.WithTimeout(childCtx, 120*time.Minute) //四川的pdf采集 一个小时不够 ticker = time.NewTicker(4 * time.Minute) // 每四分钟加五分钟的锁 go func() { for t := range ticker.C { // 阻塞等待接收ticker发出的时间信号 common.AddTelLockerX2(pdfTel, "300") logger.Info("Tick at:", t) } }() } return } // GetTaxTask 获取任务 func GetTaxTask(robotName string) (list []models.TaxTask, err error) { client := lxhttp.NewHttpClient() defer client.CloseIdleConnections() param := map[string]string{ "robotName": robotName, } bys, err2 := lxhttp.POSTJson(client, variable.TaxTaskURL+"/api/v1/getRobotQueue", param, map[string]string{}) if err2 != nil { return } data := gjson.GetBytes(bys, "data").String() list = []models.TaxTask{} err = json.Unmarshal([]byte(data), &list) return } // EndQueue 释放机器人 func EndQueue(robotName string) { client := lxhttp.NewHttpClient() defer client.CloseIdleConnections() param := map[string]string{ "robotName": robotName, } bys, err2 := lxhttp.POSTJson(client, variable.TaxTaskURL+"/api/v1/endQueue", param, map[string]string{}) // https://task.listensoft.net if err2 != nil { return } logger.Info("endQueue - ", string(bys)) } // GetRobotName 获取当前机器人名称 func GetRobotName() string { //环境变量中读取名称 envRobotName := os.Getenv("robotName") logger.Info("envRobotName:", envRobotName) if envRobotName != "" { return envRobotName } //config中读取文件 confRobotName := viper.GetString("robotName") logger.Info("confRobotName:", confRobotName) if confRobotName != "" { //如果是测试环境 固定一个 robotName 方便调试 一直获取一个任务 return confRobotName } //读取不到默认文件夹名称 dir, _ := os.Getwd() _, file := filepath.Split(dir) logger.Info("fileDIrRobotName:", file) return file } // 结束任务 func EndTask(ctx context.Context, tasks []models.TaxTask) { clientURL := variable.TaxTaskURL + "/api/v1/endTaskTax" for k, v := range tasks { symbolToRemove := "," // 使用Trim函数删除字符串两端的指定符号 tasks[k].Result.BusinessImg = strings.Trim(v.Result.BusinessImg, symbolToRemove) } for _, task := range tasks { // 检查 如果截图lv《申报清册_有遗漏》 状态不是有遗漏 这边强制改成有遗漏 遇到别的情况再额外处理 if task.TaskName == variable.TaxJcShenBao && (task.Result.BusinessStatus != variable.TaxSuccessdOmit && task.Result.BusinessStatus != variable.TaxFail) && strings.Contains(task.Result.BusinessImg, "申报清册_有遗漏") { task.Result.BusinessStatus = variable.TaxSuccessdOmit task.Result.BusinessLog = "申报清册有遗漏,请看截图" + task.Result.BusinessLog } if task.ReqNo == "" { logger.Info("跳过用于解锁的空任务:", task) continue } task.Result.ReqNo = task.ReqNo //reqNo 返回 if task.Result.Status == 0 { //如果没有状态 申报检查会带状态过来 task.Result.Status = variable.TaxSuccess //默认任务成功 } if !task.Result.BusinessStatus.Check() { //没有状态的话 task.Result.BusinessStatus = variable.TaxFail //失败 task.Result.BusinessLog = common.HandleError(ctx, taxerr.NewWebStuckTitle(false)).Error() //提示不支持的任务 } //if task.Result.BusinessStatus.Success() { //如果是成功的话 // task.Result.BusinessLog = "成功" //提示不支持的任务 //} //if task.TaskName == variable.TaxCjInInvoice && strings.Contains(task.Result.BusinessLog, "请勾选认证后再次发起采集") { // task.Result.BusinessStatus = variable.TaxSuccessNeedPay //} if strings.Contains(string(task.TaskName), `kk`) && task.Result.BusinessStatus != variable.TaxTiJiaoJinSan { if task.Result.BusinessStatus != variable.TaxSuccessPaid && task.Result.BusinessStatus != variable.TaxSuccessdPaid { task.Result.BusinessStatus = variable.TaxFail } else { if task.TaskName != variable.TaxKkShebao { //社保的扣款任务要保留原状态作为 系统扣款 和 非系统扣款 task.Result.BusinessStatus = variable.TaxSuccess } } } bys, _ := json.Marshal(task.Result) logger.Info("结束任务:", string(bys)) for i := 0; i < 6; i++ { logger.Info(time.Now(), fmt.Sprintf("-----------第%s次尝试endTaskTax", strconv.Itoa(i))) res, err := lxhttp.HttpClientPost(lxhttp.NewHttpClient(), clientURL, "application/json", bytes.NewReader(bys)) if err != nil || strings.Contains(string(res), "Sorry") { logger.Error("任务结束请求错误:" + err.Error()) time.Sleep(time.Second * 10) continue } else { logger.Info(time.Now(), fmt.Sprintf("-----------第%s次endTaskTax成功", strconv.Itoa(i))) logger.Info("任务结束发送到服务器返回结果:", string(res)) break } } } } // =================================== 历史数据采集相关 ====================================== // 校验凭证出现的所有科目是否都在中间课余表中 func CheckSubjectCodes(midSubjects []models.HisSubject, Vouchers []models.HisVoucher) bool { var Map1 map[string]bool // 凭证的所有科目 Map1 = make(map[string]bool, len(midSubjects)) var Map2 map[string]bool // 中间课余表的所有科目 Map2 = make(map[string]bool, len(midSubjects)) for _, v1 := range Vouchers { for _, v2 := range v1.Items { if !Map1[v2.SubjectCode] { Map1[v2.SubjectCode] = true } } } for _, v := range midSubjects { if !Map2[v.SubjectCode] { Map2[v.SubjectCode] = true } } for v := range Map1 { if !Map2[v] { for _, v1 := range Vouchers { for _, v2 := range v1.Items { if v == v2.SubjectCode { logger.Info(v1.VoucherNo, v1.Period) break } } } logger.Info(v) return false } } return true } // 返回错误信息 func CheckSubjectCodesError(midSubjects []models.HisSubject, Vouchers []models.HisVoucher) (bool, string) { var Map1 map[string]bool // 凭证的所有科目 Map1 = make(map[string]bool, len(midSubjects)) var Map2 map[string]bool // 中间课余表的所有科目 Map2 = make(map[string]bool, len(midSubjects)) for _, v1 := range Vouchers { for _, v2 := range v1.Items { if !Map1[v2.SubjectCode] { Map1[v2.SubjectCode] = true } } } for _, v := range midSubjects { if !Map2[v.SubjectCode] { Map2[v.SubjectCode] = true } } for v := range Map1 { if !Map2[v] { msg := "" for _, v1 := range Vouchers { for _, v2 := range v1.Items { if v == v2.SubjectCode { msg = fmt.Sprintf("%s期%s凭证出现缺失%s科目", v1.Period, v1.VoucherNo, v) logger.Info(v1.VoucherNo, v1.Period) break } } } logger.Info(v) return false, msg } } return true, "" } func Unlocking(start time.Time, tasks []models.TaxTask) { reqs := []string{} for _, v := range tasks { reqs = append(reqs, strings.Split(v.ReqNo, "&")...) } req := strings.Join(reqs, "*") UnTels := make(map[string]bool, 1000) if len(tasks) < 1 { return } //工商的任务不在这里解锁了(避免影响到这个手机号下的税局申报任务,因为如果不加锁的话120秒是可能不够工商申报的,并发的话税局任务会一直挂掉) //如果想要工商任务快一点(客户嫌慢的话),工商任务拿到的时候自己加锁,加锁时长要大于等待验证码的时间(确保收到验证码后解锁 解的是自己加的锁),然后收到验证码的时候解锁 for _, task := range tasks { if task.TaskName == variable.TaxCjGsnb || task.TaskName == variable.TaxSbGsnb { return } } // 采集pdf除外 因为超了20分钟就不解锁了 pdf统一上锁3600 if (tasks[0].Address == "jiangsu" || tasks[0].Address == "henan") && tasks[0].TaskName != variable.TaxCjInvoicePdf { //&& (tasks[0].LoginType == "政务网登录" || tasks[0].LoginType == "免验证码登录") checkPass := true info, _ := GetEacComInfo(tasks[0]) if info.Dlfs == "新版登录" && strings.Contains(tasks[0].Result.BusinessLog, "验证码接收失败") { logger.Info("结束该手机号剩余任务:" + info.Tel) common.CancelLeftTasks(info.Tel) } for _, task := range tasks { if strings.Contains(task.Result.BusinessLog, "超限") { //strings.Contains(task.Result.BusinessLog, "锁定") || checkPass = false } } if tasks[0].Address == "henan" && checkPass { if !time.Now().After(start.Add(12 * time.Minute)) { //不超过7分钟的解锁 tel := strings.Split(tasks[0].Tel, `#`)[0] if time.Since(start).Seconds() < 45 { itv := common.FloatToIntStr((45 - time.Since(start).Seconds()) / 1) logger.Info("加锁:" + tel + " " + itv) common.AddTelLockerX2(tel, itv) return } logger.Info("解锁:" + tel) common.AddTelLockerX2Req(tel, "-1", req) } else if tasks[0].TaskName == variable.TaxCjInvoicePdf { //pdf的任务,如果没有任务在执行也解锁 tel := strings.Split(tasks[0].Tel, `#`)[0] status, err := common.GetTelTaskStatus(tel) if err != nil { logger.Info("获取手机号任务状态失败") return } if !status { logger.Info("解锁:" + tel) common.AddTelLockerX2Req(tel, "-1", req) } return } } if tasks[0].Address == "jiangsu" && !time.Now().After(start.Add(18*time.Minute)) && checkPass { tel := strings.Split(tasks[0].Tel, `#`)[0] if time.Since(start).Seconds() < 45 { itv := common.FloatToIntStr((45 - time.Since(start).Seconds()) / 1) logger.Info("加锁:" + tel + " " + itv) common.AddTelLockerX2(tel, itv) return } logger.Info("解锁:" + tel) common.AddTelLockerX2Req(tel, "-1", req) } return } for _, task := range tasks { info, _ := GetEacComInfo(task) //address := info.Area // 新版登录 收不到验证码撤销掉剩余的任务,避免一直发导致超限 if info.Dlfs == "新版登录" && strings.Contains(task.Result.BusinessLog, "验证码接收失败") { logger.Info("结束该手机号剩余任务:" + info.Tel) common.CancelLeftTasks(info.Tel) } // { //// 新版=统一解锁 //if (info.Dlfs == "新版登录" || info.Dlfs == "代理登录") && info.Tel != "" && !(strings.Contains(task.Result.BusinessLog, "超限") || strings.Contains(task.Result.BusinessLog, "发送短信过于频繁")) { // if !UnTels[info.Tel] { // UnTels[info.Tel] = true // } //} //// zrridno统一解锁 //if address == Hebei || address == Hainan || address == Yunnan || address == Shandong || address == Beijing || address == Xizang || address == "zhejiang" || address == "guangdong" || address == "jilin" { // if info.Dlfs == "新版登录" { // if !UnTels[info.Tel] { // UnTels[info.Tel] = true // } // } else { // if !UnTels[info.Zzridno] { // UnTels[info.Zzridno] = true // } // } //} //// zrrxm解锁 //if address == "ningxia" { // if !UnTels[info.Zzrxm] { // UnTels[info.Zzrxm] = true // } //} //// 所有登陆方式都需要解锁的地区 //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 { // if !UnTels[info.Tel] { // UnTels[info.Tel] = true // } //} ////if (address == "tianjin" || address == "guangdong" || address == "zhejiang" || address == "hubei") && info.Dlfs == "新版登录" { //// if !UnTels[info.Zzridno+"_"+info.Area] { //// UnTels[info.Zzridno+"_"+info.Area] = true //// } ////} //// 针对发送超限 //if strings.Contains(task.Result.BusinessLog, "超限") || strings.Contains(task.Result.BusinessLog, "发送短信过于频繁") { // common.AddTelLockerX2(info.Tel, "600") //} //// 针对新疆 //if strings.Contains(task.Result.BusinessLog, "因上条短信验证码未正常使用,无法重新获取验证码,请您在5分钟后上条短信失效后") { // common.AddTelLockerX2(info.Tel, "300") //} } // 现在直接用手机号解锁,因为不管用什么加锁都会加到tel字段上 if info.Tel != "" { UnTels[info.Tel] = true } // 频繁加锁 if strings.Contains(task.Result.BusinessLog, "短信发送申请过于频繁") || strings.Contains(task.Result.BusinessLog, "超限") || strings.Contains(task.Result.BusinessLog, "发送短信过于频繁") || strings.Contains(task.Result.BusinessLog, "因上条短信验证码未正常使用,无法重新获取验证码,请您在5分钟后上条短信失效后") { UnTels[info.Tel] = false common.AddTelLockerX2(info.Tel, "300") // 直接覆盖一个5分钟的锁 } } for k := range UnTels { haspdf := false for _, v := range tasks { if v.TaskName == variable.TaxCjInvoicePdf { haspdf = true break } } if time.Since(start).Seconds() < 1195 || haspdf { logger.Info("开始时间:", start.Format("2006-01-02 15:04:05"), ";结束时间:", time.Now().Format("2006-01-02 15:04:05"), ";任务时长:", time.Since(start).Seconds()) logger.Info("解锁:" + k) common.AddTelLockerX2Req(k, "-1", req) } //if strings.Contains(k, "anhui") { // logger.Info("安徽暂时全解锁:" + k) // common.AddTelLockerX2Req(k, "-1", req) //} } }