chenhj
2026-04-24 2e71bdbcdf853bb35e68016b84f0254f7366bfeb
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -5,17 +5,17 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.enums.StockQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockUnQualifiedRecordTypeEnum;
import com.ruoyi.common.utils.StringUtils;
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.dto.ProductStructureDto;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.impl.SalesLedgerProductionAccountingServiceImpl;
import com.ruoyi.production.pojo.ProductionAccount;
import com.ruoyi.production.pojo.ProductionOperationTask;
import com.ruoyi.production.pojo.ProductionOrder;
import com.ruoyi.production.pojo.ProductionProductMain;
import com.ruoyi.production.service.ProductionOrderService;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.quality.mapper.QualityInspectMapper;
@@ -26,15 +26,17 @@
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.mapper.ShippingInfoMapper;
import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.pojo.ShippingInfo;
import com.ruoyi.sales.service.ISalesLedgerProductService;
import com.ruoyi.stock.mapper.StockInventoryMapper;
import com.ruoyi.stock.pojo.StockInventory;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import com.ruoyi.technology.bean.vo.TechnologyBomStructureVo;
import com.ruoyi.technology.mapper.TechnologyBomStructureMapper;
import com.ruoyi.technology.mapper.TechnologyRoutingMapper;
import com.ruoyi.technology.pojo.TechnologyRouting;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@@ -45,7 +47,10 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -56,45 +61,27 @@
 * @date 2025-05-08
 */
@Service
@AllArgsConstructor
@RequiredArgsConstructor
public class SalesLedgerProductServiceImpl extends ServiceImpl<SalesLedgerProductMapper, SalesLedgerProduct> implements ISalesLedgerProductService {
    private SalesLedgerProductMapper salesLedgerProductMapper;
    private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
    private SalesLedgerMapper salesLedgerMapper;
    private PurchaseLedgerMapper purchaseLedgerMapper;
    private ProductOrderMapper productOrderMapper;
    private ProcessRouteItemMapper processRouteItemMapper;
    private ProductProcessRouteItemMapper productProcessRouteItemMapper;
    private InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
    private ProcessRouteMapper processRouteMapper;
    private ProductProcessRouteMapper productProcessRouteMapper;
    private ProductWorkOrderMapper productWorkOrderMapper;
    private ProductionProductMainMapper productionProductMainMapper;
    private ProductionProductOutputMapper productionProductOutputMapper;
    private ProductionProductInputMapper productionProductInputMapper;
    private QualityInspectMapper qualityInspectMapper;
    private ShippingInfoMapper shippingInfoMapper;
    private ShippingInfoServiceImpl shippingInfoService;
    private StockUtils stockUtils;
    @Autowired
    private ProductStructureMapper productStructureMapper;
    @Autowired
    private StockInventoryMapper stockInventoryMapper;
    @Autowired
    private SalesLedgerProductionAccountingServiceImpl salesLedgerProductionAccountingServiceImpl;
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    private final ProductionAccountMapper productionAccountMapper;
    private final SalesLedgerMapper salesLedgerMapper;
    private final PurchaseLedgerMapper purchaseLedgerMapper;
    private final ProductionOrderMapper productionOrderMapper;
    private final ProductionOperationTaskMapper productionOperationTaskMapper;
    private final ProductionOrderService productionOrderService;
    private final TechnologyRoutingMapper technologyRoutingMapper;
    private final TechnologyBomStructureMapper technologyBomStructureMapper;
    private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
    private final ProductionProductMainMapper productionProductMainMapper;
    private final ProductionProductOutputMapper productionProductOutputMapper;
    private final ProductionProductInputMapper productionProductInputMapper;
    private final QualityInspectMapper qualityInspectMapper;
    private final ShippingInfoMapper shippingInfoMapper;
    private final ShippingInfoServiceImpl shippingInfoService;
    private final StockUtils stockUtils;
    private final StockInventoryMapper stockInventoryMapper;
    @Override
    public SalesLedgerProduct selectSalesLedgerProductById(Long id) {
@@ -269,75 +256,25 @@
     * 新增生产数据
     */
    public void addProductionData(SalesLedgerProduct salesLedgerProduct) {
        ProductOrder productOrder = new ProductOrder();
        productOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
        productOrder.setProductModelId(salesLedgerProduct.getProductModelId());
        productOrder.setSaleLedgerProductId(salesLedgerProduct.getId());
        productOrder.setNpsNo("SC" + String.format("%08d", salesLedgerProduct.getId()));
        productOrder.setQuantity(salesLedgerProduct.getQuantity());//需求数量
        productOrder.setCompleteQuantity(BigDecimal.ZERO);//完成数量
        productOrderMapper.insert(productOrder);
        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);
        List<ProcessRoute> processRoutes = processRouteMapper.selectList(new QueryWrapper<ProcessRoute>().lambda()
                .eq(ProcessRoute::getProductModelId, salesLedgerProduct.getProductModelId())
                .orderByDesc(ProcessRoute::getCreateTime));
        if (processRoutes.size()>0){
            ProcessRoute processRoute = processRoutes.get(0);
            //新增生产订单工艺路线主表
            ProductProcessRoute productProcessRoute = new ProductProcessRoute();
            productProcessRoute.setProductModelId(processRoute.getProductModelId());
            productProcessRoute.setProcessRouteCode(processRoute.getProcessRouteCode());
            productProcessRoute.setProductOrderId(productOrder.getId());
            productProcessRoute.setBomId(processRoute.getBomId());
            productProcessRouteMapper.insert(productProcessRoute);
            //新增生产订单工艺路线子表
            List<ProcessRouteItem> processRouteItems = processRouteItemMapper.selectList(new QueryWrapper<ProcessRouteItem>().lambda().eq(ProcessRouteItem::getRouteId, processRoute.getId()));
            // 生成当前日期的前缀:年月日
            String datePrefix = "GD" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
            for (ProcessRouteItem processRouteItem : processRouteItems) {
                ProductProcessRouteItem productProcessRouteItem = new ProductProcessRouteItem();
                productProcessRouteItem.setProductModelId(processRouteItem.getProductModelId());
                productProcessRouteItem.setProcessId(processRouteItem.getProcessId());
                productProcessRouteItem.setProductOrderId(productOrder.getId());
                productProcessRouteItem.setProductRouteId(productProcessRoute.getId());
                productProcessRouteItem.setDragSort(processRouteItem.getDragSort());
                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);
                    int sequenceNumber = 1; // 默认序号
                    if (lastWorkOrder != null && lastWorkOrder.getWorkOrderNo() != null) {
                        String lastNo = lastWorkOrder.getWorkOrderNo().toString();
                        if (lastNo.startsWith(datePrefix)) {
                            String seqStr = lastNo.substring(datePrefix.length());
                            try {
                                sequenceNumber = Integer.parseInt(seqStr) + 1;
                            } catch (NumberFormatException e) {
                                sequenceNumber = 1;
                            }
                        }
                    }
                    // 生成完整的工单号
                    String workOrderNoStr = String.format("%s%03d", datePrefix, sequenceNumber);
                    ProductWorkOrder productWorkOrder = new ProductWorkOrder();
                    productWorkOrder.setProductProcessRouteItemId(productProcessRouteItem.getId());
                    productWorkOrder.setProductOrderId(productOrder.getId());
                    productWorkOrder.setPlanQuantity(salesLedgerProduct.getQuantity());
                    productWorkOrder.setWorkOrderNo(workOrderNoStr);
                    productWorkOrder.setStatus(1);
                    productWorkOrderMapper.insert(productWorkOrder);
                }
            }
            productOrder.setRouteId(processRoute.getId());
            productOrderMapper.updateById(productOrder);
        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());
        }
    }
