package api import ( "archive/zip" "box-cost/db/model" "box-cost/db/repo" "box-cost/log" "bytes" "errors" "fmt" "io" "os" "path/filepath" "regexp" "strings" "sync" "time" "github.com/gin-gonic/gin" "github.com/xuri/excelize/v2" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) // TODO 下载代码重复提取 // 生产计划管理 func ProductPlan(r *GinRouter) { // 创建生产计划 r.POSTJWT("/plan/create", CreateProductPlan) // 获取生产计划详情 r.GETJWT("/plan/detail/:id", GetProductPlan) // 获取生产计划列表 r.GETJWT("/plan/list", GetProductPlans) // 更新生产计划 r.POSTJWT("/plan/update", UpdateProductPlan) // 删除生产计划 r.POSTJWT("/plan/delete/:id", DelProductPlan) // 下载部件单据 // r.GET("/bill/plan/download", DownLoadCompBills) r.GETJWT("/bill/plan/download", DownLoadPlanBills) r.GETJWT("/bill/comp/download", DownLoadCompBills) r.GETJWT("/bill/comp/downloadPdf", DownLoadCompBillsPdf) r.GETJWT("/bill/plan/downloadPdf", DownLoadPlanBillsPdf) // 生产成本表 r.GETJWT("/plan/cost/download", DownLoadPlanCost) // 单据批量分配给供应商 r.GETJWT("/plan/alloc/batch", PlanAllocBatch) } // 把某个计划的订单批量分配给供应商 // id 为计划id // /plan/alloc/batch?id=xxx func PlanAllocBatch(c *gin.Context, apictx *ApiSession) (interface{}, error) { // ?验证当前账户是否可发送订单 userId, _ := primitive.ObjectIDFromHex(apictx.User.Parent) user, err1 := getUserById(apictx, userId) if err1 != nil { return nil, errors.New("用户错误") } if !isSender(user.Roles) { return nil, errors.New("没有发送权限") } _planId := c.Query("id") planId, err := primitive.ObjectIDFromHex(_planId) if err != nil { return nil, errors.New("planId错误") } plan := model.ProductPlan{} found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionProductPlan, Query: repo.Map{"_id": planId}, }, &plan) if !found || err != nil { return nil, errors.New("数据未找到") } // 获取所有stages单据id billIds := make([]string, 0) for _, comp := range plan.Pack.Components { if comp.Id == "" || len(comp.Stages) == 0 { continue } for _, stage := range comp.Stages { billId, _ := primitive.ObjectIDFromHex(stage.BillId) if !billId.IsZero() { billIds = append(billIds, fmt.Sprintf("%d_%s", stage.BillType, stage.BillId)) } } } // 去重单据号 typeBillIds := removeDuplicationSort(billIds) if len(typeBillIds) < 1 { return nil, errors.New("未找到单据信息") } _isSend := true var wg sync.WaitGroup for _, tId := range typeBillIds { var err error billType := "" tidArr := strings.Split(tId, "_") // 采购 billId, _ := primitive.ObjectIDFromHex(tidArr[1]) if tidArr[0] == "1" { billType = PURCHASE_BILL_TYPE // _, err = repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillPurchase, billId.Hex(), &model.PurchaseBill{IsSend: true, SendTime: time.Now()}) _, err = repo.RepoUpdateSetDoc1(apictx.CreateRepoCtx(), repo.CollectionBillPurchase, billId.Hex(), &model.PurchaseBill{IsSend: &_isSend, SendTime: time.Now()}, &repo.RecordLogReq{ Path: c.Request.URL.Path, UserInfo: user, TargetId: billId.Hex(), Type: "send", }) } // 工艺 if tidArr[0] == "2" { billType = PRODUCE_BILL_TYPE // _, err = repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduce, billId.Hex(), &model.ProduceBill{IsSend: true, SendTime: time.Now()}) _, err = repo.RepoUpdateSetDoc1(apictx.CreateRepoCtx(), repo.CollectionBillProduce, billId.Hex(), &model.ProduceBill{IsSend: &_isSend, SendTime: time.Now()}, &repo.RecordLogReq{ Path: c.Request.URL.Path, UserInfo: user, TargetId: billId.Hex(), Type: "send", }) } // 成品采购 if tidArr[0] == "3" { billType = PRODUCT_BILL_TYPE // _, err = repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduct, billId.Hex(), &model.ProductBill{IsSend: true, SendTime: time.Now()}) _, err = repo.RepoUpdateSetDoc1(apictx.CreateRepoCtx(), repo.CollectionBillProduct, billId.Hex(), &model.ProductBill{IsSend: &_isSend, SendTime: time.Now()}, &repo.RecordLogReq{ Path: c.Request.URL.Path, UserInfo: user, TargetId: billId.Hex(), Type: "send", }) } if err == nil { // 给供应商发送通知短信 smsInfo, err := genSupplierSmsTemp(billId, billType, apictx) fmt.Println(smsInfo) if err == nil { wg.Add(1) go SendSmsNotify(smsInfo.Phone, &SupplierSmsReq{smsInfo.Product, smsInfo.SerialNumber}, &wg) // err = SendSmsNotify1(smsInfo.Phone, &SupplierSmsReq{smsInfo.Product, smsInfo.SerialNumber}) // fmt.Println(err) } } } wg.Wait() return true, nil } type UpdateBilltoStageReq struct { BillType string SupplierInfo *model.Supplier Norm string Width int Height int Price2 float64 OrderCount int OrderPrice float64 Remark string ConfirmCount int DeliveryTime time.Time PrintSize string Size string IsChangePrice2 bool } // 更新供应商确定数量与plan中stage项的同步 func updateBilltoStage(c *gin.Context, planId primitive.ObjectID, idStatges map[string]*UpdateBilltoStageReq, apictx *ApiSession) (interface{}, error) { if len(idStatges) == 0 { return true, nil } plan := model.ProductPlan{} found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionProductPlan, Query: repo.Map{"_id": planId}, }, &plan) if !found || err != nil { return nil, errors.New("数据未找到") } for _, comp := range plan.Pack.Components { if comp.Id == "" || len(comp.Stages) == 0 { continue } for _, stage := range comp.Stages { if idStatge, ok := idStatges[stage.Id]; ok { if idStatge.SupplierInfo != nil { stage.SupplierInfo = idStatge.SupplierInfo } if idStatge.IsChangePrice2 { stage.Price = idStatge.Price2 } stage.Norm = idStatge.Norm stage.BatchSizeWidth = idStatge.Width stage.BatchSizeHeight = idStatge.Height stage.OrderCount = idStatge.OrderCount stage.OrderPrice = idStatge.OrderPrice stage.Remark = idStatge.Remark stage.ConfirmCount = idStatge.ConfirmCount stage.DeliveryTime = idStatge.DeliveryTime stage.Size = idStatge.Size stage.UpdateTime = time.Now() fmt.Printf("stage信息:%#v\n", stage) } } } plan.UpdateTime = time.Now() userId, _ := primitive.ObjectIDFromHex(apictx.User.ID) user, _ := getUserById(apictx, userId) // return repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionProductPlan, planId.Hex(), &plan) return repo.RepoUpdateSetDoc1(apictx.CreateRepoCtx(), repo.CollectionProductPlan, planId.Hex(), &plan, &repo.RecordLogReq{ Path: c.Request.URL.Path, UserInfo: user, TargetId: planId.Hex(), Type: "sync", }) } // 更新供应商确定数量与plan中stage项的同步 // func updateStageCount(c *gin.Context, planId primitive.ObjectID, idCounts map[string]int, apictx *ApiSession) (interface{}, error) { // if len(idCounts) == 0 { // return true, nil // } // plan := model.ProductPlan{} // found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ // CollectName: repo.CollectionProductPlan, // Query: repo.Map{"_id": planId}, // }, &plan) // if !found || err != nil { // return nil, errors.New("数据未找到") // } // for _, comp := range plan.Pack.Components { // if comp.Id == "" || len(comp.Stages) == 0 { // continue // } // for _, stage := range comp.Stages { // if v, ok := idCounts[stage.Id]; ok { // stage.ConfirmCount = v // } // } // } // plan.UpdateTime = time.Now() // userId, _ := primitive.ObjectIDFromHex(apictx.User.ID) // user, _ := getUserById(apictx, userId) // // return repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionProductPlan, planId.Hex(), &plan) // return repo.RepoUpdateSetDoc1(apictx.CreateRepoCtx(), repo.CollectionProductPlan, planId.Hex(), &plan, &repo.RecordLogReq{ // Path: c.Request.URL.Path, // UserInfo: user, // TargetId: planId.Hex(), // Type: "sync", // }) // } type SupplierPlanCost struct { *model.ProductPlan SupplierId string } func DownLoadPlanCost(c *gin.Context, apictx *ApiSession) (interface{}, error) { _planId := c.Query("id") _supplierId := c.Query("supplierId") supplierId, _ := primitive.ObjectIDFromHex(_supplierId) planId, _ := primitive.ObjectIDFromHex(_planId) if planId.IsZero() { return nil, errors.New("planId错误") } plan := model.ProductPlan{} found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionProductPlan, Query: repo.Map{"_id": planId}, }, &plan) if !found || err != nil { return nil, errors.New("数据未找到") } summaryPlans := []*PlanSummary{} summaryPlan := GetPlanStatus(&plan, apictx) summaryPlans = append(summaryPlans, summaryPlan) if len(summaryPlans) < 1 { return nil, errors.New("数据不存在") } f := excelize.NewFile() index := f.NewSheet("Sheet1") f.SetActiveSheet(index) f.SetDefaultFont("宋体") planSummaryExcel := NewPlanCostExcel(f) planSummaryExcel.Content = &SupplierPlanSummary{ Plans: summaryPlans, SupplierId: supplierId, } // 绘制表格 planSummaryExcel.Title = fmt.Sprintf("生产成本表(%s)%d盒", plan.Name, plan.Total) planSummaryExcel.Draws() c.Header("Content-Type", "application/octet-stream") c.Header("Content-Disposition", "attachment; filename="+"planCost.xlsx") c.Header("Content-Transfer-Encoding", "binary") err = f.Write(c.Writer) if err != nil { return nil, err } return nil, nil } func DownLoadCompBills(c *gin.Context, apictx *ApiSession) (interface{}, error) { _planId := c.Query("id") compId := c.Query("compId") planId, _ := primitive.ObjectIDFromHex(_planId) if planId.IsZero() { return nil, errors.New("planId错误") } if len(compId) < 1 { return nil, errors.New("planId错误") } plan := model.ProductPlan{} found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionProductPlan, Query: repo.Map{"_id": planId}, }, &plan) if !found || err != nil { return nil, errors.New("数据未找到") } compBills := make([]string, 0) compNameId := "" for _, comp := range plan.Pack.Components { if comp.Id == "" || len(comp.Stages) == 0 { continue } if compId == comp.Id { compNameId = fmt.Sprintf("%s_%s", comp.Name, compId) for _, stage := range comp.Stages { billId, _ := primitive.ObjectIDFromHex(stage.BillId) if !billId.IsZero() { compBills = append(compBills, fmt.Sprintf("%d_%s", stage.BillType, stage.BillId)) } } } } if len(compBills) < 1 { return nil, errors.New("数据未找到") } companyName := getCompanyName(apictx) typeBillIds := removeDuplicationSort(compBills) if len(typeBillIds) < 1 { return nil, errors.New("未找到单据信息") } f := excelize.NewFile() f.SetDefaultFont("宋体") flagIndex := -1 // 采购 加工 加工-印刷 加工-覆膜 成品采购 typeRows := []int{0, 0, 0, 0, 0} for _, tId := range typeBillIds { tidArr := strings.Split(tId, "_") var billExcel IExcel // 采购 billId, _ := primitive.ObjectIDFromHex(tidArr[1]) if tidArr[0] == "1" { purchase := model.PurchaseBill{} found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionBillPurchase, Query: repo.Map{"_id": billId}, }, &purchase) if !found { continue } sheetName := "采购单" index := f.NewSheet(sheetName) if flagIndex < 0 { flagIndex = index } // index := f.NewSheet("采购单") // f.SetActiveSheet(index) billExcel = NewPurchaseBill(f) billExcel.SetSheetName(sheetName) if purchase.Reviewed == 1 { if len(purchase.SignUsers) > 0 { signs := []*model.Signature{} repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ CollectName: repo.CollectionSignature, Query: repo.Map{"_id": bson.M{"$in": purchase.SignUsers}}, Sort: bson.M{"sort": 1}, }, &signs) billExcel.SetSignatures(signs) } } billExcel.SetContent(&purchase) billExcel.SetTitle(fmt.Sprintf("%s原材料采购单", companyName)) billExcel.SetRow(typeRows[0]) billExcel.Draws() typeRows[0] = billExcel.GetRow() + 5 } // 工艺 if tidArr[0] == "2" { produce := model.ProduceBill{} found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionBillProduce, Query: repo.Map{"_id": billId}, }, &produce) if !found { continue } sheetName := "加工单" if produce.IsPrint { sheetName = "加工单-印刷" } else if produce.IsLam { sheetName = "加工单-覆膜" } index := f.NewSheet(sheetName) if flagIndex < 0 { flagIndex = index } billExcel = NewProduceBill(f) billExcel.SetSheetName(sheetName) if produce.Reviewed == 1 { if len(produce.SignUsers) > 0 { signs := []*model.Signature{} repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ CollectName: repo.CollectionSignature, Query: repo.Map{"_id": bson.M{"$in": produce.SignUsers}}, Sort: bson.M{"sort": 1}, }, &signs) billExcel.SetSignatures(signs) } } billExcel.SetContent(&produce) billExcel.SetTitle(fmt.Sprintf("%s加工单", companyName)) if produce.IsPrint { billExcel.SetRow(typeRows[2]) billExcel.Draws() typeRows[2] = billExcel.GetRow() + 5 } else if produce.IsLam { billExcel.SetRow(typeRows[3]) billExcel.Draws() typeRows[3] = billExcel.GetRow() + 5 } else { billExcel.SetRow(typeRows[1]) billExcel.Draws() typeRows[1] = billExcel.GetRow() + 5 } } // 成品采购 if tidArr[0] == "3" { product := model.ProductBill{} found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionBillProduct, Query: repo.Map{"_id": billId}, }, &product) if !found { continue } sheetName := "成品采购单" index := f.NewSheet(sheetName) if flagIndex < 0 { flagIndex = index } billExcel = NewProductBill(f) billExcel.SetSheetName(sheetName) if product.Reviewed == 1 { if len(product.SignUsers) > 0 { signs := []*model.Signature{} repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ CollectName: repo.CollectionSignature, Query: repo.Map{"_id": bson.M{"$in": product.SignUsers}}, Sort: bson.M{"sort": 1}, }, &signs) billExcel.SetSignatures(signs) } } billExcel.SetContent(&product) billExcel.SetTitle(companyName) billExcel.SetRow(typeRows[4]) billExcel.Draws() typeRows[4] = billExcel.GetRow() + 5 } } // 设置活跃sheet f.SetActiveSheet(flagIndex) // 删除默认Sheet1 f.DeleteSheet("Sheet1") c.Header("Content-Type", "application/octet-stream") c.Header("Content-Disposition", "attachment; filename="+fmt.Sprintf("%s.xlsx", compNameId)) c.Header("Content-Transfer-Encoding", "binary") f.Write(c.Writer) return nil, nil } func DownLoadPlanBills(c *gin.Context, apictx *ApiSession) (interface{}, error) { _planId := c.Query("id") planId, err := primitive.ObjectIDFromHex(_planId) if err != nil { return nil, errors.New("planId错误") } plan := model.ProductPlan{} found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionProductPlan, Query: repo.Map{"_id": planId}, }, &plan) if !found || err != nil { return nil, errors.New("数据未找到") } // 获取组件中的单据并分工序排列 // 获取所有stages单据id // billIds := make([]string, 0) type billIds []string compBillsMap := make(map[string]billIds, 0) for _, comp := range plan.Pack.Components { if comp.Id == "" || len(comp.Stages) == 0 { continue } // 唯一组价名,拼上id是因为防止可能有多个相同组件名 compNameId := fmt.Sprintf("%s_%s", comp.Name, comp.Id) for _, stage := range comp.Stages { billId, _ := primitive.ObjectIDFromHex(stage.BillId) if !billId.IsZero() { compBillsMap[compNameId] = append(compBillsMap[compNameId], fmt.Sprintf("%d_%s", stage.BillType, stage.BillId)) // billIds = append(billIds, fmt.Sprintf("%d_%s", stage.BillType, stage.BillId)) } } } if len(compBillsMap) < 1 { return nil, errors.New("数据未找到") } companyName := getCompanyName(apictx) _planName := plan.Name r := regexp.MustCompile(`/`) planName := r.ReplaceAllString(_planName, `&`) // fmt.Println(planName) // 打包pdf的缓存目录 saveTmpDir := fmt.Sprintf("tmp1/excel/%s", planName) if isExistDir(saveTmpDir) { os.RemoveAll(saveTmpDir) } for compNameId, billIds := range compBillsMap { // 去重单据号 typeBillIds := removeDuplicationSort(billIds) if len(typeBillIds) < 1 { return nil, errors.New("未找到单据信息") } f := excelize.NewFile() f.SetDefaultFont("宋体") flagIndex := -1 // 采购 加工 加工-印刷 加工-覆膜 成品采购 typeRows := []int{0, 0, 0, 0, 0} for _, tId := range typeBillIds { tidArr := strings.Split(tId, "_") var billExcel IExcel // 采购 billId, _ := primitive.ObjectIDFromHex(tidArr[1]) if tidArr[0] == "1" { purchase := model.PurchaseBill{} found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionBillPurchase, Query: repo.Map{"_id": billId}, }, &purchase) if !found { continue } sheetName := "采购单" index := f.NewSheet(sheetName) if flagIndex < 0 { flagIndex = index } // index := f.NewSheet("采购单") // f.SetActiveSheet(index) billExcel = NewPurchaseBill(f) billExcel.SetSheetName(sheetName) if purchase.Reviewed == 1 { if len(purchase.SignUsers) > 0 { signs := []*model.Signature{} repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ CollectName: repo.CollectionSignature, Query: repo.Map{"_id": bson.M{"$in": purchase.SignUsers}}, Sort: bson.M{"sort": 1}, }, &signs) billExcel.SetSignatures(signs) } } billExcel.SetContent(&purchase) billExcel.SetTitle(fmt.Sprintf("%s原材料采购单", companyName)) billExcel.SetRow(typeRows[0]) billExcel.Draws() typeRows[0] = billExcel.GetRow() + 5 } // 工艺 if tidArr[0] == "2" { produce := model.ProduceBill{} found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionBillProduce, Query: repo.Map{"_id": billId}, }, &produce) if !found { continue } sheetName := "加工单" if produce.IsPrint { sheetName = "加工单-印刷" } else if produce.IsLam { sheetName = "加工单-覆膜" } index := f.NewSheet(sheetName) if flagIndex < 0 { flagIndex = index } billExcel = NewProduceBill(f) billExcel.SetSheetName(sheetName) if produce.Reviewed == 1 { if len(produce.SignUsers) > 0 { signs := []*model.Signature{} repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ CollectName: repo.CollectionSignature, Query: repo.Map{"_id": bson.M{"$in": produce.SignUsers}}, Sort: bson.M{"sort": 1}, }, &signs) billExcel.SetSignatures(signs) } } billExcel.SetContent(&produce) billExcel.SetTitle(fmt.Sprintf("%s加工单", companyName)) if produce.IsPrint { billExcel.SetRow(typeRows[2]) billExcel.Draws() typeRows[2] = billExcel.GetRow() + 5 } else if produce.IsLam { billExcel.SetRow(typeRows[3]) billExcel.Draws() typeRows[3] = billExcel.GetRow() + 5 } else { billExcel.SetRow(typeRows[1]) billExcel.Draws() typeRows[1] = billExcel.GetRow() + 5 } } // 成品采购 if tidArr[0] == "3" { product := model.ProductBill{} found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionBillProduct, Query: repo.Map{"_id": billId}, }, &product) if !found { continue } sheetName := "成品采购单" index := f.NewSheet(sheetName) if flagIndex < 0 { flagIndex = index } billExcel = NewProductBill(f) billExcel.SetSheetName(sheetName) if product.Reviewed == 1 { if len(product.SignUsers) > 0 { signs := []*model.Signature{} repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ CollectName: repo.CollectionSignature, Query: repo.Map{"_id": bson.M{"$in": product.SignUsers}}, Sort: bson.M{"sort": 1}, }, &signs) billExcel.SetSignatures(signs) } } billExcel.SetContent(&product) billExcel.SetTitle(companyName) billExcel.SetRow(typeRows[4]) billExcel.Draws() typeRows[4] = billExcel.GetRow() + 5 } } // 设置活跃sheet f.SetActiveSheet(flagIndex) // 删除默认Sheet1 f.DeleteSheet("Sheet1") buf, _ := f.WriteToBuffer() targeEXcelName := fmt.Sprintf("%s.xlsx", compNameId) err := savePdfToTmp(saveTmpDir, targeEXcelName, buf.Bytes()) if err != nil { fmt.Println("保存文件失败!") return nil, err } } c.Header("Content-Type", "application/octet-stream") c.Header("Content-Disposition", "attachment; filename="+fmt.Sprintf("%s-execl.zip", planName)) c.Header("Content-Transfer-Encoding", "binary") archive := zip.NewWriter(c.Writer) defer archive.Close() // 遍历路径信息 filepath.Walk(saveTmpDir, func(path string, info os.FileInfo, _ error) error { // 如果是源路径,提前进行下一个遍历 if path == saveTmpDir { return nil } // 获取:文件头信息 header, _ := zip.FileInfoHeader(info) header.Name = strings.TrimPrefix(path, saveTmpDir+`/`) // 判断:文件是不是文件夹 if info.IsDir() { header.Name += `/` } else { // 设置:zip的文件压缩算法 header.Method = zip.Deflate } // 创建:压缩包头部信息 writer, _ := archive.CreateHeader(header) if !info.IsDir() { file, _ := os.Open(path) defer file.Close() io.Copy(writer, file) } return nil }) // 删除缓存目录 os.RemoveAll(saveTmpDir) return nil, nil // http://127.0.0.1:8888/boxcost/bill/plan/download?id=652206412617b328da71655e // http://127.0.0.1:8888/boxcost/bill/comp/download?id=652206412617b328da71655e&compId=1677034398070 // http://127.0.0.1:8888/boxcost/bill/comp/downloadPdf?id=652206412617b328da71655e&compId=1677034398070 } func DownLoadPlanBillsPdf(c *gin.Context, apictx *ApiSession) (interface{}, error) { _planId := c.Query("id") planId, err := primitive.ObjectIDFromHex(_planId) if err != nil { return nil, errors.New("planId错误") } plan := model.ProductPlan{} found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionProductPlan, Query: repo.Map{"_id": planId}, }, &plan) if !found || err != nil { return nil, errors.New("数据未找到") } // 获取所有stages单据id billIds := make([]string, 0) for _, comp := range plan.Pack.Components { if comp.Id == "" || len(comp.Stages) == 0 { continue } for _, stage := range comp.Stages { billId, _ := primitive.ObjectIDFromHex(stage.BillId) if !billId.IsZero() { billIds = append(billIds, fmt.Sprintf("%d_%s", stage.BillType, stage.BillId)) } } } if len(billIds) < 1 { return nil, errors.New("数据未找到") } // 去重单据号 typeBillIds := removeDuplicationSort(billIds) companyName := getCompanyName(apictx) _planName := plan.Name r := regexp.MustCompile(`/`) planName := r.ReplaceAllString(_planName, `&`) // fmt.Println(planName) // 打包pdf的缓存目录 saveTmpDir := fmt.Sprintf("tmp1/%s", planName) if isExistDir(saveTmpDir) { os.RemoveAll(saveTmpDir) } // 记录文件数量 var wg sync.WaitGroup c1 := make(chan int) for _, tId := range typeBillIds { productName := "" supplierName := "" serialNumber := "" f := excelize.NewFile() index := f.NewSheet("Sheet1") f.SetActiveSheet(index) f.SetDefaultFont("宋体") tidArr := strings.Split(tId, "_") var billExcel IExcel // 采购 billId, _ := primitive.ObjectIDFromHex(tidArr[1]) if tidArr[0] == "1" { purchase := model.PurchaseBill{} found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionBillPurchase, Query: repo.Map{"_id": billId}, }, &purchase) if !found { continue } billExcel = NewPurchaseBill(f) if purchase.Reviewed == 1 { if len(purchase.SignUsers) > 0 { signs := []*model.Signature{} repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ CollectName: repo.CollectionSignature, Query: repo.Map{"_id": bson.M{"$in": purchase.SignUsers}}, Sort: bson.M{"sort": 1}, }, &signs) billExcel.SetSignatures(signs) } } productName = purchase.ProductName supplierName = purchase.Supplier serialNumber = purchase.SerialNumber billExcel.SetContent(&purchase) billExcel.SetTitle(fmt.Sprintf("%s原材料采购单", companyName)) } // 工艺 if tidArr[0] == "2" { produce := model.ProduceBill{} found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionBillProduce, Query: repo.Map{"_id": billId}, }, &produce) if !found { continue } billExcel = NewProduceBill(f) if produce.Reviewed == 1 { if len(produce.SignUsers) > 0 { signs := []*model.Signature{} repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ CollectName: repo.CollectionSignature, Query: repo.Map{"_id": bson.M{"$in": produce.SignUsers}}, Sort: bson.M{"sort": 1}, }, &signs) billExcel.SetSignatures(signs) } } productName = produce.ProductName supplierName = produce.Supplier serialNumber = produce.SerialNumber billExcel.SetContent(&produce) billExcel.SetTitle(fmt.Sprintf("%s加工单", companyName)) } // 成品采购 if tidArr[0] == "3" { product := model.ProductBill{} found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionBillProduct, Query: repo.Map{"_id": billId}, }, &product) if !found { continue } billExcel = NewProductBill(f) if product.Reviewed == 1 { if len(product.SignUsers) > 0 { signs := []*model.Signature{} repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ CollectName: repo.CollectionSignature, Query: repo.Map{"_id": bson.M{"$in": product.SignUsers}}, Sort: bson.M{"sort": 1}, }, &signs) billExcel.SetSignatures(signs) } } productName = product.ProductName supplierName = product.Supplier serialNumber = product.SerialNumber billExcel.SetContent(&product) billExcel.SetTitle(companyName) } billExcel.SetIsPdf("true") billExcel.Draws() buf, _ := f.WriteToBuffer() // r := regexp.MustCompile(`/`) _productName := r.ReplaceAllString(productName, `&`) _supplierName := r.ReplaceAllString(supplierName, `&`) targePdfName := fmt.Sprintf("%s-%s-%s.pdf", _supplierName, _productName, serialNumber) // fmt.Println(targePdfName) wg.Add(1) go toPdfAndSaveTask(buf, apictx.Svc.Conf.PdfApiAddr, saveTmpDir, targePdfName, c1, &wg) } go func() { // 等待所有goroutine wg.Wait() // 关闭channel close(c1) }() // channel关闭后结束后停止遍历接收channel中的值 for n := range c1 { if n == -1 { return nil, errors.New("下载失败,请重试") } } c.Header("Content-Type", "application/octet-stream") c.Header("Content-Disposition", "attachment; filename="+planName+".zip") c.Header("Content-Transfer-Encoding", "binary") archive := zip.NewWriter(c.Writer) defer archive.Close() // 遍历路径信息 filepath.Walk(saveTmpDir, func(path string, info os.FileInfo, _ error) error { // 如果是源路径,提前进行下一个遍历 if path == saveTmpDir { return nil } // 获取:文件头信息 header, _ := zip.FileInfoHeader(info) header.Name = strings.TrimPrefix(path, saveTmpDir+`/`) // 判断:文件是不是文件夹 if info.IsDir() { header.Name += `/` } else { // 设置:zip的文件压缩算法 header.Method = zip.Deflate } // 创建:压缩包头部信息 writer, _ := archive.CreateHeader(header) if !info.IsDir() { file, _ := os.Open(path) defer file.Close() io.Copy(writer, file) } return nil }) // 删除缓存目录 os.RemoveAll(saveTmpDir) return nil, nil } type ToPdfResult struct { IsSucc bool Err error } func toPdfAndSaveTask(buf *bytes.Buffer, toPdfAddr, saveTmpDir, targetPdfName string, toPdfResult chan<- int, wg *sync.WaitGroup) { if buf.Len() < 1<<10 { fmt.Println("execl内容为空") log.Error("execl内容为空") toPdfResult <- -1 wg.Done() return } res, err := excelToPdf(buf, toPdfAddr) if err != nil { fmt.Println(err) log.Error(err) // pdfRes := ToPdfResult{ // IsSucc: false, // Err: err, // } // toPdfResult <- pdfRes toPdfResult <- -1 wg.Done() return } byteData, err := io.ReadAll(res.Body) if err != nil { fmt.Println(err) // pdfRes := ToPdfResult{ // IsSucc: false, // Err: err, // } // toPdfResult <- pdfRes toPdfResult <- -1 wg.Done() return } if len(byteData) < 1 { fmt.Println("pdf内容为空") log.Error("pdf内容为空") toPdfResult <- -1 wg.Done() return } defer res.Body.Close() err = savePdfToTmp(saveTmpDir, targetPdfName, byteData) if err != nil { // pdfRes := ToPdfResult{ // IsSucc: false, // Err: err, // } // toPdfResult <- pdfRes toPdfResult <- -1 wg.Done() return } // pdfRes := ToPdfResult{ // IsSucc: true, // Err: err, // } // toPdfResult <- pdfRes toPdfResult <- 1 wg.Done() } func DownLoadCompBillsPdf(c *gin.Context, apictx *ApiSession) (interface{}, error) { _planId := c.Query("id") compId := c.Query("compId") planId, _ := primitive.ObjectIDFromHex(_planId) if planId.IsZero() { return nil, errors.New("planId错误") } if len(compId) < 1 { return nil, errors.New("compId错误") } plan := model.ProductPlan{} found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionProductPlan, Query: repo.Map{"_id": planId}, }, &plan) if !found || err != nil { return nil, errors.New("数据未找到") } // 获取所有stages单据id billIds := make([]string, 0) compNameId := "" for _, comp := range plan.Pack.Components { if comp.Id == "" || len(comp.Stages) == 0 { continue } if comp.Id == compId { compNameId = fmt.Sprintf("%s_%s", comp.Name, comp.Id) for _, stage := range comp.Stages { billId, _ := primitive.ObjectIDFromHex(stage.BillId) if !billId.IsZero() { billIds = append(billIds, fmt.Sprintf("%d_%s", stage.BillType, stage.BillId)) } } } } if len(billIds) < 1 { return nil, errors.New("数据未找到") } // 去重单据号 typeBillIds := removeDuplicationSort(billIds) companyName := getCompanyName(apictx) _planName := plan.Name r := regexp.MustCompile(`/`) planName := r.ReplaceAllString(_planName, `&`) // fmt.Println(planName) // 打包pdf的缓存目录 saveTmpDir := fmt.Sprintf("tmp1/%s/%s", planName, compNameId) if isExistDir(saveTmpDir) { os.RemoveAll(saveTmpDir) } // 记录文件数量 var wg sync.WaitGroup c1 := make(chan int) for _, tId := range typeBillIds { productName := "" supplierName := "" serialNumber := "" f := excelize.NewFile() index := f.NewSheet("Sheet1") f.SetActiveSheet(index) f.SetDefaultFont("宋体") tidArr := strings.Split(tId, "_") var billExcel IExcel // 采购 billId, _ := primitive.ObjectIDFromHex(tidArr[1]) if tidArr[0] == "1" { purchase := model.PurchaseBill{} found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionBillPurchase, Query: repo.Map{"_id": billId}, }, &purchase) if !found { continue } billExcel = NewPurchaseBill(f) if purchase.Reviewed == 1 { if len(purchase.SignUsers) > 0 { signs := []*model.Signature{} repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ CollectName: repo.CollectionSignature, Query: repo.Map{"_id": bson.M{"$in": purchase.SignUsers}}, Sort: bson.M{"sort": 1}, }, &signs) billExcel.SetSignatures(signs) } } productName = purchase.ProductName supplierName = purchase.Supplier serialNumber = purchase.SerialNumber billExcel.SetContent(&purchase) billExcel.SetTitle(fmt.Sprintf("%s原材料采购单", companyName)) } // 工艺 if tidArr[0] == "2" { produce := model.ProduceBill{} found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionBillProduce, Query: repo.Map{"_id": billId}, }, &produce) if !found { continue } billExcel = NewProduceBill(f) if produce.Reviewed == 1 { if len(produce.SignUsers) > 0 { signs := []*model.Signature{} repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ CollectName: repo.CollectionSignature, Query: repo.Map{"_id": bson.M{"$in": produce.SignUsers}}, Sort: bson.M{"sort": 1}, }, &signs) billExcel.SetSignatures(signs) } } productName = produce.ProductName supplierName = produce.Supplier serialNumber = produce.SerialNumber billExcel.SetContent(&produce) billExcel.SetTitle(fmt.Sprintf("%s加工单", companyName)) } // 成品采购 if tidArr[0] == "3" { product := model.ProductBill{} found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionBillProduct, Query: repo.Map{"_id": billId}, }, &product) if !found { continue } billExcel = NewProductBill(f) if product.Reviewed == 1 { if len(product.SignUsers) > 0 { signs := []*model.Signature{} repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ CollectName: repo.CollectionSignature, Query: repo.Map{"_id": bson.M{"$in": product.SignUsers}}, Sort: bson.M{"sort": 1}, }, &signs) billExcel.SetSignatures(signs) } } productName = product.ProductName supplierName = product.Supplier serialNumber = product.SerialNumber billExcel.SetContent(&product) billExcel.SetTitle(companyName) } billExcel.SetIsPdf("true") billExcel.Draws() buf, _ := f.WriteToBuffer() // r := regexp.MustCompile(`/`) _productName := r.ReplaceAllString(productName, `&`) _supplierName := r.ReplaceAllString(supplierName, `&`) targePdfName := fmt.Sprintf("%s-%s-%s.pdf", _supplierName, _productName, serialNumber) // fmt.Println(targePdfName) wg.Add(1) go toPdfAndSaveTask(buf, apictx.Svc.Conf.PdfApiAddr, saveTmpDir, targePdfName, c1, &wg) } go func() { // 等待所有goroutine wg.Wait() // 关闭channel close(c1) }() // channel关闭后结束后停止遍历接收channel中的值 for n := range c1 { if n == -1 { return nil, errors.New("下载失败,请重试") } } c.Header("Content-Type", "application/octet-stream") c.Header("Content-Disposition", "attachment; filename="+fmt.Sprintf("%s.zip", compNameId)) c.Header("Content-Transfer-Encoding", "binary") archive := zip.NewWriter(c.Writer) defer archive.Close() // 遍历路径信息 filepath.Walk(saveTmpDir, func(path string, info os.FileInfo, _ error) error { // 如果是源路径,提前进行下一个遍历 if path == saveTmpDir { return nil } // 获取:文件头信息 header, _ := zip.FileInfoHeader(info) header.Name = strings.TrimPrefix(path, saveTmpDir+`/`) // 判断:文件是不是文件夹 if info.IsDir() { header.Name += `/` } else { // 设置:zip的文件压缩算法 header.Method = zip.Deflate } // 创建:压缩包头部信息 writer, _ := archive.CreateHeader(header) if !info.IsDir() { file, _ := os.Open(path) defer file.Close() io.Copy(writer, file) } return nil }) // 删除缓存目录 os.RemoveAll(saveTmpDir) return nil, nil } // 创建生产计划 func CreateProductPlan(c *gin.Context, apictx *ApiSession) (interface{}, error) { var plan model.ProductPlan err := c.ShouldBindJSON(&plan) if err != nil { fmt.Println(err) return nil, errors.New("参数错误!") } if plan.Name == "" { return nil, errors.New("生产计划名为空") } if plan.Total == 0 { return nil, errors.New("生产计划数应不为0") } if plan.TotalPrice == nil { var zero float64 = 0 plan.TotalPrice = &zero } plan.Status = "process" // 进行中 plan.CreateTime = time.Now() plan.UpdateTime = time.Now() userId, _ := primitive.ObjectIDFromHex(apictx.User.ID) userInfo, _ := getUserById(apictx, userId) result, err := repo.RepoAddDoc1(apictx.CreateRepoCtx(), repo.CollectionProductPlan, &plan, &repo.RecordLogReq{ Path: c.Request.URL.Path, UserInfo: userInfo, TargetId: "", Type: "created", }) return result, err } // 获取生产计划信息 func GetProductPlan(c *gin.Context, apictx *ApiSession) (interface{}, error) { planId := c.Param("id") id, err := primitive.ObjectIDFromHex(planId) if err != nil { return nil, errors.New("非法id") } var plan model.ProductPlan option := &repo.DocSearchOptions{ CollectName: repo.CollectionProductPlan, Query: repo.Map{"_id": id}, } found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), option, &plan) if !found || err != nil { log.Info(err) return nil, errors.New("数据未找到") } billData := map[string]interface{}{} if plan.Pack != nil && plan.Pack.Components != nil { for _, comp := range plan.Pack.Components { if comp.Stages != nil { for _, stage := range comp.Stages { if len(stage.BillId) > 0 { collectName := "" // 材料 if stage.BillType == 1 { collectName = repo.CollectionBillPurchase } // 工艺 if stage.BillType == 2 { collectName = repo.CollectionBillProduce } // 成品 if stage.BillType == 3 { collectName = repo.CollectionBillProduct } ok, state := repo.RepoSeachDocMap(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: collectName, Query: repo.Map{"_id": stage.BillId}, // Project: []string{"status", "isSend", "reviewed", "isAck", "serialNumber", "sendTo", "remark"} }) if ok { billData[stage.BillId] = state } } } } } } return map[string]interface{}{ "plan": plan, "billData": billData, }, nil } // 获取生产计划列表 func GetProductPlans(c *gin.Context, apictx *ApiSession) (interface{}, error) { page, size, query := UtilQueryPageSize(c) if _packId, ok := query["packId"]; ok { packId, _ := primitive.ObjectIDFromHex(_packId.(string)) query["pack._id"] = packId delete(query, "packId") } if _name, ok := query["name"]; ok { delete(query, "name") query["name"] = bson.M{"$regex": _name.(string)} } option := &repo.PageSearchOptions{ CollectName: repo.CollectionProductPlan, Query: query, Page: page, Size: size, Sort: bson.M{"createTime": -1}, Project: []string{"_id", "thumbnail", "name", "updateTime", "createTime", "createUser", "total", "totalPrice", "status"}, } return repo.RepoPageSearch(apictx.CreateRepoCtx(), option) } // 更新生产计划 func UpdateProductPlan(c *gin.Context, apictx *ApiSession) (interface{}, error) { var plan model.ProductPlan err := c.ShouldBindJSON(&plan) if err != nil { fmt.Println(err) log.Error(err) return nil, errors.New("参数错误") } if plan.Id.Hex() == "" { return nil, errors.New("id的为空") } plan.UpdateTime = time.Now() userId, _ := primitive.ObjectIDFromHex(apictx.User.ID) user, _ := getUserById(apictx, userId) // return repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), repo.CollectionProductPlan, plan.Id.Hex(), &plan) return repo.RepoUpdateSetDoc1(apictx.CreateRepoCtx(), repo.CollectionProductPlan, plan.Id.Hex(), &plan, &repo.RecordLogReq{ Path: c.Request.URL.Path, UserInfo: user, TargetId: plan.Id.Hex(), Type: "update", }) } // 删除生产计划 func DelProductPlan(c *gin.Context, apictx *ApiSession) (interface{}, error) { userId, _ := primitive.ObjectIDFromHex(apictx.User.Parent) if userId.IsZero() { return nil, errors.New("用户错误,请重新登录") } _planId := c.Param("id") planId, _ := primitive.ObjectIDFromHex(_planId) if planId.IsZero() { return nil, errors.New("计划id错误") } plan := model.ProductPlan{} found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ CollectName: repo.CollectionProductPlan, Query: repo.Map{"_id": planId}, }, &plan) if !found || err != nil { return nil, errors.New("计划数据未找到") } res, err := repo.RepoDeleteDoc(apictx.CreateRepoCtx(), repo.CollectionProductPlan, _planId) // 删除计划对应订单 if err == nil { // 获取所有stages单据id billIds := make([]string, 0) for _, comp := range plan.Pack.Components { if comp.Id == "" || len(comp.Stages) == 0 { continue } for _, stage := range comp.Stages { billId, _ := primitive.ObjectIDFromHex(stage.BillId) if !billId.IsZero() { billIds = append(billIds, fmt.Sprintf("%d_%s", stage.BillType, stage.BillId)) } } } // 去重单据号 typeBillIds := removeDuplicationSort(billIds) if len(typeBillIds) < 1 { return res, err } for _, tId := range typeBillIds { tidArr := strings.Split(tId, "_") // 采购 if tidArr[0] == "1" { repo.RepoDeleteDoc(apictx.CreateRepoCtx(), repo.CollectionBillPurchase, tidArr[1]) } // 工艺 if tidArr[0] == "2" { repo.RepoDeleteDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduce, tidArr[1]) } // 成品采购 if tidArr[0] == "3" { repo.RepoDeleteDoc(apictx.CreateRepoCtx(), repo.CollectionBillProduct, tidArr[1]) } } } return res, err }