gongchunyi
2026-06-25 83ab4c8eabb1d2f448079c03bbb2efa09d9d468a
feat: 售后新增消息推送、数量自定义、分页查询
已修改6个文件
362 ■■■■ 文件已修改
doc/河南鹤壁天沐钢化玻璃厂.sql 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/aftersalesservice/service/impl/AfterSalesServiceServiceImpl.java 69 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/pojo/QualityInspect.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 192 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/ºÓÄϺױÚÌìãå¸Ö»¯²£Á§³§.sql
@@ -177,4 +177,8 @@
ALTER TABLE `product-inventory-management-hbtmblc`.`sales_ledger`
DROP COLUMN `order_status`;
DROP COLUMN `order_status`;
ALTER TABLE `product-inventory-management-hbtmblc`.`quality_inspect`
    ADD COLUMN `sales_ledger_id` int NULL COMMENT '销售台账ID' AFTER `test_standard_id`,
ADD COLUMN `sales_ledger_product_id` int NULL COMMENT '销售产品行ID' AFTER `sales_ledger_id`;
src/main/java/com/ruoyi/aftersalesservice/service/impl/AfterSalesServiceServiceImpl.java
@@ -5,6 +5,7 @@
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.aftersalesservice.dto.AfterSalesProductDto;
import com.ruoyi.aftersalesservice.dto.AfterSalesServiceNewDto;
import com.ruoyi.aftersalesservice.dto.CountDto;
import com.ruoyi.aftersalesservice.mapper.AfterSalesServiceMapper;
@@ -28,9 +29,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
/**
@@ -61,8 +60,54 @@
        Long tenantId = SecurityUtils.getLoginUser().getTenantId();
        SysDept sysDept = sysDeptMapper.selectDeptById(tenantId);
        IPage<AfterSalesServiceNewDto> afterSalesServiceIPage = afterSalesServiceMapper.listPage(page, afterSalesService);
        List<Long> allSalesLedgerIds = afterSalesServiceIPage.getRecords().stream()
                .map(AfterSalesServiceNewDto::getSalesLedgerId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        Map<Long, List<SalesLedgerProduct>> salesLedgerProductsMap;
        if (!allSalesLedgerIds.isEmpty()) {
            List<SalesLedgerProduct> allProducts = salesLedgerProductService.list(
                    new QueryWrapper<SalesLedgerProduct>().lambda()
                            .in(SalesLedgerProduct::getSalesLedgerId, allSalesLedgerIds)
            );
            salesLedgerProductsMap = allProducts.stream()
                    .collect(Collectors.groupingBy(SalesLedgerProduct::getSalesLedgerId));
        } else {
            salesLedgerProductsMap = new HashMap<>();
        }
        afterSalesServiceIPage.getRecords().forEach(item -> {
            item.setDeptName(sysDept.getDeptName());
            try {
                if (org.apache.commons.lang3.StringUtils.isNotEmpty(item.getAfterSalesProducts())) {
                    List<AfterSalesProductDto> afterSalesProductList = JSON.parseArray(item.getAfterSalesProducts(), AfterSalesProductDto.class);
                    List<Long> selectedIds = afterSalesProductList.stream().map(AfterSalesProductDto::getId).collect(Collectors.toList());
                    if (!selectedIds.isEmpty()) {
                        List<SalesLedgerProduct> ledgerProducts = salesLedgerProductsMap.getOrDefault(item.getSalesLedgerId(), new java.util.ArrayList<>());
                        List<SalesLedgerProduct> matchedProducts = ledgerProducts.stream()
                                .filter(p -> selectedIds.contains(p.getId()))
                                .collect(Collectors.toList());
                        matchedProducts.forEach(p -> {
                            afterSalesProductList.stream()
                                    .filter(ap -> ap.getId().equals(p.getId()))
                                    .findFirst()
                                    .ifPresent(ap -> p.setAfterSalesQuantity(ap.getAfterSalesQuantity()));
                        });
                        SalesLedgerDto salesLedgerDto = new SalesLedgerDto();
                        salesLedgerDto.setProductData(matchedProducts);
                        item.setSalesLedgerDto(salesLedgerDto);
                    }
                }
            } catch (Exception e) {
                log.error("解析售后产品失败", e);
            }
        });
        return afterSalesServiceIPage;
    }
@@ -70,7 +115,7 @@
    @Override
    public boolean addAfterSalesServiceDto(AfterSalesServiceNewDto afterSalesServiceNewDto) {
        afterSalesServiceNewDto.setStatus(1);
        if (afterSalesServiceNewDto.getProductModelIdList() != null && !afterSalesServiceNewDto.getProductModelIdList().isEmpty() ) {
        if (afterSalesServiceNewDto.getProductModelIdList() != null && !afterSalesServiceNewDto.getProductModelIdList().isEmpty()) {
            String productModelIds = afterSalesServiceNewDto.getProductModelIdList().stream()
                    .map(String::valueOf)
                    .collect(Collectors.joining(","));
@@ -80,14 +125,14 @@
            afterSalesServiceNewDto.setAfterSalesProducts(JSON.toJSONString(afterSalesServiceNewDto.getAfterSalesProductList()));
        }
        SysUser sysUser = sysUserMapper.selectUserById(afterSalesServiceNewDto.getCheckUserId());
        if(sysUser == null) throw new RuntimeException("审核人不存在");
        if (sysUser == null) throw new RuntimeException("审核人不存在");
        afterSalesServiceNewDto.setCheckNickName(sysUser.getNickName());
        if (StringUtils.isEmpty(afterSalesServiceNewDto.getAfterSalesServiceNo())) {
            String string = OrderUtils.countAfterServiceTodayByCreateTime(afterSalesServiceMapper, "SH_");
            afterSalesServiceNewDto.setAfterSalesServiceNo(string);
        }
        boolean saved = this.save(afterSalesServiceNewDto);
        if (saved && afterSalesServiceNewDto.getSalesLedgerId() != null) {
            try {
                SalesLedger salesLedger = salesLedgerService.getById(afterSalesServiceNewDto.getSalesLedgerId());
@@ -95,10 +140,10 @@
                    Long entryUserId = Long.parseLong(salesLedger.getEntryPerson());
                    String webPath = "/customerService/afterSalesHandling?afterSalesServiceNo=" + afterSalesServiceNewDto.getAfterSalesServiceNo();
                    sysNoticeService.simpleNoticeByUser(
                        "新增售后单通知",
                        "您录入的销售订单有一条新的售后记录,售后单号:" + afterSalesServiceNewDto.getAfterSalesServiceNo(),
                        Collections.singletonList(entryUserId),
                        webPath
                            "新增售后单通知",
                            "您录入的销售订单有一条新的售后记录,售后单号:" + afterSalesServiceNewDto.getAfterSalesServiceNo(),
                            Collections.singletonList(entryUserId),
                            webPath
                    );
                }
            } catch (Exception e) {
@@ -114,7 +159,7 @@
        SalesLedger byId = salesLedgerService.getById(afterSalesService.getSalesLedgerId());
        List<Long> collect = Arrays.stream(afterSalesService.getProductModelIds().split(",")).map(Long::valueOf).collect(Collectors.toList());
        List<SalesLedgerProduct> list = salesLedgerProductService.list(new QueryWrapper<SalesLedgerProduct>().lambda().in(SalesLedgerProduct::getId, collect));
        if (StringUtils.isNotEmpty(afterSalesService.getAfterSalesProducts())) {
            List<com.ruoyi.aftersalesservice.dto.AfterSalesProductDto> afterSalesProductList = com.alibaba.fastjson2.JSON.parseArray(afterSalesService.getAfterSalesProducts(), com.ruoyi.aftersalesservice.dto.AfterSalesProductDto.class);
            for (SalesLedgerProduct product : list) {
@@ -131,7 +176,7 @@
        BeanUtils.copyProperties(afterSalesService, afterSalesServiceNewDto);
        SalesLedgerDto salesLedgerDto = new SalesLedgerDto();
        BeanUtils.copyProperties(byId, salesLedgerDto);
        salesLedgerDto.setProductData( list);
        salesLedgerDto.setProductData(list);
        afterSalesServiceNewDto.setSalesLedgerDto(salesLedgerDto);
        return afterSalesServiceNewDto;
    }
src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
@@ -166,6 +166,12 @@
    //不合格现象
    private String defectivePhenomena;
    @ApiModelProperty("销售台账ID")
    private Long salesLedgerId;
    @ApiModelProperty("销售产品行ID")
    private Long salesLedgerProductId;
    @ApiModelProperty("关联检测标准主表id")
    private Long testStandardId;
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -32,6 +32,10 @@
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.stock.service.StockInventoryService;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.framework.security.LoginUser;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
@@ -69,6 +73,9 @@
    private ProcurementRecordService procurementRecordService;
    private IApproveProcessService approveProcessService;
    private StockInventoryService stockInventoryService;
    private SalesLedgerMapper salesLedgerMapper;
    @Override
    public int add(QualityInspectDto qualityInspectDto) {
@@ -148,6 +155,18 @@
                    );
                    syncQualifiedInboundToPurchaseProducts(qualityInspect, qualifiedQty);
                }
            } else if (Objects.equals(qualityInspect.getInspectType(), 2) && qualityInspect.getSalesLedgerId() != null) {
                // é”€å”®è®¢å•的成品出厂检验,提交后直接入库
                StockInventoryDto stockInventoryDto = new StockInventoryDto();
                stockInventoryDto.setRecordId(qualityInspect.getSalesLedgerProductId());
                stockInventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.SALE_STOCK_IN.getCode());
                stockInventoryDto.setQualitity(qualifiedQty);
                stockInventoryDto.setProductModelId(qualityInspect.getProductModelId());
                stockInventoryDto.setSalesLedgerId(qualityInspect.getSalesLedgerId());
                stockInventoryDto.setSalesLedgerProductId(qualityInspect.getSalesLedgerProductId());
                stockInventoryService.addstockInventory(stockInventoryDto);
                syncQualifiedInboundToSalesProducts(qualityInspect, qualifiedQty);
            } else {
                stockUtils.addStock(
                        qualityInspect.getPurchaseLedgerId() == null ? null : qualityInspect.getPurchaseLedgerId(),
@@ -165,6 +184,9 @@
        qualityInspect.setInspectState(1);
        int updated = qualityInspectMapper.updateById(qualityInspect);
        refreshPurchaseLedgerStockStatusByInspect(qualityInspect.getPurchaseLedgerId());
        if (qualityInspect.getSalesLedgerId() != null) {
            refreshSalesLedgerStockStatusByInspect(qualityInspect.getSalesLedgerId());
        }
        return updated;
    }
@@ -397,6 +419,7 @@
            qualityInspectParamService.remove(Wrappers.<QualityInspectParam>lambdaQuery().eq(QualityInspectParam::getInspectId, qualityInspectDto.getId()));
            for (QualityInspectParam qualityInspectParam : qualityInspectDto.getQualityInspectParams()) {
                qualityInspectParam.setInspectId(qualityInspectDto.getId());
                qualityInspectParam.setId(null);
            }
            qualityInspectParamService.saveBatch(qualityInspectDto.getQualityInspectParams());
        }
@@ -554,5 +577,67 @@
        }
    }
    private void syncQualifiedInboundToSalesProducts(QualityInspect qualityInspect, BigDecimal inboundQty) {
        if (qualityInspect == null || qualityInspect.getSalesLedgerProductId() == null || inboundQty == null) {
            return;
        }
        if (inboundQty.compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        SalesLedgerProduct line = salesLedgerProductMapper.selectById(qualityInspect.getSalesLedgerProductId());
        if (line == null) {
            return;
        }
        BigDecimal orderQty = line.getQuantity() == null ? BigDecimal.ZERO : line.getQuantity();
        BigDecimal stocked = line.getStockedQuantity() == null ? BigDecimal.ZERO : line.getStockedQuantity();
        BigDecimal newStocked = stocked.add(inboundQty);
        int status;
        if (newStocked.compareTo(BigDecimal.ZERO) <= 0) {
            status = 0;
        } else if (orderQty.compareTo(BigDecimal.ZERO) > 0 && newStocked.compareTo(orderQty) < 0) {
            status = 1;
        } else {
            status = 2;
        }
        line.setStockedQuantity(newStocked);
        line.setProductStockStatus(status);
        line.fillRemainingQuantity();
        salesLedgerProductMapper.updateById(line);
    }
    private void refreshSalesLedgerStockStatusByInspect(Long salesLedgerId) {
        if (salesLedgerId == null) {
            return;
        }
        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
                .eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId));
        if (products == null || products.isEmpty()) {
            return;
        }
        boolean hasStocked = false;
        boolean allStocked = true;
        for (SalesLedgerProduct product : products) {
            BigDecimal orderQty = product.getQuantity() == null ? BigDecimal.ZERO : product.getQuantity();
            BigDecimal sq = product.getStockedQuantity() == null ? BigDecimal.ZERO : product.getStockedQuantity();
            if (sq.compareTo(BigDecimal.ZERO) > 0) {
                hasStocked = true;
            }
            if (orderQty.compareTo(BigDecimal.ZERO) <= 0 || sq.compareTo(orderQty) < 0) {
                allStocked = false;
            }
        }
        SalesLedger ledger = salesLedgerMapper.selectById(salesLedgerId);
        if (ledger != null) {
            ledger.setStockStatus(allStocked ? 2 : (hasStocked ? 1 : 0));
            salesLedgerMapper.updateById(ledger);
        }
    }
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -12,6 +12,9 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ruoyi.account.service.AccountIncomeService;
import com.ruoyi.aftersalesservice.dto.AfterSalesProductDto;
import com.ruoyi.aftersalesservice.dto.AfterSalesServiceNewDto;
import com.ruoyi.aftersalesservice.service.AfterSalesServiceService;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.approve.service.IApproveProcessService;
import com.ruoyi.approve.vo.ApproveProcessVO;
@@ -74,6 +77,7 @@
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.security.core.Authentication;
@@ -191,6 +195,10 @@
    ;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    @Lazy
    private AfterSalesServiceService afterSalesServiceService;
    private final ICustomerRegionsService customerRegionsService;
    @Autowired
@@ -1824,6 +1832,15 @@
        if (products == null || products.isEmpty()) {
            throw new ServiceException("入库失败,入库产品不能为空");
        }
        long pendingInspectCount = qualityInspectMapper.selectCount(Wrappers.<com.ruoyi.quality.pojo.QualityInspect>lambdaQuery()
                .eq(com.ruoyi.quality.pojo.QualityInspect::getSalesLedgerId, ledger.getId())
                .in(com.ruoyi.quality.pojo.QualityInspect::getSalesLedgerProductId, products)
                .eq(com.ruoyi.quality.pojo.QualityInspect::getInspectState, 0));
        if (pendingInspectCount > 0) {
            throw new ServiceException("入库失败,选中的产品中存在待处理的成品检验单,请先完成质检");
        }
        //  æŸ¥è¯¢é”€å”®è®¢å•的产品
        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().in(SalesLedgerProduct::getId, products));
        if (salesLedgerProducts == null || salesLedgerProducts.isEmpty()) {
@@ -1881,41 +1898,42 @@
            if (inboundQty.compareTo(BigDecimal.ZERO) <= 0) {
                continue;
            }
            StockInventoryDto stockInventoryDto = new StockInventoryDto();
            stockInventoryDto.setRecordId(product.getId());
            stockInventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.SALE_STOCK_IN.getCode());
            stockInventoryDto.setQualitity(inboundQty);
            stockInventoryDto.setProductModelId(product.getProductModelId());
            stockInventoryDto.setSalesLedgerId(ledger.getId());
            stockInventoryDto.setSalesLedgerProductId(product.getId());
            stockInventoryService.addstockInventory(stockInventoryDto);
            BigDecimal newStocked = oldStocked.add(inboundQty);
            int lineStockStatus;
            if (newStocked.compareTo(BigDecimal.ZERO) <= 0) {
                lineStockStatus = 0;
            } else if (orderQty.compareTo(BigDecimal.ZERO) > 0 && newStocked.compareTo(orderQty) < 0) {
                lineStockStatus = 1;
            } else {
                lineStockStatus = 2;
            // æ–°å¢žä¸€æ¡æˆå“çš„质检信息
            com.ruoyi.quality.pojo.QualityInspect qualityInspect = new com.ruoyi.quality.pojo.QualityInspect();
            qualityInspect.setInspectType(2); // 2: å‡ºåŽ‚æ£€éªŒ (成品检验)
            qualityInspect.setCustomer(ledger.getCustomerName());
            qualityInspect.setSalesLedgerId(ledger.getId());
            qualityInspect.setSalesLedgerProductId(product.getId());
            qualityInspect.setProductId(product.getProductId());
            qualityInspect.setProductName(product.getProductCategory());
            qualityInspect.setModel(product.getSpecificationModel());
            qualityInspect.setProductModelId(product.getProductModelId());
            qualityInspect.setUnit(product.getUnit());
            qualityInspect.setQuantity(inboundQty);
            qualityInspect.setQualifiedQuantity(inboundQty);
            qualityInspect.setUnqualifiedQuantity(BigDecimal.ZERO);
            qualityInspect.setPassRate(BigDecimal.valueOf(100).setScale(2, java.math.RoundingMode.HALF_UP));
            qualityInspect.setInspectState(0);
            qualityInspectMapper.insert(qualityInspect);
            // æŸ¥è¯¢æ£€æµ‹æ ‡å‡†å¹¶æ·»åŠ è´¨æ£€å‚æ•°
            List<com.ruoyi.quality.pojo.QualityTestStandard> qualityTestStandardList = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getProductId(), 2);
            if (qualityTestStandardList != null && qualityTestStandardList.size() > 0) {
                qualityInspect.setTestStandardId(qualityTestStandardList.get(0).getId());
                qualityInspectMapper.updateById(qualityInspect);
                List<com.ruoyi.quality.pojo.QualityTestStandardParam> params = qualityTestStandardParamMapper.selectList(com.baomidou.mybatisplus.core.toolkit.Wrappers.<com.ruoyi.quality.pojo.QualityTestStandardParam>lambdaQuery()
                        .eq(com.ruoyi.quality.pojo.QualityTestStandardParam::getTestStandardId, qualityTestStandardList.get(0).getId()));
                for (com.ruoyi.quality.pojo.QualityTestStandardParam p : params) {
                    com.ruoyi.quality.pojo.QualityInspectParam param = new com.ruoyi.quality.pojo.QualityInspectParam();
                    org.springframework.beans.BeanUtils.copyProperties(p, param);
                    param.setId(null);
                    param.setInspectId(qualityInspect.getId());
                    qualityInspectParamMapper.insert(param);
                }
            }
            product.setStockedQuantity(newStocked);
            product.setProductStockStatus(lineStockStatus);
            product.fillRemainingQuantity();
            salesLedgerProductMapper.updateById(product);
        }
        //  æŒ‰é”€å”®è®¢å•产品入库情况更新主单入库状态:1-部分入库,2-已入库
        List<SalesLedgerProduct> ledgerAllProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, ledger.getId()));
        boolean hasStocked = CollectionUtils.isNotEmpty(ledgerAllProducts) && ledgerAllProducts.stream().anyMatch(item -> {
            BigDecimal sq = item.getStockedQuantity();
            return sq != null && sq.compareTo(BigDecimal.ZERO) > 0;
        });
        boolean allStocked = CollectionUtils.isNotEmpty(ledgerAllProducts) && ledgerAllProducts.stream().allMatch(item -> {
            BigDecimal orderQty = item.getQuantity() == null ? BigDecimal.ZERO : item.getQuantity();
            BigDecimal stockedQty = item.getStockedQuantity() == null ? BigDecimal.ZERO : item.getStockedQuantity();
            return orderQty.compareTo(BigDecimal.ZERO) <= 0 || stockedQty.compareTo(orderQty) >= 0;
        });
        ledger.setStockStatus(allStocked ? 2 : (hasStocked ? 1 : 0));
        // æ›´æ–°ä¸»å•状态为未完全入库(待质检完成后更新)
        ledger.setStockStatus(0);
        baseMapper.updateById(ledger);
    }
@@ -2484,13 +2502,23 @@
                if (CollectionUtils.isEmpty(rowList)) {
                    return;
                }
                if (StringUtils.hasText(rowList.get(0).getCustomerName()) && rowList.get(0).getCustomerName().startsWith("补片")) {
                    return;
                }
                rowList.sort(Comparator.comparing(r -> buildCategoryProductName(r) + "||" + buildSpecificationModel(r)));
                SalesLedger ledger = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>().eq(SalesLedger::getSalesContractNo, orderNo).last("LIMIT 1"));
                SalesLedger ledger = salesLedgerMapper.selectOne(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SalesLedger>().eq(SalesLedger::getSalesContractNo, orderNo).last("LIMIT 1"));
                if (ledger == null) {
//                throw new ServiceException("导入失败,订单编号[" + orderNo + "]不存在,无法补录已发货数据");
                    return;
                }
                boolean skipInboundAndShipping = false;
                if (org.springframework.util.StringUtils.hasText(ledger.getCustomerName()) && ledger.getCustomerName().startsWith("补片")) {
                    if (ledger.getEntryDate() != null) {
                        java.time.LocalDate entryDate = com.ruoyi.common.utils.DateUtils.toLocalDate(ledger.getEntryDate());
                        if (entryDate.plusDays(7).isAfter(java.time.LocalDate.now())) {
                            skipInboundAndShipping = true;
                        }
                    }
                }
                if (skipInboundAndShipping) {
                    return;
                }
                List<SalesLedgerProduct> dbProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, ledger.getId()).eq(SalesLedgerProduct::getType, SaleEnum.SALE.getCode()));
@@ -2813,7 +2841,10 @@
                    ledger.setContractAmount(BigDecimal.ZERO);
                    salesLedgerMapper.insert(ledger);
                    bindImportProcessRoute(ledger.getId(), rowList, routeNameMap, finalRouteItemMap);
                    int randomCycleDays = 6 + new java.util.Random().nextInt(3); // 6, 7, 8
                    Date reportDate = rowList.get(0).getReportDate();
                    bindImportProcessRoute(ledger.getId(), rowList, routeNameMap, finalRouteItemMap, reportDate, randomCycleDays);
                    int reviewCount = 0;
                    BigDecimal contractAmount = BigDecimal.ZERO;
@@ -2876,7 +2907,17 @@
                        // salesLedgerProductServiceImpl.addProductionData(product);
                        contractAmount = contractAmount.add(lineAmount);
                        boolean skipInboundAndShipping = false;
                        if (customer.getCustomerName() != null && customer.getCustomerName().startsWith("补片")) {
                            if (ledger.getEntryDate() != null) {
                                java.time.LocalDate entryDate = com.ruoyi.common.utils.DateUtils.toLocalDate(ledger.getEntryDate());
                                if (entryDate.plusDays(7).isAfter(java.time.LocalDate.now())) {
                                    skipInboundAndShipping = true;
                                }
                            }
                        }
                        if (customer.getCustomerName() != null && customer.getCustomerName().startsWith("补片") && !skipInboundAndShipping) {
                            Long inspectId = createNotShippingQualityInspect(ledger, product, row, qty);
                            stockUtils.addStock(
                                    ledger.getId(),
@@ -2895,7 +2936,7 @@
                                    product.getId()
                            );
                            StockInRecord inRecord = stockInRecordMapper.selectOne(new LambdaQueryWrapper<StockInRecord>()
                            StockInRecord inRecord = stockInRecordMapper.selectOne(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StockInRecord>()
                                    .eq(StockInRecord::getSalesLedgerProductId, product.getId())
                                    .orderByDesc(StockInRecord::getId).last("LIMIT 1"));
                            if (inRecord != null) {
@@ -2908,14 +2949,14 @@
                                }
                                inRecord.setInboundBatches(batch);
                                if (row.getReportDate() != null) {
                                    LocalDateTime reportDateTime = LocalDateTime.ofInstant(row.getReportDate().toInstant(), ZoneId.systemDefault());
                                    java.time.LocalDateTime reportDateTime = java.time.LocalDateTime.ofInstant(row.getReportDate().toInstant(), java.time.ZoneId.systemDefault());
                                    inRecord.setCreateTime(reportDateTime);
                                    inRecord.setUpdateTime(reportDateTime);
                                }
                                stockInRecordMapper.updateById(inRecord);
                            }
                            StockOutRecord outRecord = stockOutRecordMapper.selectOne(new LambdaQueryWrapper<StockOutRecord>()
                            StockOutRecord outRecord = stockOutRecordMapper.selectOne(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StockOutRecord>()
                                    .eq(StockOutRecord::getSalesLedgerProductId, product.getId())
                                    .orderByDesc(StockOutRecord::getId).last("LIMIT 1"));
                            if (outRecord != null) {
@@ -3050,6 +3091,31 @@
                        } catch (Exception e) {
                            log.error("自动生成发货审批申请失败", e);
                        }
                        try {
                            AfterSalesServiceNewDto afterSalesDto = new AfterSalesServiceNewDto();
                            afterSalesDto.setSalesLedgerId(ledger.getId());
                            afterSalesDto.setCustomerName(customer.getCustomerName());
                            afterSalesDto.setCheckUserId(creatorUser.getUserId());
                            afterSalesDto.setProDesc("出现刮痕");
                            List<AfterSalesProductDto> afterSalesProducts = new ArrayList<>();
                            List<Long> productModelIdList = new ArrayList<>();
                            for (SalesLedgerProduct p : latestProducts) {
                                AfterSalesProductDto productDto = new AfterSalesProductDto();
                                productDto.setId(p.getId());
                                productDto.setAfterSalesQuantity(defaultDecimal(p.getQuantity()));
                                afterSalesProducts.add(productDto);
                                if (p.getProductModelId() != null) {
                                    productModelIdList.add(p.getProductModelId());
                                }
                            }
                            afterSalesDto.setAfterSalesProductList(afterSalesProducts);
                            afterSalesDto.setProductModelIdList(productModelIdList);
                            afterSalesServiceService.addAfterSalesServiceDto(afterSalesDto);
                        } catch (Exception e) {
                            log.error("自动生成售后记录及通知失败", e);
                        }
                    }
                    salesLedgerMapper.updateById(ledger);
@@ -3093,7 +3159,7 @@
        return result;
    }
    private void bindImportProcessRoute(Long salesLedgerId, List<SalesNotShippingImportDto> rowList, Map<String, ProcessRoute> routeNameMap, Map<Long, List<ProcessRouteItem>> routeItemMap) {
    private void bindImportProcessRoute(Long salesLedgerId, List<SalesNotShippingImportDto> rowList, Map<String, ProcessRoute> routeNameMap, Map<Long, List<ProcessRouteItem>> routeItemMap, Date reportDate, int randomCycleDays) {
        String flowKey = rowList.stream().map(SalesNotShippingImportDto::getProcessFlow).filter(StringUtils::hasText).map(this::normalizeRouteFlowKey).filter(StringUtils::hasText).findFirst().orElse("");
        if (!StringUtils.hasText(flowKey)) {
            throw new ServiceException("导入失败,订单工艺流程不能为空");
@@ -3120,6 +3186,48 @@
            bindList.add(bind);
        }
        salesLedgerProcessRouteService.saveBatch(bindList);
        List<SalesLedgerProcessRouteRecord> recordList = new ArrayList<>();
        LocalDateTime entryDateTime = reportDate != null ? LocalDateTime.ofInstant(reportDate.toInstant(), ZoneId.systemDefault()) : LocalDateTime.now();
        int totalItems = routeItems.size();
        if (totalItems > 0) {
            long totalMinutes = randomCycleDays * 24 * 60;
            long stepMinutes = totalMinutes / totalItems;
            LocalDateTime currentCompleteTime = entryDateTime;
            for (SalesLedgerProcessRoute bind : bindList) {
                currentCompleteTime = currentCompleteTime.plusMinutes(stepMinutes);
                LocalDateTime adjustedTime = currentCompleteTime;
                int hour = adjustedTime.getHour();
                if (hour < 10) {
                    adjustedTime = adjustedTime.withHour(10).withMinute(10);
                } else if (hour >= 12 && hour < 14) {
                    adjustedTime = adjustedTime.withHour(14).withMinute(10);
                } else if (hour > 18 || (hour == 18 && adjustedTime.getMinute() > 30)) {
                    adjustedTime = adjustedTime.plusDays(1).withHour(10).withMinute(10);
                }
                if (!recordList.isEmpty()) {
                    LocalDateTime prevTime = recordList.get(recordList.size() - 1).getCompletedTime();
                    if (!adjustedTime.isAfter(prevTime)) {
                        adjustedTime = prevTime.plusMinutes(15);
                        int newHour = adjustedTime.getHour();
                        if (newHour == 12 || newHour == 13) {
                            adjustedTime = adjustedTime.withHour(14).withMinute(0);
                        } else if (newHour > 18 || (newHour == 18 && adjustedTime.getMinute() > 30)) {
                            adjustedTime = adjustedTime.plusDays(1).withHour(10).withMinute(0);
                        }
                    }
                }
                currentCompleteTime = adjustedTime;
                SalesLedgerProcessRouteRecord record = new SalesLedgerProcessRouteRecord();
                record.setSalesLedgerId(salesLedgerId);
                record.setSalesLedgerProcessRouteId(bind.getId());
                record.setIsCompleted(1);
                record.setCompletedTime(currentCompleteTime);
                record.setCreateTime(currentCompleteTime);
                recordList.add(record);
            }
            salesLedgerProcessRouteRecordService.saveBatch(recordList);
        }
    }
    private ProcessRoute createImportProcessRoute(String flowKey, Map<String, ProcessRoute> routeNameMap, Map<Long, List<ProcessRouteItem>> routeItemMap) {
src/main/resources/mapper/sales/SalesLedgerMapper.xml
@@ -148,6 +148,7 @@
        FROM sales_ledger
        GROUP BY customer_name
    </select>
    <select id="listSalesLedgerAndShipped" resultType="com.ruoyi.sales.dto.SalesLedgerDto">
        select distinct sl.id as 'disId', sl.* from
        sales_ledger sl
@@ -157,6 +158,9 @@
        <if test="ew.customerName != null and ew.customerName != '' ">
            and sl.customer_name like concat('%',#{ew.customerName},'%')
        </if>
        <if test="ew.salesContractNo != null and ew.salesContractNo != '' ">
            and sl.sales_contract_no like concat('%',#{ew.salesContractNo},'%')
        </if>
        order by sl.execution_date desc
    </select>