zss
2026-04-24 99ac94a7cf412d9f0081c1d84b520eab051bb0fd
feat(production): 重构生产计划模块,新增和优化生产计划功能
已修改9个文件
381 ■■■■■ 文件已修改
src/main/java/com/ruoyi/production/bean/dto/ProductionPlanDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductionPlanImportDto.java 159 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/vo/ProductionPlanVo.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductionPlanMapper.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductionPlan.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java 94 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductionPlanDto.java
@@ -20,10 +20,6 @@
    @Excel(name = "产品名称")
    private String productName;
    @Schema(description = "客户名称")
    @Excel(name = "客户名称")
    private String customerName;
    @Schema(description = "产品规格")
    @Excel(name = "产品规格")
    private String model;
src/main/java/com/ruoyi/production/bean/dto/ProductionPlanImportDto.java
@@ -1,12 +1,11 @@
package com.ruoyi.production.bean.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.time.LocalDate;
/**
 * <br>
@@ -20,126 +19,43 @@
@Data
@Schema(name = "销售生产需求 Excel导入导出DTO")
public class ProductionPlanImportDto {
    /**
     * 申请单编号
     */
    @Schema(description = "申请单编号")
    @Excel(name = "申请单编号")
    private String applyNo;
    /**
     * 客户名称
     */
    @Schema(description = "客户名称")
    @Excel(name = "客户名称")
    private String customerName;
    @Schema(description = "主生产计划号")
    @Excel(name = "主生产计划号")
    private String mpsNo;
    /**
     * 物料编码
     */
    @Schema(description = "物料编码")
    @Excel(name = "物料编码")
    private String materialCode;
    @Schema(description = "需求日期")
    @Excel(name = "需求日期")
    private LocalDate requiredDate;
    /**
     * 产品名称
     */
    @Schema(description = "备注")
    @Excel(name = "备注")
    private String remark;
    @Schema(description = "需求数量")
    @Excel(name = "需求数量")
    private BigDecimal qtyRequired;
    @Schema(description = "来源 销售/内部")
    @Excel(name = "来源 销售/内部")
    private String source;
    @Schema(description = "承诺日期")
    @Excel(name = "承诺日期")
    private LocalDate promisedDeliveryDate;
    @Schema(description = "产品名称")
    @Excel(name = "产品名称")
    private String productName;
    /**
     * 产品规格
     */
    @Schema(description = "产品规格")
    @Excel(name = "产品规格")
    private String productSpec;
    @Schema(description = "规格型号")
    @Excel(name = "规格型号")
    private String model;
    /**
     * 长
     */
    @Schema(description = "长")
    @Excel(name = "长(mm)")
    private Integer length;
    @Schema(description = "单位")
    @Excel(name = "单位")
    private String unit;
    /**
     * 宽
     */
    @Schema(description = "宽")
    @Excel(name = "宽(mm)")
    private Integer width;
    /**
     * 高
     */
    @Schema(description = "高")
    @Excel(name = "高(mm)")
    private Integer height;
    /**
     * 块数
     */
    @Schema(description = "块数")
    @Excel(name = "块数")
    private Integer quantity;
    /**
     * 方数
     */
    @Schema(description = "方数")
    @Excel(name = "方数")
    private BigDecimal volume;
    /**
     * 强度
     */
    @Schema(description = "强度")
    @Excel(name = "强度")
    private String strength;
    /**
     * 开始日期
     */
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    @Schema(description = "开始日期")
    @Excel(name = "开始日期", width = 20, dateFormat = "yyyy-MM-dd")
    private Date startDate;
    /**
     * 结束日期
     */
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    @Schema(description = "结束日期")
    @Excel(name = "结束日期", width = 20, dateFormat = "yyyy-MM-dd")
    private Date endDate;
    /**
     * 提交人
     */
    @Schema(description = "提交人")
    @Excel(name = "提交人")
    private String submitter;
    /**
     * 提交人组织
     */
    @Schema(description = "提交人组织")
    @Excel(name = "提交人组织")
    private String submitOrg;
    /**
     * 备注1
     */
    @Schema(description = "备注1")
    @Excel(name = "备注1")
    private String remarkOne;
    /**
     * 备注2
     */
    @Schema(description = "备注2")
    @Excel(name = "备注2")
    private String remarkTwo;
    /**
     * 创建人
@@ -155,22 +71,11 @@
    @Excel(name = "修改人", type = Excel.Type.EXPORT)
    private String modifierName;
    /**
     * 数据同步类型:1=手动 2=定时任务
     */
    @Schema(description = "数据同步类型:1=手动 2=定时任务")
    private Integer dataSyncType;
    /**
     * 数据来源类型:1=同步 2=新增
     * 已下发数量
     */
    @Schema(description = "数据来源类型:1=同步 2=新增")
    private Integer dataSourceType;
    /**
     * 下发数量
     */
    @Schema(description = "下发数量")
    @Excel(name = "下发数量", type = Excel.Type.EXPORT)
    @Schema(description = "已下发数量")
    @Excel(name = "已下发数量", type = Excel.Type.EXPORT)
    private BigDecimal assignedQuantity;
}
src/main/java/com/ruoyi/production/bean/vo/ProductionPlanVo.java
@@ -9,8 +9,6 @@
@Data
@Schema(name = "ProductionPlanVo", description = "生产计划返回对象")
public class ProductionPlanVo extends ProductionPlan {
    @Schema(description = "物料编码")
    private String materialCode;
    @Schema(description = "产品名称")
    private String productName;
src/main/java/com/ruoyi/production/mapper/ProductionPlanMapper.java
@@ -27,5 +27,4 @@
    List<ProductionPlanDto> selectWithMaterialByIds(@Param("ids") List<Long> ids);
    ProductionPlanDto selectProductionPlanDtoById(@Param("productionPlanId") Long productionPlanId);
}
src/main/java/com/ruoyi/production/pojo/ProductionPlan.java
@@ -30,6 +30,12 @@
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @Schema(description = "销售台账id")
    private Long salesLedgerId;
    @Schema(description = "销售产品规格id")
    private Long salesLedgerProductId;
    @Schema(description = "主生产计划号")
    private String mpsNo;
