invoiceManager.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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/os/gcron"
  9. "github.com/gogf/gf/v2/util/gconv"
  10. "strconv"
  11. "time"
  12. )
  13. var (
  14. JyInvoiceManager *InvoiceManager
  15. )
  16. type InvoiceManager struct {
  17. Auth *TripartiteAuth
  18. jobRunning bool //开票是否运行中
  19. StopRunning bool //财务占用账号,需要暂停任务
  20. Login bool //登录状态
  21. runPool chan bool //任务(每次只能进行一个开票任务)
  22. phoneCode chan string //短信验证码池
  23. ScanLogin chan bool //扫码登录
  24. }
  25. func init() {
  26. JyInvoiceManager = createInvoiceManager()
  27. job, err := gcron.Add(context.Background(), g.Cfg().MustGet(context.Background(), "invoiceJob.cron").String(), JyInvoiceManager.RunJob, "invoiceJob")
  28. if err != nil {
  29. panic(err)
  30. }
  31. job.Start()
  32. //go JyInvoiceManager.RunOneJob(context.Background())//流程
  33. //go JyInvoiceManager.Demo(context.Background()) //开票
  34. //go JyInvoiceManager.RedDemo(context.Background())//红冲
  35. }
  36. func createInvoiceManager() *InvoiceManager {
  37. return &InvoiceManager{
  38. Auth: createTripartite(),
  39. Login: true, //默认已经登录
  40. runPool: make(chan bool, 1), //开票只能单线程跑
  41. phoneCode: make(chan string, 1), //手机验证码
  42. ScanLogin: make(chan bool, 1), //扫码登录通知
  43. }
  44. }
  45. func (im *InvoiceManager) ReleasePool() {
  46. <-im.runPool
  47. }
  48. func (im *InvoiceManager) MobileVerificationCode(code string) error {
  49. if code == "" {
  50. return gerror.New("验证码为空")
  51. }
  52. select {
  53. case <-time.After(time.Minute):
  54. return gerror.New("验证码接收超时")
  55. case im.phoneCode <- code:
  56. return nil
  57. }
  58. }
  59. func (im *InvoiceManager) MobileVerificationClear() error {
  60. select {
  61. case <-time.After(time.Minute):
  62. return gerror.New("清除验证码超时")
  63. case <-im.phoneCode:
  64. return nil
  65. }
  66. }
  67. // RunJob 开票定时任务
  68. func (im *InvoiceManager) RunJob(ctx context.Context) {
  69. if im.jobRunning || im.StopRunning {
  70. g.Log().Infof(ctx, "RunJob-程序本次任务中断 jobRunning:%v StopRunning:%v", im.jobRunning, im.StopRunning)
  71. return
  72. }
  73. im.jobRunning = true
  74. defer func() {
  75. im.jobRunning = false
  76. g.Log().Infof(ctx, "RunJob-开票任务完成")
  77. }()
  78. if g.Cfg().MustGet(ctx, "invoiceJob.stop", false).Bool() {
  79. g.Log().Infof(ctx, "RunJob-开票程序任务已暂停,开启请删除 config.json > invoiceJob.stop")
  80. return
  81. }
  82. if !im.Login {
  83. if err := im.Auth.Login(); err != nil {
  84. g.Log().Errorf(ctx, "模拟登录异常 %v", err)
  85. return
  86. } else {
  87. g.Log().Infof(ctx, "登录成功")
  88. }
  89. }
  90. //TODO 普通蓝票任务
  91. total, okNum, err := im.simpleMakeInvoice(ctx)
  92. if err != nil {
  93. if gerror.Is(err, consts.LoginOutErr) {
  94. g.Log().Infof(ctx, "RunJob-任务中止-身份过期,需要重新登录")
  95. return
  96. }
  97. g.Log().Errorf(ctx, "RunJob-开蓝票任务异常 %v", err)
  98. } else {
  99. g.Log().Infof(ctx, "RunJob-开蓝票任务完成 共%d个 完成%d个", total, okNum)
  100. }
  101. // TODO 蓝票自助开票(管理后台扫码开票)
  102. total, okNum, err = im.selfMakeInvoice(ctx)
  103. if err != nil {
  104. if gerror.Is(err, consts.LoginOutErr) {
  105. g.Log().Infof(ctx, "RunJob-任务中止-身份过期,需要重新登录")
  106. return
  107. }
  108. g.Log().Errorf(ctx, "RunJob-开自助蓝票任务异常 %v", err)
  109. } else {
  110. g.Log().Infof(ctx, "RunJob-开自助蓝票任务完成 共%d个 完成%d个", total, okNum)
  111. }
  112. //TODO 红票任务
  113. }
  114. // simpleMakeInvoice 简单开票
  115. func (im *InvoiceManager) simpleMakeInvoice(ctx context.Context) (total, okNum int, err error) {
  116. var (
  117. res gdb.Result
  118. )
  119. //查询需要开票的数据
  120. 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")
  121. if err != nil {
  122. return -1, -1, gerror.Wrap(err, "simpleMakeInvoice-查询待开票异常")
  123. }
  124. g.Log().Infof(ctx, "simpleMakeInvoice-本次共加载%d条开票记录", res.Len())
  125. total, okNum = res.Len(), 0
  126. for _, m := range res.List() {
  127. select {
  128. case im.runPool <- true:
  129. case <-time.After(time.Minute * 5):
  130. err = gerror.New("simpleMakeInvoice-开票等待超时")
  131. return
  132. }
  133. var (
  134. orderCode = gconv.String(m["order_code"])
  135. iType = gconv.String(m["invoice_type"])
  136. remark = gconv.String(m["remark"])
  137. prices float64
  138. )
  139. //公对公转账 账单金额可以修改 开发票应取实付金额 pay_money
  140. //微信支付宝支付 pay_money为订单金额减去微信or支付包红包
  141. if gconv.String(m["pay_way"]) == "transferAccounts" {
  142. prices = gconv.Float64(m["pay_money"]) / float64(100)
  143. } else {
  144. prices = gconv.Float64(m["order_money"]) / float64(100)
  145. }
  146. c := MakeInvoiceData{
  147. Type: "2",
  148. Id: orderCode,
  149. Notes: remark,
  150. Fhr: g.Cfg().MustGet(ctx, "company.hfr", "贺鹏飞").String(),
  151. InvoiceArr: []MakeInvoiceItems{{
  152. Xmmc: g.Cfg().MustGet(ctx, "company.taxCode").String(), //开票项
  153. WhStatus: 1, //开票项是否维护
  154. Je: strconv.FormatFloat(prices, 'f', -1, 64), //金额
  155. Sl: "1", //数量
  156. }},
  157. }
  158. if iType == "单位" {
  159. c.Gmfmc = gconv.String(m["company_name"])
  160. c.Gmfnsrsbh = gconv.String(m["taxpayer_identnum"])
  161. } else {
  162. c.Gmfmc = iType
  163. }
  164. err = im.Auth.MakeSingleInvoice(c)
  165. if err != nil {
  166. im.ReleasePool()
  167. if gerror.Is(err, consts.LoginOutErr) {
  168. g.Log().Infof(ctx, "simpleMakeInvoice-身份过期,需要重新登录")
  169. return
  170. }
  171. g.Log().Errorf(ctx, "simpleMakeInvoice-开票接口调用异常 %v", err)
  172. continue
  173. }
  174. okNum++
  175. }
  176. return
  177. }
  178. // selfMakeInvoice 自助开票
  179. func (im *InvoiceManager) selfMakeInvoice(ctx context.Context) (total, okNum int, err error) {
  180. var (
  181. res gdb.Result
  182. )
  183. res, err = g.DB().Query(ctx, "SELECT a.invoice_money,a.only_Identifying,a.invoice_type,a.company_name,a.taxpayer_identnum,a.remark FROM invoice a WHERE a.invoice_status=0 AND a.invoice_changed=0 AND a.invoice_variety='电子普通发票' AND a.invoice_order_code is not NULL GROUP BY invoice_order_code")
  184. if err != nil {
  185. return -1, -1, gerror.Wrap(err, "selfMakeInvoice-查询待开票异常")
  186. }
  187. total, okNum = res.Len(), 0
  188. for _, m := range res.List() {
  189. select {
  190. case im.runPool <- true:
  191. case <-time.After(time.Minute * 5):
  192. err = gerror.New("selfMakeInvoice-开票等待超时")
  193. return
  194. }
  195. var (
  196. orderCode = gconv.String(m["only_Identifying"])
  197. iType = gconv.String(m["invoice_type"])
  198. prices = gconv.String(m["invoice_money"])
  199. remark = gconv.String(m["remark"])
  200. )
  201. c := MakeInvoiceData{
  202. Type: "2",
  203. Id: orderCode,
  204. Notes: remark,
  205. Fhr: g.Cfg().MustGet(ctx, "company.hfr", "贺鹏飞").String(),
  206. InvoiceArr: []MakeInvoiceItems{{
  207. Xmmc: g.Cfg().MustGet(ctx, "company.taxCode").String(), //开票项
  208. WhStatus: 1, //开票项是否维护
  209. Je: prices, //金额
  210. Sl: "1", //数量
  211. }},
  212. }
  213. if iType == "单位" {
  214. c.Gmfmc = gconv.String(m["company_name"])
  215. c.Gmfnsrsbh = gconv.String(m["taxpayer_identnum"])
  216. } else {
  217. c.Gmfmc = iType
  218. }
  219. err = im.Auth.MakeSingleInvoice(c)
  220. if err != nil {
  221. im.ReleasePool()
  222. if gerror.Is(err, consts.LoginOutErr) {
  223. g.Log().Infof(ctx, "selfMakeInvoice-身份过期,需要重新登录")
  224. return
  225. }
  226. g.Log().Errorf(ctx, "selfMakeInvoice-开票接口调用异常 %v", err)
  227. continue
  228. }
  229. okNum++
  230. }
  231. return
  232. }