chen.lin
昨天 6e127398cc8b5dcd78a81029f1c747ceee37af18
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/ReviseLogServiceImpl.java
@@ -6,6 +6,7 @@
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.manager.controller.params.ReviseLogParams;
import com.vincent.rsf.server.manager.entity.*;
import com.vincent.rsf.server.manager.enums.AsnExceStatus;
import com.vincent.rsf.server.manager.enums.CommonExceStatus;
import com.vincent.rsf.server.manager.enums.OrderType;
import com.vincent.rsf.server.manager.enums.OrderWorkType;
@@ -17,6 +18,9 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -40,6 +44,12 @@
    @Autowired
    private ReviseLogItemService reviseLogItemService;
    @Autowired
    private OutStockService outStockService;
    @Autowired
    private OutStockItemService outStockItemService;
    /**
     * 库存调整单明细添加
@@ -122,33 +132,164 @@
        if (logItems.isEmpty()) {
            throw new CoolException("调整明细为空!!");
        }
        Map<Long, List<ReviseLogItem>> listMap = logItems.stream().collect(Collectors.groupingBy(ReviseLogItem::getLocId));
        listMap.keySet().forEach(items -> {
            Loc loc = locService.getById(items);
        // 按库位ID分组,如果locId为null则按locCode分组
        Map<String, List<ReviseLogItem>> listMap = logItems.stream()
                .filter(item -> item.getLocCode() != null && !item.getLocCode().isEmpty())
                .collect(Collectors.groupingBy(item -> {
                    // 优先使用locId,如果为null则使用locCode作为key
                    return item.getLocId() != null ? String.valueOf(item.getLocId()) : item.getLocCode();
                }));
        // 优化:在循环外查询所有未完成的出库单和明细,避免重复查询
        // 查询所有未完成的出库单状态:初始化、待处理、生成波次、生成工作档、作业中
        List<WkOrder> outOrders = outStockService.list(new LambdaQueryWrapper<WkOrder>()
                .eq(WkOrder::getType, OrderType.ORDER_OUT.type)
                .in(WkOrder::getExceStatus,
                    AsnExceStatus.OUT_STOCK_STATUS_TASK_INIT.val,
                    AsnExceStatus.OUT_STOCK_STATUS_TASK_EXCE.val,
                    AsnExceStatus.OUT_STOCK_STATUS_TASK_WAVE.val,
                    AsnExceStatus.OUT_STOCK_STATUS_TASK_CREATE.val,
                    AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val));
        // 预先查询所有出库单的明细,建立索引以提高查询效率
        Map<Long, List<WkOrderItem>> orderItemsMap = new HashMap<>();
        Map<Long, Boolean> orderHasItemsMap = new HashMap<>();
        if (!outOrders.isEmpty()) {
            Set<Long> orderIds = outOrders.stream().map(WkOrder::getId).collect(Collectors.toSet());
            List<WkOrderItem> allOrderItems = outStockItemService.list(
                    new LambdaQueryWrapper<WkOrderItem>().in(WkOrderItem::getOrderId, orderIds));
            // 按orderId分组建立索引
            orderItemsMap = allOrderItems.stream()
                    .collect(Collectors.groupingBy(WkOrderItem::getOrderId));
            // 记录每个出库单是否有明细
            for (Long orderId : orderIds) {
                orderHasItemsMap.put(orderId, orderItemsMap.containsKey(orderId) && !orderItemsMap.get(orderId).isEmpty());
            }
        }
        // 使用final变量以便在lambda中使用
        final Map<Long, List<WkOrderItem>> finalOrderItemsMap = orderItemsMap;
        final Map<Long, Boolean> finalOrderHasItemsMap = orderHasItemsMap;
        // 批量收集需要创建的WkOrderItem
        List<WkOrderItem> newOrderItems = new ArrayList<>();
        listMap.keySet().forEach(key -> {
            List<ReviseLogItem> reviseItems = listMap.get(key);
            if (Objects.isNull(reviseItems) || reviseItems.isEmpty()) {
                throw new CoolException("调整明细为空!!");
            }
            // 获取第一个明细的库位信息
            ReviseLogItem firstItem = reviseItems.get(0);
            String locCode = firstItem.getLocCode();
            Long locId = firstItem.getLocId();
            // 查询库位:优先使用locId,如果为null则使用locCode
            Loc loc = null;
            if (locId != null) {
                loc = locService.getById(locId);
            }
            if (loc == null && locCode != null && !locCode.isEmpty()) {
                loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, locCode).eq(Loc::getDeleted, 0));
            }
            if (Objects.isNull(loc)) {
                throw new CoolException("库位不存在!!");
                throw new CoolException("库位不存在!库位编码:" + locCode + ", 库位ID:" + locId);
            }
            List<LocItem> list = locItemService.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocId, loc.getId()));
            if (list.isEmpty()) {
                throw new CoolException("库位:" + loc.getCode() + ", 调整信息为空!!");
            }
            // 删除原库位的库存明细(如果存在)
            locItemService.remove(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocId, loc.getId()));
            listMap.get(items).forEach(logItem -> {
            Loc finalLoc = loc;
            reviseItems.forEach(logItem -> {
                LocItem locDetl = new LocItem();
                BeanUtils.copyProperties(logItem, locDetl);
                locDetl.setLocId(loc.getId())
                locDetl.setLocId(finalLoc.getId())
                        .setType(OrderType.ORDER_REVISE.type)
                        .setWkType(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_STOCK_REVISE.type))
                        .setLocCode(loc.getCode())
                        .setLocCode(finalLoc.getCode())
                        .setAnfme(logItem.getReviseQty())
                        // 如果batch不为空,同时设置splrBatch,以便查询时能匹配
                        .setSplrBatch(StringUtils.isNotBlank(logItem.getBatch()) ? logItem.getBatch() : null)
                        .setUpdateBy(loginUserId)
                        .setId(null)
                        .setCreateBy(loginUserId);
                if (!locItemService.save(locDetl)) {
                    throw new CoolException("库存明细保存失败!!");
                }
                // 为库存调整产生的库存创建对应的WkOrderItem
                // 遍历所有未完成的出库单,检查是否需要这些物料
                for (WkOrder outOrder : outOrders) {
                    // 从预加载的索引中查找该出库单的明细
                    List<WkOrderItem> orderItems = finalOrderItemsMap.getOrDefault(outOrder.getId(), new ArrayList<>());
                    // 检查该出库单是否已有匹配的明细
                    boolean hasMatchingItem = orderItems.stream().anyMatch(item -> {
                        // 物料ID必须匹配
                        if (!Objects.equals(item.getMatnrId(), logItem.getMatnrId())) {
                            return false;
                        }
                        // 如果有批次信息,需要匹配批次
                        if (StringUtils.isNotBlank(logItem.getBatch())) {
                            boolean batchMatch = Objects.equals(item.getBatch(), logItem.getBatch()) ||
                                    Objects.equals(item.getSplrBatch(), logItem.getBatch());
                            if (!batchMatch) {
                                return false;
                            }
                        }
                        // 如果有字段索引,需要匹配
                        if (StringUtils.isNotBlank(logItem.getFieldsIndex())) {
                            if (!Objects.equals(item.getFieldsIndex(), logItem.getFieldsIndex())) {
                                return false;
                            }
                        }
                        return true;
                    });
                    // 如果该出库单需要这个物料但没有对应的明细,则创建
                    if (!hasMatchingItem) {
                        // 为所有未完成的出库单创建WkOrderItem,即使出库单没有其他明细
                        // 因为库存调整的物料可能需要出库
                        WkOrderItem newOrderItem = new WkOrderItem();
                        newOrderItem.setOrderId(outOrder.getId())
                                .setOrderCode(outOrder.getCode())
                                .setMatnrId(logItem.getMatnrId())
                                .setMatnrCode(logItem.getMatnrCode())
                                .setMaktx(logItem.getMaktx())
                                .setBatch(logItem.getBatch())
                                // 如果batch不为空,同时设置splrBatch,以便查询时能匹配
                                .setSplrBatch(StringUtils.isNotBlank(logItem.getBatch()) ? logItem.getBatch() : null)
                                .setFieldsIndex(logItem.getFieldsIndex())
                                .setAnfme(logItem.getReviseQty())
                                .setWorkQty(0.0)
                                .setStockUnit(logItem.getUnit())
                                .setPurUnit(logItem.getUnit())
                                .setSpec(logItem.getSpec())
                                .setModel(logItem.getModel())
                                .setCreateBy(loginUserId)
                                .setUpdateBy(loginUserId)
                                .setCreateTime(new Date())
                                .setUpdateTime(new Date());
                        newOrderItems.add(newOrderItem);
                    }
                }
            });
        });
        // 批量保存WkOrderItem,减少数据库操作次数
        if (!newOrderItems.isEmpty()) {
            if (!outStockItemService.saveBatch(newOrderItems)) {
                throw new CoolException("库存调整单据明细创建失败!!");
            }
        }
        revise.setExceStatus(CommonExceStatus.COMMON_EXCE_STATUS_TASK_DONE.val);
        if (!locReviseService.updateById(revise)) {
            throw new CoolException("调整单修改失败!!");