package controllers import ( "errors" "fmt" "github.com/gin-gonic/gin" "github.com/shopspring/decimal" "github.com/spf13/cast" "gorm.io/gorm" "io" "net/url" "strconv" "time" "wms/constvar" "wms/extend/code" "wms/extend/util" "wms/middleware" "wms/models" "wms/pkg/logx" "wms/pkg/mysqlx" "wms/pkg/structx" "wms/request" "wms/response" "wms/service" "wms/utils/http" ) type ProductController struct { } // AddProduct // @Tags 产品 // @Summary 添加产品 // @Produce application/json // @Param object body models.Material true "产品信息" // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/addProduct [post] func (slf ProductController) AddProduct(c *gin.Context) { var params models.Material if err := c.BindJSON(¶ms); err != nil { util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误") return } if params.ID == "" { util.ResponseFormat(c, code.RequestParamError, "产品编码不能为空") return } if params.Name == "" { util.ResponseFormat(c, code.RequestParamError, "产品名称不能为空") return } if params.Model == "" { util.ResponseFormat(c, code.RequestParamError, "物料类型不能为空") return } if params.Unit == "" { util.ResponseFormat(c, code.RequestParamError, "单位不能为空") return } if params.BarCode != "" { m, err := models.NewMaterialSearch().SetBarCode(params.BarCode).First() if err == nil && m.ID != "" { //查出物料表是物料已存在 util.ResponseFormat(c, code.RequestParamError, "条形码已经被使用") return } } //params.ID = utils.GetUUID() err := models.WithTransaction(func(tx *gorm.DB) error { if err := models.NewMaterialSearch().SetOrm(tx).Create(¶ms); err != nil { return err } materialAttachmentList := []*models.MaterialAttachment{} for _, v := range params.AttachmentIDs { ma := &models.MaterialAttachment{MaterialID: params.ID, AttachmentID: v} materialAttachmentList = append(materialAttachmentList, ma) } if len(materialAttachmentList) > 0 { if err := models.NewMaterialAttachmentSearch().SetOrm(tx).CreateBatch(materialAttachmentList); err != nil { return err } } avs := make([]*models.AttributeValue, 0) for _, v := range params.Attributes { av := models.AttributeValue{ Model: gorm.Model{}, EntityID: params.ID, AttributeID: v.ID, Value: v.Value, } avs = append(avs, &av) } if err := models.NewAttributeValueSearch().SetOrm(tx).CreateBatch(avs); err != nil { return err } return nil }) if err != nil { util.ResponseFormat(c, code.RequestParamError, "产品信息保存失败") return } util.ResponseFormat(c, code.Success, "保存成功") } // GetProductList // @Tags 产品 // @Summary 获取产品列表 // @Produce application/json // @Param object body request.GetProductList true "查询参数" // @Success 200 {object} util.ResponseList{data=[]models.Material} "成功" // @Router /api-wms/v1/product/getProductList [post] func (slf ProductController) GetProductList(c *gin.Context) { var params request.GetProductList if err := c.BindJSON(¶ms); err != nil { util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误") return } search := models.NewMaterialSearch() if params.PageInfo.Check() { search.SetPage(params.Page, params.PageSize) } products, total, err := search.SetPreload(true).SetKeyword(params.KeyWord).SetCategoryId(params.CategoryId).SetOrder("created_at desc").Find() if err != nil { util.ResponseFormat(c, code.RequestParamError, "查找失败") return } ids := make([]int, 0) for _, product := range products { ids = append(ids, product.CategoryId) } categories, err := models.NewProductCategorySearch().SetIds(ids).FindNotTotal() if err != nil { util.ResponseFormat(c, code.RequestParamError, "产品类型查找失败") return } for _, product := range products { for _, category := range categories { if product.CategoryId == int(category.ID) { product.CategoryName = category.Name } } var reorderAmount request.ProductStatisticsAmount if err := models.NewOperationSearch().Orm. Table("wms_operation_details"). InnerJoins("INNER JOIN wms_operation on wms_operation_details.operation_id=wms_operation.id"). Select("wms_operation_details.product_id,SUM(wms_operation_details.amount) as total_count"). Where("wms_operation_details.product_id=? and wms_operation.`status`=? and wms_operation.base_operation_type in (?)", product.ID, constvar.OperationStatus_Ready, []constvar.BaseOperationType{constvar.BaseOperationTypeIncoming, constvar.BaseOperationTypeOutgoing, constvar.BaseOperationTypeDisuse}). Group("wms_operation_details.product_id"). //Order("wms_operation_details.product_id"). First(&reorderAmount).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { util.ResponseFormat(c, code.RequestParamError, "产品数据统计失败") return } else { reorderAmount.TotalAmount = decimal.NewFromInt(0) } } product.PredictionAmount = product.Amount.Add(reorderAmount.TotalAmount) var statisticsList []*request.ProductStatistics if err := models.NewOperationSearch().Orm.Table("wms_operation"). InnerJoins("INNER JOIN wms_operation_details on wms_operation_details.operation_id=wms_operation.id"). Select("SUM(wms_operation_details.amount) as total_amount,wms_operation.base_operation_type"). Where("wms_operation_details.product_id=? and wms_operation.`status`=? and wms_operation.base_operation_type in (?)", product.ID, constvar.OperationStatus_Finish, []constvar.BaseOperationType{constvar.BaseOperationTypeIncoming, constvar.BaseOperationTypeOutgoing, constvar.BaseOperationTypeDisuse}). Group("wms_operation.base_operation_type"). Find(&statisticsList).Error; err != nil { util.ResponseFormat(c, code.RequestParamError, "产品数据统计失败") return } for _, v := range statisticsList { if v.BaseOperationType == constvar.BaseOperationTypeIncoming { product.InputAmount = v.TotalAmount } if v.BaseOperationType == constvar.BaseOperationTypeOutgoing { product.OutputAmount = product.OutputAmount.Add(v.TotalAmount) } if v.BaseOperationType == constvar.BaseOperationTypeAdjust { product.OutputAmount = product.OutputAmount.Add(v.TotalAmount) } } reorderRules, rulesTotal, err := models.NewReorderRuleSearch().SetProductId(product.ID).Find() if err != nil { util.ResponseFormat(c, code.RequestParamError, "重订货规则统计失败") return } if rulesTotal == 1 { product.MinInventoryRule = reorderRules[0].MinInventory product.MaxInventoryRule = reorderRules[0].MaxInventory } product.ReorderRuleNum = rulesTotal attributeValues, err := models.NewAttributeValueSearch().SetEntityID(product.ID).FindNotTotal() aids := make([]uint, 0) for _, v := range attributeValues { aids = append(aids, v.AttributeID) } attributes, err := models.NewAttributeSearch().SetIDs(aids).FindNotTotal() attributesMap := make(map[uint]*models.Attribute, len(attributes)) for _, v := range attributes { attributesMap[v.ID] = v } if err != nil { util.ResponseFormat(c, code.RequestParamError, "未知动态属性") } for _, v1 := range attributeValues { attribute := attributesMap[v1.AttributeID] if attribute == nil { continue } //product.Attributes = append(product.Attributes,v1) product.Attributes = append(product.Attributes, models.Attribute{ Model: gorm.Model{ID: v1.ID, CreatedAt: v1.CreatedAt, UpdatedAt: v1.UpdatedAt, DeletedAt: v1.DeletedAt}, Name: attribute.Name, DataType: attribute.DataType, EntityType: attribute.EntityType, SelectValues: attribute.SelectValues, SelectValue: attribute.SelectValue, //Value: v1.Value, Value: v1.Value, }) } } util.ResponseFormatList(c, code.Success, products, int(total)) } // GetProductDetails // @Tags 产品 // @Summary 通过产品/商品/物料 ID获取产品详情 // @Produce application/json // @Param Authorization header string true "token" // @Param id path string true "id" "查询参数" // @Success 200 {object} util.Response{data=models.Material} "成功" // @Router /api-wms/v1/product/getProductDetails/{id} [get] func (slf ProductController) GetProductDetails(c *gin.Context) { id := c.Param("id") if id == "" { util.ResponseFormat(c, code.RequestParamError, "无效id") return } material, err := models.NewMaterialSearch().SetID(id).SetPreload(true).First() if err != nil { util.ResponseFormat(c, code.RequestParamError, "查找失败") return } attributeValues, err := models.NewAttributeValueSearch().SetEntityID(material.ID).FindNotTotal() if err != nil { util.ResponseFormat(c, code.RequestParamError, "查找失败") return } aids := make([]uint, 0) for _, v := range attributeValues { aids = append(aids, v.AttributeID) } attributes, err := models.NewAttributeSearch().SetIDs(aids).FindNotTotal() attributesMap := make(map[uint]*models.Attribute, len(attributes)) for _, v := range attributes { attributesMap[v.ID] = v } if err != nil { util.ResponseFormat(c, code.RequestParamError, "未知动态属性") } for _, v1 := range attributeValues { attribute := attributesMap[v1.AttributeID] if attribute == nil { continue } //product.Attributes = append(product.Attributes,v1) material.Attributes = append(material.Attributes, models.Attribute{ Model: gorm.Model{ID: v1.ID, CreatedAt: v1.CreatedAt, UpdatedAt: v1.UpdatedAt, DeletedAt: v1.DeletedAt}, Name: attribute.Name, DataType: attribute.DataType, EntityType: attribute.EntityType, SelectValues: attribute.SelectValues, SelectValue: attribute.SelectValue, //Value: v1.Value, Value: v1.Value, }) } util.ResponseFormat(c, code.Success, material) } // GetProductDetailsByBarCode // @Tags 产品 // @Summary 通过产品/商品/物料 条形码 获取产品详情 // @Produce application/json // @Param Authorization header string true "token" // @Param barCode path string true "barCode" "查询参数" // @Success 200 {object} util.Response{data=models.Material} "成功" // @Router /api-wms/v1/product/getProductDetailsByBarCode/{barCode} [get] func (slf ProductController) GetProductDetailsByBarCode(c *gin.Context) { barCode := c.Param("barCode") if barCode == "" { util.ResponseFormat(c, code.RequestParamError, "无效条形码") return } material, err := models.NewMaterialSearch().SetBarCode(barCode).SetPreload(true).First() if err != nil { util.ResponseFormat(c, code.RequestParamError, "查找失败") return } attributeValues, err := models.NewAttributeValueSearch().SetEntityID(material.ID).FindNotTotal() if err != nil { util.ResponseFormat(c, code.RequestParamError, "查找失败") return } aids := make([]uint, 0) for _, v := range attributeValues { aids = append(aids, v.AttributeID) } attributes, err := models.NewAttributeSearch().SetIDs(aids).FindNotTotal() attributesMap := make(map[uint]*models.Attribute, len(attributes)) for _, v := range attributes { attributesMap[v.ID] = v } if err != nil { util.ResponseFormat(c, code.RequestParamError, "未知动态属性") } for _, v1 := range attributeValues { attribute := attributesMap[v1.AttributeID] if attribute == nil { continue } //product.Attributes = append(product.Attributes,v1) material.Attributes = append(material.Attributes, models.Attribute{ Model: gorm.Model{ID: v1.ID, CreatedAt: v1.CreatedAt, UpdatedAt: v1.UpdatedAt, DeletedAt: v1.DeletedAt}, Name: attribute.Name, DataType: attribute.DataType, EntityType: attribute.EntityType, SelectValues: attribute.SelectValues, SelectValue: attribute.SelectValue, //Value: v1.Value, Value: v1.Value, }) } util.ResponseFormat(c, code.Success, material) } // UpdateProduct // @Tags 产品 // @Summary 修改产品 // @Produce application/json // @Param object body models.Material true "产品信息" // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/updateProduct [post] func (slf ProductController) UpdateProduct(c *gin.Context) { var params models.Material if err := c.BindJSON(¶ms); err != nil { util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误") return } if params.Name == "" { util.ResponseFormat(c, code.RequestParamError, "产品名称不能为空") return } if params.Model == "" { util.ResponseFormat(c, code.RequestParamError, "物料类型不能为空") return } if params.Unit == "" { util.ResponseFormat(c, code.RequestParamError, "单位不能为空") return } if params.BarCode != "" { m, err := models.NewMaterialSearch().SetBarCode(params.BarCode).First() if err == nil && m.ID != params.ID { //查出物料且ID不一样, util.ResponseFormat(c, code.RequestParamError, "条形码已经被使用") return } } err := models.NewMaterialSearch().SetID(params.ID).Save(¶ms) if err != nil { util.ResponseFormat(c, code.RequestParamError, "产品信息更新失败") return } err = models.WithTransaction(func(tx *gorm.DB) error { //更新在库的产品类型 if params.CategoryId > 0 { find, _ := models.NewLocationProductAmountSearch().SetProductId(params.ID).Find() if len(find) > 0 { var ids []int for _, f := range find { if f.ProductCategoryID != params.CategoryId { ids = append(ids, f.Id) } } m := make(map[string]interface{}) m["productCategoryId"] = params.CategoryId _ = models.NewLocationProductAmountSearch().SetOrm(tx).SetIds(ids).UpdateByMap(m) } } materialAttachmentList := []*models.MaterialAttachment{} for _, v := range params.AttachmentIDs { ma := &models.MaterialAttachment{MaterialID: params.ID, AttachmentID: v} materialAttachmentList = append(materialAttachmentList, ma) } if err := models.NewMaterialAttachmentSearch().SetOrm(tx).SetMaterialID(params.ID).Delete(); err != nil { util.ResponseFormat(c, code.RequestParamError, "产品附件清除失败") return err } if len(materialAttachmentList) > 0 { if err := models.NewMaterialAttachmentSearch().SetOrm(tx).CreateBatch(materialAttachmentList); err != nil { util.ResponseFormat(c, code.RequestParamError, "产品信息更新失败") return err } } /*attributeValueSearch := models.NewAttributeValueSearch() //删除从新插入 if err := attributeValueSearch.SetOrm(tx).SetEntityID(params.ID).Delete(); err != nil { return err }*/ //avs := make([]*models.AttributeValue, 0) for _, v := range params.Attributes { av := models.AttributeValue{ Model: gorm.Model{ID: v.ID}, EntityID: params.ID, AttributeID: v.ID, Value: v.Value, } //avs = append(avs, &av) if err := models.NewAttributeValueSearch().SetOrm(tx).Save(&av); err != nil { return err } } return nil }) if err != nil { util.ResponseFormat(c, code.RequestParamError, "产品信息更新失败") return } util.ResponseFormat(c, code.Success, "更新成功") } // DeleteProduct // @Tags 产品 // @Summary 通过产品/商品/物料 ID删除产品 // @Produce application/json // @Param id path string true "id" "查询参数" // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/deleteProduct/{id} [delete] func (slf ProductController) DeleteProduct(c *gin.Context) { id := c.Param("id") if id == "" { util.ResponseFormat(c, code.RequestParamError, "无效id") return } err := models.WithTransaction(func(tx *gorm.DB) error { if err := models.NewMaterialSearch().SetOrm(tx).SetID(id).Delete(); err != nil { return err } if err := models.NewAttributeValueSearch().SetOrm(tx).SetEntityID(id).Delete(); err != nil { //删除物料对应的动态属性 return err } return nil }) if err != nil { util.ResponseFormat(c, code.RequestParamError, "删除失败") return } util.ResponseFormat(c, code.Success, "删除成功") } // DeleteProductByBarCode // @Tags 产品 // @Summary 通过产品/商品/物料 条形码删除产品 // @Produce application/json // @Param barCode path string true "barCode" "查询参数" // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/deleteProductByBarCode/{barCode} [delete] func (slf ProductController) DeleteProductByBarCode(c *gin.Context) { barCode := c.Param("barCode") if barCode == "" { util.ResponseFormat(c, code.RequestParamError, "无效id") return } err := models.NewMaterialSearch().SetBarCode(barCode).Delete() if err != nil { util.ResponseFormat(c, code.RequestParamError, "删除失败") return } util.ResponseFormat(c, code.Success, "删除成功") } // AddProductCategory // @Tags 产品类型 // @Summary 添加产品类型 // @Produce application/json // @Param object body models.ProductCategory true "产品类型信息" // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/addProductCategory [post] func (slf ProductController) AddProductCategory(c *gin.Context) { var params models.ProductCategory if err := c.BindJSON(¶ms); err != nil { util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误") return } if params.Name == "" { util.ResponseFormat(c, code.RequestParamError, "产品类型名称不能为空") return } err := models.NewProductCategorySearch().Create(¶ms) if err != nil { util.ResponseFormat(c, code.RequestParamError, "产品类型信息保存失败") return } util.ResponseFormat(c, code.Success, "保存成功") } // GetProductCategoryList // @Tags 产品类型 // @Summary 获取产品类型列表 // @Produce application/json // @Param object body request.GetProductList true "查询参数" // @Success 200 {object} util.ResponseList{data=[]models.ProductCategory} "成功" // @Router /api-wms/v1/product/getProductCategoryList [post] func (slf ProductController) GetProductCategoryList(c *gin.Context) { var params request.GetProductList if err := c.BindJSON(¶ms); err != nil { util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误") return } search := models.NewProductCategorySearch() if params.PageInfo.Check() { search.SetPage(params.Page, params.PageSize) } list, total, err := search.SetKeyword(params.KeyWord).SetOrder("created_at desc").Find() if err != nil { util.ResponseFormat(c, code.RequestParamError, "查找失败") return } util.ResponseFormatList(c, code.Success, list, int(total)) } // GetProductCategoryDetails // @Tags 产品类型 // @Summary 获取产品类型详情 // @Produce application/json // @Param id path string true "id" "查询参数" // @Success 200 {object} util.Response{data=models.Material} "成功" // @Router /api-wms/v1/product/getProductCategoryDetails/{id} [get] func (slf ProductController) GetProductCategoryDetails(c *gin.Context) { id := c.Param("id") if id == "" { util.ResponseFormat(c, code.RequestParamError, "无效id") return } first, err := models.NewProductCategorySearch().SetID(cast.ToInt(id)).First() if err != nil { util.ResponseFormat(c, code.RequestParamError, "查找失败") return } util.ResponseFormat(c, code.Success, first) } // UpdateProductCategory // @Tags 产品类型 // @Summary 修改产品类型 // @Produce application/json // @Param object body models.ProductCategory true "产品信息" // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/updateProductCategory [post] func (slf ProductController) UpdateProductCategory(c *gin.Context) { var params models.ProductCategory if err := c.BindJSON(¶ms); err != nil { util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误") return } if params.Name == "" { util.ResponseFormat(c, code.RequestParamError, "产品类型名称不能为空") return } err := models.NewProductCategorySearch().SetID(params.Id).Save(¶ms) if err != nil { util.ResponseFormat(c, code.RequestParamError, "产品类型信息更新失败") return } util.ResponseFormat(c, code.Success, "更新成功") } // DeleteProductCategory // @Tags 产品类型 // @Summary 删除产品类型 // @Produce application/json // @Param id path string true "id" "查询参数" // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/deleteProductCategory/{id} [delete] func (slf ProductController) DeleteProductCategory(c *gin.Context) { id := c.Param("id") if id == "" { util.ResponseFormat(c, code.RequestParamError, "无效id") return } err := models.NewProductCategorySearch().SetID(cast.ToInt(id)).Delete() if err != nil { util.ResponseFormat(c, code.RequestParamError, "删除失败") return } util.ResponseFormat(c, code.Success, "删除成功") } // ListOperation // @Tags 产品 // @Summary 产品历史出入库信息 // @Produce application/json // @Param object body request.QueryOperationList true "查询参数" // @Success 200 {object} util.ResponseList{data=[]models.Operation} "成功" // @Router /api-wms/v1/product/listOperaton [post] func (slf ProductController) ListOperation(c *gin.Context) { var params request.QueryOperationList if err := c.BindJSON(¶ms); err != nil { util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误:"+err.Error()) return } if !params.PageInfo.Check() { util.ResponseFormat(c, code.RequestParamError, "页码信息错误") return } search := models.NewOperationSearch().SetPage(params.Page, params.PageSize).SetPreload(true).SetOrder("created_at desc") search.SetOrm(search.Orm.InnerJoins("inner join wms_operation_details on wms_operation_details.operation_id=wms_operation.id").Where("wms_operation_details.product_id=?", params.ProductId)) list, total, err := search.Find() if err != nil { util.ResponseFormat(c, code.RequestError, "查找失败:"+err.Error()) return } util.ResponseFormatListWithPage(c, code.Success, list, int(total), params.Page, params.PageSize) } // AddDisuse // @Tags 产品 // @Summary 添加报废信息 // @Produce application/json // @Param object body request.AddDisuse true "入库/出库信息" // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/addDisuse [post] func (slf ProductController) AddDisuse(c *gin.Context) { var params request.AddDisuse if err := c.BindJSON(¶ms); err != nil { util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误:"+err.Error()) return } if params.Amount.LessThanOrEqual(decimal.NewFromInt(0)) { util.ResponseFormat(c, code.RequestParamError, "数量异常") return } if params.FromLocationId == 0 { util.ResponseFormat(c, code.RequestParamError, "请选择源位置") return } if params.ToLocationId == 0 { util.ResponseFormat(c, code.RequestParamError, "请选择报废位置") return } if params.SourceNumber == "" { util.ResponseFormat(c, code.RequestParamError, "请输入源单据") return } if params.Number == "" { util.ResponseFormat(c, code.RequestParamError, "请输入单号") return } var numberNum int64 if err := mysqlx.GetDB().Model(&models.Operation{}).Where("number=?", params.Number).Count(&numberNum).Error; err != nil { util.ResponseFormat(c, code.RequestParamError, err.Error()) return } if numberNum > 0 { util.ResponseFormat(c, code.RequestParamError, "单号已存在") return } detail := &models.OperationDetails{ ProductId: params.ProductId, Amount: params.Amount, FromLocationID: params.FromLocationId, ToLocationID: params.ToLocationId, } operation := models.Operation{ //Number: strconv.FormatInt(time.Now().Unix(), 10), Number: params.Number, SourceNumber: params.SourceNumber, OperationTypeId: 0, Status: constvar.OperationStatus_Ready, OperationDate: time.Now().Format("2006-01-02 15:04:05"), Details: []*models.OperationDetails{detail}, BaseOperationType: constvar.BaseOperationTypeDisuse, OperationTypeName: "库存报废", } if err := models.NewOperationSearch().Create(&operation); err != nil { logx.Errorf("Operation create err: %v", err) util.ResponseFormat(c, code.SaveFail, "添加失败:"+err.Error()) return } util.ResponseFormat(c, code.Success, "添加成功") } // ListDisuse // @Tags 产品 // @Summary 报废列表 // @Produce application/json // @Param object body request.QueryDisuseList true "查询参数" // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/listDisuse [post] func (slf ProductController) ListDisuse(c *gin.Context) { var params request.QueryDisuseList if err := c.BindJSON(¶ms); err != nil { util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误:"+err.Error()) return } if !params.PageInfo.Check() { util.ResponseFormat(c, code.RequestParamError, "数据分页信息错误") return } db := models.NewOperationSearch().Orm. Table("wms_operation"). Select("wms_operation.id,wms_operation.number,wms_operation.source_number,wms_operation.status,wms_operation_details.from_location_id,"+ "wms_operation_details.to_location_id,wms_operation.operation_date,wms_operation.contacter_id,wms_operation.contacter_name,"+ "wms_operation.company_id,wms_operation.company_name,wms_operation.comment,wms_operation_details.product_id,"+ "material.name as product_name,material.unit,wms_operation_details.amount,wms_operation.base_operation_type"). InnerJoins("inner join wms_operation_details on wms_operation_details.operation_id=wms_operation.id"). InnerJoins("inner join material on material.id=wms_operation_details.product_id"). Where("wms_operation.base_operation_type=?", constvar.BaseOperationTypeDisuse) if params.Number != "" { db = db.Where("wms_operation.number like ? or wms_operation.source_number like ? or material.name like ?", fmt.Sprintf("%%%v%%", params.Number), fmt.Sprintf("%%%v%%", params.Number), fmt.Sprintf("%%%v%%", params.Number)) } db = db.Where("wms_operation.operation_type_id=?", 0) var ( records = make([]*models.ResponseDisuseList, 0) total int64 ) //list, total, err := search.SetDisuse(true).SetPreload(true).SetOrder("created_at desc").Find() if err := db.Count(&total).Error; err != nil { util.ResponseFormat(c, code.RequestError, fmt.Errorf("find count err: %v", err)) return } db = db.Preload("ToLocation").Preload("FromLocation") if params.Page*params.PageSize > 0 { db = db.Offset((params.Page - 1) * params.PageSize).Limit(params.PageSize) } if err := db.Order("wms_operation.created_at desc").Find(&records).Error; err != nil { util.ResponseFormat(c, code.RequestError, fmt.Errorf("find count err: %v", err)) return } util.ResponseFormatListWithPage(c, code.Success, records, int(total), params.Page, params.PageSize) } // FinishDisuse // // @Tags 产品 // @Summary 验证报废 // @Produce application/json // @Param id path int true "id" // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/finishDisuse/{id} [put] func (slf ProductController) FinishDisuse(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) if err != nil { util.ResponseFormat(c, code.RequestParamError, "错误的id值") return } if id == 0 { util.ResponseFormat(c, code.RequestParamError, "id为0") return } operation, err := models.NewOperationSearch().SetID(id).First() if err != nil { util.ResponseFormat(c, code.RequestParamError, "未找到相关信息:"+err.Error()) return } if operation.Status != constvar.OperationStatus_Ready { util.ResponseFormat(c, code.RequestError, "该验证无法完成") return } if err := models.WithTransaction(func(tx *gorm.DB) error { if err := models.NewOperationSearch().SetOrm(tx).SetID(id).Update(&models.Operation{Status: constvar.OperationStatus_Finish, AuditDate: time.Now().Format("2006-01-02 15:04:05")}); err != nil { return err } listDetails, err := models.NewOperationDetailsSearch().SetOperationId(operation.Id).SetPreload(true).FindAll() if err != nil { return err } for k, v := range listDetails { if v.Product.Amount.LessThan(v.Amount) { return errors.New(fmt.Sprintf("产品:%v,库存:%v,报废:%v,数量不够,无法完成报废操作", v.Product.Name, v.Product.Amount.String(), v.Amount.String())) } listDetails[k].Product.Amount = listDetails[k].Product.Amount.Sub(v.Amount) if err := tx.Save(&listDetails[k].Product).Error; err != nil { return err } locAmount, res := models.NewLocationProductAmountSearch(). SetProductId(v.ProductId). SetLocationId(v.FromLocationID). FirstRes() if res.Error != nil { return err } if locAmount.Amount.LessThan(v.Amount) { return errors.New(fmt.Sprintf("产品:%v,库存:%v,报废:%v,数量不够,无法完成报废操作", v.Product.Name, locAmount.Amount.String(), v.Amount.String())) } locAmount.Amount = locAmount.Amount.Sub(v.Amount) if err := models.NewLocationProductAmountSearch().SetID(locAmount.Id).Update(locAmount); err != nil { return err } } return nil }); err != nil { util.ResponseFormat(c, code.RequestError, err.Error()) return } util.ResponseFormat(c, code.Success, "操作成功") } // UpdateDisuse // @Tags 产品 // @Summary 修改报废信息 // @Produce application/json // @Param object body request.UpdateDisuse true "入库/出库信息" // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/updateDisuse [post] func (slf ProductController) UpdateDisuse(c *gin.Context) { var params request.UpdateDisuse if err := c.BindJSON(¶ms); err != nil { util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误:"+err.Error()) return } if params.Amount.LessThanOrEqual(decimal.NewFromInt(0)) { util.ResponseFormat(c, code.RequestParamError, "数量异常") return } if params.FromLocationId == 0 { util.ResponseFormat(c, code.RequestParamError, "请选择源位置") return } if params.ToLocationId == 0 { util.ResponseFormat(c, code.RequestParamError, "请选择报废位置") return } if params.SourceNumber == "" { util.ResponseFormat(c, code.RequestParamError, "请输入源单据") return } if params.Status != constvar.OperationStatus_Ready { util.ResponseFormat(c, code.RequestParamError, "该信息无法修改") return } if params.ProductId == "" { util.ResponseFormat(c, code.RequestParamError, "请选择报废产品") return } detail := &models.OperationDetails{ ProductId: params.ProductId, //ProductName: params.ProductName, Amount: params.Amount, //Unit: params.Unit, FromLocationID: params.FromLocationId, ToLocationID: params.ToLocationId, } operation := models.Operation{ Id: params.Id, Number: params.Number, SourceNumber: params.SourceNumber, OperationTypeId: 0, Status: params.Status, OperationDate: params.OperationDate, Details: []*models.OperationDetails{detail}, BaseOperationType: params.BaseOperationType, } if err := models.WithTransaction(func(tx *gorm.DB) error { if err := models.NewOperationDetailsSearch().SetOrm(tx).SetOperationId(params.Id).Delete(); err != nil { return err } operationSearch := models.NewOperationSearch().SetOrm(tx) if err := operationSearch.Orm.Model(&operation).Association("Details").Replace(operation.Details); err != nil { return err } if err := models.NewOperationSearch().SetOrm(tx).SetID(params.Id).Save(&operation); err != nil { return err } return nil }); err != nil { util.ResponseFormat(c, code.RequestParamError, "修改失败:"+err.Error()) return } util.ResponseFormat(c, code.Success, "添加成功") } // ListHistory // @Tags 产品 // @Summary 产品位置历史信息 // @Produce application/json // @Param object body request.QueryOperationHistory true "查询参数" // @Success 200 {object} util.ResponseList{data=[]models.Operation} "成功" // @Router /api-wms/v1/product/listHistory [post] func (slf ProductController) ListHistory(c *gin.Context) { var params request.QueryOperationHistory if err := c.BindJSON(¶ms); err != nil { util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误:"+err.Error()) return } if !params.PageInfo.Check() { util.ResponseFormat(c, code.RequestParamError, "页码信息错误") return } search := models.NewOperationSearch().SetPage(params.Page, params.PageSize).SetPreload(true).SetOrder("created_at desc") search.SetOrm(search.Orm.InnerJoins("inner join wms_operation_details on wms_operation_details.operation_id=wms_operation.id").Where("wms_operation_details.product_id=? and (wms_operation_details.from_location_id=? or wms_operation_details.to_location_id=?)", params.ProductId, params.LocationId, params.LocationId)) list, total, err := search.SetBaseOperationType(constvar.BaseOperationTypeAdjust).Find() if err != nil { util.ResponseFormat(c, code.RequestError, "查找失败:"+err.Error()) return } util.ResponseFormatListWithPage(c, code.Success, list, int(total), params.Page, params.PageSize) } // CancelDisuse // // @Tags 产品 // @Summary 取消报废 // @Produce application/json // @Param id path int true "id" // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/cancelDisuse/{id} [put] func (slf ProductController) CancelDisuse(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) if err != nil { util.ResponseFormat(c, code.RequestParamError, "错误的id值") return } if id == 0 { util.ResponseFormat(c, code.RequestParamError, "id为0") return } operation, err := models.NewOperationSearch().SetID(id).First() if err != nil { util.ResponseFormat(c, code.RequestParamError, "未找到相关信息:"+err.Error()) return } if operation.Status != constvar.OperationStatus_Ready { util.ResponseFormat(c, code.RequestError, "该信息无法取消") return } operation.Status = constvar.OperationStatus_Cancel operation.AuditDate = time.Now().Format("2006-01-02 15:04:05") if err := models.NewOperationSearch().SetID(operation.Id).Save(operation); err != nil { util.ResponseFormat(c, code.SaveFail, err.Error()) return } util.ResponseFormat(c, code.Success, "操作成功") } // GetUserInfo // // @Tags 产品 // @Summary 获取登录用户信息 // @Produce application/json // @Success 200 {object} util.ResponseList{data=map[string]interface{}} "成功" // @Router /api-wms/v1/product/getUserInfo [get] func (slf ProductController) GetUserInfo(c *gin.Context) { userInfo := middleware.GetUserInfo(c) m := make(map[string]interface{}) m["userName"] = userInfo.Username util.ResponseFormat(c, code.Success, m) } // GetUnitInfo // // @Tags 产品 // @Summary 获取单位信息 // @Produce application/json // @Success 200 {object} util.ResponseList{data=[]models.UnitDict} "成功" // @Router /api-wms/v1/product/getUnitInfo [get] func (slf ProductController) GetUnitInfo(c *gin.Context) { dicts, total, err := models.NewUnitDictSearch().Find() if err != nil { util.ResponseFormat(c, code.RequestParamError, "查询出错") return } util.ResponseFormatList(c, code.Success, dicts, int(total)) } // SaveUnitDict // // @Tags 数据字典 // @Summary 更新计量单位字典 // @Produce application/json // @Param object body request.SaveUnitDict true "参数" // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/saveUnitDict [post] func (slf ProductController) SaveUnitDict(c *gin.Context) { var reqParams request.SaveUnitDict var params []*models.UnitDict if err := c.BindJSON(&reqParams); err != nil { util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误") return } if err := structx.AssignTo(reqParams.Data, ¶ms); err != nil { util.ResponseFormat(c, code.RequestParamError, "数据转换错误") return } for i, v := range params { if len(v.Name) == 0 { util.ResponseFormat(c, code.RequestParamError, "名称为空") return } v.Sort = i + 1 } err := models.WithTransaction(func(tx *gorm.DB) error { err := models.NewUnitDictSearch().SetOrm(tx).Delete() if err != nil { return err } err = models.NewUnitDictSearch().SetOrm(tx).CreateBatch(params) if err != nil { return err } return nil }) if err != nil { util.ResponseFormat(c, code.RequestParamError, "删除失败") return } util.ResponseFormat(c, code.Success, "添加成功") } // InputProduct // // @Tags 产品 // @Summary 导入物料/产品 // // @Accept multipart/form-data // @Param file formData file true "file" // @Param Authorization header string true "token" // // @Produce application/xlsx // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/inputProduct [post] func (slf ProductController) InputProduct(c *gin.Context) { file, _, err := c.Request.FormFile("file") if err != nil { util.ResponseFormat(c, code.RequestParamError, err.Error()) return } defer file.Close() resp := response.MaterialInputRes{InputCount: 0, ErrCount: 0, FileAddress: ""} userInfo := middleware.GetUserInfo(c) insertCount, err := service.InputMaterial(file, userInfo.Username) if err != nil { util.ResponseFormat(c, code.RequestParamError, err.Error()) return } resp.InputCount = insertCount util.ResponseFormat(c, code.Success, resp) } // DownloadInputFormat // // @Tags 产品 // @Summary 下载导入物料/产品模板 // // @Param Authorization header string true "token" // // @Success 200 {object} util.Response "成功" // @Router /api-wms/v1/product/downloadInputFormat [get] func (slf ProductController) DownloadInputFormat(c *gin.Context) { template, err := models.NewFileTemplateAttachmentSearch().SetCategory(constvar.FileWarehouseCategory_JialianInput3).First() //物料导入模板 if err != nil { util.ResponseFormat(c, code.NoTemplateError, "获取模版记录失败:"+err.Error()) return } readerCloser, err := http.HttpGetWithReadCloser(template.FileUrl) if err != nil { util.ResponseFormat(c, code.NoTemplateError, "获取模版记录失败:"+err.Error()) return } fileContentDisposition := "attachment;filename=\"" + url.QueryEscape("物料导入.xlsx") + "\"" w := c.Writer w.Header().Set("Content-Type", "application/octet-stream") w.Header().Set("Content-Disposition", fileContentDisposition) w.Header().Set("Content-Transfer-Encoding", "binary") w.Header().Set("Cache-Control", "no-cache") _, err = io.Copy(w, readerCloser) if err != nil { util.ResponseFormat(c, code.NoTemplateError, "下载失败:"+err.Error()) return } w.Flush() _ = readerCloser.Close() util.ResponseFormat(c, code.Success, "") }