@@ -55,6 +61,10 @@
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
    @Schema(description = "部门ID")
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @Schema(description = "产品型号id")
    private Long productModelId;
@@ -64,7 +74,7 @@
    @Schema(description = "是否下发制造订单")
    private Boolean issued;
    @Schema(description = "来源")
    @Schema(description = "来源 销售/内部")
    private String source;
    @Schema(description = "审核状态")
@@ -72,9 +82,6 @@
    @Schema(description = "承诺日期")
    private LocalDate promisedDeliveryDate;
    @Schema(description = "申请单编号")
    private String applyNo;
    @Schema(description = "状态 0未下发 1部分下发 2已下发")
    private Integer status;
src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java
@@ -1,6 +1,7 @@
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.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -26,7 +27,9 @@
import org.springframework.web.multipart.MultipartFile;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@@ -135,12 +138,11 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(ProductionPlanDto dto) {
        if (StringUtils.isBlank(dto.getApplyNo())) {
            throw new ServiceException("新增失败,申请单编号不能为空");
        }
        checkApplyNoUnique(dto.getApplyNo(), null);
        if (StringUtils.isBlank(dto.getMpsNo())) {
            dto.setMpsNo(generateNextPlanNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))));
        }else checkMpsNoUnique(dto.getMpsNo(), null);
        dto.setStatus(PLAN_STATUS_WAIT);
        dto.setSource("内部");
        return productionPlanMapper.insert(dto) > 0;
    }
@@ -160,21 +162,21 @@
            throw new BaseException("编辑失败,该生产计划已下发或部分下发,禁止编辑");
        }
        if (StringUtils.isNotBlank(dto.getApplyNo()) && !dto.getApplyNo().equals(old.getApplyNo())) {
            checkApplyNoUnique(dto.getApplyNo(), dto.getId());
        if (StringUtils.isNotBlank(dto.getMpsNo()) && !dto.getMpsNo().equals(old.getMpsNo())) {
            checkMpsNoUnique(dto.getMpsNo(), dto.getId());
        }
        return productionPlanMapper.updateById(dto) > 0;
    }
    private void checkApplyNoUnique(String applyNo, Long excludeId) {
    private void checkMpsNoUnique(String mpsNo, Long excludeId) {
        LambdaQueryWrapper<ProductionPlan> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ProductionPlan::getApplyNo, applyNo);
        wrapper.eq(ProductionPlan::getMpsNo, mpsNo);
        if (excludeId != null) {
            wrapper.ne(ProductionPlan::getId, excludeId);
        }
        if (productionPlanMapper.selectCount(wrapper) > 0) {
            throw new ServiceException("申请单编号 " + applyNo + " 已存在");
            throw new ServiceException("生产计划号 " + mpsNo + " 已存在");
        }
    }
