plan.go 31 KB

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