report.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. package api
  2. import (
  3. "box-cost/db/model"
  4. "box-cost/db/repo"
  5. "errors"
  6. "fmt"
  7. "github.com/gin-gonic/gin"
  8. "github.com/xuri/excelize/v2"
  9. "go.mongodb.org/mongo-driver/bson"
  10. "go.mongodb.org/mongo-driver/bson/primitive"
  11. )
  12. // 统计报表
  13. func Report(r *GinRouter) {
  14. // 加工列表
  15. r.POST("/report/produce/list", ReportProduceList)
  16. // 采购列表
  17. r.POST("/report/purchase/list", ReportPurchaseList)
  18. r.POST("/report/produce/download", ReportProduceDownload)
  19. r.POST("/report/purchase/download", ReportPurchaseDownload)
  20. }
  21. type ReportListReq struct {
  22. SupplierId primitive.ObjectID
  23. TimeRange []string
  24. PackIds []primitive.ObjectID
  25. PlanIds []primitive.ObjectID
  26. Page int64
  27. Size int64
  28. }
  29. // 加工单
  30. func ReportProduceList(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  31. // 财务管理】 添加统计报表功能。按 时间范围, 供应商(单选) 包装(多选) 计划(多选) 四个维度进行过滤,形成报表。可以下载
  32. var form ReportListReq
  33. err := c.ShouldBindJSON(&form)
  34. if err != nil {
  35. return nil, errors.New("参数错误")
  36. }
  37. var page int64 = 1
  38. var size int64 = 10
  39. if form.Page > 0 {
  40. page = form.Page
  41. }
  42. if form.Size > 0 {
  43. size = form.Size
  44. }
  45. // 条件处理
  46. query := make(map[string]interface{}, 0)
  47. query["status"] = "complete"
  48. if !form.SupplierId.IsZero() {
  49. query["supplierId"] = form.SupplierId
  50. }
  51. // 时间范围
  52. if len(form.TimeRange) == 2 {
  53. start, end := getTimeRange(form.TimeRange[0], form.TimeRange[1])
  54. query["updateTime"] = bson.M{"$gte": start, "$lte": end}
  55. }
  56. // 包装
  57. if len(form.PackIds) > 0 {
  58. packQuery := []bson.M{}
  59. for _, packId := range form.PackIds {
  60. packQuery = append(packQuery, bson.M{"packId": packId})
  61. }
  62. query["$or"] = packQuery
  63. }
  64. // 计划
  65. if len(form.PlanIds) > 0 {
  66. planQuery := bson.A{}
  67. for _, planId := range form.PlanIds {
  68. planQuery = append(planQuery, bson.M{"planId": planId})
  69. }
  70. query["$or"] = planQuery
  71. }
  72. // 获取采购单符合条件的信息
  73. return repo.RepoPageSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  74. CollectName: repo.CollectionBillPurchase,
  75. Query: query,
  76. Page: page,
  77. Size: size,
  78. })
  79. }
  80. // 采购单
  81. func ReportPurchaseList(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  82. // 财务管理】 添加统计报表功能。按 时间范围, 供应商(单选) 包装(多选) 计划(多选) 四个维度进行过滤,形成报表。可以下载
  83. var form ReportListReq
  84. err := c.ShouldBindJSON(&form)
  85. if err != nil {
  86. return nil, errors.New("参数错误")
  87. }
  88. var page int64 = 1
  89. var size int64 = 10
  90. if form.Page > 0 {
  91. page = form.Page
  92. }
  93. if form.Size > 0 {
  94. size = form.Size
  95. }
  96. // 条件处理
  97. query := make(map[string]interface{}, 0)
  98. query["status"] = "complete"
  99. if !form.SupplierId.IsZero() {
  100. query["supplierId"] = form.SupplierId
  101. }
  102. // 时间范围
  103. if len(form.TimeRange) == 2 {
  104. start, end := getTimeRange(form.TimeRange[0], form.TimeRange[1])
  105. query["updateTime"] = bson.M{"$gte": start, "$lte": end}
  106. }
  107. // 包装
  108. if len(form.PackIds) > 0 {
  109. packQuery := []bson.M{}
  110. for _, packId := range form.PackIds {
  111. packQuery = append(packQuery, bson.M{"packId": packId})
  112. }
  113. query["$or"] = packQuery
  114. }
  115. // 计划
  116. if len(form.PlanIds) > 0 {
  117. planQuery := bson.A{}
  118. for _, planId := range form.PlanIds {
  119. planQuery = append(planQuery, bson.M{"planId": planId})
  120. }
  121. query["$or"] = planQuery
  122. }
  123. // 获取采购单符合条件的信息
  124. return repo.RepoPageSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  125. CollectName: repo.CollectionBillPurchase,
  126. Query: query,
  127. Page: page,
  128. Size: size,
  129. })
  130. }
  131. // func ReportProduceList(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  132. // // 财务管理】 添加统计报表功能。按 时间范围, 供应商(单选) 包装(多选) 计划(多选) 四个维度进行过滤,形成报表。可以下载
  133. // var form ReportListReq
  134. // err := c.ShouldBindJSON(&form)
  135. // if err != nil {
  136. // return nil, errors.New("参数错误")
  137. // }
  138. // var page int64 = 1
  139. // var size int64 = 10
  140. // if form.Page > 0 {
  141. // page = form.Page
  142. // } else {
  143. // page = 1
  144. // }
  145. // if form.Size > 0 {
  146. // size = form.Size
  147. // } else {
  148. // size = 10
  149. // }
  150. // start := (page - 1) * size
  151. // end := page*size - 1
  152. // // 条件处理
  153. // query := make(map[string]interface{}, 0)
  154. // query["status"] = "complete"
  155. // if !form.SupplierId.IsZero() {
  156. // query["supplierId"] = form.SupplierId
  157. // }
  158. // // 时间范围
  159. // if len(form.TimeRange) == 2 {
  160. // start, end := getTimeRange(form.TimeRange[0], form.TimeRange[1])
  161. // query["createTime"] = bson.M{"$gte": start, "$lte": end}
  162. // }
  163. // // 包装
  164. // if len(form.PackIds) > 0 {
  165. // packQuery := []bson.M{}
  166. // for _, packId := range form.PackIds {
  167. // packQuery = append(packQuery, bson.M{"packId": packId})
  168. // }
  169. // query["$or"] = packQuery
  170. // }
  171. // // 计划
  172. // if len(form.PlanIds) > 0 {
  173. // planQuery := bson.A{}
  174. // for _, planId := range form.PlanIds {
  175. // planQuery = append(planQuery, bson.M{"planId": planId})
  176. // }
  177. // query["$or"] = planQuery
  178. // }
  179. // // 获取采购单符合条件的信息
  180. // purchases := []model.PurchaseBill{}
  181. // repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  182. // CollectName: repo.CollectionBillPurchase,
  183. // Query: query,
  184. // }, &purchases)
  185. // // 获取加工单符合条件的信息
  186. // produces := []model.ProduceBill{}
  187. // repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  188. // CollectName: repo.CollectionBillProduce,
  189. // Query: query,
  190. // }, &produces)
  191. // // 组装数据
  192. // cacheKey := "report:list"
  193. // apictx.Svc.Redis.Del(apictx.CreateRepoCtx().Ctx, cacheKey)
  194. // // key存在时
  195. // // if apictx.Svc.Redis.Exists(apictx.CreateRepoCtx().Ctx, cacheKey).Val() == 1 {
  196. // // ret := apictx.Svc.Redis.ZRange(apictx.CreateRepoCtx().Ctx, cacheKey, start, end)
  197. // // retList = ret.Val()
  198. // // } else {
  199. // // }
  200. // mlen := len(purchases) + len(produces)
  201. // type MapList map[string]interface{}
  202. // lists := make([]MapList, mlen)
  203. // if len(purchases) > 0 {
  204. // for _, purchase := range purchases {
  205. // apictx.Svc.Redis.ZAdd(apictx.CreateRepoCtx().Ctx, cacheKey, &redis.Z{
  206. // Score: float64(purchase.CreateTime.Unix()),
  207. // Member: purchase.Id.Hex(),
  208. // })
  209. // list := MapList{purchase.Id.Hex(): purchase, "type": "purchase"}
  210. // lists = append(lists, list)
  211. // }
  212. // }
  213. // if len(produces) > 0 {
  214. // for _, produce := range produces {
  215. // apictx.Svc.Redis.ZAdd(apictx.CreateRepoCtx().Ctx, cacheKey, &redis.Z{
  216. // Score: float64(produce.CreateTime.Unix()),
  217. // Member: produce.Id.Hex(),
  218. // })
  219. // list := MapList{produce.Id.Hex(): produce, "type": "produce"}
  220. // lists = append(lists, list)
  221. // }
  222. // }
  223. // // 当前key存在时
  224. // retList := make([]map[string]interface{}, 0)
  225. // // 所有id
  226. // ids := make([]map[string]string, 0)
  227. // if apictx.Svc.Redis.Exists(apictx.CreateRepoCtx().Ctx, cacheKey).Val() == 1 {
  228. // // ret := apictx.Svc.Redis.ExpireLT(apictx.CreateRepoCtx().Ctx, cacheKey, 20*time.Second)
  229. // // 按创建时间升序排
  230. // result := apictx.Svc.Redis.ZRange(apictx.CreateRepoCtx().Ctx, cacheKey, start, end)
  231. // if result.Err() != nil {
  232. // log.Error(err)
  233. // return nil, errors.New("缓存数据内部错误")
  234. // }
  235. // retids := apictx.Svc.Redis.ZRange(apictx.CreateRepoCtx().Ctx, cacheKey, 0, -1)
  236. // // 所有id
  237. // if len(retids.Val()) > 0 {
  238. // for _, id := range retids.Val() {
  239. // for _, item := range lists {
  240. // if _, ok := item[id]; ok {
  241. // ids = append(ids, map[string]string{"id": id, "type": item["type"].(string)})
  242. // }
  243. // }
  244. // }
  245. // }
  246. // // 返回的列表
  247. // if len(result.Val()) > 0 {
  248. // for _, id := range result.Val() {
  249. // for _, item := range lists {
  250. // if _, ok := item[id]; ok {
  251. // retList = append(retList, item)
  252. // }
  253. // }
  254. // }
  255. // }
  256. // }
  257. // type PageResult struct {
  258. // List []map[string]interface{} `json:"list"`
  259. // Total int64 `json:"total"`
  260. // Page int64 `json:"page"`
  261. // Size int64 `json:"size"`
  262. // Ids []map[string]string `json:"ids"`
  263. // }
  264. // out := &PageResult{
  265. // List: retList,
  266. // Total: int64(mlen),
  267. // Page: page,
  268. // Size: size,
  269. // Ids: ids,
  270. // }
  271. // return out, nil
  272. // }
  273. func ReportProduceDownload(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  274. var form ReportListReq
  275. err := c.ShouldBindJSON(&form)
  276. if err != nil {
  277. return nil, errors.New("参数错误")
  278. }
  279. // 条件处理
  280. query := make(map[string]interface{}, 0)
  281. query["status"] = "complete"
  282. if !form.SupplierId.IsZero() {
  283. query["supplierId"] = form.SupplierId
  284. }
  285. // 时间范围
  286. if len(form.TimeRange) == 2 {
  287. start, end := getTimeRange(form.TimeRange[0], form.TimeRange[1])
  288. query["updateTime"] = bson.M{"$gte": start, "$lte": end}
  289. }
  290. // 包装
  291. if len(form.PackIds) > 0 {
  292. packQuery := []bson.M{}
  293. for _, packId := range form.PackIds {
  294. packQuery = append(packQuery, bson.M{"packId": packId})
  295. }
  296. query["$or"] = packQuery
  297. }
  298. // 计划
  299. if len(form.PlanIds) > 0 {
  300. planQuery := bson.A{}
  301. for _, planId := range form.PlanIds {
  302. planQuery = append(planQuery, bson.M{"planId": planId})
  303. }
  304. query["$or"] = planQuery
  305. }
  306. // 获取采符合条件的信息
  307. produces := []model.ProduceBill{}
  308. err = repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  309. CollectName: repo.CollectionBillProduce,
  310. Query: query,
  311. }, &produces)
  312. if err != nil || len(produces) < 1 {
  313. return nil, errors.New("数据不存在")
  314. }
  315. f := excelize.NewFile()
  316. index := f.NewSheet("Sheet1")
  317. sheetName := f.GetSheetName(index)
  318. f.SetActiveSheet(index)
  319. f.SetDefaultFont("宋体")
  320. border := []excelize.Border{
  321. {Type: "top", Style: 1, Color: "000000"},
  322. {Type: "left", Style: 1, Color: "000000"},
  323. {Type: "right", Style: 1, Color: "000000"},
  324. {Type: "bottom", Style: 1, Color: "000000"},
  325. }
  326. alignCenterStyle, _ := f.NewStyle(&excelize.Style{
  327. Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
  328. Border: border,
  329. })
  330. offset := 0
  331. info := model.Setting{}
  332. repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  333. CollectName: "infos",
  334. }, &info)
  335. var budgetCount float64 = 0
  336. var realCount float64 = 0
  337. for _, produce := range produces {
  338. produceExcel := NewReportProduceExcel(f)
  339. produceExcel.Content = &produce
  340. budgetCount += produceExcel.BudgetCount
  341. realCount += produceExcel.RealCount
  342. produceExcel.Title = fmt.Sprintf("%ss加工单", info.CompanyName)
  343. //设置对应的数据
  344. produceExcel.Offset = offset
  345. produceExcel.Draws()
  346. offset += 15
  347. }
  348. row := offset + 1
  349. startCell := fmt.Sprintf("%s%d", "A", row)
  350. endCell := fmt.Sprintf("%s%d", "H", row)
  351. f.MergeCell(sheetName, startCell, endCell)
  352. f.SetCellStyle(sheetName, startCell, endCell, alignCenterStyle)
  353. f.SetCellValue(sheetName, startCell, "汇总金额")
  354. // 预算金额汇总
  355. budgetCountCell := fmt.Sprintf("%s%d", "I", row)
  356. budgetCountStr := ""
  357. if realCount > 0 {
  358. budgetCountStr = fmt.Sprintf("%.2f", budgetCount)
  359. }
  360. f.SetCellValue(sheetName, budgetCountCell, budgetCountStr)
  361. f.SetCellStyle(sheetName, budgetCountCell, budgetCountCell, alignCenterStyle)
  362. // 实际金额汇总
  363. RealCountCell := fmt.Sprintf("%s%d", "J", row)
  364. realCountStr := ""
  365. if realCount > 0 {
  366. realCountStr = fmt.Sprintf("%.2f", realCount)
  367. }
  368. f.SetCellValue(sheetName, RealCountCell, realCountStr)
  369. f.SetCellStyle(sheetName, RealCountCell, RealCountCell, alignCenterStyle)
  370. f.SetRowHeight(sheetName, row, 21)
  371. c.Header("Content-Type", "application/octet-stream")
  372. c.Header("Content-Disposition", "attachment; filename="+"reportProduce.xlsx")
  373. c.Header("Content-Transfer-Encoding", "binary")
  374. err = f.Write(c.Writer)
  375. if err != nil {
  376. return nil, err
  377. }
  378. return nil, nil
  379. }
  380. func ReportPurchaseDownload(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  381. var form ReportListReq
  382. err := c.ShouldBindJSON(&form)
  383. if err != nil {
  384. return nil, errors.New("参数错误")
  385. }
  386. // 条件处理
  387. query := make(map[string]interface{}, 0)
  388. query["status"] = "complete"
  389. if !form.SupplierId.IsZero() {
  390. query["supplierId"] = form.SupplierId
  391. }
  392. // 时间范围
  393. if len(form.TimeRange) == 2 {
  394. start, end := getTimeRange(form.TimeRange[0], form.TimeRange[1])
  395. query["updateTime"] = bson.M{"$gte": start, "$lte": end}
  396. }
  397. // 包装
  398. if len(form.PackIds) > 0 {
  399. packQuery := []bson.M{}
  400. for _, packId := range form.PackIds {
  401. packQuery = append(packQuery, bson.M{"packId": packId})
  402. }
  403. query["$or"] = packQuery
  404. }
  405. // 计划
  406. if len(form.PlanIds) > 0 {
  407. planQuery := bson.A{}
  408. for _, planId := range form.PlanIds {
  409. planQuery = append(planQuery, bson.M{"planId": planId})
  410. }
  411. query["$or"] = planQuery
  412. }
  413. // 获取符合条件的信息
  414. purchases := []model.PurchaseBill{}
  415. err = repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  416. CollectName: repo.CollectionBillPurchase,
  417. Query: query,
  418. }, &purchases)
  419. if err != nil || len(purchases) < 1 {
  420. return nil, errors.New("数据不存在")
  421. }
  422. f := excelize.NewFile()
  423. index := f.NewSheet("Sheet1")
  424. sheetName := f.GetSheetName(index)
  425. f.SetActiveSheet(index)
  426. f.SetDefaultFont("宋体")
  427. border := []excelize.Border{
  428. {Type: "top", Style: 1, Color: "000000"},
  429. {Type: "left", Style: 1, Color: "000000"},
  430. {Type: "right", Style: 1, Color: "000000"},
  431. {Type: "bottom", Style: 1, Color: "000000"},
  432. }
  433. alignCenterStyle, _ := f.NewStyle(&excelize.Style{
  434. Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
  435. Border: border,
  436. })
  437. offset := 0
  438. info := model.Setting{}
  439. repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  440. CollectName: "infos",
  441. }, &info)
  442. var budgetCount float64 = 0
  443. var realCount float64 = 0
  444. for _, purchase := range purchases {
  445. purchaseExcel := NewReportPurchaseExcel(f)
  446. purchaseExcel.Content = &purchase
  447. budgetCount += purchaseExcel.BudgetCount
  448. realCount += purchaseExcel.RealCount
  449. purchaseExcel.Title = fmt.Sprintf("%s原材料采购单", info.CompanyName)
  450. //设置对应的数据
  451. purchaseExcel.Offset = offset
  452. purchaseExcel.Draws()
  453. offset += 15
  454. }
  455. row := offset + 1
  456. startCell := fmt.Sprintf("%s%d", "A", row)
  457. endCell := fmt.Sprintf("%s%d", "H", row)
  458. f.MergeCell(sheetName, startCell, endCell)
  459. f.SetCellStyle(sheetName, startCell, endCell, alignCenterStyle)
  460. f.SetCellValue(sheetName, startCell, "汇总金额")
  461. // 预算金额汇总
  462. budgetCountCell := fmt.Sprintf("%s%d", "I", row)
  463. budgetCountStr := ""
  464. if realCount > 0 {
  465. budgetCountStr = fmt.Sprintf("%.2f", budgetCount)
  466. }
  467. f.SetCellValue(sheetName, budgetCountCell, budgetCountStr)
  468. f.SetCellStyle(sheetName, budgetCountCell, budgetCountCell, alignCenterStyle)
  469. // 实际金额汇总
  470. RealCountCell := fmt.Sprintf("%s%d", "J", row)
  471. realCountStr := ""
  472. if realCount > 0 {
  473. realCountStr = fmt.Sprintf("%.2f", realCount)
  474. }
  475. f.SetCellValue(sheetName, RealCountCell, realCountStr)
  476. f.SetCellStyle(sheetName, RealCountCell, RealCountCell, alignCenterStyle)
  477. f.SetRowHeight(sheetName, row, 21)
  478. c.Header("Content-Type", "application/octet-stream")
  479. c.Header("Content-Disposition", "attachment; filename="+"reportPurchase.xlsx")
  480. c.Header("Content-Transfer-Encoding", "binary")
  481. err = f.Write(c.Writer)
  482. if err != nil {
  483. return nil, err
  484. }
  485. return nil, nil
  486. }