@@ -202,7 +204,6 @@
        if (file == null || file.isEmpty()) {
            throw new ServiceException("导入数据不能为空");
        }
        ExcelUtil<ProductionPlanImportDto> excelUtil = new ExcelUtil<>(ProductionPlanImportDto.class);
        List<ProductionPlanImportDto> list;
        try {
@@ -210,77 +211,54 @@
        } catch (Exception e) {
            throw new ServiceException("Excel解析失败");
        }
        if (list == null || list.isEmpty()) {
            throw new ServiceException("Excel没有数据");
        }
        Set<String> applyNos = new HashSet<>();
        Set<String> materialCodes = new HashSet<>();
        Set<String> mpsNos = new HashSet<>();
        for (int i = 0; i < list.size(); i++) {
            ProductionPlanImportDto dto = list.get(i);
            String applyNo = dto.getApplyNo();
            String materialCode = dto.getMaterialCode();
            if (StringUtils.isEmpty(applyNo)) {
                throw new ServiceException("导入失败:第 " + (i + 2) + " 行申请单编号不能为空");
            String mpsNo = dto.getMpsNo();
            if (StringUtils.isEmpty(mpsNo)) {
                generateNextPlanNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
            }
            if (!applyNos.add(applyNo)) {
                throw new ServiceException("导入失败:Excel 中存在重复的申请单编号 " + applyNo);
            if (!mpsNos.add(mpsNo)) {
                throw new ServiceException("导入失败:Excel 中存在重复的申请单编号 " + mpsNo);
            }
            if (StringUtils.isEmpty(materialCode)) {
                throw new ServiceException("导入失败:第 " + (i + 2) + " 行物料编码不能为空");
            }
            String strength = dto.getStrength();
            if (StringUtils.isNotEmpty(strength) && !"A3.5".equals(strength) && !"A5.0".equals(strength)) {
                throw new ServiceException("导入失败:第 " + (i + 2) + " 行强度只能是 A3.5 或 A5.0");
            }
            materialCodes.add(materialCode);
        }
        Long existApplyNoCount = baseMapper.selectCount(Wrappers.<ProductionPlan>lambdaQuery()
                .in(ProductionPlan::getApplyNo, applyNos));
                .in(ProductionPlan::getMpsNo, mpsNos));
        if (existApplyNoCount > 0) {
            List<String> existApplyNos = baseMapper.selectList(Wrappers.<ProductionPlan>lambdaQuery()
                            .in(ProductionPlan::getApplyNo, applyNos))
            List<String> existMpsNos = baseMapper.selectList(Wrappers.<ProductionPlan>lambdaQuery()
                            .in(ProductionPlan::getMpsNo, mpsNos))
                    .stream()
                    .map(ProductionPlan::getApplyNo)
                    .map(ProductionPlan::getMpsNo)
                    .collect(Collectors.toList());
            throw new ServiceException("导入失败,申请单编号已存在: " + String.join(", ", existApplyNos));
            throw new ServiceException("导入失败,生产计划号已存在: " + String.join(", ", existMpsNos));
        }
        LocalDateTime now = LocalDateTime.now();
        List<ProductionPlan> entityList = list.stream().map(dto -> {
            ProductionPlan entity = new ProductionPlan();
            BeanUtils.copyProperties(dto, entity);
            entity.setStatus(PLAN_STATUS_WAIT);
            entity.setSource("内部");
            entity.setCreateTime(now);
            entity.setUpdateTime(now);
            return entity;
        }).collect(Collectors.toList());
        this.saveBatch(entityList);
    }
    @Override
    public void exportProdData(HttpServletResponse response, List<Long> ids) {
        List<ProductionPlan> list;
        if (ids != null && !ids.isEmpty()) {
            list = baseMapper.selectBatchIds(ids);
        } else {
            list = baseMapper.selectList(null);
        }
        List<ProductionPlanDto> list = productionPlanMapper.selectWithMaterialByIds(ids);
        List<ProductionPlanImportDto> exportList = new ArrayList<>();
        for (ProductionPlan entity : list) {
        for (ProductionPlanDto entity : list) {
            ProductionPlanImportDto dto = new ProductionPlanImportDto();
            BeanUtils.copyProperties(entity, dto);
            exportList.add(dto);
        }
        ExcelUtil<ProductionPlanImportDto> util = new ExcelUtil<>(ProductionPlanImportDto.class);
        util.exportExcel(response, exportList, "销售生产需求数据");
        util.exportExcel(response, exportList, "主生产计划");
    }
    private String formatPlanIds(List<Long> planIds) {
@@ -290,4 +268,22 @@
                .map(String::valueOf)
                .collect(Collectors.joining(",", "[", "]"));
    }
    private String generateNextPlanNo(String datePrefix) {
        QueryWrapper<ProductionPlan> queryWrapper = new QueryWrapper<>();
        queryWrapper.likeRight("mps_no", "JH" + datePrefix);
        queryWrapper.orderByDesc("mps_no");
        queryWrapper.last("LIMIT 1");
        ProductionPlan latestPlan = productionPlanMapper.selectOne(queryWrapper);
        int sequence = 1;
        if (latestPlan != null && latestPlan.getMpsNo() != null && !latestPlan.getMpsNo().isEmpty()) {
            String sequenceStr = latestPlan.getMpsNo().substring(("JH" + datePrefix).length());
            try {
                sequence = Integer.parseInt(sequenceStr) + 1;
            } catch (NumberFormatException e) {
                sequence = 1;
            }
        }
        return "JH" + datePrefix + String.format("%04d", sequence);
    }
}
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -232,6 +232,7 @@
    private BigDecimal ticketsTotal = BigDecimal.ZERO;
    @Schema(description = "是否质检")
    //针对采购台账,是否质检
    private Boolean isChecked;
    @TableField(exist = false)
