plan.go 31 KB

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