liyong
2026-04-23 accb86943163e6224d4ef9a3418ad4f4cf830160
feat(production): 添加工艺路线反向新增功能

- 新增 ProcessRouteAnticlockwiseDto 数据传输对象
- 在 ProcessRouteItem 和 ProductProcessRouteItem 中添加工序相关字段
- 实现工艺路线反向新增方法,支持 BOM、工艺路线及其子表的批量创建
- 新增产品规格型号反向新增功能,支持销售 ledger 中的产品数据处理
- 添加数据库查询方法用于查找已有产品规格型号
- 更新销售 ledger 服务以集成反向新增逻辑
已添加1个文件
已修改9个文件
318 ■■■■■ 文件已修改
src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/IProductModelService.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProcessRouteAnticlockwiseDto.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProcessRouteItem.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductProcessRouteItem.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductStructure.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProcessRouteServiceImpl.java 183 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/ProductModelMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java
@@ -29,4 +29,6 @@
    List<Map<String, Object>> getProductAndModelList();
    List<ProductModel> selectModelListByProductIds(@NotNull @Param("ids") List<Long> ids);
    ProductModel selectOldProductModel(@Param("model") String model, @Param("productName") String productName);
}
src/main/java/com/ruoyi/basic/service/IProductModelService.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.basic.dto.ProductDto;
import com.ruoyi.basic.dto.ProductModelAnticlockwiseDto;
import com.ruoyi.basic.dto.ProductModelDto;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.framework.web.domain.AjaxResult;
@@ -28,13 +29,17 @@
    List<ProductModel> selectModelListByProductIds(List<Long> ids);
    Long productModelAnticlockwise(ProductModelAnticlockwiseDto productModelDto);
    /**
     * æ ¹æ®id查询产品规格分页查询
     *
     * @param page
     * @param productDto
     * @return
     */
    IPage<ProductModel> modelListPage(Page page , ProductDto productDto);
    IPage<ProductModel> modelListPage(Page page, ProductDto productDto);
    AjaxResult importProductModel(MultipartFile file, Integer productId);
}
src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
@@ -16,6 +16,7 @@
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.basic.service.IProductModelService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -165,9 +166,40 @@
        }
    }
    public Boolean checkProductModelExist(ProductModelAnticlockwiseDto productModelDto, String uuid) {
    //反向新增成品产品,只有销售关联新增的时候调用
    @Override
    public Long productModelAnticlockwise(ProductModelAnticlockwiseDto productModelDto) {
        ProductModel oldProductModel = productModelMapper.selectOldProductModel(productModelDto.getModel(), productModelDto.getProductName());
        //存在就更新
        if (oldProductModel != null) {
            oldProductModel.setModel(productModelDto.getModel());
            oldProductModel.setUnit(productModelDto.getUnit());
            oldProductModel.setSubUnit(productModelDto.getSubUnit());
            oldProductModel.setDeptId(SecurityUtils.getDeptId()[0]);
            productModelMapper.updateById(oldProductModel);
            Product product = productMapper.selectById(oldProductModel.getProductId());
            product.setProductName(productModelDto.getProductName());
            productMapper.updateById(product);
            return oldProductModel.getId();
        }else {
            //找到父节点
            Product productParent = productMapper.selectOne(new QueryWrapper<Product>().lambda().eq(Product::getProductName, "成品").last("limit 1"));
            //新增产品大类
            Product product = new Product();
            product.setProductName(productModelDto.getProductName());
            product.setParentId(productParent.getId());
            product.setDeptId(SecurityUtils.getDeptId()[0]);
            productMapper.insert( product);
            //新增产品规格
            ProductModel productModel = new ProductModel();
            productModel.setProductId(product.getId());
            productModel.setModel(productModelDto.getModel());
            productModel.setUnit(productModelDto.getUnit());
            productModel.setSubUnit(productModelDto.getSubUnit());
            productModel.setDeptId(SecurityUtils.getDeptId()[0]);
            productModelMapper.insert(productModel);
            return productModel.getId();
        return true;
        }
    }
}
src/main/java/com/ruoyi/production/dto/ProcessRouteAnticlockwiseDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.production.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class ProcessRouteAnticlockwiseDto {
    //工序id
    private Long processId;
    //工序名称
    private String processRouteName;
    //工序开数
    private BigDecimal processRouteOpenNum;
    //工艺正数
    private BigDecimal processRouteNum;
    //加放数
    private BigDecimal processRouteAddNum;
    //工艺要求
    private String processRouteRequire;
    private Long productModelId;
}
src/main/java/com/ruoyi/production/pojo/ProcessRouteItem.java
@@ -5,6 +5,7 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@@ -48,4 +49,15 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    //工序名称
    private String processRouteName;
    //工序开数
    private BigDecimal processRouteOpenNum;
    //工艺正数
    private BigDecimal processRouteNum;
    //加放数
    private BigDecimal processRouteAddNum;
    //工艺要求
    private String processRouteRequire;
}
src/main/java/com/ruoyi/production/pojo/ProductProcessRouteItem.java
@@ -4,6 +4,7 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@@ -48,4 +49,15 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    //工序名称
    private String processRouteName;
    //工序开数
    private BigDecimal processRouteOpenNum;
    //工艺正数
    private BigDecimal processRouteNum;
    //加放数
    private BigDecimal processRouteAddNum;
    //工艺要求
    private String processRouteRequire;
}
src/main/java/com/ruoyi/production/pojo/ProductStructure.java
@@ -64,4 +64,15 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    //工序名称
    private String processRouteName;
    //工序开数
    private BigDecimal processRouteOpenNum;
    //工艺正数
    private BigDecimal processRouteNum;
    //加放数
    private BigDecimal processRouteAddNum;
    //工艺要求
    private String processRouteRequire;
}
src/main/java/com/ruoyi/production/service/impl/ProcessRouteServiceImpl.java
@@ -4,16 +4,13 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.production.dto.ProcessRouteAnticlockwiseDto;
import com.ruoyi.production.dto.ProcessRouteDto;
import com.ruoyi.production.mapper.ProcessRouteItemMapper;
import com.ruoyi.production.mapper.ProcessRouteMapper;
import com.ruoyi.production.mapper.ProductOrderMapper;
import com.ruoyi.production.mapper.ProductProcessRouteMapper;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProcessRouteItem;
import com.ruoyi.production.pojo.ProductOrder;
import com.ruoyi.production.pojo.ProductProcessRoute;
import com.ruoyi.production.service.ProcessRouteService;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -22,7 +19,7 @@
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
@Service
@@ -38,6 +35,22 @@
    @Autowired
    private ProductOrderMapper productOrderMapper;
    @Autowired
    private ProductStructureService productStructureService;
    @Autowired
    private ProcessRouteItemService processRouteItemService;
    @Autowired
    private ProductWorkOrderService productWorkOrderService;
    @Autowired
    private ProductBomService productBomService;
    @Autowired
    private ProductProcessRouteService productProcessRouteService;
    @Autowired
    private ProductProcessRouteItemService productProcessRouteItemService;
    @Autowired
    private ProductOrderService productOrderService;
    @Autowired
    private ProductProcessService productProcessService;
    @Override
    public IPage<ProcessRouteDto> pageProcessRouteDto(Page<ProcessRouteDto> page, ProcessRouteDto processRouteDto) {
@@ -60,11 +73,165 @@
    public int batchDelete(List<Long> ids) {
        //先判断是否已经引用了
        List<ProductOrder> productOrders = productOrderMapper.selectList(Wrappers.<ProductOrder>lambdaQuery().in(ProductOrder::getRouteId, ids));
        if (productOrders.size()>0){
        if (productOrders.size() > 0) {
            throw new RuntimeException("该工艺路线生产已引用,不能删除");
        }
        //删除工艺路线详情
        processRouteItemMapper.delete(Wrappers.<ProcessRouteItem>lambdaQuery().in(ProcessRouteItem::getRouteId, ids));
        return processRouteMapper.deleteBatchIds(ids);
    }
    /**
     * å·¥è‰ºè·¯çº¿åå‘新增  åªæ–°å¢žäº†bom bom子表  å·¥è‰ºè·¯çº¿  å·¥è‰ºè·¯çº¿å­è¡¨
     * @param processRouteAnticlockwiseDtos  å·¥è‰ºå­è¡¨
     * @param productModelId æˆå“è§„格型号id
     * @param productOrderId ç”Ÿäº§è®¢å•id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Long processRouteAnticlockwise(List<ProcessRouteAnticlockwiseDto> processRouteAnticlockwiseDtos, Long productModelId, Long productOrderId) {
        ProductOrder byId = productOrderService.getById(productOrderId);
        // 1. æ–°å¢žBOM
        ProductBom productBom = createProductBom(productModelId);
        // 2. æ–°å¢žBOM子表
        List<ProductStructure> productStructures = buildProductStructures(processRouteAnticlockwiseDtos, productBom.getId());
        productStructureService.saveBatch(productStructures);
        // 3. æ–°å¢žå·¥è‰ºè·¯çº¿
        ProcessRoute processRoute = createProcessRoute(productModelId, productBom.getId());
        // 4. æ–°å¢žå·¥è‰ºè·¯çº¿å­è¡¨
        List<ProcessRouteItem> processRouteItems = buildProcessRouteItems(processRouteAnticlockwiseDtos, processRoute.getId(), productModelId);
        processRouteItemService.saveBatch(processRouteItems);
//        // 5. æ–°å¢žç”Ÿäº§å·¥è‰ºè·¯çº¿
//        ProductProcessRoute productProcessRoute = createProductProcessRoute(productModelId, productOrderId, productBom.getId(), processRoute.getProcessRouteCode());
//
//        // 6. æ–°å¢žç”Ÿäº§å·¥è‰ºè·¯çº¿å­è¡¨
//        List<ProductProcessRouteItem> productProcessRouteItems = buildProductProcessRouteItems(processRouteAnticlockwiseDtos, productProcessRoute.getId(), productModelId);
//        productProcessRouteItemService.saveBatch(productProcessRouteItems);
//        for (ProductProcessRouteItem item : productProcessRouteItems) {
//            ProductProcess productProcess = productProcessService.getById(item.getProcessId());
//            ProductWorkOrder productWorkOrder = new ProductWorkOrder();
//            productWorkOrder.setProductProcessRouteItemId(item.getId());
//            productWorkOrder.setProductOrderId(productOrderId);
//            ProductOrder order = productOrderMapper.selectById(productOrderId);
//            productWorkOrder.setPlanQuantity(order.getQuantity());
//            productWorkOrder.setWorkOrderNo(productWorkOrderService.generateProductWorkOrder(null, productProcess.getName(), byId.getNpsNo()));
//            productWorkOrder.setStatus(1);
//            productWorkOrderService.save(productWorkOrder);
//        }
        return processRoute.getId();
    }
    /**
     * åˆ›å»ºäº§å“BOM
     */
    private ProductBom createProductBom(Long productModelId) {
        ProductBom productBom = new ProductBom();
        productBom.setProductModelId(productModelId);
        productBom.setVersion("1.0.0");
        productBomService.save(productBom);
        productBom.setBomNo("BM." + String.format("%05d", productBom.getId()));
        productBomService.updateById(productBom);
        return productBom;
    }
    /**
     * æž„建产品结构列表
     */
    private List<ProductStructure> buildProductStructures(List<ProcessRouteAnticlockwiseDto> dtos, Integer bomId) {
        List<ProductStructure> structures = new ArrayList<>(dtos.size());
        for (ProcessRouteAnticlockwiseDto dto : dtos) {
            ProductStructure structure = new ProductStructure();
            structure.setProductModelId(dto.getProductModelId());
            structure.setProcessId(dto.getProcessId());
            structure.setProcessRouteOpenNum(dto.getProcessRouteOpenNum());
            structure.setProcessRouteNum(dto.getProcessRouteNum());
            structure.setProcessRouteAddNum(dto.getProcessRouteAddNum());
            structure.setProcessRouteRequire(dto.getProcessRouteRequire());
            structure.setBomId(bomId);
            structure.setProcessRouteName(dto.getProcessRouteName());
            structures.add(structure);
        }
        return structures;
    }
    /**
     * åˆ›å»ºå·¥è‰ºè·¯çº¿
     */
    private ProcessRoute createProcessRoute(Long productModelId, Integer bomId) {
        ProcessRoute processRoute = new ProcessRoute();
        processRoute.setProductModelId(productModelId);
        processRoute.setBomId(bomId);
        processRoute.setDescription("");
        this.save(processRoute);
        processRoute.setProcessRouteCode("GYLX." + String.format("%05d", processRoute.getId()));
        this.updateById(processRoute);
        return processRoute;
    }
    /**
     * æž„建工艺路线子项列表
     */
    private List<ProcessRouteItem> buildProcessRouteItems(List<ProcessRouteAnticlockwiseDto> dtos, Long routeId, Long productModelId) {
        List<ProcessRouteItem> items = new ArrayList<>(dtos.size());
        for (ProcessRouteAnticlockwiseDto dto : dtos) {
            ProcessRouteItem item = new ProcessRouteItem();
            item.setRouteId(routeId);
            item.setProcessId(dto.getProcessId());
            item.setProductModelId(dto.getProductModelId());
            item.setProcessRouteName(dto.getProcessRouteName());
            item.setProcessRouteOpenNum(dto.getProcessRouteOpenNum());
            item.setProcessRouteNum(dto.getProcessRouteNum());
            item.setProcessRouteAddNum(dto.getProcessRouteAddNum());
            item.setProcessRouteRequire(dto.getProcessRouteRequire());
            items.add(item);
        }
        return items;
    }
    /**
     * åˆ›å»ºç”Ÿäº§å·¥è‰ºè·¯çº¿
     */
    private ProductProcessRoute createProductProcessRoute(Long productModelId, Long productOrderId, Integer bomId, String processRouteCode) {
        ProductProcessRoute productProcessRoute = new ProductProcessRoute();
        productProcessRoute.setProductModelId(productModelId);
        productProcessRoute.setProductOrderId(productOrderId);
        productProcessRoute.setBomId(bomId);
        productProcessRoute.setProcessRouteCode(processRouteCode);
        productProcessRouteService.save(productProcessRoute);
        return productProcessRoute;
    }
    /**
     * æž„建生产工艺路线子项列表
     */
    private List<ProductProcessRouteItem> buildProductProcessRouteItems(List<ProcessRouteAnticlockwiseDto> dtos, Long productRouteId, Long productModelId) {
        List<ProductProcessRouteItem> items = new ArrayList<>(dtos.size());
        for (ProcessRouteAnticlockwiseDto dto : dtos) {
            ProductProcessRouteItem item = new ProductProcessRouteItem();
            item.setProductRouteId(productRouteId);
            item.setProcessId(dto.getProcessId());
            item.setProductModelId(dto.getProductModelId());
            item.setProcessRouteName(dto.getProcessRouteName());
            item.setProcessRouteOpenNum(dto.getProcessRouteOpenNum());
            item.setProcessRouteNum(dto.getProcessRouteNum());
            item.setProcessRouteAddNum(dto.getProcessRouteAddNum());
            item.setProcessRouteRequire(dto.getProcessRouteRequire());
            items.add(item);
        }
        return items;
    }
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -19,12 +19,13 @@
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.ruoyi.account.service.AccountIncomeService;
import com.ruoyi.basic.dto.CustomerPrivatePoolDto;
import com.ruoyi.basic.dto.ProductModelAnticlockwiseDto;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.mapper.CustomerPrivatePoolMapper;
import com.ruoyi.basic.mapper.ProductMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.CustomerPrivatePool;
import com.ruoyi.basic.service.IProductModelService;
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.enums.SaleEnum;
import com.ruoyi.common.exception.base.BaseException;
@@ -37,13 +38,12 @@
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.other.mapper.TempFileMapper;
import com.ruoyi.other.pojo.TempFile;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.mapper.ProductStructureMapper;
import com.ruoyi.production.service.ProductionProductMainService;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysDeptMapper;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.sales.dto.*;
import com.ruoyi.sales.mapper.*;
import com.ruoyi.sales.pojo.*;
@@ -134,6 +134,8 @@
    private SysUserMapper sysUserMapper;
    @Autowired
    private CustomerPrivatePoolMapper customerPrivatePoolMapper;
    @Autowired
    private IProductModelService productModelService;
    @Override
    public List<SalesLedger> selectSalesLedgerList(SalesLedgerDto salesLedgerDto) {
@@ -676,12 +678,13 @@
            SalesLedger salesLedger = convertToEntity(salesLedgerDto);
            salesLedger.setCustomerName(customer.getCustomerName());
            salesLedger.setTenantId(customer.getTenantId());
            // 3. æ–°å¢žæˆ–更新主表
            if (salesLedger.getId() == null) {
                // ä¸ºç©º è‡ªåŠ¨ç”Ÿæˆ
                String contractNo =StrUtil.isBlank(salesLedgerDto.getSalesContractNo())? generateSalesContractNoBy8Date():salesLedgerDto.getSalesContractNo();
                // ä¸èƒ½æœ‰é‡å¤æ•°æ®çš„合同号
               Assert.isFalse(salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>()
               Assert.isTrue(salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>()
                        .eq(SalesLedger::getSalesContractNo, contractNo)
                        .last("limit 1")) == null, contractNo+"合同号已存在");
                salesLedger.setSalesContractNo(contractNo);
@@ -693,6 +696,18 @@
            // 4. å¤„理子表数据
            List<SalesLedgerProduct> productList = salesLedgerDto.getProductData();
            for (SalesLedgerProduct product : productList) {
                //空的先新增基础数据  éžç©ºç›´æŽ¥å¾€ä¸‹èµ°
                if (ObjectUtils.isEmpty(product.getProductModelId())) {
                    ProductModelAnticlockwiseDto  productModelAnticlockwiseDto =  new ProductModelAnticlockwiseDto();
                    productModelAnticlockwiseDto.setModel(product.getSpecificationModel());
                    productModelAnticlockwiseDto.setProductName(product.getProductCategory());
                    productModelAnticlockwiseDto.setUnit(product.getUnit());
                    productModelAnticlockwiseDto.setSubUnit(product.getUnit());
                    Long productModelId = productModelService.productModelAnticlockwise(productModelAnticlockwiseDto);
                    product.setProductModelId(productModelId);
                }
            }
            if (productList != null && !productList.isEmpty()) {
                handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class, salesLedgerDto.getType()));
                updateMainContractAmount(
src/main/resources/mapper/basic/ProductModelMapper.xml
@@ -125,4 +125,10 @@
        INNER JOIN product t2 ON t1.product_id = t2.id
        INNER JOIN tree t ON t2.id = t.id;
    </select>
    <select id="selectOldProductModel" resultType="com.ruoyi.basic.pojo.ProductModel">
        select * from product_model left join
            product on product_model.product_id = product.id
        where product_model.model = #{model}
        and product.product_name = #{productName}
    </select>
</mapper>