@@ -251,4 +252,8 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @Schema(description = "是否生产")
    //针对销售台账,是否生产
    private Boolean isProduction;
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -6,17 +6,14 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.pojo.ProductionPlan;
import com.ruoyi.production.service.ProductionOrderService;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.sales.dto.InvoiceRegistrationProductDto;
import com.ruoyi.sales.dto.SalesLedgerProductDto;
import com.ruoyi.sales.mapper.InvoiceRegistrationProductMapper;
@@ -65,7 +62,7 @@
    private final ProductionAccountMapper productionAccountMapper;
    private final SalesLedgerMapper salesLedgerMapper;
    private final PurchaseLedgerMapper purchaseLedgerMapper;
    private final ProductionOrderMapper productionOrderMapper;
    private final ProductionPlanMapper productionPlanMapper;
    private final ProductionOperationTaskMapper productionOperationTaskMapper;
    private final ProductionOrderService productionOrderService;
    private final TechnologyRoutingMapper technologyRoutingMapper;
@@ -253,70 +250,36 @@
     * 新增生产数据
     */
    public void addProductionData(SalesLedgerProduct salesLedgerProduct) {
        ProductionOrder productionOrder = new ProductionOrder();
        productionOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
        productionOrder.setProductModelId(salesLedgerProduct.getProductModelId());
        productionOrder.setSaleLedgerProductId(salesLedgerProduct.getId().intValue());
        productionOrder.setNpsNo(generateNextOrderNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))));
        productionOrder.setQuantity(salesLedgerProduct.getQuantity());
        productionOrder.setCompleteQuantity(BigDecimal.ZERO);
        //先判断该产品是否需要生产
        if (!salesLedgerProduct.getIsProduction()) {
            return;
        }
        ProductionPlan productionPlan = new ProductionPlan();
        productionPlan.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
        productionPlan.setProductModelId(salesLedgerProduct.getProductModelId());
        productionPlan.setSalesLedgerProductId(salesLedgerProduct.getId());
        productionPlan.setMpsNo(generateNextPlanNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))));
        productionPlan.setQtyRequired(salesLedgerProduct.getQuantity());
        productionPlanMapper.insert(productionPlan);
        TechnologyRouting routing = technologyRoutingMapper.selectOne(
                new QueryWrapper<TechnologyRouting>().lambda()
                        .eq(TechnologyRouting::getProductModelId, salesLedgerProduct.getProductModelId())
                        .orderByDesc(TechnologyRouting::getCreateTime)
                        .last("LIMIT 1"));
        if (routing != null) {
            productionOrder.setTechnologyRoutingId(routing.getId());
        }
        productionOrderMapper.insert(productionOrder);
        if (productionOrder.getTechnologyRoutingId() != null) {
            productionOrderService.syncProductionOrderSnapshot(productionOrder.getId());
        }
    }
    /**
     * 删除生产数据
     * 删除生产计划
     */
    public void deleteProductionData(List<Long> productIds) {
        List<ProductionOrder> productionOrders = productionOrderMapper.selectList(
                new LambdaQueryWrapper<ProductionOrder>()
                        .in(ProductionOrder::getSaleLedgerProductId, productIds.stream().map(Long::intValue).collect(Collectors.toList())));
        if (org.springframework.util.CollectionUtils.isEmpty(productionOrders)) {
        List<ProductionPlan> productionPlans = productionPlanMapper.selectList(
                new LambdaQueryWrapper<ProductionPlan>()
                        .in(ProductionPlan::getSalesLedgerProductId, productIds.stream().map(Long::intValue).collect(Collectors.toList())));
        if (org.springframework.util.CollectionUtils.isEmpty(productionPlans)) {
            return;
        }
        List<Long> orderIds = productionOrders.stream().map(ProductionOrder::getId).collect(Collectors.toList());
        List<Long> taskIds = productionOperationTaskMapper.selectList(
                        new LambdaQueryWrapper<ProductionOperationTask>()
                                .in(ProductionOperationTask::getProductionOrderId, orderIds))
                .stream().map(ProductionOperationTask::getId).collect(Collectors.toList());
        if (!taskIds.isEmpty()) {
            List<ProductionProductMain> productMains = productionProductMainMapper.selectList(
                    new LambdaQueryWrapper<ProductionProductMain>()
                            .in(ProductionProductMain::getProductionOperationTaskId, taskIds));
            List<Long> productMainIds = productMains.stream().map(ProductionProductMain::getId).collect(Collectors.toList());
            if (!productMainIds.isEmpty()) {
                List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
                        new LambdaQueryWrapper<QualityInspect>().in(QualityInspect::getProductMainId, productMainIds));
                qualityInspects.forEach(qualityInspect -> {
                    if (qualityInspect.getInspectState() == 1) {
                        throw new RuntimeException("已提交的检验单不能删除");
                    }
                });
                productionProductOutputMapper.deleteByProductMainIds(productMainIds);
                productionProductInputMapper.deleteByProductMainIds(productMainIds);
                qualityInspectMapper.deleteByProductMainIds(productMainIds);
                productionAccountMapper.delete(new LambdaQueryWrapper<ProductionAccount>()
                        .in(ProductionAccount::getProductionProductMainId, productMainIds));
                for (Long productMainId : productMainIds) {
                    stockUtils.deleteStockOutRecord(productMainId, StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
                    stockUtils.deleteStockInRecord(productMainId, StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
                }
            }
            productionProductMainMapper.delete(new LambdaQueryWrapper<ProductionProductMain>()
                    .in(ProductionProductMain::getProductionOperationTaskId, taskIds));
        //如果生产计划已下发则不能删除
        if (productionPlans.stream().anyMatch(productionPlan -> productionPlan.getStatus() != 0)) {
            throw new RuntimeException("生产计划已下发,不能删除该销售产品");
        }
        productionOrderService.removeProductionOrder(orderIds);
        List<Long> ids = productionPlans.stream().map(ProductionPlan::getId).collect(Collectors.toList());
        productionPlanMapper.deleteByIds(ids);
    }
    @Override
@@ -429,21 +392,21 @@
        return R.ok();
    }
    private String generateNextOrderNo(String datePrefix) {
        QueryWrapper<ProductionOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.likeRight("nps_no", "SC" + datePrefix);
        queryWrapper.orderByDesc("nps_no");
    private String generateNextPlanNo(String datePrefix) {
        QueryWrapper<ProductionPlan> queryWrapper = new QueryWrapper<>();
        queryWrapper.likeRight("mps_no", "JH" + datePrefix);
        queryWrapper.orderByDesc("mps_no");
        queryWrapper.last("LIMIT 1");
        ProductionOrder latestOrder = productionOrderMapper.selectOne(queryWrapper);
        ProductionPlan latestPlan = productionPlanMapper.selectOne(queryWrapper);
        int sequence = 1;
        if (latestOrder != null && latestOrder.getNpsNo() != null && !latestOrder.getNpsNo().isEmpty()) {
            String sequenceStr = latestOrder.getNpsNo().substring(("SC" + datePrefix).length());
        if (latestPlan != null && latestPlan.getMpsNo() != null && !latestPlan.getMpsNo().isEmpty()) {
            String sequenceStr = latestPlan.getMpsNo().substring(("JH" + datePrefix).length());
            try {
                sequence = Integer.parseInt(sequenceStr) + 1;
            } catch (NumberFormatException e) {
                sequence = 1;
            }
        }
        return "SC" + datePrefix + String.format("%04d", sequence);
        return "JH" + datePrefix + String.format("%04d", sequence);
    }
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -520,7 +520,7 @@
        List<Long> productIds = products.stream()
                .map(SalesLedgerProduct::getId)
                .collect(Collectors.toList());
        //删除生产数据
        //删除生产计划
        salesLedgerProductServiceImpl.deleteProductionData(productIds);
        // 批量删除产品子表