@@ -345,93 +282,44 @@
     * 删除生产数据
     */
    public void deleteProductionData(List<Long> productIds) {
        //批量查询productOrder
        List<ProductOrder> productOrders = productOrderMapper.selectList(
                new LambdaQueryWrapper<ProductOrder>()
                        .in(ProductOrder::getSaleLedgerProductId, productIds)
        );
        if (!org.springframework.util.CollectionUtils.isEmpty(productOrders)) {
            List<Long> orderIds = productOrders.stream()
                    .map(ProductOrder::getId)
                    .collect(Collectors.toList());
            // 批量查询processRouteItems
            List<ProductProcessRouteItem> allRouteItems = productProcessRouteItemMapper.selectList(
                    new LambdaQueryWrapper<ProductProcessRouteItem>()
                            .in(ProductProcessRouteItem::getProductOrderId, orderIds)
            );
            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));
        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)) {
            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("已提交的检验单不能删除");
                    }
                    // 删除生产主表数据
                    productionProductMainMapper.deleteByWorkOrderIds(workOrderIds);
                    // 删除工单数据
                    productWorkOrderMapper.delete(new LambdaQueryWrapper<ProductWorkOrder>()
                            .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds));
                });
                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());
                }
            }
            // 批量删除processRouteItem
            productProcessRouteItemMapper.delete(new LambdaQueryWrapper<ProductProcessRouteItem>()
                    .in(ProductProcessRouteItem::getProductOrderId, orderIds));
            // 批量删除productProcessRoute
            productProcessRouteMapper.delete(new LambdaQueryWrapper<ProductProcessRoute>()
                    .in(ProductProcessRoute::getProductOrderId, orderIds));
            // 批量删除productOrder
            productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
                    .in(ProductOrder::getSaleLedgerProductId, productIds));
            productionProductMainMapper.delete(new LambdaQueryWrapper<ProductionProductMain>()
                    .in(ProductionProductMain::getProductionOperationTaskId, taskIds));
        }
        productionOrderService.removeProductionOrder(orderIds);
    }
    @Override
