plan.go 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  1. package api
  2. import (
  3. "archive/zip"
  4. "box-cost/db/model"
  5. "box-cost/db/repo"
  6. "box-cost/log"
  7. "bytes"
  8. "errors"
  9. "fmt"
  10. "io"
  11. "os"
  12. "path/filepath"
  13. "regexp"
  14. "strings"
  15. "sync"
  16. "time"
  17. "github.com/gin-gonic/gin"
  18. "github.com/xuri/excelize/v2"
  19. "go.mongodb.org/mongo-driver/bson"
  20. "go.mongodb.org/mongo-driver/bson/primitive"
  21. )
  22. // 生产计划管理
  23. func ProductPlan(r *GinRouter) {
  24. // 创建生产计划
  25. r.POST("/plan/create", CreateProductPlan)
  26. // 获取生产计划详情
  27. r.GET("/plan/detail/:id", GetProductPlan)
  28. // 获取生产计划列表
  29. r.GET("/plan/list", GetProductPlans)
  30. // 更新生产计划
  31. r.POST("/plan/update", UpdateProductPlan)
  32. // 删除生产计划
  33. r.POST("/plan/delete/:id", DelProductPlan)
  34. // 下载部件单据
  35. // r.GET("/bill/plan/download", DownLoadCompBills)
  36. r.GET("/bill/plan/download", DownLoadPlanBills)
  37. r.GET("/bill/plan/downloadPdf", DownLoadPlanBillsPdf)
  38. // 生产成本表
  39. r.GET("/plan/cost/download", DownLoadPlanCost)
  40. // 单据批量分配给供应商
  41. r.GET("/plan/alloc/batch", PlanAllocBatch)
  42. }
  43. // 把某个计划的订单批量分配给供应商
  44. // id 为计划id
  45. // /plan/alloc/batch?id=xxx
  46. func PlanAllocBatch(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  47. _planId := c.Query("id")
  48. planId, err := primitive.ObjectIDFromHex(_planId)
  49. if err != nil {
  50. return nil, errors.New("planId错误")
  51. }
  52. plan := model.ProductPlan{}
  53. found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  54. CollectName: repo.CollectionProductPlan,
  55. Query: repo.Map{"_id": planId},
  56. }, &plan)
  57. if !found || err != nil {
  58. return nil, errors.New("数据未找到")
  59. }
  60. // 获取所有stages单据id
  61. billIds := make([]string, 0)
  62. for _, comp := range plan.Pack.Components {
  63. if comp.Id == "" || len(comp.Stages) == 0 {
  64. continue
  65. }
  66. for _, stage := range comp.Stages {
  67. billId, _ := primitive.ObjectIDFromHex(stage.BillId)
  68. if !billId.IsZero() {
  69. billIds = append(billIds, fmt.Sprintf("%d_%s", stage.BillType, stage.BillId))
  70. }
  71. }
  72. }
  73. // 去重单据号
  74. typeBillIds := removeDuplicationSort(billIds)
  75. if len(typeBillIds) < 1 {
  76. return nil, errors.New("未找到单据信息")
  77. }
  78. for _, tId := range typeBillIds {
  79. tidArr := strings.Split(tId, "_")
  80. // 采购
  81. billId, _ := primitive.ObjectIDFromHex(tidArr[1])
  82. if tidArr[0] == "1" {
  83. repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillPurchase, billId.Hex(), &model.PurchaseBill{IsSend: true, SendTime: time.Now()})
  84. }
  85. // 工艺
  86. if tidArr[0] == "2" {
  87. repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduce, billId.Hex(), &model.ProduceBill{IsSend: true, SendTime: time.Now()})
  88. }
  89. // 成品采购
  90. if tidArr[0] == "3" {
  91. repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduct, billId.Hex(), &model.ProductBill{IsSend: true, SendTime: time.Now()})
  92. }
  93. }
  94. return true, nil
  95. }
  96. // 更新供应商确定数量与plan中stage项的同步
  97. func updateStageCount(billId primitive.ObjectID, planId primitive.ObjectID, idCounts map[string]int, apictx *ApiSession) (interface{}, error) {
  98. if len(idCounts) == 0 {
  99. return true, nil
  100. }
  101. plan := model.ProductPlan{}
  102. found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  103. CollectName: repo.CollectionProductPlan,
  104. Query: repo.Map{"_id": planId},
  105. }, &plan)
  106. if !found || err != nil {
  107. return nil, errors.New("数据未找到")
  108. }
  109. for _, comp := range plan.Pack.Components {
  110. if comp.Id == "" || len(comp.Stages) == 0 {
  111. continue
  112. }
  113. for _, stage := range comp.Stages {
  114. if v, ok := idCounts[stage.Id]; ok {
  115. stage.ConfirmCount = v
  116. }
  117. }
  118. }
  119. plan.UpdateTime = time.Now()
  120. result, err := repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionProductPlan, planId.Hex(), &plan)
  121. if err != nil {
  122. log.Error(err)
  123. fmt.Println(err)
  124. }
  125. return result, err
  126. }
  127. type SupplierPlanCost struct {
  128. *model.ProductPlan
  129. SupplierId string
  130. }
  131. func DownLoadPlanCost(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  132. _planId := c.Query("id")
  133. supplierId := c.Query("supplierId")
  134. planId, _ := primitive.ObjectIDFromHex(_planId)
  135. if planId.IsZero() {
  136. return nil, errors.New("planId错误")
  137. }
  138. supplierPlanCost := &SupplierPlanCost{}
  139. plan := model.ProductPlan{}
  140. found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  141. CollectName: repo.CollectionProductPlan,
  142. Query: repo.Map{"_id": planId},
  143. }, &plan)
  144. if !found || err != nil {
  145. return nil, errors.New("数据未找到")
  146. }
  147. supplierPlanCost.ProductPlan = &plan
  148. supplierPlanCost.SupplierId = supplierId
  149. f := excelize.NewFile()
  150. index := f.NewSheet("Sheet1")
  151. f.SetActiveSheet(index)
  152. f.SetDefaultFont("宋体")
  153. planCostExcel := NewPlanCostExcel(f)
  154. planCostExcel.Title = fmt.Sprintf("生产成本表(%s)%d盒", plan.Name, plan.Total)
  155. planCostExcel.Content = supplierPlanCost
  156. planCostExcel.Draws()
  157. c.Header("Content-Type", "application/octet-stream")
  158. c.Header("Content-Disposition", "attachment; filename="+"planCost.xlsx")
  159. c.Header("Content-Transfer-Encoding", "binary")
  160. err = f.Write(c.Writer)
  161. if err != nil {
  162. return nil, err
  163. }
  164. return nil, nil
  165. }
  166. func DownLoadPlanBills(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  167. _planId := c.Query("id")
  168. planId, err := primitive.ObjectIDFromHex(_planId)
  169. if err != nil {
  170. return nil, errors.New("planId错误")
  171. }
  172. plan := model.ProductPlan{}
  173. found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  174. CollectName: repo.CollectionProductPlan,
  175. Query: repo.Map{"_id": planId},
  176. }, &plan)
  177. if !found || err != nil {
  178. return nil, errors.New("数据未找到")
  179. }
  180. // 获取所有stages单据id
  181. billIds := make([]string, 0)
  182. for _, comp := range plan.Pack.Components {
  183. if comp.Id == "" || len(comp.Stages) == 0 {
  184. continue
  185. }
  186. for _, stage := range comp.Stages {
  187. billId, _ := primitive.ObjectIDFromHex(stage.BillId)
  188. if !billId.IsZero() {
  189. billIds = append(billIds, fmt.Sprintf("%d_%s", stage.BillType, stage.BillId))
  190. }
  191. }
  192. }
  193. // 去重单据号
  194. typeBillIds := removeDuplicationSort(billIds)
  195. if len(typeBillIds) < 1 {
  196. return nil, errors.New("未找到单据信息")
  197. }
  198. f := excelize.NewFile()
  199. f.SetDefaultFont("宋体")
  200. flagIndex := -1
  201. companyName := getCompanyName(apictx)
  202. // 采购 加工 加工-印刷 加工-覆膜 成品采购
  203. typeRows := []int{0, 0, 0, 0, 0}
  204. for _, tId := range typeBillIds {
  205. tidArr := strings.Split(tId, "_")
  206. var billExcel IExcel
  207. // 采购
  208. billId, _ := primitive.ObjectIDFromHex(tidArr[1])
  209. if tidArr[0] == "1" {
  210. purchase := model.PurchaseBill{}
  211. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  212. CollectName: repo.CollectionBillPurchase,
  213. Query: repo.Map{"_id": billId},
  214. }, &purchase)
  215. if found {
  216. sheetName := "采购单"
  217. index := f.NewSheet(sheetName)
  218. if flagIndex < 0 {
  219. flagIndex = index
  220. }
  221. // index := f.NewSheet("采购单")
  222. // f.SetActiveSheet(index)
  223. billExcel = NewPurchaseBill(f)
  224. billExcel.SetSheetName(sheetName)
  225. if purchase.Reviewed == 1 {
  226. if len(purchase.SignUsers) > 0 {
  227. signs := []*model.Signature{}
  228. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  229. CollectName: repo.CollectionSignature,
  230. Query: repo.Map{"_id": bson.M{"$in": purchase.SignUsers}},
  231. Sort: bson.M{"sort": 1},
  232. }, &signs)
  233. billExcel.SetSignatures(signs)
  234. }
  235. }
  236. billExcel.SetContent(&purchase)
  237. billExcel.SetTitle(fmt.Sprintf("%s原材料采购单", companyName))
  238. }
  239. billExcel.SetRow(typeRows[0])
  240. billExcel.Draws()
  241. typeRows[0] = billExcel.GetRow() + 5
  242. }
  243. // 工艺
  244. if tidArr[0] == "2" {
  245. produce := model.ProduceBill{}
  246. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  247. CollectName: repo.CollectionBillProduce,
  248. Query: repo.Map{"_id": billId},
  249. }, &produce)
  250. if found {
  251. sheetName := "加工单"
  252. if produce.IsPrint {
  253. sheetName = "加工单-印刷"
  254. } else if produce.IsLam {
  255. sheetName = "加工单-覆膜"
  256. }
  257. index := f.NewSheet(sheetName)
  258. if flagIndex < 0 {
  259. flagIndex = index
  260. }
  261. billExcel = NewProduceBill(f)
  262. billExcel.SetSheetName(sheetName)
  263. if produce.Reviewed == 1 {
  264. if len(produce.SignUsers) > 0 {
  265. signs := []*model.Signature{}
  266. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  267. CollectName: repo.CollectionSignature,
  268. Query: repo.Map{"_id": bson.M{"$in": produce.SignUsers}},
  269. Sort: bson.M{"sort": 1},
  270. }, &signs)
  271. billExcel.SetSignatures(signs)
  272. }
  273. }
  274. billExcel.SetContent(&produce)
  275. billExcel.SetTitle(fmt.Sprintf("%s加工单", companyName))
  276. }
  277. if produce.IsPrint {
  278. billExcel.SetRow(typeRows[2])
  279. billExcel.Draws()
  280. typeRows[2] = billExcel.GetRow() + 5
  281. } else if produce.IsLam {
  282. billExcel.SetRow(typeRows[3])
  283. billExcel.Draws()
  284. typeRows[3] = billExcel.GetRow() + 5
  285. } else {
  286. billExcel.SetRow(typeRows[1])
  287. billExcel.Draws()
  288. typeRows[1] = billExcel.GetRow() + 5
  289. }
  290. }
  291. // 成品采购
  292. if tidArr[0] == "3" {
  293. product := model.ProductBill{}
  294. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  295. CollectName: repo.CollectionBillProduct,
  296. Query: repo.Map{"_id": billId},
  297. }, &product)
  298. if found {
  299. sheetName := "成品采购单"
  300. index := f.NewSheet(sheetName)
  301. if flagIndex < 0 {
  302. flagIndex = index
  303. }
  304. billExcel = NewProductBill(f)
  305. billExcel.SetSheetName(sheetName)
  306. if product.Reviewed == 1 {
  307. if len(product.SignUsers) > 0 {
  308. signs := []*model.Signature{}
  309. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  310. CollectName: repo.CollectionSignature,
  311. Query: repo.Map{"_id": bson.M{"$in": product.SignUsers}},
  312. Sort: bson.M{"sort": 1},
  313. }, &signs)
  314. billExcel.SetSignatures(signs)
  315. }
  316. }
  317. billExcel.SetContent(&product)
  318. billExcel.SetTitle(companyName)
  319. }
  320. billExcel.SetRow(typeRows[4])
  321. billExcel.Draws()
  322. typeRows[4] = billExcel.GetRow() + 5
  323. }
  324. if billExcel == nil {
  325. continue
  326. }
  327. }
  328. // 设置活跃sheet
  329. f.SetActiveSheet(flagIndex)
  330. // 删除默认Sheet1
  331. f.DeleteSheet("Sheet1")
  332. c.Header("Content-Type", "application/octet-stream")
  333. c.Header("Content-Disposition", "attachment; filename="+"bill.xlsx")
  334. c.Header("Content-Transfer-Encoding", "binary")
  335. err = f.Write(c.Writer)
  336. if err != nil {
  337. return nil, err
  338. }
  339. return nil, nil
  340. }
  341. // todo old 功能确定后删除
  342. func DownLoadPlanBillsBack(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  343. _planId := c.Query("id")
  344. planId, err := primitive.ObjectIDFromHex(_planId)
  345. if err != nil {
  346. return nil, errors.New("planId错误")
  347. }
  348. plan := model.ProductPlan{}
  349. found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  350. CollectName: repo.CollectionProductPlan,
  351. Query: repo.Map{"_id": planId},
  352. }, &plan)
  353. if !found || err != nil {
  354. return nil, errors.New("数据未找到")
  355. }
  356. // 获取所有stages单据id
  357. billIds := make([]string, 0)
  358. for _, comp := range plan.Pack.Components {
  359. if comp.Id == "" || len(comp.Stages) == 0 {
  360. continue
  361. }
  362. for _, stage := range comp.Stages {
  363. billId, _ := primitive.ObjectIDFromHex(stage.BillId)
  364. if !billId.IsZero() {
  365. billIds = append(billIds, fmt.Sprintf("%d_%s", stage.BillType, stage.BillId))
  366. }
  367. }
  368. }
  369. // 去重单据号
  370. typeBillIds := removeDuplicationSort(billIds)
  371. if len(typeBillIds) < 1 {
  372. return nil, errors.New("未找到单据信息")
  373. }
  374. f := excelize.NewFile()
  375. index := f.NewSheet("Sheet1")
  376. f.SetActiveSheet(index)
  377. f.SetDefaultFont("宋体")
  378. companyName := getCompanyName(apictx)
  379. row := 0
  380. for _, tId := range typeBillIds {
  381. tidArr := strings.Split(tId, "_")
  382. var billExcel IExcel
  383. // 采购
  384. billId, _ := primitive.ObjectIDFromHex(tidArr[1])
  385. if tidArr[0] == "1" {
  386. purchase := model.PurchaseBill{}
  387. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  388. CollectName: repo.CollectionBillPurchase,
  389. Query: repo.Map{"_id": billId},
  390. }, &purchase)
  391. if found {
  392. billExcel = NewPurchaseBill(f)
  393. if purchase.Reviewed == 1 {
  394. if len(purchase.SignUsers) > 0 {
  395. signs := []*model.Signature{}
  396. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  397. CollectName: repo.CollectionSignature,
  398. Query: repo.Map{"_id": bson.M{"$in": purchase.SignUsers}},
  399. Sort: bson.M{"sort": 1},
  400. }, &signs)
  401. billExcel.SetSignatures(signs)
  402. }
  403. }
  404. billExcel.SetContent(&purchase)
  405. billExcel.SetTitle(fmt.Sprintf("%s原材料采购单", companyName))
  406. }
  407. }
  408. // 工艺
  409. if tidArr[0] == "2" {
  410. produce := model.ProduceBill{}
  411. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  412. CollectName: repo.CollectionBillProduce,
  413. Query: repo.Map{"_id": billId},
  414. }, &produce)
  415. if found {
  416. billExcel = NewProduceBill(f)
  417. if produce.Reviewed == 1 {
  418. if len(produce.SignUsers) > 0 {
  419. signs := []*model.Signature{}
  420. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  421. CollectName: repo.CollectionSignature,
  422. Query: repo.Map{"_id": bson.M{"$in": produce.SignUsers}},
  423. Sort: bson.M{"sort": 1},
  424. }, &signs)
  425. billExcel.SetSignatures(signs)
  426. }
  427. }
  428. billExcel.SetContent(&produce)
  429. billExcel.SetTitle(fmt.Sprintf("%s加工单", companyName))
  430. }
  431. }
  432. // 成品采购
  433. if tidArr[0] == "3" {
  434. product := model.ProductBill{}
  435. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  436. CollectName: repo.CollectionBillProduct,
  437. Query: repo.Map{"_id": billId},
  438. }, &product)
  439. if found {
  440. billExcel = NewProductBill(f)
  441. if product.Reviewed == 1 {
  442. if len(product.SignUsers) > 0 {
  443. signs := []*model.Signature{}
  444. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  445. CollectName: repo.CollectionSignature,
  446. Query: repo.Map{"_id": bson.M{"$in": product.SignUsers}},
  447. Sort: bson.M{"sort": 1},
  448. }, &signs)
  449. billExcel.SetSignatures(signs)
  450. }
  451. }
  452. billExcel.SetContent(&product)
  453. billExcel.SetTitle(companyName)
  454. }
  455. }
  456. if billExcel == nil {
  457. continue
  458. }
  459. billExcel.SetRow(row)
  460. billExcel.Draws()
  461. row = billExcel.GetRow() + 5
  462. }
  463. c.Header("Content-Type", "application/octet-stream")
  464. c.Header("Content-Disposition", "attachment; filename="+"bill.xlsx")
  465. c.Header("Content-Transfer-Encoding", "binary")
  466. err = f.Write(c.Writer)
  467. if err != nil {
  468. return nil, err
  469. }
  470. return nil, nil
  471. }
  472. func DownLoadPlanBillsPdf(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  473. _planId := c.Query("id")
  474. planId, err := primitive.ObjectIDFromHex(_planId)
  475. if err != nil {
  476. return nil, errors.New("planId错误")
  477. }
  478. plan := model.ProductPlan{}
  479. found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  480. CollectName: repo.CollectionProductPlan,
  481. Query: repo.Map{"_id": planId},
  482. }, &plan)
  483. if !found || err != nil {
  484. return nil, errors.New("数据未找到")
  485. }
  486. // 获取所有stages单据id
  487. billIds := make([]string, 0)
  488. for _, comp := range plan.Pack.Components {
  489. if comp.Id == "" || len(comp.Stages) == 0 {
  490. continue
  491. }
  492. for _, stage := range comp.Stages {
  493. billId, _ := primitive.ObjectIDFromHex(stage.BillId)
  494. if !billId.IsZero() {
  495. billIds = append(billIds, fmt.Sprintf("%d_%s", stage.BillType, stage.BillId))
  496. }
  497. }
  498. }
  499. // 去重单据号
  500. typeBillIds := removeDuplicationSort(billIds)
  501. if len(typeBillIds) < 1 {
  502. return nil, errors.New("未找到单据信息")
  503. }
  504. companyName := getCompanyName(apictx)
  505. _planName := plan.Name
  506. r := regexp.MustCompile(`/`)
  507. planName := r.ReplaceAllString(_planName, `&`)
  508. // fmt.Println(planName)
  509. // 打包pdf的缓存目录
  510. saveTmpDir := fmt.Sprintf("tmp1/%s", planName)
  511. if isExistDir(saveTmpDir) {
  512. os.RemoveAll(saveTmpDir)
  513. }
  514. // 记录文件数量
  515. var wg sync.WaitGroup
  516. c1 := make(chan int)
  517. for _, tId := range typeBillIds {
  518. productName := ""
  519. supplierName := ""
  520. serialNumber := ""
  521. f := excelize.NewFile()
  522. index := f.NewSheet("Sheet1")
  523. f.SetActiveSheet(index)
  524. f.SetDefaultFont("宋体")
  525. tidArr := strings.Split(tId, "_")
  526. var billExcel IExcel
  527. // 采购
  528. billId, _ := primitive.ObjectIDFromHex(tidArr[1])
  529. if tidArr[0] == "1" {
  530. purchase := model.PurchaseBill{}
  531. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  532. CollectName: repo.CollectionBillPurchase,
  533. Query: repo.Map{"_id": billId},
  534. }, &purchase)
  535. if found {
  536. billExcel = NewPurchaseBill(f)
  537. if purchase.Reviewed == 1 {
  538. if len(purchase.SignUsers) > 0 {
  539. signs := []*model.Signature{}
  540. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  541. CollectName: repo.CollectionSignature,
  542. Query: repo.Map{"_id": bson.M{"$in": purchase.SignUsers}},
  543. Sort: bson.M{"sort": 1},
  544. }, &signs)
  545. billExcel.SetSignatures(signs)
  546. }
  547. }
  548. productName = purchase.ProductName
  549. supplierName = purchase.Supplier
  550. serialNumber = purchase.SerialNumber
  551. billExcel.SetContent(&purchase)
  552. billExcel.SetTitle(fmt.Sprintf("%s原材料采购单", companyName))
  553. }
  554. }
  555. // 工艺
  556. if tidArr[0] == "2" {
  557. produce := model.ProduceBill{}
  558. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  559. CollectName: repo.CollectionBillProduce,
  560. Query: repo.Map{"_id": billId},
  561. }, &produce)
  562. if found {
  563. billExcel = NewProduceBill(f)
  564. if produce.Reviewed == 1 {
  565. if len(produce.SignUsers) > 0 {
  566. signs := []*model.Signature{}
  567. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  568. CollectName: repo.CollectionSignature,
  569. Query: repo.Map{"_id": bson.M{"$in": produce.SignUsers}},
  570. Sort: bson.M{"sort": 1},
  571. }, &signs)
  572. billExcel.SetSignatures(signs)
  573. }
  574. }
  575. productName = produce.ProductName
  576. supplierName = produce.Supplier
  577. serialNumber = produce.SerialNumber
  578. billExcel.SetContent(&produce)
  579. billExcel.SetTitle(fmt.Sprintf("%s加工单", companyName))
  580. }
  581. }
  582. // 成品采购
  583. if tidArr[0] == "3" {
  584. product := model.ProductBill{}
  585. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  586. CollectName: repo.CollectionBillProduct,
  587. Query: repo.Map{"_id": billId},
  588. }, &product)
  589. if found {
  590. billExcel = NewProductBill(f)
  591. if product.Reviewed == 1 {
  592. if len(product.SignUsers) > 0 {
  593. signs := []*model.Signature{}
  594. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  595. CollectName: repo.CollectionSignature,
  596. Query: repo.Map{"_id": bson.M{"$in": product.SignUsers}},
  597. Sort: bson.M{"sort": 1},
  598. }, &signs)
  599. billExcel.SetSignatures(signs)
  600. }
  601. }
  602. productName = product.ProductName
  603. supplierName = product.Supplier
  604. serialNumber = product.SerialNumber
  605. billExcel.SetContent(&product)
  606. billExcel.SetTitle(companyName)
  607. }
  608. }
  609. if billExcel == nil {
  610. continue
  611. }
  612. billExcel.SetIsPdf("true")
  613. billExcel.Draws()
  614. buf, _ := f.WriteToBuffer()
  615. // r := regexp.MustCompile(`/`)
  616. _productName := r.ReplaceAllString(productName, `&`)
  617. _supplierName := r.ReplaceAllString(supplierName, `&`)
  618. targePdfName := fmt.Sprintf("%s-%s-%s.pdf", _supplierName, _productName, serialNumber)
  619. // fmt.Println(targePdfName)
  620. wg.Add(1)
  621. go toPdfAndSaveTask(buf, apictx.Svc.Conf.PdfApiAddr, saveTmpDir, targePdfName, c1, &wg)
  622. }
  623. go func() {
  624. // 等待所有goroutine
  625. wg.Wait()
  626. // 关闭channel
  627. close(c1)
  628. }()
  629. // channel关闭后结束后停止遍历接收channel中的值
  630. for n := range c1 {
  631. if n == -1 {
  632. return nil, errors.New("下载失败,请重试")
  633. }
  634. }
  635. c.Header("Content-Type", "application/octet-stream")
  636. c.Header("Content-Disposition", "attachment; filename="+planName+".zip")
  637. c.Header("Content-Transfer-Encoding", "binary")
  638. archive := zip.NewWriter(c.Writer)
  639. defer archive.Close()
  640. // 遍历路径信息
  641. filepath.Walk(saveTmpDir, func(path string, info os.FileInfo, _ error) error {
  642. // 如果是源路径,提前进行下一个遍历
  643. if path == saveTmpDir {
  644. return nil
  645. }
  646. // 获取:文件头信息
  647. header, _ := zip.FileInfoHeader(info)
  648. header.Name = strings.TrimPrefix(path, saveTmpDir+`/`)
  649. // 判断:文件是不是文件夹
  650. if info.IsDir() {
  651. header.Name += `/`
  652. } else {
  653. // 设置:zip的文件压缩算法
  654. header.Method = zip.Deflate
  655. }
  656. // 创建:压缩包头部信息
  657. writer, _ := archive.CreateHeader(header)
  658. if !info.IsDir() {
  659. file, _ := os.Open(path)
  660. defer file.Close()
  661. io.Copy(writer, file)
  662. }
  663. return nil
  664. })
  665. // 删除缓存目录
  666. os.RemoveAll(saveTmpDir)
  667. return nil, nil
  668. }
  669. type ToPdfResult struct {
  670. IsSucc bool
  671. Err error
  672. }
  673. func toPdfAndSaveTask(buf *bytes.Buffer, toPdfAddr, saveTmpDir, targetPdfName string, toPdfResult chan<- int, wg *sync.WaitGroup) {
  674. if buf.Len() < 1<<10 {
  675. fmt.Println("execl内容为空")
  676. log.Error("execl内容为空")
  677. toPdfResult <- -1
  678. wg.Done()
  679. return
  680. }
  681. res, err := excelToPdf(buf, toPdfAddr)
  682. if err != nil {
  683. fmt.Println(err)
  684. log.Error(err)
  685. // pdfRes := ToPdfResult{
  686. // IsSucc: false,
  687. // Err: err,
  688. // }
  689. // toPdfResult <- pdfRes
  690. toPdfResult <- -1
  691. wg.Done()
  692. return
  693. }
  694. byteData, err := io.ReadAll(res.Body)
  695. if err != nil {
  696. fmt.Println(err)
  697. // pdfRes := ToPdfResult{
  698. // IsSucc: false,
  699. // Err: err,
  700. // }
  701. // toPdfResult <- pdfRes
  702. toPdfResult <- -1
  703. wg.Done()
  704. return
  705. }
  706. if len(byteData) < 1 {
  707. fmt.Println("pdf内容为空")
  708. log.Error("pdf内容为空")
  709. toPdfResult <- -1
  710. wg.Done()
  711. return
  712. }
  713. defer res.Body.Close()
  714. err = savePdfToTmp(saveTmpDir, targetPdfName, byteData)
  715. if err != nil {
  716. // pdfRes := ToPdfResult{
  717. // IsSucc: false,
  718. // Err: err,
  719. // }
  720. // toPdfResult <- pdfRes
  721. toPdfResult <- -1
  722. wg.Done()
  723. return
  724. }
  725. // pdfRes := ToPdfResult{
  726. // IsSucc: true,
  727. // Err: err,
  728. // }
  729. // toPdfResult <- pdfRes
  730. toPdfResult <- 1
  731. wg.Done()
  732. }
  733. // todo 已弃用 功能稳定后删除
  734. func DownLoadCompBills(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  735. _planId := c.Query("id")
  736. compId := c.Query("compId")
  737. planId, err := primitive.ObjectIDFromHex(_planId)
  738. if err != nil {
  739. return nil, errors.New("planId错误")
  740. }
  741. plan := model.ProductPlan{}
  742. found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  743. CollectName: repo.CollectionProductPlan,
  744. Query: repo.Map{"_id": planId},
  745. }, &plan)
  746. if !found || err != nil {
  747. return nil, errors.New("数据未找到")
  748. }
  749. // 获取部件单据
  750. curComp := &model.PackComponent{}
  751. for _, comp := range plan.Pack.Components {
  752. if comp.Id == compId {
  753. curComp = comp
  754. }
  755. }
  756. if curComp.Id == "" {
  757. return nil, errors.New("该组件不存在")
  758. }
  759. // 获取bill
  760. if len(curComp.Stages) == 0 {
  761. return nil, errors.New("该组件数据不存在")
  762. }
  763. // 获取不同类型的单据id
  764. billIds := make([]string, 0)
  765. for _, stage := range curComp.Stages {
  766. billId, _ := primitive.ObjectIDFromHex(stage.BillId)
  767. if !billId.IsZero() {
  768. billIds = append(billIds, fmt.Sprintf("%d_%s", stage.BillType, stage.BillId))
  769. }
  770. }
  771. // 去重单据号
  772. typeBillIds := removeDuplicationSort(billIds)
  773. if len(typeBillIds) < 1 {
  774. return nil, errors.New("未找到单据信息")
  775. }
  776. f := excelize.NewFile()
  777. index := f.NewSheet("Sheet1")
  778. f.SetActiveSheet(index)
  779. f.SetDefaultFont("宋体")
  780. companyName := getCompanyName(apictx)
  781. row := 0
  782. for _, tId := range typeBillIds {
  783. tidArr := strings.Split(tId, "_")
  784. var billExcel IExcel
  785. // 采购
  786. billId, _ := primitive.ObjectIDFromHex(tidArr[1])
  787. if tidArr[0] == "1" {
  788. purchase := model.PurchaseBill{}
  789. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  790. CollectName: repo.CollectionBillPurchase,
  791. Query: repo.Map{"_id": billId},
  792. }, &purchase)
  793. if found {
  794. billExcel = NewPurchaseBill(f)
  795. if purchase.Reviewed == 1 {
  796. if len(purchase.SignUsers) > 0 {
  797. signs := []*model.Signature{}
  798. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  799. CollectName: repo.CollectionSignature,
  800. Query: repo.Map{"_id": bson.M{"$in": purchase.SignUsers}},
  801. Sort: bson.M{"sort": 1},
  802. }, &signs)
  803. billExcel.SetSignatures(signs)
  804. }
  805. }
  806. billExcel.SetContent(&purchase)
  807. billExcel.SetTitle(fmt.Sprintf("%s原材料采购单", companyName))
  808. }
  809. }
  810. // 工艺
  811. if tidArr[0] == "2" {
  812. produce := model.ProduceBill{}
  813. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  814. CollectName: repo.CollectionBillProduce,
  815. Query: repo.Map{"_id": billId},
  816. }, &produce)
  817. if found {
  818. billExcel = NewProduceBill(f)
  819. if produce.Reviewed == 1 {
  820. if len(produce.SignUsers) > 0 {
  821. signs := []*model.Signature{}
  822. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  823. CollectName: repo.CollectionSignature,
  824. Query: repo.Map{"_id": bson.M{"$in": produce.SignUsers}},
  825. Sort: bson.M{"sort": 1},
  826. }, &signs)
  827. billExcel.SetSignatures(signs)
  828. }
  829. }
  830. billExcel.SetContent(&produce)
  831. billExcel.SetTitle(fmt.Sprintf("%s加工单", companyName))
  832. }
  833. }
  834. // 成品采购
  835. if tidArr[0] == "3" {
  836. product := model.ProductBill{}
  837. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  838. CollectName: repo.CollectionBillProduct,
  839. Query: repo.Map{"_id": billId},
  840. }, &product)
  841. if found {
  842. billExcel = NewProductBill(f)
  843. if product.Reviewed == 1 {
  844. if len(product.SignUsers) > 0 {
  845. signs := []*model.Signature{}
  846. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  847. CollectName: repo.CollectionSignature,
  848. Query: repo.Map{"_id": bson.M{"$in": product.SignUsers}},
  849. Sort: bson.M{"sort": 1},
  850. }, &signs)
  851. billExcel.SetSignatures(signs)
  852. }
  853. }
  854. billExcel.SetContent(&product)
  855. billExcel.SetTitle(companyName)
  856. }
  857. }
  858. if billExcel == nil {
  859. continue
  860. }
  861. billExcel.SetRow(row)
  862. billExcel.Draws()
  863. row = billExcel.GetRow() + 5
  864. }
  865. c.Header("Content-Type", "application/octet-stream")
  866. c.Header("Content-Disposition", "attachment; filename="+"bill.xlsx")
  867. c.Header("Content-Transfer-Encoding", "binary")
  868. err = f.Write(c.Writer)
  869. if err != nil {
  870. return nil, err
  871. }
  872. return nil, nil
  873. }
  874. // 创建生产计划
  875. func CreateProductPlan(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  876. var plan model.ProductPlan
  877. err := c.ShouldBindJSON(&plan)
  878. if err != nil {
  879. fmt.Println(err)
  880. return nil, errors.New("参数错误!")
  881. }
  882. if plan.Name == "" {
  883. return nil, errors.New("生产计划名为空")
  884. }
  885. if plan.Total == 0 {
  886. return nil, errors.New("生产计划数应不为0")
  887. }
  888. plan.Status = "process" // 进行中
  889. plan.CreateTime = time.Now()
  890. plan.UpdateTime = time.Now()
  891. result, err := repo.RepoAddDoc(apictx.CreateRepoCtx(), repo.CollectionProductPlan, &plan)
  892. return result, err
  893. }
  894. // 获取生产计划信息
  895. func GetProductPlan(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  896. planId := c.Param("id")
  897. id, err := primitive.ObjectIDFromHex(planId)
  898. if err != nil {
  899. return nil, errors.New("非法id")
  900. }
  901. var plan model.ProductPlan
  902. option := &repo.DocSearchOptions{
  903. CollectName: repo.CollectionProductPlan,
  904. Query: repo.Map{"_id": id},
  905. }
  906. found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), option, &plan)
  907. if !found || err != nil {
  908. log.Info(err)
  909. return nil, errors.New("数据未找到")
  910. }
  911. billStates := map[string]string{}
  912. billIsSend := map[string]bool{}
  913. if plan.Pack != nil && plan.Pack.Components != nil {
  914. for _, comp := range plan.Pack.Components {
  915. if comp.Stages != nil {
  916. for _, stage := range comp.Stages {
  917. if len(stage.BillId) > 0 {
  918. collectName := ""
  919. // 材料
  920. if stage.BillType == 1 {
  921. collectName = repo.CollectionBillPurchase
  922. }
  923. // 工艺
  924. if stage.BillType == 2 {
  925. collectName = repo.CollectionBillProduce
  926. }
  927. // 成品
  928. if stage.BillType == 3 {
  929. collectName = repo.CollectionBillProduct
  930. }
  931. ok, state := repo.RepoSeachDocMap(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  932. CollectName: collectName,
  933. Query: repo.Map{"_id": stage.BillId},
  934. Project: []string{"status", "isSend", "serialNumber", "remark"}})
  935. if ok {
  936. billStates[stage.BillId] = state["status"].(string)
  937. if v, ok := state["isSend"]; ok {
  938. billIsSend[stage.BillId] = v.(bool)
  939. } else {
  940. billIsSend[stage.BillId] = false
  941. }
  942. }
  943. }
  944. }
  945. }
  946. }
  947. }
  948. return map[string]interface{}{
  949. "plan": plan,
  950. "billStates": billStates,
  951. "billIsSend": billIsSend,
  952. }, nil
  953. }
  954. // 获取生产计划列表
  955. func GetProductPlans(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  956. page, size, query := UtilQueryPageSize(c)
  957. if _packId, ok := query["packId"]; ok {
  958. packId, _ := primitive.ObjectIDFromHex(_packId.(string))
  959. query["pack._id"] = packId
  960. delete(query, "packId")
  961. }
  962. if _name, ok := query["name"]; ok {
  963. delete(query, "name")
  964. query["name"] = bson.M{"$regex": _name.(string)}
  965. }
  966. option := &repo.PageSearchOptions{
  967. CollectName: repo.CollectionProductPlan,
  968. Query: query,
  969. Page: page,
  970. Size: size,
  971. Sort: bson.M{"createTime": -1},
  972. Project: []string{"_id", "thumbnail", "name", "updateTime", "createTime", "createUser", "total", "totalPrice", "status"},
  973. }
  974. return repo.RepoPageSearch(apictx.CreateRepoCtx(), option)
  975. }
  976. // 更新生产计划
  977. func UpdateProductPlan(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  978. var plan model.ProductPlan
  979. err := c.ShouldBindJSON(&plan)
  980. if err != nil {
  981. return nil, errors.New("参数错误")
  982. }
  983. if plan.Id.Hex() == "" {
  984. return nil, errors.New("id的为空")
  985. }
  986. plan.UpdateTime = time.Now()
  987. return repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionProductPlan, plan.Id.Hex(), &plan)
  988. }
  989. // 删除生产计划
  990. func DelProductPlan(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  991. planId := c.Param("id")
  992. if planId == "" {
  993. return nil, errors.New("id为空")
  994. }
  995. return repo.RepoDeleteDoc(apictx.CreateRepoCtx(), repo.CollectionProductPlan, planId)
  996. }