invoiceManager.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package service
  2. import (
  3. "ElectronicInvoice/internal/consts"
  4. "context"
  5. "github.com/gogf/gf/v2/database/gdb"
  6. "github.com/gogf/gf/v2/errors/gerror"
  7. "github.com/gogf/gf/v2/frame/g"
  8. "github.com/gogf/gf/v2/util/gconv"
  9. "strconv"
  10. "time"
  11. )
  12. var (
  13. JyInvoiceManager *InvoiceManager
  14. )
  15. type InvoiceManager struct {
  16. Auth *TripartiteAuth
  17. Login bool //登录状态
  18. OCRPass bool //活体检测状态是否通过
  19. runPool chan bool //任务(每次只能进行一个开票任务)
  20. phoneCode chan string //短信验证码池
  21. ScanLogin chan bool //扫码登录
  22. }
  23. func init() {
  24. JyInvoiceManager = createInvoiceManager()
  25. //_, err := gcron.Add(context.Background(), "", JyInvoiceManager.RunJob, "invoiceJob")
  26. //if err != nil {
  27. // panic(err)
  28. //}
  29. //go JyInvoiceManager.RunOneJob(context.Background())
  30. //go JyInvoiceManager.Demo(context.Background()) //开票
  31. //go JyInvoiceManager.RedDemo(context.Background())//红冲
  32. }
  33. func createInvoiceManager() *InvoiceManager {
  34. return &InvoiceManager{
  35. Auth: createTripartite(),
  36. Login: true, //默认已经登录
  37. OCRPass: true,
  38. runPool: make(chan bool, 1), //开票只能单线程跑
  39. phoneCode: make(chan string, 1), //手机验证码
  40. ScanLogin: make(chan bool, 1), //扫码登录通知
  41. }
  42. }
  43. func (im *InvoiceManager) ReleasePool() {
  44. <-im.runPool
  45. }
  46. func (im *InvoiceManager) MobileVerificationCode(code string) error {
  47. if code == "" {
  48. return gerror.New("验证码为空")
  49. }
  50. select {
  51. case <-time.After(time.Minute):
  52. return gerror.New("验证码接收超时")
  53. case im.phoneCode <- code:
  54. return nil
  55. }
  56. }
  57. func (im *InvoiceManager) MobileVerificationClear() error {
  58. select {
  59. case <-time.After(time.Minute):
  60. return gerror.New("清除验证码超时")
  61. case <-im.phoneCode:
  62. return nil
  63. }
  64. }
  65. // RunJob 开票定时任务
  66. func (im *InvoiceManager) RunJob(ctx context.Context) {
  67. if g.Cfg().MustGet(ctx, "invoiceJob.stop", false).Bool() {
  68. g.Log().Infof(ctx, "RunJob-开票程序任务已暂停,开启请删除 config.json > invoiceJob.stop")
  69. return
  70. }
  71. if im.Login {
  72. if err := im.Auth.Login(); err != nil {
  73. g.Log().Errorf(ctx, "模拟登录异常 %v", err)
  74. return
  75. } else {
  76. g.Log().Infof(ctx, "登录成功")
  77. }
  78. }
  79. total, okNum, err := im.simpleMakeInvoice(ctx)
  80. if err != nil {
  81. g.Log().Errorf(ctx, "开蓝票任务异常 %v", err)
  82. } else {
  83. g.Log().Infof(ctx, "开蓝票任务完成 共%d个 完成%d个", total, okNum)
  84. }
  85. g.Log().Infof(ctx, "RunJob-开票任务完成")
  86. }
  87. // simpleMakeInvoice 简单开票
  88. func (im *InvoiceManager) simpleMakeInvoice(ctx context.Context) (total, okNum int, err error) {
  89. var (
  90. res gdb.Result
  91. )
  92. //查询需要开票的数据
  93. res, err = g.DB().Query(ctx, "SELECT * FROM invoice WHERE invoice_status=0 AND invoice_variety='普通发票(电子发票)' AND invoice_order_code is NULL ")
  94. if err != nil {
  95. g.Log().Errorf(ctx, "RunJob-simpleMakeInvoice-查询待开票异常 %s", err)
  96. return -1, -1, gerror.Wrap(err, "simpleMakeInvoice-查询待开票异常")
  97. }
  98. g.Log().Infof(ctx, "RunJob-simpleMakeInvoice-本次共加载%d条开票记录", res.Len())
  99. total, okNum = res.Len(), 0
  100. for _, m := range res.List() {
  101. select {
  102. case im.runPool <- true:
  103. case <-time.After(time.Minute * 5):
  104. g.Log().Errorf(ctx, "RunJob-simpleMakeInvoice-开票等待异常,结束此次任务")
  105. return
  106. }
  107. var (
  108. orderCode = gconv.String(m["order_code"])
  109. phone = gconv.String(m["phone_num"])
  110. iType = gconv.String(m["invoice_type"])
  111. prices float64
  112. )
  113. //公对公转账 账单金额可以修改 开发票应取实付金额 pay_money
  114. //微信支付宝支付 pay_money为订单金额减去微信or支付包红包
  115. if gconv.String(m["pay_way"]) == "transferAccounts" {
  116. prices = gconv.Float64(m["pay_money"]) / float64(100)
  117. } else {
  118. prices = gconv.Float64(m["order_money"]) / float64(100)
  119. }
  120. c := MakeInvoiceData{
  121. Type: "2",
  122. Id: orderCode,
  123. Lxdh: phone,
  124. Fhr: g.Cfg().MustGet(ctx, "company.hfr", "贺鹏飞").String(),
  125. InvoiceArr: []MakeInvoiceItems{{
  126. Xmmc: g.Cfg().MustGet(ctx, "company.taxCode").String(), //开票项
  127. WhStatus: 1, //开票项是否维护
  128. Je: strconv.FormatFloat(prices, 'f', -1, 64), //金额
  129. Sl: "1", //数量
  130. }},
  131. }
  132. if iType == "单位" {
  133. c.Gmfmc = gconv.String(m["company_name"])
  134. c.Gmfnsrsbh = gconv.String(m["taxpayer_identnum"])
  135. } else {
  136. c.Gmfmc = iType
  137. }
  138. err = im.Auth.MakeSingleInvoice(c)
  139. if err != nil {
  140. im.ReleasePool()
  141. if gerror.Is(err, consts.LoginOutErr) {
  142. g.Log().Infof(ctx, "RunJob-simpleMakeInvoice-身份过期,需要重新登录")
  143. return
  144. }
  145. g.Log().Errorf(ctx, "RunJob-simpleMakeInvoice-开票接口调用异常 %v", err)
  146. continue
  147. }
  148. okNum++
  149. }
  150. return
  151. }