src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java
@@ -85,9 +85,16 @@ @Override public Boolean updateApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto) { // 检查模板是否被审批实例引用 if (isTemplateReferenced(approvalTemplateDto.getId())) { throw new RuntimeException("该审批模板已被审批流程引用,无法编辑"); ApprovalTemplate existingTemplate = approvalTemplateMapper.selectById(approvalTemplateDto.getId()); if (existingTemplate == null) { throw new IllegalArgumentException("模板不存在"); } // 启用中的模板只能修改启用状态,其他项需先停用后再编辑 if (existingTemplate.getEnabled() != null && existingTemplate.getEnabled() == 1) { ApprovalTemplate updateEntity = new ApprovalTemplate(); updateEntity.setId(approvalTemplateDto.getId()); updateEntity.setEnabled(approvalTemplateDto.getEnabled()); return approvalTemplateMapper.updateById(updateEntity) > 0; } approvalTemplateMapper.updateById(approvalTemplateDto); approvalTemplateNodeService.remove( src/main/java/com/ruoyi/basic/service/IProductService.java
@@ -20,4 +20,11 @@ List<ProductTreeDto> selectProductList(ProductDto productDto); IPage<ProductModelVo> listPageProductModel(Page<ProductModelVo> page, ProductModel productModel); /** * 台账手工录入品名/材质/规格型号时,自动注册产品大类(品名)-子类(材质)-规格型号,已存在则复用 * * @return 规格型号记录,未注册时返回 null */ ProductModel ensureProductHierarchy(String productName, String material, String modelName, String unit); } src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
@@ -55,7 +55,8 @@ String productCode = StringUtils.trim(productModelDto.getProductCode()); productModelDto.setModel(model); productModelDto.setProductCode(productCode); checkModelAndProductCodeUnique(model, productCode, productModelDto.getId()); // 产品编号非必填,规格型号在同一产品下唯一 checkModelUnique(productModelDto.getProductId(), model, productModelDto.getId()); if (productModelDto.getId() == null) { ProductModel productModel = new ProductModel(); @@ -66,18 +67,18 @@ } } private void checkModelAndProductCodeUnique(String model, String productCode, Long currentId) { if (StringUtils.isEmpty(model) || StringUtils.isEmpty(productCode)) { private void checkModelUnique(Long productId, String model, Long currentId) { if (StringUtils.isEmpty(model)) { return; } LambdaQueryWrapper<ProductModel> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(ProductModel::getModel, model) .eq(ProductModel::getProductCode, productCode) queryWrapper.eq(ProductModel::getProductId, productId) .eq(ProductModel::getModel, model) .ne(currentId != null, ProductModel::getId, currentId) .last("limit 1"); ProductModel duplicateProductModel = productModelMapper.selectOne(queryWrapper); if (duplicateProductModel != null) { throw new ServiceException("对应的型号" + model + "的产品编码" + productCode + "已经存在"); throw new ServiceException("对应的型号" + model + "已经存在"); } } src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
@@ -89,21 +89,27 @@ @Override public int addOrEditProduct(ProductDto productDto) { if (ObjectUtils.isEmpty(productDto.getParentId())) { throw new IllegalArgumentException("请选择父节点"); } String productName = StringUtils.trim(productDto.getProductName()); if (StringUtils.isEmpty(productName)) { throw new IllegalArgumentException("产品名称不能为空"); } // 父节点为空表示新增一级大类 if (ObjectUtils.isEmpty(productDto.getParentId())) { if (productDto.getId() != null) { throw new IllegalArgumentException("请选择父节点"); } productDto.setParentId(null); } productDto.setProductName(productName); checkProductNameUnique(productDto.getParentId(), productName, productDto.getId()); if (productDto.getId() == null) { // 新增产品逻辑 // 检查父节点是否存在(可选,根据业务需求) Product parent = productMapper.selectById(productDto.getParentId()); if (parent == null) { throw new IllegalArgumentException("父节点不存在,无法添加子产品"); // 检查父节点是否存在(一级大类无父节点) if (productDto.getParentId() != null) { Product parent = productMapper.selectById(productDto.getParentId()); if (parent == null) { throw new IllegalArgumentException("父节点不存在,无法添加子产品"); } } return productMapper.insert(productDto); } else { @@ -119,8 +125,12 @@ private void checkProductNameUnique(Long parentId, String productName, Long currentId) { LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Product::getParentId, parentId) .eq(Product::getProductName, productName) if (parentId == null) { queryWrapper.isNull(Product::getParentId); } else { queryWrapper.eq(Product::getParentId, parentId); } queryWrapper.eq(Product::getProductName, productName) .ne(currentId != null, Product::getId, currentId) .last("limit 1"); Product duplicateProduct = productMapper.selectOne(queryWrapper); @@ -131,6 +141,26 @@ @Override public int delProductByIds(Long[] ids) { // 存在子类时不允许删除 LambdaQueryWrapper<Product> childWrapper = new LambdaQueryWrapper<>(); childWrapper.in(Product::getParentId, ids).last("limit 1"); Product childProduct = productMapper.selectOne(childWrapper); if (childProduct != null) { throw new IllegalArgumentException("该大类下存在子类,不能删除"); } // 大类下存在规格型号数据时不允许删除 for (Product product : productMapper.selectBatchIds(Arrays.asList(ids))) { if (product.getParentId() != null) { continue; } LambdaQueryWrapper<ProductModel> modelWrapper = new LambdaQueryWrapper<>(); modelWrapper.eq(ProductModel::getProductId, product.getId()).last("limit 1"); if (productModelMapper.selectOne(modelWrapper) != null) { throw new IllegalArgumentException("该大类下存在数据,不能删除"); } } // 1. 删除子表 product_model 中关联的数据 LambdaQueryWrapper<ProductModel> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(ProductModel::getProductId, ids); @@ -142,4 +172,54 @@ return deleteCount; } @Override public ProductModel ensureProductHierarchy(String productName, String material, String modelName, String unit) { productName = StringUtils.trim(productName); material = StringUtils.trim(material); modelName = StringUtils.trim(modelName); if (StringUtils.isEmpty(productName) || StringUtils.isEmpty(material) || StringUtils.isEmpty(modelName)) { return null; } // 品名:一级大类(parentId 为空) LambdaQueryWrapper<Product> categoryWrapper = new LambdaQueryWrapper<>(); categoryWrapper.isNull(Product::getParentId) .eq(Product::getProductName, productName) .last("limit 1"); Product category = productMapper.selectOne(categoryWrapper); if (category == null) { category = new Product(); category.setProductName(productName); productMapper.insert(category); } // 材质:大类下的子类 LambdaQueryWrapper<Product> materialWrapper = new LambdaQueryWrapper<>(); materialWrapper.eq(Product::getParentId, category.getId()) .eq(Product::getProductName, material) .last("limit 1"); Product materialProduct = productMapper.selectOne(materialWrapper); if (materialProduct == null) { materialProduct = new Product(); materialProduct.setParentId(category.getId()); materialProduct.setProductName(material); productMapper.insert(materialProduct); } // 规格型号:子类下的规格 LambdaQueryWrapper<ProductModel> modelWrapper = new LambdaQueryWrapper<>(); modelWrapper.eq(ProductModel::getProductId, materialProduct.getId()) .eq(ProductModel::getModel, modelName) .last("limit 1"); ProductModel productModel = productModelMapper.selectOne(modelWrapper); if (productModel == null) { productModel = new ProductModel(); productModel.setProductId(materialProduct.getId()); productModel.setModel(modelName); productModel.setUnit(unit); productModelMapper.insert(productModel); } return productModel; } } src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -22,6 +22,7 @@ import com.ruoyi.basic.pojo.Product; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.basic.pojo.SupplierManage; import com.ruoyi.basic.service.IProductService; import com.ruoyi.basic.utils.FileUtil; import com.ruoyi.common.enums.ApprovalStatusEnum; import com.ruoyi.common.enums.ReviewStatusEnum; @@ -103,6 +104,7 @@ private final SupplierManageMapper supplierManageMapper; private final ProductMapper productMapper; private final ProductModelMapper productModelMapper; private final IProductService productService; private final SysUserMapper sysUserMapper; private final StringRedisTemplate redisTemplate; private final QualityInspectMapper qualityInspectMapper; @@ -631,6 +633,11 @@ } Integer ledgerType = type == null ? 2 : type; // 手工录入「品名+材质+规格型号」时,自动注册到产品维护 for (SalesLedgerProduct product : products) { registerProductFromLedgerProduct(product); } // 提前收集所有需要查询的ID Set<Long> productIds = products.stream() .map(SalesLedgerProduct::getProductId) @@ -658,6 +665,11 @@ // 设置字段 for (SalesLedgerProduct product : products) { product.setSalesLedgerId(salesLedgerId); // 手工录入品名/材质/规格型号的行已在注册时写入,不再用产品树节点名称覆盖 if (StringUtils.isNotEmpty(product.getMaterial())) { continue; } Long productId = product.getProductId(); if (productId != null && productMap.containsKey(productId)) { @@ -710,6 +722,28 @@ } } /** * 手工录入「品名+材质+规格型号」时,在产品维护自动注册: * 品名=一级大类,材质=大类下的子类,规格型号=子类下的规格 */ private void registerProductFromLedgerProduct(SalesLedgerProduct product) { String productName = StringUtils.trim(product.getProductCategory()); String material = StringUtils.trim(product.getMaterial()); String modelName = StringUtils.trim(product.getSpecificationModel()); if (StringUtils.isEmpty(productName) || StringUtils.isEmpty(material) || StringUtils.isEmpty(modelName)) { return; } product.setProductCategory(productName); product.setMaterial(material); product.setSpecificationModel(modelName); ProductModel productModel = productService.ensureProductHierarchy(productName, material, modelName, product.getUnit()); if (productModel != null) { product.setProductId(productModel.getProductId()); product.setProductModelId(productModel.getId()); } } @Override @Transactional(rollbackFor = Exception.class) public int deletePurchaseLedgerByIds(Long[] ids) { src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -44,12 +44,18 @@ private BigDecimal warnNum; /** * 产品大类 * 产品大类(品名) */ @Excel(name = "产品大类") private String productCategory; /** * 材质 */ @Excel(name = "材质") private String material; /** * 规格型号 */ @Excel(name = "规格型号") src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.basic.service.IProductService; import com.ruoyi.framework.web.domain.R; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.production.mapper.*; @@ -26,6 +28,7 @@ import com.ruoyi.technology.mapper.TechnologyRoutingMapper; import com.ruoyi.technology.pojo.TechnologyRouting; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -86,6 +89,8 @@ private StockUtils stockUtils; @Autowired private StockInventoryMapper stockInventoryMapper; @Autowired private IProductService productService; @Override public SalesLedgerProduct selectSalesLedgerProductById(Long id) { @@ -178,6 +183,20 @@ @Transactional(rollbackFor = Exception.class) public int addOrUpdateSalesLedgerProduct(SalesLedgerProduct salesLedgerProduct) { // 采购台账(type=2)手工录入品名/材质/规格型号时,自动注册到产品维护 if (Integer.valueOf(2).equals(salesLedgerProduct.getType()) && StringUtils.isNotBlank(salesLedgerProduct.getMaterial())) { ProductModel productModel = productService.ensureProductHierarchy( salesLedgerProduct.getProductCategory(), salesLedgerProduct.getMaterial(), salesLedgerProduct.getSpecificationModel(), salesLedgerProduct.getUnit()); if (productModel != null) { salesLedgerProduct.setProductId(productModel.getProductId()); salesLedgerProduct.setProductModelId(productModel.getId()); } } int result; Long salesLedgerId = salesLedgerProduct.getSalesLedgerId(); if (salesLedgerProduct.getId() == null) { src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -26,9 +26,10 @@ T1.is_production, T1.create_user, T1.dept_id, p.product_name as product_category, pm.model as specification_model, pm.unit as unit, COALESCE(NULLIF(T1.product_category, ''), p.product_name) as product_category, T1.material, COALESCE(NULLIF(T1.specification_model, ''), pm.model) as specification_model, COALESCE(NULLIF(T1.unit, ''), pm.unit) as unit, CASE WHEN (IFNULL(t2.qualitity, 0) - IFNULL(t2.locked_quantity, 0)) >0 THEN 1 ELSE 0