plan.go 29 KB

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