package service import ( "ElectronicInvoice/internal/consts" "context" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gcron" "github.com/gogf/gf/v2/util/gconv" "strconv" "time" ) var ( JyInvoiceManager *InvoiceManager ) type InvoiceManager struct { Auth *TripartiteAuth jobRunning bool //开票是否运行中 StopRunning bool //财务占用账号,需要暂停任务 Login bool //登录状态 OCRPass bool //活体检测状态是否通过 runPool chan bool //任务(每次只能进行一个开票任务) phoneCode chan string //短信验证码池 ScanLogin chan bool //扫码登录 } func init() { JyInvoiceManager = createInvoiceManager() job, err := gcron.Add(context.Background(), g.Cfg().MustGet(context.Background(), "invoiceJob.cron").String(), JyInvoiceManager.RunJob, "invoiceJob") if err != nil { panic(err) } job.Start() //go JyInvoiceManager.RunOneJob(context.Background())//流程 //go JyInvoiceManager.Demo(context.Background()) //开票 //go JyInvoiceManager.RedDemo(context.Background())//红冲 } func createInvoiceManager() *InvoiceManager { return &InvoiceManager{ Auth: createTripartite(), Login: true, //默认已经登录 OCRPass: true, runPool: make(chan bool, 1), //开票只能单线程跑 phoneCode: make(chan string, 1), //手机验证码 ScanLogin: make(chan bool, 1), //扫码登录通知 } } func (im *InvoiceManager) ReleasePool() { <-im.runPool } func (im *InvoiceManager) MobileVerificationCode(code string) error { if code == "" { return gerror.New("验证码为空") } select { case <-time.After(time.Minute): return gerror.New("验证码接收超时") case im.phoneCode <- code: return nil } } func (im *InvoiceManager) MobileVerificationClear() error { select { case <-time.After(time.Minute): return gerror.New("清除验证码超时") case <-im.phoneCode: return nil } } // RunJob 开票定时任务 func (im *InvoiceManager) RunJob(ctx context.Context) { if im.jobRunning || im.StopRunning { g.Log().Infof(ctx, "RunJob-程序本次任务中断 jobRunning:%v StopRunning:%v", im.jobRunning, im.StopRunning) return } im.jobRunning = true defer func() { im.jobRunning = false g.Log().Infof(ctx, "RunJob-开票任务完成") }() if g.Cfg().MustGet(ctx, "invoiceJob.stop", false).Bool() { g.Log().Infof(ctx, "RunJob-开票程序任务已暂停,开启请删除 config.json > invoiceJob.stop") return } if !im.Login { if err := im.Auth.Login(); err != nil { g.Log().Errorf(ctx, "模拟登录异常 %v", err) return } else { g.Log().Infof(ctx, "登录成功") } } //TODO 普通蓝票任务 total, okNum, err := im.simpleMakeInvoice(ctx) if err != nil { if gerror.Is(err, consts.LoginOutErr) { g.Log().Infof(ctx, "RunJob-任务中止-身份过期,需要重新登录") return } g.Log().Errorf(ctx, "RunJob-开蓝票任务异常 %v", err) } else { g.Log().Infof(ctx, "RunJob-开蓝票任务完成 共%d个 完成%d个", total, okNum) } //TODO 红票任务 } // simpleMakeInvoice 简单开票 func (im *InvoiceManager) simpleMakeInvoice(ctx context.Context) (total, okNum int, err error) { var ( res gdb.Result ) //查询需要开票的数据 res, err = g.DB().Query(ctx, "SELECT a.*,b.pay_way,b.order_money,b.pay_money FROM invoice a INNER JOIN dataexport_order b ON a.order_code=b.order_code WHERE a.invoice_status=0 AND a.invoice_changed=0 AND a.invoice_variety='普通发票(电子发票)' AND a.invoice_order_code is NULL") if err != nil { g.Log().Errorf(ctx, "RunJob-simpleMakeInvoice-查询待开票异常 %s", err) return -1, -1, gerror.Wrap(err, "simpleMakeInvoice-查询待开票异常") } g.Log().Infof(ctx, "RunJob-simpleMakeInvoice-本次共加载%d条开票记录", res.Len()) total, okNum = res.Len(), 0 for _, m := range res.List() { select { case im.runPool <- true: case <-time.After(time.Minute * 5): g.Log().Errorf(ctx, "RunJob-simpleMakeInvoice-开票等待超时,结束此次任务") return } var ( orderCode = gconv.String(m["order_code"]) phone = gconv.String(m["phone_num"]) iType = gconv.String(m["invoice_type"]) prices float64 ) //公对公转账 账单金额可以修改 开发票应取实付金额 pay_money //微信支付宝支付 pay_money为订单金额减去微信or支付包红包 if gconv.String(m["pay_way"]) == "transferAccounts" { prices = gconv.Float64(m["pay_money"]) / float64(100) } else { prices = gconv.Float64(m["order_money"]) / float64(100) } c := MakeInvoiceData{ Type: "2", Id: orderCode, Lxdh: phone, Fhr: g.Cfg().MustGet(ctx, "company.hfr", "贺鹏飞").String(), InvoiceArr: []MakeInvoiceItems{{ Xmmc: g.Cfg().MustGet(ctx, "company.taxCode").String(), //开票项 WhStatus: 1, //开票项是否维护 Je: strconv.FormatFloat(prices, 'f', -1, 64), //金额 Sl: "1", //数量 }}, } if iType == "单位" { c.Gmfmc = gconv.String(m["company_name"]) c.Gmfnsrsbh = gconv.String(m["taxpayer_identnum"]) } else { c.Gmfmc = iType } err = im.Auth.MakeSingleInvoice(c) if err != nil { im.ReleasePool() if gerror.Is(err, consts.LoginOutErr) { g.Log().Infof(ctx, "RunJob-simpleMakeInvoice-身份过期,需要重新登录") return } g.Log().Errorf(ctx, "RunJob-simpleMakeInvoice-开票接口调用异常 %v", err) continue } okNum++ } return }