summary.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. package api
  2. import (
  3. "box-cost/db/model"
  4. "box-cost/db/repo"
  5. "box-cost/log"
  6. "errors"
  7. "strings"
  8. "time"
  9. "github.com/gin-gonic/gin"
  10. "github.com/xuri/excelize/v2"
  11. "go.mongodb.org/mongo-driver/bson"
  12. "go.mongodb.org/mongo-driver/bson/primitive"
  13. )
  14. // 汇总
  15. func Summary(r *GinRouter) {
  16. // 下载详细汇总
  17. r.GETJWT("/summary/download", SummaryDownload)
  18. // 下载简单汇总
  19. r.GETJWT("/summary/sample/download", SummarySampleDownload)
  20. // !10.27 时间和供应商查询
  21. // summary/supplier/plan query={"supplierId":"xxx","timeRange":["xxx","xxx"]}
  22. // 返回planIds数组 []string
  23. r.GETJWT("/summary/supplier/plan", SummarySupplierPlan)
  24. }
  25. type SupplierPlanSummary struct {
  26. Plans []*PlanSummary
  27. SupplierId primitive.ObjectID
  28. ApiSession *ApiSession
  29. }
  30. type PlanSummary struct {
  31. Plan *model.ProductPlan
  32. IsSend map[string]bool
  33. IsAck map[string]bool
  34. Reviewed map[string]int32
  35. State map[string]string
  36. CreateTimes map[string]time.Time
  37. SerialNumber map[string]string
  38. SendTo map[string]string
  39. }
  40. type PlanSimple struct {
  41. Id primitive.ObjectID `bson:"_id,omitempty" json:"_id"`
  42. Name string `bson:"name,omitempty" json:"name"`
  43. CreateUser string `bson:"createUser,omitempty" json:"createUser"`
  44. //生产数量
  45. Total int `bson:"total,omitempty" json:"total"`
  46. //状态
  47. Status string `bson:"status,omitempty" json:"status"`
  48. //总价
  49. TotalPrice float64 `bson:"totalPrice,omitempty" json:"totalPrice"`
  50. CreateTime time.Time `bson:"createTime,omitempty" json:"createTime"`
  51. }
  52. func SummarySupplierPlan(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  53. _, _, query := UtilQueryPageSize(c)
  54. supplierId := primitive.NilObjectID
  55. if _supplierId, ok := query["supplierId"]; ok {
  56. supplierId, _ = primitive.ObjectIDFromHex(_supplierId.(string))
  57. delete(query, "supplierId")
  58. }
  59. if _timeRange, ok := query["timeRange"]; ok {
  60. timeRange, _ := _timeRange.([]interface{})
  61. if len(timeRange) == 2 {
  62. start, end := getTimeRange(timeRange[0].(string), timeRange[1].(string))
  63. query["createTime"] = bson.M{"$gte": start, "$lte": end}
  64. }
  65. delete(query, "timeRange")
  66. }
  67. // 遍历判断包含供应商的数据,返回planIds
  68. plans := []*model.ProductPlan{}
  69. err := repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  70. CollectName: repo.CollectionProductPlan,
  71. Query: query,
  72. Sort: bson.M{"createTime": -1},
  73. }, &plans)
  74. if err != nil {
  75. log.Error(err)
  76. return nil, errors.New("查询数据错误!")
  77. }
  78. planSimples := []*PlanSimple{}
  79. if len(plans) < 1 {
  80. return planSimples, nil
  81. }
  82. // 遍历
  83. for _, plan := range plans {
  84. flag := false
  85. // !20240425兼容totalPrice为空的情况
  86. var totalPrice float64 = 0
  87. if plan.TotalPrice != nil {
  88. totalPrice = *plan.TotalPrice
  89. }
  90. ps := &PlanSimple{
  91. Id: plan.Id,
  92. Name: plan.Name,
  93. CreateUser: plan.CreateUser,
  94. Total: plan.Total,
  95. Status: plan.Status,
  96. TotalPrice: totalPrice,
  97. CreateTime: plan.CreateTime,
  98. }
  99. // 选供应商
  100. if !supplierId.IsZero() {
  101. for _, comp := range plan.Pack.Components {
  102. if comp.Id == "" || len(comp.Stages) == 0 {
  103. continue
  104. }
  105. for _, stage := range comp.Stages {
  106. // 只要任意一个stage中存在选中的供应商,那么这个计划包含这个供应商,这时应该跳出来
  107. if stage.SupplierInfo == nil {
  108. continue
  109. }
  110. if stage.SupplierInfo.Id == supplierId {
  111. planSimples = append(planSimples, ps)
  112. flag = true
  113. break
  114. }
  115. }
  116. if flag {
  117. break
  118. }
  119. }
  120. } else {
  121. planSimples = append(planSimples, ps)
  122. }
  123. }
  124. return planSimples, nil
  125. }
  126. // /summary/download?planIds=id1,id2&supplierId=xxx
  127. func SummaryDownload(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  128. // 获取planIds supplierId
  129. _planIds := c.Query("planIds") // id1,id2...
  130. _supplierId := c.Query("supplierId") // 供应商id
  131. planIds := strings.Split(_planIds, ",")
  132. supplierId, _ := primitive.ObjectIDFromHex(_supplierId)
  133. // 获取详情
  134. if len(planIds) < 1 {
  135. return nil, errors.New("数据不存在")
  136. }
  137. summaryPlans := []*PlanSummary{}
  138. for _, _planId := range planIds {
  139. id, _ := primitive.ObjectIDFromHex(_planId)
  140. if id.IsZero() {
  141. return nil, errors.New("非法id")
  142. }
  143. plan := &model.ProductPlan{}
  144. found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  145. CollectName: repo.CollectionProductPlan,
  146. Query: repo.Map{"_id": id},
  147. }, plan)
  148. if !found || err != nil {
  149. continue
  150. }
  151. summaryPlan := GetPlanStatus(plan, apictx)
  152. summaryPlans = append(summaryPlans, summaryPlan)
  153. }
  154. if len(summaryPlans) < 1 {
  155. return nil, errors.New("数据不存在")
  156. }
  157. // 实例化表格,传入数据
  158. f := excelize.NewFile()
  159. index := f.NewSheet("Sheet1")
  160. f.SetActiveSheet(index)
  161. f.SetDefaultFont("宋体")
  162. planSummaryExcel := NewPlanSummaryExcel(f)
  163. planSummaryExcel.Content = &SupplierPlanSummary{
  164. Plans: summaryPlans,
  165. SupplierId: supplierId,
  166. ApiSession: apictx,
  167. }
  168. // 绘制表格
  169. planSummaryExcel.Draws()
  170. c.Header("Content-Type", "application/octet-stream")
  171. c.Header("Content-Disposition", "attachment; filename="+"planSummary.xlsx")
  172. c.Header("Content-Transfer-Encoding", "binary")
  173. err := f.Write(c.Writer)
  174. if err != nil {
  175. return nil, err
  176. }
  177. return nil, nil
  178. }
  179. // /summary/sample/download?planIds=id1,id2&supplierId=xxx
  180. func SummarySampleDownload(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  181. // 获取planIds supplierId
  182. _planIds := c.Query("planIds") // id1,id2...
  183. _supplierId := c.Query("supplierId") // 供应商id
  184. planIds := strings.Split(_planIds, ",")
  185. supplierId, _ := primitive.ObjectIDFromHex(_supplierId)
  186. // 获取详情
  187. if len(planIds) < 1 {
  188. return nil, errors.New("数据不存在")
  189. }
  190. summaryPlans := []*PlanSummary{}
  191. for _, _planId := range planIds {
  192. id, _ := primitive.ObjectIDFromHex(_planId)
  193. if id.IsZero() {
  194. return nil, errors.New("非法id")
  195. }
  196. plan := &model.ProductPlan{}
  197. found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  198. CollectName: repo.CollectionProductPlan,
  199. Query: repo.Map{"_id": id},
  200. }, plan)
  201. if !found || err != nil {
  202. continue
  203. }
  204. summaryPlan := GetPlanStatus(plan, apictx)
  205. summaryPlans = append(summaryPlans, summaryPlan)
  206. }
  207. if len(summaryPlans) < 1 {
  208. return nil, errors.New("数据不存在")
  209. }
  210. // 实例化表格,传入数据
  211. f := excelize.NewFile()
  212. index := f.NewSheet("Sheet1")
  213. f.SetActiveSheet(index)
  214. f.SetDefaultFont("宋体")
  215. planSummaryExcel := NewSummarySampleExcel(f)
  216. planSummaryExcel.Content = &SupplierPlanSummary{
  217. Plans: summaryPlans,
  218. SupplierId: supplierId,
  219. }
  220. // 绘制表格
  221. planSummaryExcel.Draws()
  222. c.Header("Content-Type", "application/octet-stream")
  223. c.Header("Content-Disposition", "attachment; filename="+"planSummary.xlsx")
  224. c.Header("Content-Transfer-Encoding", "binary")
  225. err := f.Write(c.Writer)
  226. if err != nil {
  227. return nil, err
  228. }
  229. return nil, nil
  230. }
  231. func GetPlanStatus(plan *model.ProductPlan, apictx *ApiSession) *PlanSummary {
  232. billStates := map[string]string{}
  233. billSerialNumber := map[string]string{}
  234. billSendTo := map[string]string{}
  235. billIsSend := map[string]bool{}
  236. billReviewed := map[string]int32{}
  237. billIsAck := map[string]bool{}
  238. billCreateTimes := map[string]time.Time{}
  239. if plan.Pack != nil && plan.Pack.Components != nil {
  240. for _, comp := range plan.Pack.Components {
  241. if comp.Stages != nil {
  242. for _, stage := range comp.Stages {
  243. if len(stage.BillId) > 0 {
  244. collectName := ""
  245. // 材料
  246. if stage.BillType == 1 {
  247. collectName = repo.CollectionBillPurchase
  248. }
  249. // 工艺
  250. if stage.BillType == 2 {
  251. collectName = repo.CollectionBillProduce
  252. }
  253. // 成品
  254. if stage.BillType == 3 {
  255. collectName = repo.CollectionBillProduct
  256. }
  257. ok, state := repo.RepoSeachDocMap(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  258. CollectName: collectName,
  259. Query: repo.Map{"_id": stage.BillId},
  260. Project: []string{"status", "isSend", "reviewed", "isAck", "serialNumber", "sendTo", "remark", "createTime"}})
  261. if ok {
  262. billStates[stage.BillId] = state["status"].(string)
  263. billSerialNumber[stage.BillId] = state["serialNumber"].(string)
  264. if v, ok := state["sendTo"]; ok {
  265. billSendTo[stage.BillId] = v.(string)
  266. }
  267. if v, ok := state["isSend"]; ok {
  268. billIsSend[stage.BillId] = v.(bool)
  269. } else {
  270. billIsSend[stage.BillId] = false
  271. }
  272. if v, ok := state["reviewed"]; ok {
  273. billReviewed[stage.BillId] = v.(int32)
  274. } else {
  275. billReviewed[stage.BillId] = -1
  276. }
  277. if v, ok := state["isAck"]; ok {
  278. billIsAck[stage.BillId] = v.(bool)
  279. } else {
  280. billIsAck[stage.BillId] = false
  281. }
  282. if v, ok := state["createTime"]; ok {
  283. billCreateTimes[stage.BillId] = v.(primitive.DateTime).Time()
  284. }
  285. }
  286. }
  287. }
  288. }
  289. }
  290. }
  291. return &PlanSummary{
  292. Plan: plan,
  293. IsSend: billIsSend,
  294. IsAck: billIsAck,
  295. Reviewed: billReviewed,
  296. State: billStates,
  297. CreateTimes: billCreateTimes,
  298. SerialNumber: billSerialNumber,
  299. SendTo: billSendTo,
  300. }
  301. }