@@ -498,37 +386,67 @@
    }
    @Override
    public R judgmentInventory(SalesLedgerProduct salesLedgerProduct) {
        //获取产品最新的工艺路线
        ProcessRoute processRoute = processRouteMapper.selectOne(new QueryWrapper<ProcessRoute>().lambda().eq(ProcessRoute::getProductModelId, salesLedgerProduct.getProductModelId()).orderByDesc(ProcessRoute::getCreateTime).last("LIMIT 1"));
        if (processRoute == null) {
        TechnologyRouting routing = technologyRoutingMapper.selectOne(
                new QueryWrapper<TechnologyRouting>().lambda()
                        .eq(TechnologyRouting::getProductModelId, salesLedgerProduct.getProductModelId())
                        .orderByDesc(TechnologyRouting::getCreateTime)
                        .last("LIMIT 1"));
        if (routing == null) {
            return R.fail("请先设置工艺路线");
        }
        List<ProductStructureDto> productStructureDtos = productStructureMapper.listBybomId(processRoute.getBomId());
        if (productStructureDtos.isEmpty()) {
        List<TechnologyBomStructureVo> structureList = technologyBomStructureMapper.listByBomId(routing.getBomId().longValue());
        if (structureList == null || structureList.isEmpty()) {
            return R.fail("请先设置产品结构");
        }
        int count = 0;
        StringBuilder stringBuffer = new StringBuilder();
        for (ProductStructureDto productStructureDto : productStructureDtos) {
            StockInventory stockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, productStructureDto.getProductModelId()));
            //所需数量
            BigDecimal multiply = salesLedgerProduct.getQuantity().multiply(productStructureDto.getUnitQuantity());
            BigDecimal subtract =stockInventory.getQualitity().subtract(stockInventory.getLockedQuantity()).subtract(multiply).divide(BigDecimal.ONE, 2, RoundingMode.CEILING);
            if (subtract.compareTo(BigDecimal.ZERO) <= 0) {
        for (TechnologyBomStructureVo structure : structureList) {
            if (structure.getParentId() == null) {
                continue;
            }
            StockInventory stockInventory = stockInventoryMapper.selectOne(
                    new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, structure.getProductModelId()));
            if (stockInventory == null) {
                count++;
                stringBuffer.append(productStructureDto.getProductName())
                stringBuffer.append(structure.getProductName()).append("-").append(structure.getModel()).append("库存不足").append(System.lineSeparator());
                continue;
            }
            BigDecimal required = salesLedgerProduct.getQuantity().multiply(structure.getUnitQuantity() == null ? BigDecimal.ZERO : structure.getUnitQuantity());
            BigDecimal remain = stockInventory.getQualitity()
                    .subtract(stockInventory.getLockedQuantity())
                    .subtract(required)
                    .divide(BigDecimal.ONE, 2, RoundingMode.CEILING);
            if (remain.compareTo(BigDecimal.ZERO) < 0) {
                count++;
                stringBuffer.append(structure.getProductName())
                        .append("-")
                        .append(productStructureDto.getModel())
                        .append(structure.getModel())
                        .append("库存不足,少")
                        .append(subtract)
                        .append(remain.abs())
                        .append(System.lineSeparator());
            }
        }
        if (count>0) {
        if (count > 0) {
            return R.fail(stringBuffer.toString());
        }else {
            return R.ok();
        }
        return R.ok();
    }
    private String generateNextOrderNo(String datePrefix) {
        QueryWrapper<ProductionOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.likeRight("nps_no", "SC" + datePrefix);
        queryWrapper.orderByDesc("nps_no");
        queryWrapper.last("LIMIT 1");
        ProductionOrder latestOrder = productionOrderMapper.selectOne(queryWrapper);
        int sequence = 1;
        if (latestOrder != null && latestOrder.getNpsNo() != null && !latestOrder.getNpsNo().isEmpty()) {
            String sequenceStr = latestOrder.getNpsNo().substring(("SC" + datePrefix).length());
            try {
                sequence = Integer.parseInt(sequenceStr) + 1;
            } catch (NumberFormatException e) {
                sequence = 1;
            }
        }
        return "SC" + datePrefix + String.format("%04d", sequence);
    }
}