plan.go 31 KB

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