作者 yangfu

feat: 产品信息优化

... ... @@ -2,3 +2,6 @@
-- 表product_material_group 增加唯一索引 idx_unq_product_material_group_company_id_org_id_material_group_number
create UNIQUE INDEX idx_unq_product_material_group_company_id_org_id_material_group_number on manufacture.product_material_group using btree(company_id,org_id,material_group_number);
-- 表product_material 增加唯一索引 idx_unq_product_material_company_id_material_number
create UNIQUE INDEX idx_unq_product_material_company_id_material_number on manufacture.product_material using btree(company_id,material_number);
\ No newline at end of file
... ...
... ... @@ -14,19 +14,15 @@ type CreateProductCommand struct {
// 组织ID
OrgId int `cname:"组织ID" json:"orgId" valid:"Required"`
// 产品编号 编码规则为“CP”+2 位年+2 位月+2 位日+3 位流水码,如 CP211229001
ProductCode string `cname:"产品编号 编码规则为“CP”+2 位年+2 位月+2 位日+3 位流水码,如 CP211229001" json:"productCode"`
ProductCode string `cname:"产品编号 编码规则为“CP”+2 位年+2 位月+2 位日+3 位流水码,如 CP211229001" json:"productCode" valid:"Required"`
// 产品名称
ProductName string `cname:"产品名称" json:"productName" valid:"Required"`
// ProductName string `cname:"产品名称" json:"productName" valid:"Required"`
// 产品类别
ProductCategory string `cname:"产品类别" json:"productCategory" valid:"Required"`
// 数量(保留两位小数)
//Quantity float64 `cname:"数量(保留两位小数)" json:"quantity" valid:"Required"`
// ProductCategory string `cname:"产品类别" json:"productCategory" valid:"Required"`
// 单位
Unit string `cname:"单位" json:"unit" valid:"Required"`
// Unit string `cname:"单位" json:"unit" valid:"Required"`
// 单份重量(原材料)
UnitWeight float64 `cname:"单份重量(原材料)" json:"unitWeight" valid:"Required"`
// 重量
//Weight float64 `cname:"重量" json:"weight" valid:"Required"`
}
func (createProductCommand *CreateProductCommand) Valid(validation *validation.Validation) {
... ...
... ... @@ -12,19 +12,15 @@ type UpdateProductCommand struct {
// 产品ID
ProductId int `cname:"产品ID" json:"productId" valid:"Required"`
// 产品编号 编码规则为“CP”+2 位年+2 位月+2 位日+3 位流水码,如 CP211229001
ProductCode string `cname:"产品编号 编码规则为“CP”+2 位年+2 位月+2 位日+3 位流水码,如 CP211229001" json:"productCode"`
//ProductCode string `cname:"产品编号 编码规则为“CP”+2 位年+2 位月+2 位日+3 位流水码,如 CP211229001" json:"productCode"`
// 产品名称
ProductName string `cname:"产品名称" json:"productName" valid:"Required"`
ProductName string `cname:"产品名称" json:"productName" `
// 产品类别
ProductCategory string `cname:"产品类别" json:"productCategory" valid:"Required"`
// 数量(保留两位小数)
//Quantity float64 `cname:"数量(保留两位小数)" json:"quantity" valid:"Required"`
ProductCategory string `cname:"产品类别" json:"productCategory"`
// 单位
Unit string `cname:"单位" json:"unit" valid:"Required"`
Unit string `cname:"单位" json:"unit"`
// 单份重量(原材料)
UnitWeight float64 `cname:"单份重量(原材料)" json:"unitWeight" valid:"Required"`
// 重量
//Weight float64 `cname:"重量" json:"weight" valid:"Required"`
}
func (updateProductCommand *UpdateProductCommand) Valid(validation *validation.Validation) {
... ...
... ... @@ -14,7 +14,6 @@ import (
"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/infrastructure/redis"
"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/infrastructure/utils"
"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/log"
"time"
)
// 产品服务
... ... @@ -22,7 +21,7 @@ type ProductService struct {
}
// 创建产品服务
func (productService *ProductService) CreateProduct(createProductCommand *command.CreateProductCommand) (interface{}, error) {
func (productService *ProductService) CreateProduct(opt *domain.OperateInfo, createProductCommand *command.CreateProductCommand) (interface{}, error) {
if err := createProductCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
... ... @@ -37,50 +36,23 @@ func (productService *ProductService) CreateProduct(createProductCommand *comman
transactionContext.RollbackTransaction()
}()
if len(createProductCommand.ProductCode) == 0 {
generator := redis.NewProductCodeCache(createProductCommand.CompanyId)
code, err := redis.GenCode(generator)
if err != nil {
log.Logger.Error(err.Error())
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "服务器异常")
}
createProductCommand.ProductCode = code
batchAddProductService, _ := domainService.NewPGBatchAddProductService(transactionContext.(*pgTransaction.TransactionContext))
item := &domain.ImportProductItem{
ProductCode: createProductCommand.ProductCode,
UnitWeight: utils.AssertString(createProductCommand.UnitWeight),
}
var userService = domainService.NewUserService()
var org *domain.Org
org, err = userService.Organization(createProductCommand.OrgId)
if err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
if _, err = batchAddProductService.BatchAddProduct(opt, []*domain.ImportProductItem{
item,
}, false); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
newProduct := &domain.Product{
CompanyId: createProductCommand.CompanyId,
OrgId: createProductCommand.OrgId,
ProductCode: createProductCommand.ProductCode,
ProductName: createProductCommand.ProductName,
ProductCategory: createProductCommand.ProductCategory,
ProductSpec: &domain.UnitQuantity{
Unit: createProductCommand.Unit,
UnitWeight: createProductCommand.UnitWeight,
},
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Ext: domain.NewExt(org.OrgName),
}
productRepository, _, _ := factory.FastPgProduct(transactionContext, 0)
if item, err := productRepository.FindOne(map[string]interface{}{"companyId": createProductCommand.CompanyId, "productCode": createProductCommand.ProductCode}); err == nil && item != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "产品编号重复,请重新提交")
if len(item.FailReason) > 0 {
return nil, application.ThrowError(application.TRANSACTION_ERROR, item.FailReason)
}
if product, err := productRepository.Save(newProduct); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
} else {
if err := transactionContext.CommitTransaction(); err != nil {
return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
}
return product, nil
}
return struct{}{}, nil
}
// 返回产品服务
... ... @@ -242,7 +214,7 @@ func (productService *ProductService) BatchRemoveProduct(cmd *command.BatchRemov
}
// 更新产品服务
func (productService *ProductService) UpdateProduct(updateProductCommand *command.UpdateProductCommand) (interface{}, error) {
func (productService *ProductService) UpdateProduct(opt *domain.OperateInfo, updateProductCommand *command.UpdateProductCommand) (interface{}, error) {
if err := updateProductCommand.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
... ... @@ -260,19 +232,11 @@ func (productService *ProductService) UpdateProduct(updateProductCommand *comman
if err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
if len(updateProductCommand.ProductCode) == 0 {
generator := redis.NewProductCodeCache(product.CompanyId)
code, err := redis.GenCode(generator)
if err != nil {
log.Logger.Error(err.Error())
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "服务器异常")
}
updateProductCommand.ProductCode = code
}
if updateProductCommand.ProductCode != product.ProductCode {
if item, err := productRepository.FindOne(map[string]interface{}{"companyId": product.CompanyId, "productCode": updateProductCommand.ProductCode}); err == nil && item != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "产品编号重复,请重新提交")
}
var material *domain.ProductMaterial
productMaterialRepository, _, _ := factory.FastProductMaterial(transactionContext, 0)
if material, err = productMaterialRepository.FindOne(map[string]interface{}{"companyId": product.CompanyId, "materialNumber": product.ProductCode}); err != nil || material == nil {
return nil, application.ThrowError(application.BUSINESS_ERROR, "物料不存在")
}
var userService = domainService.NewUserService()
... ... @@ -281,8 +245,13 @@ func (productService *ProductService) UpdateProduct(updateProductCommand *comman
if err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
updateProductCommand.ProductName = material.MaterialName
updateProductCommand.Unit = material.ProductMaterialExt.Unit
updateProductCommand.ProductCategory = material.MaterialCategory.Category
data := tool_funs.SimpleStructToMap(updateProductCommand)
data["orgName"] = org.OrgName
if err := product.Update(data); err != nil {
return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error())
}
... ...
... ... @@ -2,6 +2,7 @@ package domain
import (
"fmt"
"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/infrastructure/utils"
"strconv"
"time"
)
... ... @@ -99,15 +100,18 @@ type ImportProductItem struct {
}
func (item *ImportProductItem) Valid() error {
if len(item.ProductName) == 0 {
return fmt.Errorf("品名不能为空")
}
if len(item.Unit) == 0 {
return fmt.Errorf("规格不能为空")
}
if len(item.ProductCategory) == 0 {
return fmt.Errorf("类别不能为空")
if len(item.ProductCode) == 0 {
return fmt.Errorf("产品编号不能为空")
}
//if len(item.ProductName) == 0 {
// return fmt.Errorf("品名不能为空")
//}
//if len(item.Unit) == 0 {
// return fmt.Errorf("规格不能为空")
//}
//if len(item.ProductCategory) == 0 {
// return fmt.Errorf("类别不能为空")
//}
if len(item.UnitWeight) == 0 {
item.UnitWeight = "0"
}
... ... @@ -116,3 +120,13 @@ func (item *ImportProductItem) Valid() error {
}
return nil
}
type Products []*Product
func (products Products) ProductCodes() []string {
var result = utils.NewSet()
for _, v := range products {
result.Add(v.ProductCode)
}
return result.KeysStr()
}
... ...
... ... @@ -59,3 +59,11 @@ func (productMaterials ProductMaterials) ToMapById() map[int]*ProductMaterial {
}
return mapProductMaterial
}
func (productMaterials ProductMaterials) ToMapByNumber() map[string]*ProductMaterial {
var mapProductMaterial = make(map[string]*ProductMaterial, 0)
for _, v := range productMaterials {
mapProductMaterial[v.MaterialNumber] = v
}
return mapProductMaterial
}
... ...
... ... @@ -6,8 +6,8 @@ import (
pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
"github.com/linmadan/egglib-go/utils/tool_funs"
"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/domain"
"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/infrastructure/redis"
"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/infrastructure/repository"
"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/infrastructure/utils"
"gitlab.fjmaimaimai.com/allied-creation/allied-creation-manufacture/pkg/log"
"strconv"
"time"
... ... @@ -36,10 +36,22 @@ func (ptr *PGBatchAddProductService) BatchAddProduct(opt *domain.OperateInfo, li
if err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
var generator = redis.NewProductCodeCache(opt.CompanyId)
var materials domain.ProductMaterials
if materials, err = ptr.GetProductMaterialByImportItems(opt.CompanyId, list); err != nil {
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
}
mapMaterials := materials.ToMapByNumber()
for i := range list {
item := list[i]
if v, ok := mapMaterials[item.ProductCode]; !ok {
item.FailReason = "导入的产品编号不存在"
failRows = append(failRows, item)
continue
} else {
item.Unit = v.ProductMaterialExt.Unit
item.ProductName = v.MaterialName
item.ProductCategory = v.MaterialCategory.Category
}
if err := item.Valid(); err != nil {
item.FailReason = err.Error()
failRows = append(failRows, item)
... ... @@ -69,14 +81,6 @@ func (ptr *PGBatchAddProductService) BatchAddProduct(opt *domain.OperateInfo, li
continue
}
}
if len(newItem.ProductCode) == 0 {
code, err := redis.GenCode(generator)
if err != nil {
log.Logger.Error(err.Error())
return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, "服务器异常")
}
newItem.ProductCode = code
}
if _, ok := mapProduct[newItem.ProductCode]; !ok {
mapProduct[newItem.ProductCode] = newItem
... ... @@ -105,6 +109,28 @@ func (ptr *PGBatchAddProductService) updateProduct(opt *domain.OperateInfo, item
return nil
}
func (ptr *PGBatchAddProductService) GetProductMaterialByProductCodes(companyId int, productCodes []string) ([]*domain.ProductMaterial, error) {
productMaterialRepository, _ := repository.NewProductMaterialRepository(ptr.transactionContext)
_, productMaterials, err := productMaterialRepository.Find(map[string]interface{}{"companyId": companyId, "materialNumbers": productCodes})
return productMaterials, err
}
func (ptr *PGBatchAddProductService) GetProductMaterialByImportItems(companyId int, list []*domain.ImportProductItem) ([]*domain.ProductMaterial, error) {
productCodes := ptr.GetProductCodesByImportItems(list)
if len(productCodes) == 0 {
return []*domain.ProductMaterial{}, nil
}
return ptr.GetProductMaterialByProductCodes(companyId, productCodes)
}
func (ptr *PGBatchAddProductService) GetProductCodesByImportItems(list []*domain.ImportProductItem) []string {
var result = utils.NewSet()
for _, v := range list {
result.Add(v.ProductCode)
}
return result.KeysStr()
}
func NewPGBatchAddProductService(transactionContext *pgTransaction.TransactionContext) (*PGBatchAddProductService, error) {
if transactionContext == nil {
return nil, fmt.Errorf("transactionContext参数不能为nil")
... ...
... ... @@ -157,6 +157,9 @@ func (repository *ProductMaterialRepository) Find(queryOptions map[string]interf
if v, ok := queryOptions["productMaterialIds"]; ok && len(v.([]int)) > 0 {
query.Where("product_material_id in (?)", pg.In(v))
}
if v, ok := queryOptions["materialNumbers"]; ok && len(v.([]string)) > 0 {
query.Where("material_number in (?)", pg.In(v))
}
query.SetOffsetAndLimit(domain.MaxQueryRow)
query.SetOrderDirect("product_material_id", "DESC")
if count, err := query.SelectAndCount(); err != nil {
... ...
... ... @@ -19,7 +19,7 @@ func (controller *ProductController) CreateProduct() {
op := ParseOperateInfo(controller.BaseController)
createProductCommand.CompanyId = op.CompanyId
createProductCommand.OrgId = op.OrgId
data, err := productService.CreateProduct(createProductCommand)
data, err := productService.CreateProduct(ParseOperateInfo(controller.BaseController), createProductCommand)
controller.Response(data, err)
}
... ... @@ -29,7 +29,7 @@ func (controller *ProductController) UpdateProduct() {
Must(controller.Unmarshal(updateProductCommand))
productId, _ := controller.GetInt(":productId")
updateProductCommand.ProductId = productId
data, err := productService.UpdateProduct(updateProductCommand)
data, err := productService.UpdateProduct(ParseOperateInfo(controller.BaseController), updateProductCommand)
controller.Response(data, err)
}
... ...