liyong
昨天 6248c3f2d94debc1633cfcc66496263cef8b18b3
feat(production): 新增生产订单功能并优化工单号生成逻辑
已修改10个文件
230 ■■■■ 文件已修改
src/main/java/com/ruoyi/production/controller/ProductOrderController.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductWorkOrderMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductOrderService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteItemServiceImpl.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductOrderMapper.xml 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductWorkOrderMapper.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductOrderController.java
@@ -87,4 +87,15 @@
    }
    @ApiOperation("新增生产订单")
    @PostMapping("addProductOrder")
    public R addProductOrder(@RequestBody ProductOrder productOrder) {
        return R.ok(productOrderService.addProductOrder(productOrder));
    }
    @ApiOperation("删除生产订单")
    @DeleteMapping("/{ids}")
    public R delete(@PathVariable("ids") Long[] ids) {
        return R.ok(productOrderService.delete(ids));
    }
}
src/main/java/com/ruoyi/production/mapper/ProductWorkOrderMapper.java
@@ -20,4 +20,6 @@
    ProductWorkOrderDto getProductWorkOrderFlowCard(@Param("id") Long id);
    List<ProductWorkOrderDto> selectWorkOrderStartStats(@Param("startDate") String startDate, @Param("endDate") String endDate);
    ProductWorkOrder selectMax(@Param("datePrefix") String datePrefix);
}
src/main/java/com/ruoyi/production/service/ProductOrderService.java
@@ -21,4 +21,8 @@
    List<ProcessRoute> listProcessRoute(Long productModelId);
    List<ProductStructureDto> listProcessBom(Long orderId);
    Boolean addProductOrder(ProductOrder productOrder);
    Boolean delete(Long[] id);
}
src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
@@ -1,9 +1,14 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.enums.StockQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockUnQualifiedRecordTypeEnum;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.production.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.dto.ProductStructureDto;
@@ -11,12 +16,16 @@
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProcessRouteService;
import com.ruoyi.production.service.ProductOrderService;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, ProductOrder> implements ProductOrderService {
@@ -39,6 +48,23 @@
    @Autowired
    private ProductWorkOrderMapper productWorkOrderMapper;
    @Autowired
    private ProductionProductMainMapper productionProductMainMapper;
    @Autowired
    private ProductionProductOutputMapper productionProductOutputMapper;
    @Autowired
    private ProductionProductInputMapper productionProductInputMapper;
    @Autowired
    private QualityInspectMapper qualityInspectMapper;
    @Autowired
    private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
    @Autowired
    private StockUtils stockUtils;
    @Override
    public IPage<ProductOrderDto> pageProductOrder(Page page, ProductOrderDto productOrder) {
@@ -69,11 +95,7 @@
            int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
            if (insert > 0) {
                // 查询今日已存在的最大工单号
                QueryWrapper<ProductWorkOrder> queryWrapper = new QueryWrapper<>();
                queryWrapper.likeRight("work_order_no", datePrefix)
                        .orderByDesc("work_order_no")
                        .last("LIMIT 1");
                ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectOne(queryWrapper);
                ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectMax(datePrefix);
                int sequenceNumber = 1; // 默认序号
                if (lastWorkOrder != null && lastWorkOrder.getWorkOrderNo() != null) {
                    String lastNo = lastWorkOrder.getWorkOrderNo().toString();
@@ -110,4 +132,139 @@
    public List<ProductStructureDto> listProcessBom(Long orderId) {
        return productOrderMapper.listProcessBom(orderId);
    }
    @Override
    public Boolean addProductOrder(ProductOrder productOrder) {
        String string = generateNextOrderNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        productOrder.setNpsNo(string);
        productOrder.setCompleteQuantity(BigDecimal.ZERO);
        this.save(productOrder);
        if (ObjectUtils.isNotEmpty(productOrder.getRouteId())) {
            this.bindingRoute(productOrder);
        }
        return true;
    }
    @Override
    public Boolean delete(Long[] ids) {
        //批量查询productOrder
        List<ProductOrder> productOrders = productOrderMapper.selectList(
                new LambdaQueryWrapper<ProductOrder>()
                        .in(ProductOrder::getId, ids)
        );
        if (!org.springframework.util.CollectionUtils.isEmpty(productOrders)) {
            // 批量查询processRouteItems
            List<ProductProcessRouteItem> allRouteItems = productProcessRouteItemMapper.selectList(
                    new LambdaQueryWrapper<ProductProcessRouteItem>()
                            .in(ProductProcessRouteItem::getProductOrderId, ids)
            );
            if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(allRouteItems)) {
                // 获取要删除的工序项ID
                List<Long> routeItemIds = allRouteItems.stream()
                        .map(ProductProcessRouteItem::getId)
                        .collect(Collectors.toList());
                // 查询关联的工单ID
                List<ProductWorkOrder> workOrders = productWorkOrderMapper.selectList(
                        new LambdaQueryWrapper<ProductWorkOrder>()
                                .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds)
                );
                if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(workOrders)) {
                    List<Long> workOrderIds = workOrders.stream()
                            .map(ProductWorkOrder::getId)
                            .collect(Collectors.toList());
                    // 查询关联的生产主表ID
                    List<ProductionProductMain> productMains = productionProductMainMapper.selectList(
                            new LambdaQueryWrapper<ProductionProductMain>()
                                    .in(ProductionProductMain::getWorkOrderId, workOrderIds)
                    );
                    List<Long> productMainIds = productMains.stream()
                            .map(ProductionProductMain::getId)
                            .collect(Collectors.toList());
                    // 删除产出表、投入表数据
                    if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(productMainIds)) {
                        productionProductOutputMapper.deleteByProductMainIds(productMainIds);
                        productionProductInputMapper.deleteByProductMainIds(productMainIds);
                        List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
                                new LambdaQueryWrapper<QualityInspect>()
                                        .in(QualityInspect::getProductMainId, productMainIds)
                        );
                        //删除出库记录
                        for (Long productMainId : productMainIds) {
                            //删除生产出库记录
                            stockUtils.deleteStockOutRecord(productMainId, StockQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
                            //删除报废的入库记录
                            stockUtils.deleteStockInRecord(productMainId, StockUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
                        }
                        qualityInspects.forEach(qualityInspect -> {
                            //inspectState=1 已提交 不能删除
                            if (qualityInspect.getInspectState() == 1) {
                                throw new RuntimeException("已提交的检验单不能删除");
                            }
                        });
                        qualityInspectMapper.deleteByProductMainIds(productMainIds);
                        salesLedgerProductionAccountingMapper.delete(new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
                                .in(SalesLedgerProductionAccounting::getProductMainId, productMainIds));
                    }
                    // 删除生产主表数据
                    productionProductMainMapper.deleteByWorkOrderIds(workOrderIds);
                    // 删除工单数据
                    productWorkOrderMapper.delete(new LambdaQueryWrapper<ProductWorkOrder>()
                            .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds));
                }
            }
            // 批量删除processRouteItem
            productProcessRouteItemMapper.delete(new LambdaQueryWrapper<ProductProcessRouteItem>()
                    .in(ProductProcessRouteItem::getProductOrderId, ids));
            // 批量删除productProcessRoute
            productProcessRouteMapper.delete(new LambdaQueryWrapper<ProductProcessRoute>()
                    .in(ProductProcessRoute::getProductOrderId, ids));
            // 批量删除productOrder
            productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
                    .in(ProductOrder::getId, ids));
        }
        return true;
    }
    //获取当前生产订单号
    public String getMaxOrderNoByDate(String datePrefix) {
        QueryWrapper<ProductOrder> queryWrapper = new QueryWrapper<>();
        // 匹配以 SC + 日期开头的订单号
        queryWrapper.likeRight("nps_no", "SC" + datePrefix);
        // 按订单号倒序排列
        queryWrapper.orderByDesc("nps_no");
        queryWrapper.last("LIMIT 1");
        ProductOrder latestOrder = this.getOne(queryWrapper);
        return latestOrder != null ? latestOrder.getNpsNo() : null;
    }
    public String generateNextOrderNo(String datePrefix) {
        String maxOrderNo = getMaxOrderNoByDate(datePrefix);
        int sequence = 1; // 默认起始序号
        if (maxOrderNo != null && !maxOrderNo.isEmpty()) {
            // 提取流水号部分(假设格式为 SC + 日期 + 流水号)
            String sequenceStr = maxOrderNo.substring(("SC" + datePrefix).length());
            try {
                sequence = Integer.parseInt(sequenceStr) + 1;
            } catch (NumberFormatException e) {
                // 异常情况下重置为1
                sequence = 1;
            }
        }
        // 生成新订单号
        return "SC" + datePrefix + String.format("%04d", sequence);
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteItemServiceImpl.java
@@ -142,11 +142,7 @@
        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        if (insert > 0) {
            // 查询今日已存在的最大工单号
            QueryWrapper<ProductWorkOrder> queryWrapper = new QueryWrapper<>();
            queryWrapper.likeRight("work_order_no", datePrefix)
                    .orderByDesc("work_order_no")
                    .last("LIMIT 1");
            ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectOne(queryWrapper);
            ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectMax(datePrefix);
            int sequenceNumber = 1; // 默认序号
            if (lastWorkOrder != null && lastWorkOrder.getWorkOrderNo() != null) {
                String lastNo = lastWorkOrder.getWorkOrderNo().toString();
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -24,6 +24,8 @@
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.quality.mapper.*;
import com.ruoyi.quality.pojo.*;
import com.ruoyi.quality.service.IQualityInspectService;
import com.ruoyi.quality.service.impl.QualityInspectFileServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -42,6 +44,7 @@
@Transactional(rollbackFor = Exception.class)
public class ProductionProductMainServiceImpl extends ServiceImpl<ProductionProductMainMapper, ProductionProductMain> implements ProductionProductMainService {
    private IQualityInspectService qualityInspectService;
    private ProductionProductMainMapper productionProductMainMapper;
@@ -283,7 +286,9 @@
                    new LambdaQueryWrapper<QualityInspectParam>()
                            .eq(QualityInspectParam::getInspectId, q.getId()));
            qualityInspectMapper.deleteById(q.getId());
                stockUtils.deleteStockInRecord(q.getId(), StockQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode());
        });
        // 删除产出记录
        productionProductOutputMapper.delete(new LambdaQueryWrapper<ProductionProductOutput>()
                .eq(ProductionProductOutput::getProductMainId, productionProductMain.getId()));
src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
@@ -98,11 +98,7 @@
                            int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
                            if (insert > 0) {
                                // 查询今日已存在的最大工单号
                                QueryWrapper<ProductWorkOrder> queryWrapper = new QueryWrapper<>();
                                queryWrapper.likeRight("work_order_no", datePrefix)
                                        .orderByDesc("work_order_no")
                                        .last("LIMIT 1");
                                ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectOne(queryWrapper);
                                ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectMax(datePrefix);
                                int sequenceNumber = 1; // 默认序号
                                if (lastWorkOrder != null && lastWorkOrder.getWorkOrderNo() != null) {
                                    String lastNo = lastWorkOrder.getWorkOrderNo().toString();
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -15,6 +15,7 @@
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.impl.ProductOrderServiceImpl;
import com.ruoyi.production.service.impl.SalesLedgerProductionAccountingServiceImpl;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
@@ -94,7 +95,7 @@
    @Autowired
    private StockInventoryMapper stockInventoryMapper;
    @Autowired
    private SalesLedgerProductionAccountingServiceImpl salesLedgerProductionAccountingServiceImpl;
    private ProductOrderServiceImpl productOrderServiceImpl;
    @Override
    public SalesLedgerProduct selectSalesLedgerProductById(Long id) {
@@ -273,7 +274,8 @@
        productOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
        productOrder.setProductModelId(salesLedgerProduct.getProductModelId());
        productOrder.setSaleLedgerProductId(salesLedgerProduct.getId());
        productOrder.setNpsNo("SC" + String.format("%08d", salesLedgerProduct.getId()));
        String string = productOrderServiceImpl.generateNextOrderNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        productOrder.setNpsNo(string);
        productOrder.setQuantity(salesLedgerProduct.getQuantity());//需求数量
        productOrder.setCompleteQuantity(BigDecimal.ZERO);//完成数量
        productOrderMapper.insert(productOrder);
@@ -304,13 +306,7 @@
                int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
                if (insert > 0) {
                    // 查询今日已存在的最大工单号
                    QueryWrapper<ProductWorkOrder> queryWrapper = new QueryWrapper<>();
                    queryWrapper.likeRight("work_order_no", datePrefix)
                            .orderByDesc("work_order_no")
                            .last("LIMIT 1");
                    ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectOne(queryWrapper);
                    ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectMax(datePrefix);
                    int sequenceNumber = 1; // 默认序号
                    if (lastWorkOrder != null && lastWorkOrder.getWorkOrderNo() != null) {
                        String lastNo = lastWorkOrder.getWorkOrderNo().toString();
src/main/resources/mapper/production/ProductOrderMapper.xml
@@ -17,8 +17,9 @@
        select po.*,
        sl.sales_contract_no,
        sl.customer_name,
        slp.product_category,
        slp.specification_model,
        p.product_name as product_category,
        pm.model as specification_model,
        pm.unit,
        ppr.process_route_code,
        pb.bom_no,
        ROUND(po.complete_quantity / po.quantity * 100, 2) AS completionStatus,
@@ -38,6 +39,8 @@
        FROM shipping_info
        GROUP BY sales_ledger_id
        ) shipping_status_counts ON sl.id = shipping_status_counts.sales_ledger_id
            left join product_model pm on po.product_model_id = pm.id
            left join product p on pm.product_id = p.id
        left join sales_ledger_product slp on po.sale_ledger_product_id = slp.id
        left join product_process_route ppr on po.id = ppr.product_order_id
        left join product_bom pb on pb.id = ppr.bom_id
src/main/resources/mapper/production/ProductWorkOrderMapper.xml
@@ -87,4 +87,12 @@
            actual_start_time &gt;= #{startDate}
            AND actual_start_time &lt;= #{endDate}
    </select>
    <select id="selectMax" resultType="com.ruoyi.production.pojo.ProductWorkOrder">
        SELECT SUBSTRING(work_order_no, 3) as work_order_no
        FROM product_work_order
        WHERE SUBSTRING(work_order_no, 3) like concat(#{datePrefix},'%')
        order by work_order_no  desc
        limit 1
        ;
    </select>
</mapper>