report.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. package api
  2. import (
  3. "box-cost/db/model"
  4. "box-cost/db/repo"
  5. "errors"
  6. "fmt"
  7. "strings"
  8. "time"
  9. "github.com/gin-gonic/gin"
  10. "github.com/go-redis/redis/v8"
  11. "github.com/xuri/excelize/v2"
  12. "go.mongodb.org/mongo-driver/bson/primitive"
  13. )
  14. // 统计报表 按时间范围,供应商 包装-计划(多选) 维度进行过滤,形成报表。可以下载
  15. func Report(r *GinRouter) {
  16. // 加工列表
  17. r.GET("/report/produce/list", ReportProduceList)
  18. // 采购列表
  19. r.GET("/report/purchase/list", ReportPurchaseList)
  20. r.GET("/report/product/list", ReportProductList)
  21. r.GET("/report/produce/download", ReportProduceDownload)
  22. r.GET("/report/purchase/download", ReportPurchaseDownload)
  23. r.GET("/report/product/download", ReportProductDownload)
  24. r.GETJWT("/report/list", ReportList)
  25. }
  26. // 加工单
  27. func ReportList(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  28. page, size, query := UtilQueryPageSize(c)
  29. start, stop := CreatePageRange(page, size)
  30. fmt.Println(start, stop)
  31. filtter := handleReportQuery(query)
  32. purchases := []*model.PurchaseBill{}
  33. produces := []*model.ProduceBill{}
  34. products := []*model.ProductBill{}
  35. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  36. CollectName: repo.CollectionBillPurchase,
  37. Query: filtter,
  38. Project: []string{"_id", "completeTime"},
  39. }, &purchases)
  40. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  41. CollectName: repo.CollectionBillProduce,
  42. Query: filtter,
  43. Project: []string{"_id", "completeTime"},
  44. }, &produces)
  45. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  46. CollectName: repo.CollectionBillProduct,
  47. Query: filtter,
  48. Project: []string{"_id", "completeTime"},
  49. }, &products)
  50. // 加入redis有序集合中
  51. redisCli := apictx.Svc.Redis
  52. reportBillKey := "report-bill-list:" + apictx.User.Parent
  53. isExist := redisCli.Exists(apictx.CreateRepoCtx().Ctx, reportBillKey).Val()
  54. // 不存在这个key时
  55. if isExist < 1 {
  56. if len(purchases) > 0 {
  57. for _, purchase := range purchases {
  58. member := "purchase_" + purchase.Id.Hex()
  59. score := purchase.CompleteTime.Unix()
  60. redisCli.ZAdd(apictx.CreateRepoCtx().Ctx, reportBillKey, &redis.Z{Score: float64(score), Member: member})
  61. }
  62. }
  63. if len(produces) > 0 {
  64. for _, produce := range produces {
  65. member := "produce_" + produce.Id.Hex()
  66. score := produce.CompleteTime.Unix()
  67. redisCli.ZAdd(apictx.CreateRepoCtx().Ctx, reportBillKey, &redis.Z{Score: float64(score), Member: member})
  68. }
  69. }
  70. if len(products) > 0 {
  71. for _, product := range products {
  72. member := "product_" + product.Id.Hex()
  73. score := product.CompleteTime.Unix()
  74. redisCli.ZAdd(apictx.CreateRepoCtx().Ctx, reportBillKey, &redis.Z{Score: float64(score), Member: member})
  75. }
  76. }
  77. // 设置过期时间
  78. redisCli.Expire(apictx.CreateRepoCtx().Ctx, reportBillKey, 20*time.Second)
  79. }
  80. total, err := redisCli.ZCard(apictx.CreateRepoCtx().Ctx, reportBillKey).Uint64()
  81. if err != nil {
  82. fmt.Println(err)
  83. return nil, err
  84. }
  85. reports, err := redisCli.ZRevRange(apictx.CreateRepoCtx().Ctx, reportBillKey, start, stop).Result()
  86. if err != nil {
  87. return nil, err
  88. }
  89. if len(reports) < 1 {
  90. return repo.PageResult{
  91. Page: page,
  92. Size: size,
  93. Total: 0,
  94. }, nil
  95. }
  96. lists := []map[string]interface{}{}
  97. for _, report := range reports {
  98. billArray := strings.Split(report, "_")
  99. billType := billArray[0]
  100. _billId := billArray[1]
  101. billId, _ := primitive.ObjectIDFromHex(_billId)
  102. billData := map[string]interface{}{}
  103. found := false
  104. if billType == "purchase" {
  105. found, billData = repo.RepoSeachDocMap(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  106. CollectName: repo.CollectionBillPurchase,
  107. Query: repo.Map{"_id": billId},
  108. })
  109. }
  110. if billType == "produce" {
  111. found, billData = repo.RepoSeachDocMap(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  112. CollectName: repo.CollectionBillProduce,
  113. Query: repo.Map{"_id": billId},
  114. })
  115. }
  116. if billType == "product" {
  117. found, billData = repo.RepoSeachDocMap(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  118. CollectName: repo.CollectionBillProduct,
  119. Query: repo.Map{"_id": billId},
  120. })
  121. }
  122. if found {
  123. billData["billType"] = billType
  124. lists = append(lists, billData)
  125. }
  126. }
  127. return repo.PageResult{
  128. List: lists,
  129. Total: int64(total),
  130. Page: page,
  131. Size: size,
  132. }, nil
  133. }
  134. func CreatePageRange(page, size int64) (int64, int64) {
  135. if page < 1 {
  136. page = 1
  137. }
  138. if size < 1 {
  139. size = 10
  140. }
  141. // var start int64 = 0
  142. // var stop int64 = 9
  143. // if size < 1 {
  144. // return start, stop
  145. // }
  146. // if page > 0 {
  147. start := (page - 1) * size
  148. stop := page*size - 1
  149. // }
  150. return start, stop
  151. }
  152. func ReportProduceList(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  153. page, size, query := UtilQueryPageSize(c)
  154. // 条件处理
  155. // 获取采购单符合条件的信息
  156. return repo.RepoPageSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  157. CollectName: repo.CollectionBillProduce,
  158. Query: handleReportQuery(query),
  159. Page: page,
  160. Size: size,
  161. })
  162. }
  163. // 采购单
  164. func ReportPurchaseList(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  165. page, size, query := UtilQueryPageSize(c)
  166. return repo.RepoPageSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  167. CollectName: repo.CollectionBillPurchase,
  168. Query: handleReportQuery(query),
  169. Page: page,
  170. Size: size,
  171. })
  172. }
  173. func ReportProductList(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  174. page, size, query := UtilQueryPageSize(c)
  175. return repo.RepoPageSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  176. CollectName: repo.CollectionBillProduct,
  177. Query: handleReportQuery(query),
  178. Page: page,
  179. Size: size,
  180. })
  181. }
  182. func ReportProduceDownload(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  183. _, _, query := UtilQueryPageSize(c)
  184. // 获取采符合条件的信息
  185. produces := []*model.ProduceBill{}
  186. err := repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  187. CollectName: repo.CollectionBillProduce,
  188. Query: handleReportQuery(query),
  189. }, &produces)
  190. if err != nil || len(produces) < 1 {
  191. return nil, errors.New("数据不存在")
  192. }
  193. f := excelize.NewFile()
  194. index := f.NewSheet("Sheet1")
  195. sheetName := f.GetSheetName(index)
  196. f.SetActiveSheet(index)
  197. f.SetDefaultFont("宋体")
  198. border := []excelize.Border{
  199. {Type: "top", Style: 1, Color: "000000"},
  200. {Type: "left", Style: 1, Color: "000000"},
  201. {Type: "right", Style: 1, Color: "000000"},
  202. {Type: "bottom", Style: 1, Color: "000000"},
  203. }
  204. alignCenterStyle, _ := f.NewStyle(&excelize.Style{
  205. Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
  206. Border: border,
  207. })
  208. companyName := getCompanyName(apictx)
  209. var budgetAmount float64 = 0
  210. var realAmount float64 = 0
  211. var row int = 0
  212. for _, produce := range produces {
  213. produceExcel := NewReportProduceExcel(f)
  214. produceExcel.Row = row
  215. produceExcel.Content = produce
  216. produceExcel.Title = fmt.Sprintf("%s加工单", companyName)
  217. //设置对应的数据
  218. produceExcel.Draws()
  219. budgetAmount += produceExcel.BudgetAmount
  220. realAmount += produceExcel.RealAmount
  221. row = produceExcel.Row + 3
  222. }
  223. row = row - 2
  224. startCell := fmt.Sprintf("%s%d", "A", row)
  225. endCell := fmt.Sprintf("%s%d", "H", row)
  226. f.MergeCell(sheetName, startCell, endCell)
  227. f.SetCellStyle(sheetName, startCell, endCell, alignCenterStyle)
  228. f.SetCellValue(sheetName, startCell, "汇总金额")
  229. // 预算金额汇总
  230. budgetAmountCell := fmt.Sprintf("%s%d", "I", row)
  231. budgetAmountStr := ""
  232. if budgetAmount > 0 {
  233. budgetAmountStr = fmt.Sprintf("%.3f", budgetAmount)
  234. }
  235. f.SetCellValue(sheetName, budgetAmountCell, budgetAmountStr)
  236. f.SetCellStyle(sheetName, budgetAmountCell, budgetAmountCell, alignCenterStyle)
  237. // 实际金额汇总
  238. realAmountCell := fmt.Sprintf("%s%d", "J", row)
  239. realAmountStr := ""
  240. if realAmount > 0 {
  241. realAmountStr = fmt.Sprintf("%.3f", realAmount)
  242. }
  243. f.SetCellValue(sheetName, realAmountCell, realAmountStr)
  244. f.SetCellStyle(sheetName, realAmountCell, realAmountCell, alignCenterStyle)
  245. f.SetRowHeight(sheetName, row, 21)
  246. c.Header("Content-Type", "application/octet-stream")
  247. c.Header("Content-Disposition", "attachment; filename="+"reportProduce.xlsx")
  248. c.Header("Content-Transfer-Encoding", "binary")
  249. err = f.Write(c.Writer)
  250. if err != nil {
  251. return nil, err
  252. }
  253. return nil, nil
  254. }
  255. func ReportPurchaseDownload(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  256. _, _, query := UtilQueryPageSize(c)
  257. purchases := []model.PurchaseBill{}
  258. err := repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  259. CollectName: repo.CollectionBillPurchase,
  260. Query: handleReportQuery(query),
  261. }, &purchases)
  262. if err != nil || len(purchases) < 1 {
  263. return nil, errors.New("数据不存在")
  264. }
  265. f := excelize.NewFile()
  266. index := f.NewSheet("Sheet1")
  267. sheetName := f.GetSheetName(index)
  268. f.SetActiveSheet(index)
  269. f.SetDefaultFont("宋体")
  270. border := []excelize.Border{
  271. {Type: "top", Style: 1, Color: "000000"},
  272. {Type: "left", Style: 1, Color: "000000"},
  273. {Type: "right", Style: 1, Color: "000000"},
  274. {Type: "bottom", Style: 1, Color: "000000"},
  275. }
  276. alignCenterStyle, _ := f.NewStyle(&excelize.Style{
  277. Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
  278. Border: border,
  279. })
  280. companyName := getCompanyName(apictx)
  281. var budgetCount float64 = 0
  282. var realCount float64 = 0
  283. var row int = 0
  284. for _, purchase := range purchases {
  285. var reportBill *ReportPurchaseExcel
  286. if len(purchase.Paper) > 0 {
  287. reportBill = NewReportPurchaseExcel(f)
  288. }
  289. if reportBill == nil {
  290. return nil, errors.New("数据不存在")
  291. }
  292. reportBill.Row = row
  293. reportBill.Content = &purchase
  294. reportBill.Title = fmt.Sprintf("%s原材料采购单", companyName)
  295. reportBill.Draws()
  296. budgetCount += reportBill.BudgetAmount
  297. realCount += reportBill.RealAmount
  298. row = reportBill.Row + 3
  299. }
  300. row = row - 2
  301. startCell := fmt.Sprintf("%s%d", "A", row)
  302. endCell := fmt.Sprintf("%s%d", "H", row)
  303. f.MergeCell(sheetName, startCell, endCell)
  304. f.SetCellStyle(sheetName, startCell, endCell, alignCenterStyle)
  305. f.SetCellValue(sheetName, startCell, "汇总金额")
  306. // 预算金额汇总
  307. budgetCountCell := fmt.Sprintf("%s%d", "I", row)
  308. budgetCountStr := ""
  309. if realCount > 0 {
  310. budgetCountStr = fmt.Sprintf("%.3f", budgetCount)
  311. }
  312. f.SetCellValue(sheetName, budgetCountCell, budgetCountStr)
  313. f.SetCellStyle(sheetName, budgetCountCell, budgetCountCell, alignCenterStyle)
  314. // 实际金额汇总
  315. RealCountCell := fmt.Sprintf("%s%d", "J", row)
  316. realCountStr := ""
  317. if realCount > 0 {
  318. realCountStr = fmt.Sprintf("%.3f", realCount)
  319. }
  320. f.SetCellValue(sheetName, RealCountCell, realCountStr)
  321. f.SetCellStyle(sheetName, RealCountCell, RealCountCell, alignCenterStyle)
  322. f.SetRowHeight(sheetName, row, 21)
  323. c.Header("Content-Type", "application/octet-stream")
  324. c.Header("Content-Disposition", "attachment; filename="+"reportPurchase.xlsx")
  325. c.Header("Content-Transfer-Encoding", "binary")
  326. err = f.Write(c.Writer)
  327. if err != nil {
  328. return nil, err
  329. }
  330. return nil, nil
  331. }
  332. func ReportProductDownload(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  333. _, _, query := UtilQueryPageSize(c)
  334. // 获取采符合条件的信息
  335. products := []*model.ProductBill{}
  336. err := repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  337. CollectName: repo.CollectionBillProduct,
  338. Query: handleReportQuery(query),
  339. }, &products)
  340. if err != nil || len(products) < 1 {
  341. return nil, errors.New("数据不存在")
  342. }
  343. f := excelize.NewFile()
  344. index := f.NewSheet("Sheet1")
  345. sheetName := f.GetSheetName(index)
  346. f.SetActiveSheet(index)
  347. f.SetDefaultFont("宋体")
  348. border := []excelize.Border{
  349. {Type: "top", Style: 1, Color: "000000"},
  350. {Type: "left", Style: 1, Color: "000000"},
  351. {Type: "right", Style: 1, Color: "000000"},
  352. {Type: "bottom", Style: 1, Color: "000000"},
  353. }
  354. alignCenterStyle, _ := f.NewStyle(&excelize.Style{
  355. Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
  356. Border: border,
  357. })
  358. companyName := getCompanyName(apictx)
  359. var budgetAmount float64 = 0
  360. var realAmount float64 = 0
  361. var row int = 0
  362. for _, product := range products {
  363. productExcel := NewReportProductBill(f)
  364. productExcel.Row = row
  365. productExcel.Content = product
  366. productExcel.Title = companyName
  367. productExcel.Draws()
  368. budgetAmount += productExcel.BudgetAmount
  369. realAmount += productExcel.RealAmount
  370. row = productExcel.Row + 3
  371. }
  372. row = row - 2
  373. startCell := fmt.Sprintf("%s%d", "A", row)
  374. endCell := fmt.Sprintf("%s%d", "H", row)
  375. f.MergeCell(sheetName, startCell, endCell)
  376. f.SetCellStyle(sheetName, startCell, endCell, alignCenterStyle)
  377. f.SetCellValue(sheetName, startCell, "汇总金额")
  378. // 预算金额汇总
  379. budgetAmountCell := fmt.Sprintf("%s%d", "I", row)
  380. budgetCountStr := ""
  381. if realAmount > 0 {
  382. budgetCountStr = fmt.Sprintf("%.3f", realAmount)
  383. }
  384. f.SetCellValue(sheetName, budgetAmountCell, budgetCountStr)
  385. f.SetCellStyle(sheetName, budgetAmountCell, budgetAmountCell, alignCenterStyle)
  386. // 实际金额汇总
  387. realAmountCell := fmt.Sprintf("%s%d", "J", row)
  388. realAmountStr := ""
  389. if realAmount > 0 {
  390. realAmountStr = fmt.Sprintf("%.3f", realAmount)
  391. }
  392. f.SetCellValue(sheetName, realAmountCell, realAmountStr)
  393. f.SetCellStyle(sheetName, realAmountCell, realAmountCell, alignCenterStyle)
  394. f.SetRowHeight(sheetName, row, 21)
  395. c.Header("Content-Type", "application/octet-stream")
  396. c.Header("Content-Disposition", "attachment; filename="+"reportProduce.xlsx")
  397. c.Header("Content-Transfer-Encoding", "binary")
  398. err = f.Write(c.Writer)
  399. if err != nil {
  400. return nil, err
  401. }
  402. return nil, nil
  403. }